From 0e4d8d03125b5b7c471bb4ab5130563afbd0b52d Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 1 Mar 2024 21:24:42 +0800 Subject: [PATCH 001/211] Using Required-start/stop to improve init script --- packages/clickhouse-server.init | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/clickhouse-server.init b/packages/clickhouse-server.init index f215e52b6f3..0ac9cf7ae1f 100755 --- a/packages/clickhouse-server.init +++ b/packages/clickhouse-server.init @@ -1,10 +1,11 @@ #!/bin/sh ### BEGIN INIT INFO # Provides: clickhouse-server +# Required-Start: $network +# Required-Stop: $network +# Should-Start: $time # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 -# Should-Start: $time $network -# Should-Stop: $network # Short-Description: clickhouse-server daemon ### END INIT INFO # From 06524e330fe9320aedf680e335099efd83a62cbf Mon Sep 17 00:00:00 2001 From: anonymous Date: Tue, 23 Apr 2024 20:54:23 +0800 Subject: [PATCH 002/211] add TableFunctionLoop --- src/TableFunctions/TableFunctionLoop.cpp | 126 ++++++++++++++++++ src/TableFunctions/registerTableFunctions.cpp | 1 + src/TableFunctions/registerTableFunctions.h | 1 + 3 files changed, 128 insertions(+) create mode 100644 src/TableFunctions/TableFunctionLoop.cpp diff --git a/src/TableFunctions/TableFunctionLoop.cpp b/src/TableFunctions/TableFunctionLoop.cpp new file mode 100644 index 00000000000..059a30ca7b0 --- /dev/null +++ b/src/TableFunctions/TableFunctionLoop.cpp @@ -0,0 +1,126 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "registerTableFunctions.h" + +#include + +namespace DB +{ +namespace ErrorCodes +{ + extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; + extern const int ILLEGAL_TYPE_OF_ARGUMENT; + extern const int UNKNOWN_TABLE; +} +namespace +{ +class TableFunctionLoop : public ITableFunction{ +public: + static constexpr auto name = "loop"; + std::string getName() const override { return name; } +private: + StoragePtr executeImpl(const ASTPtr & ast_function, ContextPtr context, const String & table_name, ColumnsDescription cached_columns, bool is_insert_query) const override; + const char * getStorageTypeName() const override { return "Loop"; } + ColumnsDescription getActualTableStructure(ContextPtr context, bool is_insert_query) const override; + void parseArguments(const ASTPtr & ast_function, ContextPtr context) override; + + // save the inner table function AST + ASTPtr inner_table_function_ast; + // save database and table + std::string database_name_; + std::string table_name_; +}; + +} + +void TableFunctionLoop::parseArguments(const ASTPtr & ast_function, ContextPtr context) +{ + const auto & args_func = ast_function->as(); + + if (!args_func.arguments) + throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Table function 'loop' must have arguments."); + + auto & args = args_func.arguments->children; + if (args.empty()) + throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "No arguments provided for table function 'loop'"); + + // loop(database, table) + if (args.size() == 2) + { + args[0] = evaluateConstantExpressionForDatabaseName(args[0], context); + args[1] = evaluateConstantExpressionOrIdentifierAsLiteral(args[1], context); + + database_name_ = checkAndGetLiteralArgument(args[0], "database"); + table_name_ = checkAndGetLiteralArgument(args[1], "table"); + /*if (const auto * lit = args[0]->as()) + database_name_ = lit->value.safeGet(); + else + throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Expected literal for argument 1 of function 'loop', got {}", args[0]->getID()); + + if (const auto * lit = args[1]->as()) + table_name_ = lit->value.safeGet(); + else + throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Expected literal for argument 2 of function 'loop', got {}", args[1]->getID());*/ + } + // loop(other_table_function(...)) + else if (args.size() == 1) + inner_table_function_ast = args[0]; + + else + throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Table function 'loop' must have 1 or 2 arguments."); +} + +ColumnsDescription TableFunctionLoop::getActualTableStructure(ContextPtr context, bool is_insert_query) const +{ + auto inner_table_function = TableFunctionFactory::instance().get(inner_table_function_ast, context); + + return inner_table_function->getActualTableStructure(context, is_insert_query); + +} + +StoragePtr TableFunctionLoop::executeImpl( + const ASTPtr & /*ast_function*/, + ContextPtr context, + const std::string & table_name, + ColumnsDescription cached_columns, + bool is_insert_query) const +{ + StoragePtr storage; + if (!database_name_.empty() && !table_name_.empty()) + { + auto database = DatabaseCatalog::instance().getDatabase(database_name_); + storage = database->tryGetTable(table_name_ ,context); + if (!storage) + throw Exception(ErrorCodes::UNKNOWN_TABLE, "Table '{}' not found in database '{}'", table_name_, database_name_); + } + else + { + auto inner_table_function = TableFunctionFactory::instance().get(inner_table_function_ast, context); + storage = inner_table_function->execute( + inner_table_function_ast, + context, + table_name, + std::move(cached_columns), + is_insert_query); + } + + return storage; +} + +void registerTableFunctionLoop(TableFunctionFactory & factory) +{ + factory.registerFunction(); +} + +} diff --git a/src/TableFunctions/registerTableFunctions.cpp b/src/TableFunctions/registerTableFunctions.cpp index 927457ff9f6..f5d2160fc55 100644 --- a/src/TableFunctions/registerTableFunctions.cpp +++ b/src/TableFunctions/registerTableFunctions.cpp @@ -11,6 +11,7 @@ void registerTableFunctions() registerTableFunctionMerge(factory); registerTableFunctionRemote(factory); registerTableFunctionNumbers(factory); + registerTableFunctionLoop(factory); registerTableFunctionGenerateSeries(factory); registerTableFunctionNull(factory); registerTableFunctionZeros(factory); diff --git a/src/TableFunctions/registerTableFunctions.h b/src/TableFunctions/registerTableFunctions.h index 296af146faf..f9a68918bbf 100644 --- a/src/TableFunctions/registerTableFunctions.h +++ b/src/TableFunctions/registerTableFunctions.h @@ -8,6 +8,7 @@ class TableFunctionFactory; void registerTableFunctionMerge(TableFunctionFactory & factory); void registerTableFunctionRemote(TableFunctionFactory & factory); void registerTableFunctionNumbers(TableFunctionFactory & factory); +void registerTableFunctionLoop(TableFunctionFactory & factory); void registerTableFunctionGenerateSeries(TableFunctionFactory & factory); void registerTableFunctionNull(TableFunctionFactory & factory); void registerTableFunctionZeros(TableFunctionFactory & factory); From 2d02deb2a22e691e216848394651d501352356bf Mon Sep 17 00:00:00 2001 From: anonymous Date: Wed, 24 Apr 2024 16:11:14 +0800 Subject: [PATCH 003/211] Trivial count optimization is disabled --- src/Storages/StorageLoop.cpp | 63 +++++++++++++++++++++ src/Storages/StorageLoop.h | 33 +++++++++++ src/Storages/registerStorages.cpp | 2 + src/TableFunctions/TableFunctionLoop.cpp | 72 ++++++++++++++++-------- 4 files changed, 145 insertions(+), 25 deletions(-) create mode 100644 src/Storages/StorageLoop.cpp create mode 100644 src/Storages/StorageLoop.h diff --git a/src/Storages/StorageLoop.cpp b/src/Storages/StorageLoop.cpp new file mode 100644 index 00000000000..5f3023364fe --- /dev/null +++ b/src/Storages/StorageLoop.cpp @@ -0,0 +1,63 @@ +#include "StorageLoop.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace DB +{ +namespace ErrorCodes +{ +extern const int UNKNOWN_TABLE; +} +StorageLoop::StorageLoop( + const StorageID & table_id_, + StoragePtr inner_storage_) + : IStorage(table_id_) + , inner_storage(std::move(inner_storage_)) +{ + StorageInMemoryMetadata storage_metadata = inner_storage->getInMemoryMetadata(); + setInMemoryMetadata(storage_metadata); +} + + +void StorageLoop::read( + QueryPlan & query_plan, + const Names & column_names, + const StorageSnapshotPtr & storage_snapshot, + SelectQueryInfo & query_info, + ContextPtr context, + QueryProcessingStage::Enum processed_stage, + size_t max_block_size, + size_t num_streams) +{ + + query_info.optimize_trivial_count = false; + + inner_storage->read(query_plan, + column_names, + storage_snapshot, + query_info, + context, + processed_stage, + max_block_size, + num_streams); +} + +void registerStorageLoop(StorageFactory & factory) +{ + factory.registerStorage("Loop", [](const StorageFactory::Arguments & args) + { + StoragePtr inner_storage; + return std::make_shared(args.table_id, inner_storage); + }); +} +} diff --git a/src/Storages/StorageLoop.h b/src/Storages/StorageLoop.h new file mode 100644 index 00000000000..869febc9f31 --- /dev/null +++ b/src/Storages/StorageLoop.h @@ -0,0 +1,33 @@ +#pragma once +#include "config.h" +#include + + +namespace DB +{ + +class StorageLoop final : public IStorage +{ +public: + StorageLoop( + const StorageID & table_id, + StoragePtr inner_storage_); + + std::string getName() const override { return "Loop"; } + + void read( + QueryPlan & query_plan, + const Names & column_names, + const StorageSnapshotPtr & storage_snapshot, + SelectQueryInfo & query_info, + ContextPtr context, + QueryProcessingStage::Enum processed_stage, + size_t max_block_size, + size_t num_streams) override; + + bool supportsTrivialCountOptimization(const StorageSnapshotPtr &, ContextPtr) const override { return false; } + +private: + StoragePtr inner_storage; +}; +} diff --git a/src/Storages/registerStorages.cpp b/src/Storages/registerStorages.cpp index dea9feaf28b..31789e4351f 100644 --- a/src/Storages/registerStorages.cpp +++ b/src/Storages/registerStorages.cpp @@ -25,6 +25,7 @@ void registerStorageLiveView(StorageFactory & factory); void registerStorageGenerateRandom(StorageFactory & factory); void registerStorageExecutable(StorageFactory & factory); void registerStorageWindowView(StorageFactory & factory); +void registerStorageLoop(StorageFactory & factory); #if USE_RAPIDJSON || USE_SIMDJSON void registerStorageFuzzJSON(StorageFactory & factory); #endif @@ -126,6 +127,7 @@ void registerStorages() registerStorageGenerateRandom(factory); registerStorageExecutable(factory); registerStorageWindowView(factory); + registerStorageLoop(factory); #if USE_RAPIDJSON || USE_SIMDJSON registerStorageFuzzJSON(factory); #endif diff --git a/src/TableFunctions/TableFunctionLoop.cpp b/src/TableFunctions/TableFunctionLoop.cpp index 059a30ca7b0..2b717d7194b 100644 --- a/src/TableFunctions/TableFunctionLoop.cpp +++ b/src/TableFunctions/TableFunctionLoop.cpp @@ -1,20 +1,17 @@ #include "config.h" #include #include -#include #include #include +#include #include +#include #include -#include #include #include -#include -#include +#include #include "registerTableFunctions.h" -#include - namespace DB { namespace ErrorCodes @@ -55,30 +52,45 @@ void TableFunctionLoop::parseArguments(const ASTPtr & ast_function, ContextPtr c if (args.empty()) throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "No arguments provided for table function 'loop'"); + if (args.size() == 1) + { + if (const auto * id = args[0]->as()) + { + String id_name = id->name(); + + size_t dot_pos = id_name.find('.'); + if (dot_pos != String::npos) + { + database_name_ = id_name.substr(0, dot_pos); + table_name_ = id_name.substr(dot_pos + 1); + } + else + { + table_name_ = id_name; + } + } + else if (const auto * func = args[0]->as()) + { + inner_table_function_ast = args[0]; + } + else + { + throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Expected identifier or function for argument 1 of function 'loop', got {}", args[0]->getID()); + } + } // loop(database, table) - if (args.size() == 2) + else if (args.size() == 2) { args[0] = evaluateConstantExpressionForDatabaseName(args[0], context); args[1] = evaluateConstantExpressionOrIdentifierAsLiteral(args[1], context); database_name_ = checkAndGetLiteralArgument(args[0], "database"); table_name_ = checkAndGetLiteralArgument(args[1], "table"); - /*if (const auto * lit = args[0]->as()) - database_name_ = lit->value.safeGet(); - else - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Expected literal for argument 1 of function 'loop', got {}", args[0]->getID()); - - if (const auto * lit = args[1]->as()) - table_name_ = lit->value.safeGet(); - else - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Expected literal for argument 2 of function 'loop', got {}", args[1]->getID());*/ } - // loop(other_table_function(...)) - else if (args.size() == 1) - inner_table_function_ast = args[0]; - else + { throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Table function 'loop' must have 1 or 2 arguments."); + } } ColumnsDescription TableFunctionLoop::getActualTableStructure(ContextPtr context, bool is_insert_query) const @@ -97,13 +109,18 @@ StoragePtr TableFunctionLoop::executeImpl( bool is_insert_query) const { StoragePtr storage; - if (!database_name_.empty() && !table_name_.empty()) + if (!table_name_.empty()) { - auto database = DatabaseCatalog::instance().getDatabase(database_name_); + String database_name = database_name_; + if (database_name.empty()) + database_name = context->getCurrentDatabase(); + + auto database = DatabaseCatalog::instance().getDatabase(database_name); storage = database->tryGetTable(table_name_ ,context); if (!storage) - throw Exception(ErrorCodes::UNKNOWN_TABLE, "Table '{}' not found in database '{}'", table_name_, database_name_); + throw Exception(ErrorCodes::UNKNOWN_TABLE, "Table '{}' not found in database '{}'", table_name_, database_name); } + else { auto inner_table_function = TableFunctionFactory::instance().get(inner_table_function_ast, context); @@ -114,8 +131,13 @@ StoragePtr TableFunctionLoop::executeImpl( std::move(cached_columns), is_insert_query); } - - return storage; + auto res = std::make_shared( + StorageID(getDatabaseName(), table_name), + storage + ); + res->startup(); + return res; + // return storage; } void registerTableFunctionLoop(TableFunctionFactory & factory) From 402bbb9f53f76d346016f9929bf6b31c10c640a6 Mon Sep 17 00:00:00 2001 From: anonymous Date: Wed, 24 Apr 2024 17:29:56 +0800 Subject: [PATCH 004/211] debug --- src/Storages/StorageLoop.cpp | 2 +- src/TableFunctions/TableFunctionLoop.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Storages/StorageLoop.cpp b/src/Storages/StorageLoop.cpp index 5f3023364fe..069a92ece8c 100644 --- a/src/Storages/StorageLoop.cpp +++ b/src/Storages/StorageLoop.cpp @@ -16,7 +16,7 @@ namespace DB { namespace ErrorCodes { -extern const int UNKNOWN_TABLE; + } StorageLoop::StorageLoop( const StorageID & table_id_, diff --git a/src/TableFunctions/TableFunctionLoop.cpp b/src/TableFunctions/TableFunctionLoop.cpp index 2b717d7194b..bfe0711384d 100644 --- a/src/TableFunctions/TableFunctionLoop.cpp +++ b/src/TableFunctions/TableFunctionLoop.cpp @@ -137,7 +137,6 @@ StoragePtr TableFunctionLoop::executeImpl( ); res->startup(); return res; - // return storage; } void registerTableFunctionLoop(TableFunctionFactory & factory) From 42fe5be400b26494b02460f34e9117879ce4d2f8 Mon Sep 17 00:00:00 2001 From: Sariel <1059293451@qq.com> Date: Thu, 25 Apr 2024 11:30:19 +0800 Subject: [PATCH 005/211] add loop --- src/Storages/StorageLoop.cpp | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/Storages/StorageLoop.cpp b/src/Storages/StorageLoop.cpp index 069a92ece8c..d106a6812ac 100644 --- a/src/Storages/StorageLoop.cpp +++ b/src/Storages/StorageLoop.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include namespace DB @@ -39,17 +41,26 @@ void StorageLoop::read( size_t max_block_size, size_t num_streams) { - query_info.optimize_trivial_count = false; + QueryPlan temp_query_plan(std::move(query_plan)); + for (size_t i = 0; i < 10; ++i) + { + QueryPlan swapped_query_plan; + std::swap(temp_query_plan, swapped_query_plan); - inner_storage->read(query_plan, - column_names, - storage_snapshot, - query_info, - context, - processed_stage, - max_block_size, - num_streams); + inner_storage->read(temp_query_plan, + column_names, + storage_snapshot, + query_info, + context, + processed_stage, + max_block_size, + num_streams); + + // std::cout << "Loop iteration: " << (i + 1) << std::endl; + + } + query_plan = std::move(temp_query_plan); } void registerStorageLoop(StorageFactory & factory) From 1d089eac089ecde7e76b7838e15635ae5e089ce1 Mon Sep 17 00:00:00 2001 From: Sariel <1059293451@qq.com> Date: Thu, 25 Apr 2024 11:35:35 +0800 Subject: [PATCH 006/211] optimization headers --- src/Storages/StorageLoop.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/Storages/StorageLoop.cpp b/src/Storages/StorageLoop.cpp index d106a6812ac..374871804b8 100644 --- a/src/Storages/StorageLoop.cpp +++ b/src/Storages/StorageLoop.cpp @@ -1,17 +1,8 @@ #include "StorageLoop.h" -#include -#include -#include #include #include -#include -#include -#include -#include -#include #include #include -#include namespace DB From f0ca96fddf756f56f51ffd9f54750d3638db977e Mon Sep 17 00:00:00 2001 From: Sariel <1059293451@qq.com> Date: Thu, 25 Apr 2024 23:33:36 +0800 Subject: [PATCH 007/211] add readfromloop --- src/Processors/QueryPlan/ReadFromLoopStep.cpp | 69 +++++++++++++++++++ src/Processors/QueryPlan/ReadFromLoopStep.h | 40 +++++++++++ src/Storages/StorageLoop.cpp | 30 ++++---- 3 files changed, 121 insertions(+), 18 deletions(-) create mode 100644 src/Processors/QueryPlan/ReadFromLoopStep.cpp create mode 100644 src/Processors/QueryPlan/ReadFromLoopStep.h diff --git a/src/Processors/QueryPlan/ReadFromLoopStep.cpp b/src/Processors/QueryPlan/ReadFromLoopStep.cpp new file mode 100644 index 00000000000..10932db3f08 --- /dev/null +++ b/src/Processors/QueryPlan/ReadFromLoopStep.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace DB +{ + +ReadFromLoopStep::ReadFromLoopStep( + const Names & column_names_, + const SelectQueryInfo & query_info_, + const StorageSnapshotPtr & storage_snapshot_, + const ContextPtr & context_, + QueryProcessingStage::Enum processed_stage_, + StoragePtr inner_storage_, + size_t max_block_size_, + size_t num_streams_) + : SourceStepWithFilter( + DataStream{.header = storage_snapshot_->getSampleBlockForColumns(column_names_)}, + column_names_, + query_info_, + storage_snapshot_, + context_) + , column_names(column_names_) + , processed_stage(processed_stage_) + , inner_storage(std::move(inner_storage_)) + , max_block_size(max_block_size_) + , num_streams(num_streams_) +{ +} + +Pipe ReadFromLoopStep::makePipe() +{ + Pipes res_pipe; + + for (size_t i = 0; i < 10; ++i) + { + QueryPlan plan; + inner_storage->read( + plan, + column_names, + storage_snapshot, + query_info, + context, + processed_stage, + max_block_size, + num_streams); + auto builder = plan.buildQueryPipeline( + QueryPlanOptimizationSettings::fromContext(context), + BuildQueryPipelineSettings::fromContext(context)); + + QueryPlanResourceHolder resources; + auto pipe = QueryPipelineBuilder::getPipe(std::move(*builder), resources); + + res_pipe.emplace_back(std::move(pipe)); + } + + return Pipe::unitePipes(std::move(res_pipe)); +} + +void ReadFromLoopStep::initializePipeline(QueryPipelineBuilder & pipeline, const BuildQueryPipelineSettings &) +{ + pipeline.init(makePipe()); +} + +} diff --git a/src/Processors/QueryPlan/ReadFromLoopStep.h b/src/Processors/QueryPlan/ReadFromLoopStep.h new file mode 100644 index 00000000000..e8062282d5e --- /dev/null +++ b/src/Processors/QueryPlan/ReadFromLoopStep.h @@ -0,0 +1,40 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +namespace DB +{ + +class ReadFromLoopStep final : public SourceStepWithFilter +{ +public: + ReadFromLoopStep( + const Names & column_names_, + const SelectQueryInfo & query_info_, + const StorageSnapshotPtr & storage_snapshot_, + const ContextPtr & context_, + QueryProcessingStage::Enum processed_stage_, + StoragePtr inner_storage_, + size_t max_block_size_, + size_t num_streams_); + + String getName() const override { return "ReadFromLoop"; } + + void initializePipeline(QueryPipelineBuilder & pipeline, const BuildQueryPipelineSettings &) override; + +private: + + Pipe makePipe(); + + const Names column_names; + QueryProcessingStage::Enum processed_stage; + StoragePtr inner_storage; + size_t max_block_size; + size_t num_streams; +}; +} diff --git a/src/Storages/StorageLoop.cpp b/src/Storages/StorageLoop.cpp index 374871804b8..935ab8bc401 100644 --- a/src/Storages/StorageLoop.cpp +++ b/src/Storages/StorageLoop.cpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace DB @@ -33,25 +34,18 @@ void StorageLoop::read( size_t num_streams) { query_info.optimize_trivial_count = false; - QueryPlan temp_query_plan(std::move(query_plan)); - for (size_t i = 0; i < 10; ++i) - { - QueryPlan swapped_query_plan; - std::swap(temp_query_plan, swapped_query_plan); - inner_storage->read(temp_query_plan, - column_names, - storage_snapshot, - query_info, - context, - processed_stage, - max_block_size, - num_streams); - - // std::cout << "Loop iteration: " << (i + 1) << std::endl; - - } - query_plan = std::move(temp_query_plan); + query_plan.addStep(std::make_unique( + column_names, query_info, storage_snapshot, context, processed_stage, inner_storage, max_block_size, num_streams + )); + /*inner_storage->read(query_plan, + column_names, + storage_snapshot, + query_info, + context, + processed_stage, + max_block_size, + num_streams);*/ } void registerStorageLoop(StorageFactory & factory) From 93370410fc53af3d54aa74b45e6c6fe6bbef7b1f Mon Sep 17 00:00:00 2001 From: Sariel <1059293451@qq.com> Date: Mon, 29 Apr 2024 19:44:44 +0800 Subject: [PATCH 008/211] add loopsource --- src/Processors/QueryPlan/ReadFromLoopStep.cpp | 109 +++++++++++++----- src/Storages/StorageLoop.cpp | 8 -- src/TableFunctions/TableFunctionLoop.cpp | 7 +- 3 files changed, 85 insertions(+), 39 deletions(-) diff --git a/src/Processors/QueryPlan/ReadFromLoopStep.cpp b/src/Processors/QueryPlan/ReadFromLoopStep.cpp index 10932db3f08..79ed10327cd 100644 --- a/src/Processors/QueryPlan/ReadFromLoopStep.cpp +++ b/src/Processors/QueryPlan/ReadFromLoopStep.cpp @@ -2,13 +2,85 @@ #include #include #include +#include #include #include #include +#include +#include +#include +#include namespace DB { +class LoopSource : public ISource +{ +public: + + LoopSource( + const Names & column_names_, + const SelectQueryInfo & query_info_, + const StorageSnapshotPtr & storage_snapshot_, + ContextPtr & context_, + QueryProcessingStage::Enum processed_stage_, + StoragePtr inner_storage_, + size_t max_block_size_, + size_t num_streams_) + : ISource(storage_snapshot_->getSampleBlockForColumns(column_names_)) + , column_names(column_names_) + , query_info(query_info_) + , storage_snapshot(storage_snapshot_) + , processed_stage(processed_stage_) + , context(context_) + , inner_storage(std::move(inner_storage_)) + , max_block_size(max_block_size_) + , num_streams(num_streams_) + { + } + + String getName() const override { return "Loop"; } + + Chunk generate() override + { + QueryPlan plan; + inner_storage->read( + plan, + column_names, + storage_snapshot, + query_info, + context, + processed_stage, + max_block_size, + num_streams); + auto builder = plan.buildQueryPipeline( + QueryPlanOptimizationSettings::fromContext(context), + BuildQueryPipelineSettings::fromContext(context)); + QueryPipeline query_pipeline = QueryPipelineBuilder::getPipeline(std::move(*builder)); + PullingPipelineExecutor executor(query_pipeline); + + Chunk chunk; + while (executor.pull(chunk)) + { + if (chunk) + return chunk; + } + + return {}; + } + +private: + + const Names column_names; + SelectQueryInfo query_info; + const StorageSnapshotPtr storage_snapshot; + QueryProcessingStage::Enum processed_stage; + ContextPtr context; + StoragePtr inner_storage; + size_t max_block_size; + size_t num_streams; +}; + ReadFromLoopStep::ReadFromLoopStep( const Names & column_names_, const SelectQueryInfo & query_info_, @@ -34,36 +106,21 @@ ReadFromLoopStep::ReadFromLoopStep( Pipe ReadFromLoopStep::makePipe() { - Pipes res_pipe; - - for (size_t i = 0; i < 10; ++i) - { - QueryPlan plan; - inner_storage->read( - plan, - column_names, - storage_snapshot, - query_info, - context, - processed_stage, - max_block_size, - num_streams); - auto builder = plan.buildQueryPipeline( - QueryPlanOptimizationSettings::fromContext(context), - BuildQueryPipelineSettings::fromContext(context)); - - QueryPlanResourceHolder resources; - auto pipe = QueryPipelineBuilder::getPipe(std::move(*builder), resources); - - res_pipe.emplace_back(std::move(pipe)); - } - - return Pipe::unitePipes(std::move(res_pipe)); + return Pipe(std::make_shared( + column_names, query_info, storage_snapshot, context, processed_stage, inner_storage, max_block_size, num_streams)); } void ReadFromLoopStep::initializePipeline(QueryPipelineBuilder & pipeline, const BuildQueryPipelineSettings &) { - pipeline.init(makePipe()); + auto pipe = makePipe(); + + if (pipe.empty()) + { + assert(output_stream != std::nullopt); + pipe = Pipe(std::make_shared(output_stream->header)); + } + + pipeline.init(std::move(pipe)); } } diff --git a/src/Storages/StorageLoop.cpp b/src/Storages/StorageLoop.cpp index 935ab8bc401..6a319fc9741 100644 --- a/src/Storages/StorageLoop.cpp +++ b/src/Storages/StorageLoop.cpp @@ -38,14 +38,6 @@ void StorageLoop::read( query_plan.addStep(std::make_unique( column_names, query_info, storage_snapshot, context, processed_stage, inner_storage, max_block_size, num_streams )); - /*inner_storage->read(query_plan, - column_names, - storage_snapshot, - query_info, - context, - processed_stage, - max_block_size, - num_streams);*/ } void registerStorageLoop(StorageFactory & factory) diff --git a/src/TableFunctions/TableFunctionLoop.cpp b/src/TableFunctions/TableFunctionLoop.cpp index bfe0711384d..1a0b2c3552d 100644 --- a/src/TableFunctions/TableFunctionLoop.cpp +++ b/src/TableFunctions/TableFunctionLoop.cpp @@ -93,12 +93,9 @@ void TableFunctionLoop::parseArguments(const ASTPtr & ast_function, ContextPtr c } } -ColumnsDescription TableFunctionLoop::getActualTableStructure(ContextPtr context, bool is_insert_query) const +ColumnsDescription TableFunctionLoop::getActualTableStructure(ContextPtr /*context*/, bool /*is_insert_query*/) const { - auto inner_table_function = TableFunctionFactory::instance().get(inner_table_function_ast, context); - - return inner_table_function->getActualTableStructure(context, is_insert_query); - + return ColumnsDescription(); } StoragePtr TableFunctionLoop::executeImpl( From 2a0e2226920ad04fb563540477b59ab36cd7ca37 Mon Sep 17 00:00:00 2001 From: Sariel <1059293451@qq.com> Date: Tue, 30 Apr 2024 11:39:42 +0800 Subject: [PATCH 009/211] add loopsource --- src/Processors/QueryPlan/ReadFromLoopStep.cpp | 60 ++++++++++++------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/src/Processors/QueryPlan/ReadFromLoopStep.cpp b/src/Processors/QueryPlan/ReadFromLoopStep.cpp index 79ed10327cd..85210185fc7 100644 --- a/src/Processors/QueryPlan/ReadFromLoopStep.cpp +++ b/src/Processors/QueryPlan/ReadFromLoopStep.cpp @@ -13,6 +13,7 @@ namespace DB { +class PullingPipelineExecutor; class LoopSource : public ISource { @@ -43,30 +44,42 @@ public: Chunk generate() override { - QueryPlan plan; - inner_storage->read( - plan, - column_names, - storage_snapshot, - query_info, - context, - processed_stage, - max_block_size, - num_streams); - auto builder = plan.buildQueryPipeline( - QueryPlanOptimizationSettings::fromContext(context), - BuildQueryPipelineSettings::fromContext(context)); - QueryPipeline query_pipeline = QueryPipelineBuilder::getPipeline(std::move(*builder)); - PullingPipelineExecutor executor(query_pipeline); - - Chunk chunk; - while (executor.pull(chunk)) + while (true) { - if (chunk) - return chunk; + if (!loop) + { + QueryPlan plan; + inner_storage->read( + plan, + column_names, + storage_snapshot, + query_info, + context, + processed_stage, + max_block_size, + num_streams); + auto builder = plan.buildQueryPipeline( + QueryPlanOptimizationSettings::fromContext(context), + BuildQueryPipelineSettings::fromContext(context)); + QueryPlanResourceHolder resources; + auto pipe = QueryPipelineBuilder::getPipe(std::move(*builder), resources); + query_pipeline = QueryPipeline(std::move(pipe)); + executor = std::make_unique(query_pipeline); + loop = true; + } + Chunk chunk; + if (executor->pull(chunk)) + { + if (chunk) + return chunk; + } + else + { + loop = false; + executor.reset(); + query_pipeline.reset(); + } } - - return {}; } private: @@ -79,6 +92,9 @@ private: StoragePtr inner_storage; size_t max_block_size; size_t num_streams; + bool loop = false; + QueryPipeline query_pipeline; + std::unique_ptr executor; }; ReadFromLoopStep::ReadFromLoopStep( From cbc05c7a74445bf7915f4bb988bf8dc01e7fd195 Mon Sep 17 00:00:00 2001 From: Sariel <1059293451@qq.com> Date: Tue, 30 Apr 2024 12:05:23 +0800 Subject: [PATCH 010/211] add loopsource --- contrib/curl | 2 +- contrib/openssl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/curl b/contrib/curl index 1a05e833f8f..de7b3e89218 160000 --- a/contrib/curl +++ b/contrib/curl @@ -1 +1 @@ -Subproject commit 1a05e833f8f7140628b27882b10525fd9ec4b873 +Subproject commit de7b3e89218467159a7af72d58cea8425946e97d diff --git a/contrib/openssl b/contrib/openssl index 417f9d28257..f7b8721dfc6 160000 --- a/contrib/openssl +++ b/contrib/openssl @@ -1 +1 @@ -Subproject commit 417f9d2825799769708d99917d0465574c36f79a +Subproject commit f7b8721dfc66abb147f24ca07b9c9d1d64f40f71 From f452ea9c022469015ffcf0af5a6006654e5ab17c Mon Sep 17 00:00:00 2001 From: Sariel <1059293451@qq.com> Date: Sun, 5 May 2024 23:58:04 +0800 Subject: [PATCH 011/211] add test --- docs/en/sql-reference/table-functions/loop.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/en/sql-reference/table-functions/loop.md diff --git a/docs/en/sql-reference/table-functions/loop.md b/docs/en/sql-reference/table-functions/loop.md new file mode 100644 index 00000000000..036d139766a --- /dev/null +++ b/docs/en/sql-reference/table-functions/loop.md @@ -0,0 +1,5 @@ +# loop + +**Syntax** + +**Parameters** \ No newline at end of file From a643f2ff99e04acdaa230b0b9166d6a95e91e980 Mon Sep 17 00:00:00 2001 From: sarielwxm <1059293451@qq.com> Date: Thu, 16 May 2024 21:22:54 +0800 Subject: [PATCH 012/211] fix --- docs/en/sql-reference/table-functions/loop.md | 52 +++- src/Processors/QueryPlan/ReadFromLoopStep.cpp | 226 +++++++++--------- src/Processors/QueryPlan/ReadFromLoopStep.h | 47 ++-- src/Storages/StorageLoop.cpp | 70 +++--- src/Storages/StorageLoop.h | 40 ++-- src/TableFunctions/TableFunctionLoop.cpp | 224 +++++++++-------- .../03147_table_function_loop.reference | 65 +++++ .../0_stateless/03147_table_function_loop.sql | 12 + 8 files changed, 435 insertions(+), 301 deletions(-) create mode 100644 tests/queries/0_stateless/03147_table_function_loop.reference create mode 100644 tests/queries/0_stateless/03147_table_function_loop.sql diff --git a/docs/en/sql-reference/table-functions/loop.md b/docs/en/sql-reference/table-functions/loop.md index 036d139766a..3a9367b2d10 100644 --- a/docs/en/sql-reference/table-functions/loop.md +++ b/docs/en/sql-reference/table-functions/loop.md @@ -2,4 +2,54 @@ **Syntax** -**Parameters** \ No newline at end of file +``` sql +SELECT ... FROM loop(database, table); +SELECT ... FROM loop(database.table); +SELECT ... FROM loop(table); +SELECT ... FROM loop(other_table_function(...)); +``` + +**Parameters** + +- `database` — database name. +- `table` — table name. +- `other_table_function(...)` — other table function. + Example: `SELECT * FROM loop(numbers(10));` + `other_table_function(...)` here is `numbers(10)`. + +**Returned Value** + +Infinite loop to return query results. + +**Examples** + +Selecting data from ClickHouse: + +``` sql +SELECT * FROM loop(test_database, test_table); +SELECT * FROM loop(test_database.test_table); +SELECT * FROM loop(test_table); +``` + +Or using other table function: + +``` sql +SELECT * FROM loop(numbers(3)) LIMIT 7; + ┌─number─┐ +1. │ 0 │ +2. │ 1 │ +3. │ 2 │ + └────────┘ + ┌─number─┐ +4. │ 0 │ +5. │ 1 │ +6. │ 2 │ + └────────┘ + ┌─number─┐ +7. │ 0 │ + └────────┘ +``` +``` sql +SELECT * FROM loop(mysql('localhost:3306', 'test', 'test', 'user', 'password')); +... +``` \ No newline at end of file diff --git a/src/Processors/QueryPlan/ReadFromLoopStep.cpp b/src/Processors/QueryPlan/ReadFromLoopStep.cpp index 85210185fc7..9c788de24f2 100644 --- a/src/Processors/QueryPlan/ReadFromLoopStep.cpp +++ b/src/Processors/QueryPlan/ReadFromLoopStep.cpp @@ -9,134 +9,134 @@ #include #include #include -#include namespace DB { -class PullingPipelineExecutor; + class PullingPipelineExecutor; -class LoopSource : public ISource -{ -public: - - LoopSource( - const Names & column_names_, - const SelectQueryInfo & query_info_, - const StorageSnapshotPtr & storage_snapshot_, - ContextPtr & context_, - QueryProcessingStage::Enum processed_stage_, - StoragePtr inner_storage_, - size_t max_block_size_, - size_t num_streams_) - : ISource(storage_snapshot_->getSampleBlockForColumns(column_names_)) - , column_names(column_names_) - , query_info(query_info_) - , storage_snapshot(storage_snapshot_) - , processed_stage(processed_stage_) - , context(context_) - , inner_storage(std::move(inner_storage_)) - , max_block_size(max_block_size_) - , num_streams(num_streams_) + class LoopSource : public ISource { - } + public: - String getName() const override { return "Loop"; } - - Chunk generate() override - { - while (true) + LoopSource( + const Names & column_names_, + const SelectQueryInfo & query_info_, + const StorageSnapshotPtr & storage_snapshot_, + ContextPtr & context_, + QueryProcessingStage::Enum processed_stage_, + StoragePtr inner_storage_, + size_t max_block_size_, + size_t num_streams_) + : ISource(storage_snapshot_->getSampleBlockForColumns(column_names_)) + , column_names(column_names_) + , query_info(query_info_) + , storage_snapshot(storage_snapshot_) + , processed_stage(processed_stage_) + , context(context_) + , inner_storage(std::move(inner_storage_)) + , max_block_size(max_block_size_) + , num_streams(num_streams_) { - if (!loop) + } + + String getName() const override { return "Loop"; } + + Chunk generate() override + { + while (true) { - QueryPlan plan; - inner_storage->read( - plan, - column_names, - storage_snapshot, - query_info, - context, - processed_stage, - max_block_size, - num_streams); - auto builder = plan.buildQueryPipeline( - QueryPlanOptimizationSettings::fromContext(context), - BuildQueryPipelineSettings::fromContext(context)); - QueryPlanResourceHolder resources; - auto pipe = QueryPipelineBuilder::getPipe(std::move(*builder), resources); - query_pipeline = QueryPipeline(std::move(pipe)); - executor = std::make_unique(query_pipeline); - loop = true; - } - Chunk chunk; - if (executor->pull(chunk)) - { - if (chunk) - return chunk; - } - else - { - loop = false; - executor.reset(); - query_pipeline.reset(); + if (!loop) + { + QueryPlan plan; + auto storage_snapshot_ = inner_storage->getStorageSnapshotForQuery(inner_storage->getInMemoryMetadataPtr(), nullptr, context); + inner_storage->read( + plan, + column_names, + storage_snapshot_, + query_info, + context, + processed_stage, + max_block_size, + num_streams); + auto builder = plan.buildQueryPipeline( + QueryPlanOptimizationSettings::fromContext(context), + BuildQueryPipelineSettings::fromContext(context)); + QueryPlanResourceHolder resources; + auto pipe = QueryPipelineBuilder::getPipe(std::move(*builder), resources); + query_pipeline = QueryPipeline(std::move(pipe)); + executor = std::make_unique(query_pipeline); + loop = true; + } + Chunk chunk; + if (executor->pull(chunk)) + { + if (chunk) + return chunk; + } + else + { + loop = false; + executor.reset(); + query_pipeline.reset(); + } } } - } -private: + private: - const Names column_names; - SelectQueryInfo query_info; - const StorageSnapshotPtr storage_snapshot; - QueryProcessingStage::Enum processed_stage; - ContextPtr context; - StoragePtr inner_storage; - size_t max_block_size; - size_t num_streams; - bool loop = false; - QueryPipeline query_pipeline; - std::unique_ptr executor; -}; + const Names column_names; + SelectQueryInfo query_info; + const StorageSnapshotPtr storage_snapshot; + QueryProcessingStage::Enum processed_stage; + ContextPtr context; + StoragePtr inner_storage; + size_t max_block_size; + size_t num_streams; + bool loop = false; + QueryPipeline query_pipeline; + std::unique_ptr executor; + }; -ReadFromLoopStep::ReadFromLoopStep( - const Names & column_names_, - const SelectQueryInfo & query_info_, - const StorageSnapshotPtr & storage_snapshot_, - const ContextPtr & context_, - QueryProcessingStage::Enum processed_stage_, - StoragePtr inner_storage_, - size_t max_block_size_, - size_t num_streams_) - : SourceStepWithFilter( - DataStream{.header = storage_snapshot_->getSampleBlockForColumns(column_names_)}, - column_names_, - query_info_, - storage_snapshot_, - context_) - , column_names(column_names_) - , processed_stage(processed_stage_) - , inner_storage(std::move(inner_storage_)) - , max_block_size(max_block_size_) - , num_streams(num_streams_) -{ -} - -Pipe ReadFromLoopStep::makePipe() -{ - return Pipe(std::make_shared( - column_names, query_info, storage_snapshot, context, processed_stage, inner_storage, max_block_size, num_streams)); -} - -void ReadFromLoopStep::initializePipeline(QueryPipelineBuilder & pipeline, const BuildQueryPipelineSettings &) -{ - auto pipe = makePipe(); - - if (pipe.empty()) + ReadFromLoopStep::ReadFromLoopStep( + const Names & column_names_, + const SelectQueryInfo & query_info_, + const StorageSnapshotPtr & storage_snapshot_, + const ContextPtr & context_, + QueryProcessingStage::Enum processed_stage_, + StoragePtr inner_storage_, + size_t max_block_size_, + size_t num_streams_) + : SourceStepWithFilter( + DataStream{.header = storage_snapshot_->getSampleBlockForColumns(column_names_)}, + column_names_, + query_info_, + storage_snapshot_, + context_) + , column_names(column_names_) + , processed_stage(processed_stage_) + , inner_storage(std::move(inner_storage_)) + , max_block_size(max_block_size_) + , num_streams(num_streams_) { - assert(output_stream != std::nullopt); - pipe = Pipe(std::make_shared(output_stream->header)); } - pipeline.init(std::move(pipe)); -} + Pipe ReadFromLoopStep::makePipe() + { + return Pipe(std::make_shared( + column_names, query_info, storage_snapshot, context, processed_stage, inner_storage, max_block_size, num_streams)); + } + + void ReadFromLoopStep::initializePipeline(QueryPipelineBuilder & pipeline, const BuildQueryPipelineSettings &) + { + auto pipe = makePipe(); + + if (pipe.empty()) + { + assert(output_stream != std::nullopt); + pipe = Pipe(std::make_shared(output_stream->header)); + } + + pipeline.init(std::move(pipe)); + } } diff --git a/src/Processors/QueryPlan/ReadFromLoopStep.h b/src/Processors/QueryPlan/ReadFromLoopStep.h index e8062282d5e..4eee0ca5605 100644 --- a/src/Processors/QueryPlan/ReadFromLoopStep.h +++ b/src/Processors/QueryPlan/ReadFromLoopStep.h @@ -1,40 +1,37 @@ #pragma once #include -#include #include #include -#include #include -#include namespace DB { -class ReadFromLoopStep final : public SourceStepWithFilter -{ -public: - ReadFromLoopStep( - const Names & column_names_, - const SelectQueryInfo & query_info_, - const StorageSnapshotPtr & storage_snapshot_, - const ContextPtr & context_, - QueryProcessingStage::Enum processed_stage_, - StoragePtr inner_storage_, - size_t max_block_size_, - size_t num_streams_); + class ReadFromLoopStep final : public SourceStepWithFilter + { + public: + ReadFromLoopStep( + const Names & column_names_, + const SelectQueryInfo & query_info_, + const StorageSnapshotPtr & storage_snapshot_, + const ContextPtr & context_, + QueryProcessingStage::Enum processed_stage_, + StoragePtr inner_storage_, + size_t max_block_size_, + size_t num_streams_); - String getName() const override { return "ReadFromLoop"; } + String getName() const override { return "ReadFromLoop"; } - void initializePipeline(QueryPipelineBuilder & pipeline, const BuildQueryPipelineSettings &) override; + void initializePipeline(QueryPipelineBuilder & pipeline, const BuildQueryPipelineSettings &) override; -private: + private: - Pipe makePipe(); + Pipe makePipe(); - const Names column_names; - QueryProcessingStage::Enum processed_stage; - StoragePtr inner_storage; - size_t max_block_size; - size_t num_streams; -}; + const Names column_names; + QueryProcessingStage::Enum processed_stage; + StoragePtr inner_storage; + size_t max_block_size; + size_t num_streams; + }; } diff --git a/src/Storages/StorageLoop.cpp b/src/Storages/StorageLoop.cpp index 6a319fc9741..2062749e60b 100644 --- a/src/Storages/StorageLoop.cpp +++ b/src/Storages/StorageLoop.cpp @@ -1,51 +1,49 @@ #include "StorageLoop.h" -#include #include -#include #include #include namespace DB { -namespace ErrorCodes -{ + namespace ErrorCodes + { -} -StorageLoop::StorageLoop( - const StorageID & table_id_, - StoragePtr inner_storage_) - : IStorage(table_id_) - , inner_storage(std::move(inner_storage_)) -{ - StorageInMemoryMetadata storage_metadata = inner_storage->getInMemoryMetadata(); - setInMemoryMetadata(storage_metadata); -} + } + StorageLoop::StorageLoop( + const StorageID & table_id_, + StoragePtr inner_storage_) + : IStorage(table_id_) + , inner_storage(std::move(inner_storage_)) + { + StorageInMemoryMetadata storage_metadata = inner_storage->getInMemoryMetadata(); + setInMemoryMetadata(storage_metadata); + } -void StorageLoop::read( - QueryPlan & query_plan, - const Names & column_names, - const StorageSnapshotPtr & storage_snapshot, - SelectQueryInfo & query_info, - ContextPtr context, - QueryProcessingStage::Enum processed_stage, - size_t max_block_size, - size_t num_streams) -{ - query_info.optimize_trivial_count = false; + void StorageLoop::read( + QueryPlan & query_plan, + const Names & column_names, + const StorageSnapshotPtr & storage_snapshot, + SelectQueryInfo & query_info, + ContextPtr context, + QueryProcessingStage::Enum processed_stage, + size_t max_block_size, + size_t num_streams) + { + query_info.optimize_trivial_count = false; - query_plan.addStep(std::make_unique( - column_names, query_info, storage_snapshot, context, processed_stage, inner_storage, max_block_size, num_streams + query_plan.addStep(std::make_unique( + column_names, query_info, storage_snapshot, context, processed_stage, inner_storage, max_block_size, num_streams )); -} + } -void registerStorageLoop(StorageFactory & factory) -{ - factory.registerStorage("Loop", [](const StorageFactory::Arguments & args) - { - StoragePtr inner_storage; - return std::make_shared(args.table_id, inner_storage); - }); -} + void registerStorageLoop(StorageFactory & factory) + { + factory.registerStorage("Loop", [](const StorageFactory::Arguments & args) + { + StoragePtr inner_storage; + return std::make_shared(args.table_id, inner_storage); + }); + } } diff --git a/src/Storages/StorageLoop.h b/src/Storages/StorageLoop.h index 869febc9f31..48760b169c2 100644 --- a/src/Storages/StorageLoop.h +++ b/src/Storages/StorageLoop.h @@ -6,28 +6,28 @@ namespace DB { -class StorageLoop final : public IStorage -{ -public: - StorageLoop( - const StorageID & table_id, - StoragePtr inner_storage_); + class StorageLoop final : public IStorage + { + public: + StorageLoop( + const StorageID & table_id, + StoragePtr inner_storage_); - std::string getName() const override { return "Loop"; } + std::string getName() const override { return "Loop"; } - void read( - QueryPlan & query_plan, - const Names & column_names, - const StorageSnapshotPtr & storage_snapshot, - SelectQueryInfo & query_info, - ContextPtr context, - QueryProcessingStage::Enum processed_stage, - size_t max_block_size, - size_t num_streams) override; + void read( + QueryPlan & query_plan, + const Names & column_names, + const StorageSnapshotPtr & storage_snapshot, + SelectQueryInfo & query_info, + ContextPtr context, + QueryProcessingStage::Enum processed_stage, + size_t max_block_size, + size_t num_streams) override; - bool supportsTrivialCountOptimization(const StorageSnapshotPtr &, ContextPtr) const override { return false; } + bool supportsTrivialCountOptimization(const StorageSnapshotPtr &, ContextPtr) const override { return false; } -private: - StoragePtr inner_storage; -}; + private: + StoragePtr inner_storage; + }; } diff --git a/src/TableFunctions/TableFunctionLoop.cpp b/src/TableFunctions/TableFunctionLoop.cpp index 1a0b2c3552d..0281002e50f 100644 --- a/src/TableFunctions/TableFunctionLoop.cpp +++ b/src/TableFunctions/TableFunctionLoop.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -14,131 +13,144 @@ namespace DB { -namespace ErrorCodes -{ - extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int UNKNOWN_TABLE; -} -namespace -{ -class TableFunctionLoop : public ITableFunction{ -public: - static constexpr auto name = "loop"; - std::string getName() const override { return name; } -private: - StoragePtr executeImpl(const ASTPtr & ast_function, ContextPtr context, const String & table_name, ColumnsDescription cached_columns, bool is_insert_query) const override; - const char * getStorageTypeName() const override { return "Loop"; } - ColumnsDescription getActualTableStructure(ContextPtr context, bool is_insert_query) const override; - void parseArguments(const ASTPtr & ast_function, ContextPtr context) override; - - // save the inner table function AST - ASTPtr inner_table_function_ast; - // save database and table - std::string database_name_; - std::string table_name_; -}; - -} - -void TableFunctionLoop::parseArguments(const ASTPtr & ast_function, ContextPtr context) -{ - const auto & args_func = ast_function->as(); - - if (!args_func.arguments) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Table function 'loop' must have arguments."); - - auto & args = args_func.arguments->children; - if (args.empty()) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "No arguments provided for table function 'loop'"); - - if (args.size() == 1) + namespace ErrorCodes { - if (const auto * id = args[0]->as()) + extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; + extern const int ILLEGAL_TYPE_OF_ARGUMENT; + extern const int UNKNOWN_TABLE; + } + namespace + { + class TableFunctionLoop : public ITableFunction { - String id_name = id->name(); + public: + static constexpr auto name = "loop"; + std::string getName() const override { return name; } + private: + StoragePtr executeImpl(const ASTPtr & ast_function, ContextPtr context, const String & table_name, ColumnsDescription cached_columns, bool is_insert_query) const override; + const char * getStorageTypeName() const override { return "Loop"; } + ColumnsDescription getActualTableStructure(ContextPtr context, bool is_insert_query) const override; + void parseArguments(const ASTPtr & ast_function, ContextPtr context) override; - size_t dot_pos = id_name.find('.'); - if (dot_pos != String::npos) + // save the inner table function AST + ASTPtr inner_table_function_ast; + // save database and table + std::string loop_database_name; + std::string loop_table_name; + }; + + } + + void TableFunctionLoop::parseArguments(const ASTPtr & ast_function, ContextPtr context) + { + const auto & args_func = ast_function->as(); + + if (!args_func.arguments) + throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Table function 'loop' must have arguments."); + + auto & args = args_func.arguments->children; + if (args.empty()) + throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "No arguments provided for table function 'loop'"); + + if (args.size() == 1) + { + if (const auto * id = args[0]->as()) { - database_name_ = id_name.substr(0, dot_pos); - table_name_ = id_name.substr(dot_pos + 1); + String id_name = id->name(); + + size_t dot_pos = id_name.find('.'); + if (id_name.find('.', dot_pos + 1) != String::npos) + throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "There are more than one dot"); + if (dot_pos != String::npos) + { + loop_database_name = id_name.substr(0, dot_pos); + loop_table_name = id_name.substr(dot_pos + 1); + } + else + { + loop_table_name = id_name; + } + } + else if (const auto * func = args[0]->as()) + { + inner_table_function_ast = args[0]; } else { - table_name_ = id_name; + throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Expected identifier or function for argument 1 of function 'loop', got {}", args[0]->getID()); } } - else if (const auto * func = args[0]->as()) + // loop(database, table) + else if (args.size() == 2) { - inner_table_function_ast = args[0]; + args[0] = evaluateConstantExpressionForDatabaseName(args[0], context); + args[1] = evaluateConstantExpressionOrIdentifierAsLiteral(args[1], context); + + loop_database_name = checkAndGetLiteralArgument(args[0], "database"); + loop_table_name = checkAndGetLiteralArgument(args[1], "table"); } else { - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Expected identifier or function for argument 1 of function 'loop', got {}", args[0]->getID()); + throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Table function 'loop' must have 1 or 2 arguments."); } } - // loop(database, table) - else if (args.size() == 2) + + ColumnsDescription TableFunctionLoop::getActualTableStructure(ContextPtr /*context*/, bool /*is_insert_query*/) const { - args[0] = evaluateConstantExpressionForDatabaseName(args[0], context); - args[1] = evaluateConstantExpressionOrIdentifierAsLiteral(args[1], context); - - database_name_ = checkAndGetLiteralArgument(args[0], "database"); - table_name_ = checkAndGetLiteralArgument(args[1], "table"); - } - else - { - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Table function 'loop' must have 1 or 2 arguments."); - } -} - -ColumnsDescription TableFunctionLoop::getActualTableStructure(ContextPtr /*context*/, bool /*is_insert_query*/) const -{ - return ColumnsDescription(); -} - -StoragePtr TableFunctionLoop::executeImpl( - const ASTPtr & /*ast_function*/, - ContextPtr context, - const std::string & table_name, - ColumnsDescription cached_columns, - bool is_insert_query) const -{ - StoragePtr storage; - if (!table_name_.empty()) - { - String database_name = database_name_; - if (database_name.empty()) - database_name = context->getCurrentDatabase(); - - auto database = DatabaseCatalog::instance().getDatabase(database_name); - storage = database->tryGetTable(table_name_ ,context); - if (!storage) - throw Exception(ErrorCodes::UNKNOWN_TABLE, "Table '{}' not found in database '{}'", table_name_, database_name); + return ColumnsDescription(); } - else + StoragePtr TableFunctionLoop::executeImpl( + const ASTPtr & /*ast_function*/, + ContextPtr context, + const std::string & table_name, + ColumnsDescription cached_columns, + bool is_insert_query) const { - auto inner_table_function = TableFunctionFactory::instance().get(inner_table_function_ast, context); - storage = inner_table_function->execute( - inner_table_function_ast, - context, - table_name, - std::move(cached_columns), - is_insert_query); - } - auto res = std::make_shared( - StorageID(getDatabaseName(), table_name), - storage + StoragePtr storage; + if (!loop_table_name.empty()) + { + String database_name = loop_database_name; + if (database_name.empty()) + database_name = context->getCurrentDatabase(); + + auto database = DatabaseCatalog::instance().getDatabase(database_name); + storage = database->tryGetTable(loop_table_name, context); + if (!storage) + throw Exception(ErrorCodes::UNKNOWN_TABLE, "Table '{}' not found in database '{}'", loop_table_name, database_name); + } + + else + { + auto inner_table_function = TableFunctionFactory::instance().get(inner_table_function_ast, context); + storage = inner_table_function->execute( + inner_table_function_ast, + context, + table_name, + std::move(cached_columns), + is_insert_query); + } + auto res = std::make_shared( + StorageID(getDatabaseName(), table_name), + storage ); - res->startup(); - return res; -} + res->startup(); + return res; + } -void registerTableFunctionLoop(TableFunctionFactory & factory) -{ - factory.registerFunction(); -} + void registerTableFunctionLoop(TableFunctionFactory & factory) + { + factory.registerFunction( + {.documentation + = {.description=R"(The table function can be used to continuously output query results in an infinite loop.)", + .examples{{"loop", "SELECT * FROM loop((numbers(3)) LIMIT 7", "0" + "1" + "2" + "0" + "1" + "2" + "0"}} + }}); + } } diff --git a/tests/queries/0_stateless/03147_table_function_loop.reference b/tests/queries/0_stateless/03147_table_function_loop.reference new file mode 100644 index 00000000000..46a2310b65f --- /dev/null +++ b/tests/queries/0_stateless/03147_table_function_loop.reference @@ -0,0 +1,65 @@ +0 +1 +2 +0 +1 +2 +0 +1 +2 +0 +0 +1 +2 +0 +1 +2 +0 +1 +2 +0 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +0 +1 +2 +3 +4 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +0 +1 +2 +3 +4 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +0 +1 +2 +3 +4 diff --git a/tests/queries/0_stateless/03147_table_function_loop.sql b/tests/queries/0_stateless/03147_table_function_loop.sql new file mode 100644 index 00000000000..90cfe99fc39 --- /dev/null +++ b/tests/queries/0_stateless/03147_table_function_loop.sql @@ -0,0 +1,12 @@ +SELECT * FROM loop(numbers(3)) LIMIT 10; +SELECT * FROM loop (numbers(3)) LIMIT 10 settings max_block_size = 1; + +DROP DATABASE IF EXISTS 03147_db; +CREATE DATABASE 03147_db; +CREATE TABLE 03147_db.t (n Int8) ENGINE=MergeTree ORDER BY n; +INSERT INTO 03147_db.t SELECT * FROM numbers(10); +USE 03147_db; + +SELECT * FROM loop(03147_db.t) LIMIT 15; +SELECT * FROM loop(t) LIMIT 15; +SELECT * FROM loop(03147_db, t) LIMIT 15; From 056dcd61c4fb07e2893748af4997510191c32ebf Mon Sep 17 00:00:00 2001 From: sarielwxm <1059293451@qq.com> Date: Fri, 17 May 2024 17:09:14 +0800 Subject: [PATCH 013/211] fix --- src/Processors/QueryPlan/ReadFromLoopStep.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Processors/QueryPlan/ReadFromLoopStep.cpp b/src/Processors/QueryPlan/ReadFromLoopStep.cpp index 9c788de24f2..10436490a2a 100644 --- a/src/Processors/QueryPlan/ReadFromLoopStep.cpp +++ b/src/Processors/QueryPlan/ReadFromLoopStep.cpp @@ -12,6 +12,10 @@ namespace DB { + namespace ErrorCodes + { + extern const int TOO_MANY_RETRIES_TO_FETCH_PARTS; + } class PullingPipelineExecutor; class LoopSource : public ISource @@ -71,10 +75,17 @@ namespace DB if (executor->pull(chunk)) { if (chunk) + { + retries_count = 0; return chunk; + } + } else { + ++retries_count; + if (retries_count > max_retries_count) + throw Exception(ErrorCodes::TOO_MANY_RETRIES_TO_FETCH_PARTS, "Too many retries to pull from storage"); loop = false; executor.reset(); query_pipeline.reset(); @@ -92,6 +103,9 @@ namespace DB StoragePtr inner_storage; size_t max_block_size; size_t num_streams; + // add retries. If inner_storage failed to pull X times in a row we'd better to fail here not to hang + size_t retries_count = 0; + size_t max_retries_count = 3; bool loop = false; QueryPipeline query_pipeline; std::unique_ptr executor; From 97376119dd218ebbe3b9e00f805427402b459587 Mon Sep 17 00:00:00 2001 From: Nikita Taranov Date: Wed, 22 May 2024 20:44:51 +0100 Subject: [PATCH 014/211] create and destroy maps on thread pool --- src/Common/CurrentMetrics.cpp | 3 + src/Interpreters/ConcurrentHashJoin.cpp | 95 ++++++++++++++++++++++--- src/Interpreters/ConcurrentHashJoin.h | 3 +- 3 files changed, 89 insertions(+), 12 deletions(-) diff --git a/src/Common/CurrentMetrics.cpp b/src/Common/CurrentMetrics.cpp index 0f25397a961..58a4693a775 100644 --- a/src/Common/CurrentMetrics.cpp +++ b/src/Common/CurrentMetrics.cpp @@ -127,6 +127,9 @@ M(DestroyAggregatesThreads, "Number of threads in the thread pool for destroy aggregate states.") \ M(DestroyAggregatesThreadsActive, "Number of threads in the thread pool for destroy aggregate states running a task.") \ M(DestroyAggregatesThreadsScheduled, "Number of queued or active jobs in the thread pool for destroy aggregate states.") \ + M(ConcurrentHashJoinPoolThreads, "Number of threads in the thread pool for concurrent hash join.") \ + M(ConcurrentHashJoinPoolThreadsActive, "Number of threads in the thread pool for concurrent hash join running a task.") \ + M(ConcurrentHashJoinPoolThreadsScheduled, "Number of queued or active jobs in the thread pool for concurrent hash join.") \ M(HashedDictionaryThreads, "Number of threads in the HashedDictionary thread pool.") \ M(HashedDictionaryThreadsActive, "Number of threads in the HashedDictionary thread pool running a task.") \ M(HashedDictionaryThreadsScheduled, "Number of queued or active jobs in the HashedDictionary thread pool.") \ diff --git a/src/Interpreters/ConcurrentHashJoin.cpp b/src/Interpreters/ConcurrentHashJoin.cpp index 96be70c5527..a82f568fa66 100644 --- a/src/Interpreters/ConcurrentHashJoin.cpp +++ b/src/Interpreters/ConcurrentHashJoin.cpp @@ -1,5 +1,3 @@ -#include -#include #include #include #include @@ -19,6 +17,17 @@ #include #include #include +#include + +#include +#include + +namespace CurrentMetrics +{ +extern const Metric ConcurrentHashJoinPoolThreads; +extern const Metric ConcurrentHashJoinPoolThreadsActive; +extern const Metric ConcurrentHashJoinPoolThreadsScheduled; +} namespace DB { @@ -36,20 +45,84 @@ static UInt32 toPowerOfTwo(UInt32 x) return static_cast(1) << (32 - std::countl_zero(x - 1)); } -ConcurrentHashJoin::ConcurrentHashJoin(ContextPtr context_, std::shared_ptr table_join_, size_t slots_, const Block & right_sample_block, bool any_take_last_row_) +ConcurrentHashJoin::ConcurrentHashJoin( + ContextPtr context_, std::shared_ptr table_join_, size_t slots_, const Block & right_sample_block, bool any_take_last_row_) : context(context_) , table_join(table_join_) , slots(toPowerOfTwo(std::min(static_cast(slots_), 256))) + , pool( + CurrentMetrics::ConcurrentHashJoinPoolThreads, + CurrentMetrics::ConcurrentHashJoinPoolThreadsActive, + CurrentMetrics::ConcurrentHashJoinPoolThreadsScheduled, + slots) { - for (size_t i = 0; i < slots; ++i) - { - auto inner_hash_join = std::make_shared(); + hash_joins.resize(slots); - inner_hash_join->data = std::make_unique(table_join_, right_sample_block, any_take_last_row_, 0, fmt::format("concurrent{}", i)); - /// Non zero `max_joined_block_rows` allows to process block partially and return not processed part. - /// TODO: It's not handled properly in ConcurrentHashJoin case, so we set it to 0 to disable this feature. - inner_hash_join->data->setMaxJoinedBlockRows(0); - hash_joins.emplace_back(std::move(inner_hash_join)); + try + { + for (size_t i = 0; i < slots; ++i) + { + pool.trySchedule( + [&, idx = i, thread_group = CurrentThread::getGroup()]() + { + SCOPE_EXIT_SAFE({ + if (thread_group) + CurrentThread::detachFromGroupIfNotDetached(); + }); + + if (thread_group) + CurrentThread::attachToGroupIfDetached(thread_group); + + setThreadName("ConcurrentJoin"); + + auto inner_hash_join = std::make_shared(); + + inner_hash_join->data = std::make_unique( + table_join_, right_sample_block, any_take_last_row_, 0, fmt::format("concurrent{}", idx)); + /// Non zero `max_joined_block_rows` allows to process block partially and return not processed part. + /// TODO: It's not handled properly in ConcurrentHashJoin case, so we set it to 0 to disable this feature. + inner_hash_join->data->setMaxJoinedBlockRows(0); + hash_joins[idx] = std::move(inner_hash_join); + }); + } + + pool.wait(); + } + catch (...) + { + tryLogCurrentException(__PRETTY_FUNCTION__); + pool.wait(); + throw; + } +} + +ConcurrentHashJoin::~ConcurrentHashJoin() +{ + try + { + for (size_t i = 0; i < slots; ++i) + { + pool.trySchedule( + [join = std::move(hash_joins[i]), thread_group = CurrentThread::getGroup()]() + { + SCOPE_EXIT_SAFE({ + if (thread_group) + CurrentThread::detachFromGroupIfNotDetached(); + }); + + if (thread_group) + CurrentThread::attachToGroupIfDetached(thread_group); + + setThreadName("ConcurrentJoin"); + }); + } + + pool.wait(); + } + catch (...) + { + tryLogCurrentException(__PRETTY_FUNCTION__); + pool.wait(); } } diff --git a/src/Interpreters/ConcurrentHashJoin.h b/src/Interpreters/ConcurrentHashJoin.h index 40796376d23..bf165371b5b 100644 --- a/src/Interpreters/ConcurrentHashJoin.h +++ b/src/Interpreters/ConcurrentHashJoin.h @@ -39,7 +39,7 @@ public: const Block & right_sample_block, bool any_take_last_row_ = false); - ~ConcurrentHashJoin() override = default; + ~ConcurrentHashJoin() override; std::string getName() const override { return "ConcurrentHashJoin"; } const TableJoin & getTableJoin() const override { return *table_join; } @@ -66,6 +66,7 @@ private: ContextPtr context; std::shared_ptr table_join; size_t slots; + ThreadPool pool; std::vector> hash_joins; std::mutex totals_mutex; From 12d582155e19e80e5bad6cbe66ac3119acc6006d Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Thu, 23 May 2024 14:50:14 +0200 Subject: [PATCH 015/211] Allow comparing Ipv4 and IPv6 values --- src/Functions/FunctionsComparison.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Functions/FunctionsComparison.h b/src/Functions/FunctionsComparison.h index 57aebc11da0..ae475a35e90 100644 --- a/src/Functions/FunctionsComparison.h +++ b/src/Functions/FunctionsComparison.h @@ -1170,14 +1170,12 @@ public: bool both_represented_by_number = arguments[0]->isValueRepresentedByNumber() && arguments[1]->isValueRepresentedByNumber(); bool has_date = left.isDateOrDate32() || right.isDateOrDate32(); - if (!((both_represented_by_number && !has_date) /// Do not allow to compare date and number. || (left.isStringOrFixedString() || right.isStringOrFixedString()) /// Everything can be compared with string by conversion. /// You can compare the date, datetime, or datatime64 and an enumeration with a constant string. || ((left.isDate() || left.isDate32() || left.isDateTime() || left.isDateTime64()) && (right.isDate() || right.isDate32() || right.isDateTime() || right.isDateTime64()) && left.idx == right.idx) /// only date vs date, or datetime vs datetime || (left.isUUID() && right.isUUID()) - || (left.isIPv4() && right.isIPv4()) - || (left.isIPv6() && right.isIPv6()) + || ((left.isIPv4() || left.isIPv6()) && (left.isIPv4() || left.isIPv6())) || (left.isEnum() && right.isEnum() && arguments[0]->getName() == arguments[1]->getName()) /// only equivalent enum type values can be compared against || (left_tuple && right_tuple && left_tuple->getElements().size() == right_tuple->getElements().size()) || (arguments[0]->equals(*arguments[1])))) @@ -1266,6 +1264,8 @@ public: const bool left_is_float = which_left.isFloat(); const bool right_is_float = which_right.isFloat(); + const bool left_is_ipv4 = which_left.isIPv4(); + const bool right_is_ipv4 = which_right.isIPv4(); const bool left_is_ipv6 = which_left.isIPv6(); const bool right_is_ipv6 = which_right.isIPv6(); const bool left_is_fixed_string = which_left.isFixedString(); @@ -1334,6 +1334,15 @@ public: return executeGenericIdenticalTypes(left_column.get(), right_column.get()); } + else if ((left_is_ipv4 || left_is_ipv6) && (right_is_ipv4 || right_is_ipv6)) + { + ColumnPtr left_column = left_is_ipv6 ? + col_with_type_and_name_left.column : castColumn(col_with_type_and_name_left, right_type); + ColumnPtr right_column = right_is_ipv6 ? + col_with_type_and_name_right.column : castColumn(col_with_type_and_name_right, left_type); + + return executeGenericIdenticalTypes(left_column.get(), right_column.get()); + } else if ((isColumnedAsDecimal(left_type) || isColumnedAsDecimal(right_type))) { // Comparing Date/Date32 and DateTime64 requires implicit conversion, From 80ead5a2902c295a7d5a47c82582ba9194f03ffe Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Thu, 23 May 2024 15:05:08 +0200 Subject: [PATCH 016/211] add tests --- .../0_stateless/03161_ipv4_ipv6_equality.reference | 8 ++++++++ .../queries/0_stateless/03161_ipv4_ipv6_equality.sql | 11 +++++++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/queries/0_stateless/03161_ipv4_ipv6_equality.reference create mode 100644 tests/queries/0_stateless/03161_ipv4_ipv6_equality.sql diff --git a/tests/queries/0_stateless/03161_ipv4_ipv6_equality.reference b/tests/queries/0_stateless/03161_ipv4_ipv6_equality.reference new file mode 100644 index 00000000000..2a4cb2e658f --- /dev/null +++ b/tests/queries/0_stateless/03161_ipv4_ipv6_equality.reference @@ -0,0 +1,8 @@ +1 +1 +0 +0 +0 +0 +0 +0 diff --git a/tests/queries/0_stateless/03161_ipv4_ipv6_equality.sql b/tests/queries/0_stateless/03161_ipv4_ipv6_equality.sql new file mode 100644 index 00000000000..da2a660977a --- /dev/null +++ b/tests/queries/0_stateless/03161_ipv4_ipv6_equality.sql @@ -0,0 +1,11 @@ +-- Equal +SELECT toIPv4('127.0.0.1') = toIPv6('::ffff:127.0.0.1'); +SELECT toIPv6('::ffff:127.0.0.1') = toIPv4('127.0.0.1'); + +-- Not equal +SELECT toIPv4('127.0.0.1') = toIPv6('::ffff:127.0.0.2'); +SELECT toIPv4('127.0.0.2') = toIPv6('::ffff:127.0.0.1'); +SELECT toIPv6('::ffff:127.0.0.1') = toIPv4('127.0.0.2'); +SELECT toIPv6('::ffff:127.0.0.2') = toIPv4('127.0.0.1'); +SELECT toIPv4('127.0.0.1') = toIPv6('::ffef:127.0.0.1'); +SELECT toIPv6('::ffef:127.0.0.1') = toIPv4('127.0.0.1'); \ No newline at end of file From 5718375131970bf8107b38d54f7747bb27d30978 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Thu, 23 May 2024 15:15:02 +0200 Subject: [PATCH 017/211] Restore newline --- src/Functions/FunctionsComparison.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Functions/FunctionsComparison.h b/src/Functions/FunctionsComparison.h index ae475a35e90..777404d2594 100644 --- a/src/Functions/FunctionsComparison.h +++ b/src/Functions/FunctionsComparison.h @@ -1169,6 +1169,7 @@ public: const DataTypeTuple * right_tuple = checkAndGetDataType(arguments[1].get()); bool both_represented_by_number = arguments[0]->isValueRepresentedByNumber() && arguments[1]->isValueRepresentedByNumber(); + bool has_date = left.isDateOrDate32() || right.isDateOrDate32(); if (!((both_represented_by_number && !has_date) /// Do not allow to compare date and number. || (left.isStringOrFixedString() || right.isStringOrFixedString()) /// Everything can be compared with string by conversion. From 6cd8bec3fc0fb1b4a01c2779bc8031f9ea6eed26 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Thu, 23 May 2024 15:31:56 +0200 Subject: [PATCH 018/211] Remove unnecessary repetition --- src/Functions/FunctionsComparison.h | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/Functions/FunctionsComparison.h b/src/Functions/FunctionsComparison.h index 777404d2594..0da9b6aadf0 100644 --- a/src/Functions/FunctionsComparison.h +++ b/src/Functions/FunctionsComparison.h @@ -1324,10 +1324,13 @@ public: { return res; } - else if (((left_is_ipv6 && right_is_fixed_string) || (right_is_ipv6 && left_is_fixed_string)) && fixed_string_size == IPV6_BINARY_LENGTH) + else if ( + (((left_is_ipv6 && right_is_fixed_string) || (right_is_ipv6 && left_is_fixed_string)) && fixed_string_size == IPV6_BINARY_LENGTH) + || ((left_is_ipv4 || left_is_ipv6) && (right_is_ipv4 || right_is_ipv6)) + ) { - /// Special treatment for FixedString(16) as a binary representation of IPv6 - - /// CAST is customized for this case + /// Special treatment for FixedString(16) as a binary representation of IPv6 & for comparing IPv4 & IPv6 values - + /// CAST is customized for this cases ColumnPtr left_column = left_is_ipv6 ? col_with_type_and_name_left.column : castColumn(col_with_type_and_name_left, right_type); ColumnPtr right_column = right_is_ipv6 ? @@ -1335,15 +1338,6 @@ public: return executeGenericIdenticalTypes(left_column.get(), right_column.get()); } - else if ((left_is_ipv4 || left_is_ipv6) && (right_is_ipv4 || right_is_ipv6)) - { - ColumnPtr left_column = left_is_ipv6 ? - col_with_type_and_name_left.column : castColumn(col_with_type_and_name_left, right_type); - ColumnPtr right_column = right_is_ipv6 ? - col_with_type_and_name_right.column : castColumn(col_with_type_and_name_right, left_type); - - return executeGenericIdenticalTypes(left_column.get(), right_column.get()); - } else if ((isColumnedAsDecimal(left_type) || isColumnedAsDecimal(right_type))) { // Comparing Date/Date32 and DateTime64 requires implicit conversion, From cd395ef346059620ddb1fa4898f6d9c9f8f0bd29 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Thu, 23 May 2024 15:33:31 +0200 Subject: [PATCH 019/211] Restore whitespace --- src/Functions/FunctionsComparison.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Functions/FunctionsComparison.h b/src/Functions/FunctionsComparison.h index 0da9b6aadf0..b45b8783059 100644 --- a/src/Functions/FunctionsComparison.h +++ b/src/Functions/FunctionsComparison.h @@ -1169,8 +1169,8 @@ public: const DataTypeTuple * right_tuple = checkAndGetDataType(arguments[1].get()); bool both_represented_by_number = arguments[0]->isValueRepresentedByNumber() && arguments[1]->isValueRepresentedByNumber(); - bool has_date = left.isDateOrDate32() || right.isDateOrDate32(); + if (!((both_represented_by_number && !has_date) /// Do not allow to compare date and number. || (left.isStringOrFixedString() || right.isStringOrFixedString()) /// Everything can be compared with string by conversion. /// You can compare the date, datetime, or datatime64 and an enumeration with a constant string. From 3ea362373b35f2e675ae12a1b0aaf6f6040e4d0a Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Thu, 23 May 2024 15:37:46 +0200 Subject: [PATCH 020/211] Update docs --- docs/en/sql-reference/data-types/ipv4.md | 12 ++++++++++++ docs/en/sql-reference/data-types/ipv6.md | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/docs/en/sql-reference/data-types/ipv4.md b/docs/en/sql-reference/data-types/ipv4.md index 637ed543e08..98ba9f4abac 100644 --- a/docs/en/sql-reference/data-types/ipv4.md +++ b/docs/en/sql-reference/data-types/ipv4.md @@ -57,6 +57,18 @@ SELECT toTypeName(from), hex(from) FROM hits LIMIT 1; └──────────────────┴───────────┘ ``` +IPv4 addresses can be directly compared to IPv6 addresses: + +```sql +SELECT toIPv4('127.0.0.1') = toIPv6('::ffff:127.0.0.1'); +``` + +```text +┌─equals(toIPv4('127.0.0.1'), toIPv6('::ffff:127.0.0.1'))─┐ +│ 1 │ +└─────────────────────────────────────────────────────────┘ +``` + **See Also** - [Functions for Working with IPv4 and IPv6 Addresses](../functions/ip-address-functions.md) diff --git a/docs/en/sql-reference/data-types/ipv6.md b/docs/en/sql-reference/data-types/ipv6.md index 642a7db81fc..d3b7cc72a1a 100644 --- a/docs/en/sql-reference/data-types/ipv6.md +++ b/docs/en/sql-reference/data-types/ipv6.md @@ -57,6 +57,19 @@ SELECT toTypeName(from), hex(from) FROM hits LIMIT 1; └──────────────────┴──────────────────────────────────┘ ``` +IPv6 addresses can be directly compared to IPv4 addresses: + +```sql +SELECT toIPv4('127.0.0.1') = toIPv6('::ffff:127.0.0.1'); +``` + +```text +┌─equals(toIPv4('127.0.0.1'), toIPv6('::ffff:127.0.0.1'))─┐ +│ 1 │ +└─────────────────────────────────────────────────────────┘ +``` + + **See Also** - [Functions for Working with IPv4 and IPv6 Addresses](../functions/ip-address-functions.md) From 4af0ead9ce9e459832ba66f4d75705ee65f50d75 Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Thu, 23 May 2024 20:31:36 +0000 Subject: [PATCH 021/211] allow prefetch in vertical merges --- src/Storages/MergeTree/MergeTask.cpp | 54 ++++++++++++------ src/Storages/MergeTree/MergeTask.h | 4 ++ .../MergeTree/MergeTreeSequentialSource.cpp | 57 +++++++------------ .../MergeTree/MergeTreeSequentialSource.h | 5 +- src/Storages/MergeTree/MergeTreeSettings.h | 1 + 5 files changed, 67 insertions(+), 54 deletions(-) diff --git a/src/Storages/MergeTree/MergeTask.cpp b/src/Storages/MergeTree/MergeTask.cpp index a9109832521..77e8308e823 100644 --- a/src/Storages/MergeTree/MergeTask.cpp +++ b/src/Storages/MergeTree/MergeTask.cpp @@ -535,6 +535,7 @@ bool MergeTask::VerticalMergeStage::prepareVerticalMergeForAllColumns() const std::unique_ptr reread_buf = wbuf_readable ? wbuf_readable->tryGetReadBuffer() : nullptr; if (!reread_buf) throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot read temporary file {}", ctx->rows_sources_uncompressed_write_buf->getFileName()); + auto * reread_buffer_raw = dynamic_cast(reread_buf.get()); if (!reread_buffer_raw) { @@ -555,6 +556,7 @@ bool MergeTask::VerticalMergeStage::prepareVerticalMergeForAllColumns() const ctx->it_name_and_type = global_ctx->gathering_columns.cbegin(); const auto & settings = global_ctx->context->getSettingsRef(); + size_t max_delayed_streams = 0; if (global_ctx->new_data_part->getDataPartStorage().supportParallelWrite()) { @@ -563,20 +565,20 @@ bool MergeTask::VerticalMergeStage::prepareVerticalMergeForAllColumns() const else max_delayed_streams = DEFAULT_DELAYED_STREAMS_FOR_PARALLEL_WRITE; } + ctx->max_delayed_streams = max_delayed_streams; + bool all_parts_on_remote_disks = std::ranges::all_of(global_ctx->future_part->parts, [](const auto & part) { return part->isStoredOnRemoteDisk(); }); + ctx->use_prefetch = all_parts_on_remote_disks && global_ctx->data->getSettings()->vertical_merge_remote_filesystem_prefetch; + + if (ctx->use_prefetch) + ctx->prepared_pipe = createPipeForReadingOneColumn(ctx->it_name_and_type->name); + return false; } -void MergeTask::VerticalMergeStage::prepareVerticalMergeForOneColumn() const +Pipe MergeTask::VerticalMergeStage::createPipeForReadingOneColumn(const String & column_name) const { - const auto & [column_name, column_type] = *ctx->it_name_and_type; - Names column_names{column_name}; - - ctx->progress_before = global_ctx->merge_list_element_ptr->progress.load(std::memory_order_relaxed); - - global_ctx->column_progress = std::make_unique(ctx->progress_before, ctx->column_sizes->columnWeight(column_name)); - Pipes pipes; for (size_t part_num = 0; part_num < global_ctx->future_part->parts.size(); ++part_num) { @@ -585,18 +587,39 @@ void MergeTask::VerticalMergeStage::prepareVerticalMergeForOneColumn() const *global_ctx->data, global_ctx->storage_snapshot, global_ctx->future_part->parts[part_num], - column_names, + Names{column_name}, /*mark_ranges=*/ {}, + global_ctx->input_rows_filtered, /*apply_deleted_mask=*/ true, ctx->read_with_direct_io, - /*take_column_types_from_storage=*/ true, - /*quiet=*/ false, - global_ctx->input_rows_filtered); + ctx->use_prefetch); pipes.emplace_back(std::move(pipe)); } - auto pipe = Pipe::unitePipes(std::move(pipes)); + return Pipe::unitePipes(std::move(pipes)); +} + +void MergeTask::VerticalMergeStage::prepareVerticalMergeForOneColumn() const +{ + const auto & column_name = ctx->it_name_and_type->name; + + ctx->progress_before = global_ctx->merge_list_element_ptr->progress.load(std::memory_order_relaxed); + global_ctx->column_progress = std::make_unique(ctx->progress_before, ctx->column_sizes->columnWeight(column_name)); + + Pipe pipe; + if (ctx->prepared_pipe) + { + pipe = std::move(*ctx->prepared_pipe); + + auto next_column_it = std::next(ctx->it_name_and_type); + if (next_column_it != global_ctx->gathering_columns.end()) + ctx->prepared_pipe = createPipeForReadingOneColumn(next_column_it->name); + } + else + { + pipe = createPipeForReadingOneColumn(column_name); + } ctx->rows_sources_read_buf->seek(0, 0); @@ -952,11 +975,10 @@ void MergeTask::ExecuteAndFinalizeHorizontalPart::createMergedStream() part, global_ctx->merging_column_names, /*mark_ranges=*/ {}, + global_ctx->input_rows_filtered, /*apply_deleted_mask=*/ true, ctx->read_with_direct_io, - /*take_column_types_from_storage=*/ true, - /*quiet=*/ false, - global_ctx->input_rows_filtered); + /*prefetch=*/ false); if (global_ctx->metadata_snapshot->hasSortingKey()) { diff --git a/src/Storages/MergeTree/MergeTask.h b/src/Storages/MergeTree/MergeTask.h index c8b0662e3eb..1294fa30449 100644 --- a/src/Storages/MergeTree/MergeTask.h +++ b/src/Storages/MergeTree/MergeTask.h @@ -299,7 +299,9 @@ private: Float64 progress_before = 0; std::unique_ptr column_to{nullptr}; + std::optional prepared_pipe; size_t max_delayed_streams = 0; + bool use_prefetch = false; std::list> delayed_streams; size_t column_elems_written{0}; QueryPipeline column_parts_pipeline; @@ -340,6 +342,8 @@ private: bool executeVerticalMergeForOneColumn() const; void finalizeVerticalMergeForOneColumn() const; + Pipe createPipeForReadingOneColumn(const String & column_name) const; + VerticalMergeRuntimeContextPtr ctx; GlobalRuntimeContextPtr global_ctx; }; diff --git a/src/Storages/MergeTree/MergeTreeSequentialSource.cpp b/src/Storages/MergeTree/MergeTreeSequentialSource.cpp index fbb48b37482..865371b7d2c 100644 --- a/src/Storages/MergeTree/MergeTreeSequentialSource.cpp +++ b/src/Storages/MergeTree/MergeTreeSequentialSource.cpp @@ -42,8 +42,7 @@ public: std::optional mark_ranges_, bool apply_deleted_mask, bool read_with_direct_io_, - bool take_column_types_from_storage, - bool quiet = false); + bool prefetch); ~MergeTreeSequentialSource() override; @@ -96,8 +95,7 @@ MergeTreeSequentialSource::MergeTreeSequentialSource( std::optional mark_ranges_, bool apply_deleted_mask, bool read_with_direct_io_, - bool take_column_types_from_storage, - bool quiet) + bool prefetch) : ISource(storage_snapshot_->getSampleBlockForColumns(columns_to_read_)) , storage(storage_) , storage_snapshot(storage_snapshot_) @@ -107,16 +105,13 @@ MergeTreeSequentialSource::MergeTreeSequentialSource( , mark_ranges(std::move(mark_ranges_)) , mark_cache(storage.getContext()->getMarkCache()) { - if (!quiet) - { - /// Print column name but don't pollute logs in case of many columns. - if (columns_to_read.size() == 1) - LOG_DEBUG(log, "Reading {} marks from part {}, total {} rows starting from the beginning of the part, column {}", - data_part->getMarksCount(), data_part->name, data_part->rows_count, columns_to_read.front()); - else - LOG_DEBUG(log, "Reading {} marks from part {}, total {} rows starting from the beginning of the part", - data_part->getMarksCount(), data_part->name, data_part->rows_count); - } + /// Print column name but don't pollute logs in case of many columns. + if (columns_to_read.size() == 1) + LOG_DEBUG(log, "Reading {} marks from part {}, total {} rows starting from the beginning of the part, column {}", + data_part->getMarksCount(), data_part->name, data_part->rows_count, columns_to_read.front()); + else + LOG_DEBUG(log, "Reading {} marks from part {}, total {} rows starting from the beginning of the part", + data_part->getMarksCount(), data_part->name, data_part->rows_count); auto alter_conversions = storage.getAlterConversionsForPart(data_part); @@ -131,21 +126,12 @@ MergeTreeSequentialSource::MergeTreeSequentialSource( storage.supportsSubcolumns(), columns_to_read); - NamesAndTypesList columns_for_reader; - if (take_column_types_from_storage) - { - auto options = GetColumnsOptions(GetColumnsOptions::AllPhysical) - .withExtendedObjects() - .withVirtuals() - .withSubcolumns(storage.supportsSubcolumns()); + auto options = GetColumnsOptions(GetColumnsOptions::AllPhysical) + .withExtendedObjects() + .withVirtuals() + .withSubcolumns(storage.supportsSubcolumns()); - columns_for_reader = storage_snapshot->getColumnsByNames(options, columns_to_read); - } - else - { - /// take columns from data_part - columns_for_reader = data_part->getColumns().addTypes(columns_to_read); - } + auto columns_for_reader = storage_snapshot->getColumnsByNames(options, columns_to_read); const auto & context = storage.getContext(); ReadSettings read_settings = context->getReadSettings(); @@ -191,6 +177,9 @@ MergeTreeSequentialSource::MergeTreeSequentialSource( reader_settings, /*avg_value_size_hints=*/ {}, /*profile_callback=*/ {}); + + if (prefetch) + reader->prefetchBeginOfRange(Priority{}); } static void fillBlockNumberColumns( @@ -313,11 +302,10 @@ Pipe createMergeTreeSequentialSource( MergeTreeData::DataPartPtr data_part, Names columns_to_read, std::optional mark_ranges, + std::shared_ptr> filtered_rows_count, bool apply_deleted_mask, bool read_with_direct_io, - bool take_column_types_from_storage, - bool quiet, - std::shared_ptr> filtered_rows_count) + bool prefetch) { /// The part might have some rows masked by lightweight deletes @@ -329,7 +317,7 @@ Pipe createMergeTreeSequentialSource( auto column_part_source = std::make_shared(type, storage, storage_snapshot, data_part, columns_to_read, std::move(mark_ranges), - /*apply_deleted_mask=*/ false, read_with_direct_io, take_column_types_from_storage, quiet); + /*apply_deleted_mask=*/ false, read_with_direct_io, prefetch); Pipe pipe(std::move(column_part_source)); @@ -408,11 +396,10 @@ public: data_part, columns_to_read, std::move(mark_ranges), + /*filtered_rows_count=*/ nullptr, apply_deleted_mask, /*read_with_direct_io=*/ false, - /*take_column_types_from_storage=*/ true, - /*quiet=*/ false, - /*filtered_rows_count=*/ nullptr); + /*prefetch=*/ false); pipeline.init(Pipe(std::move(source))); } diff --git a/src/Storages/MergeTree/MergeTreeSequentialSource.h b/src/Storages/MergeTree/MergeTreeSequentialSource.h index a5e36a7726f..e6f055f776c 100644 --- a/src/Storages/MergeTree/MergeTreeSequentialSource.h +++ b/src/Storages/MergeTree/MergeTreeSequentialSource.h @@ -23,11 +23,10 @@ Pipe createMergeTreeSequentialSource( MergeTreeData::DataPartPtr data_part, Names columns_to_read, std::optional mark_ranges, + std::shared_ptr> filtered_rows_count, bool apply_deleted_mask, bool read_with_direct_io, - bool take_column_types_from_storage, - bool quiet, - std::shared_ptr> filtered_rows_count); + bool prefetch); class QueryPlan; diff --git a/src/Storages/MergeTree/MergeTreeSettings.h b/src/Storages/MergeTree/MergeTreeSettings.h index a00508fd1c1..f0cf6db7369 100644 --- a/src/Storages/MergeTree/MergeTreeSettings.h +++ b/src/Storages/MergeTree/MergeTreeSettings.h @@ -148,6 +148,7 @@ struct Settings; M(UInt64, vertical_merge_algorithm_min_rows_to_activate, 16 * 8192, "Minimal (approximate) sum of rows in merging parts to activate Vertical merge algorithm.", 0) \ M(UInt64, vertical_merge_algorithm_min_bytes_to_activate, 0, "Minimal (approximate) uncompressed size in bytes in merging parts to activate Vertical merge algorithm.", 0) \ M(UInt64, vertical_merge_algorithm_min_columns_to_activate, 11, "Minimal amount of non-PK columns to activate Vertical merge algorithm.", 0) \ + M(Bool, vertical_merge_remote_filesystem_prefetch, true, "If true prefetching of data from remote filesystem is used for the next column during merge", 0) \ M(UInt64, max_postpone_time_for_failed_mutations_ms, 5ULL * 60 * 1000, "The maximum postpone time for failed mutations.", 0) \ \ /** Compatibility settings */ \ From e663136358b209aaec9d39cf95085ebca2111e7b Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Thu, 23 May 2024 22:35:31 +0200 Subject: [PATCH 022/211] Fix right side of condition --- src/Functions/FunctionsComparison.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Functions/FunctionsComparison.h b/src/Functions/FunctionsComparison.h index b45b8783059..4bee19ba87a 100644 --- a/src/Functions/FunctionsComparison.h +++ b/src/Functions/FunctionsComparison.h @@ -1176,7 +1176,7 @@ public: /// You can compare the date, datetime, or datatime64 and an enumeration with a constant string. || ((left.isDate() || left.isDate32() || left.isDateTime() || left.isDateTime64()) && (right.isDate() || right.isDate32() || right.isDateTime() || right.isDateTime64()) && left.idx == right.idx) /// only date vs date, or datetime vs datetime || (left.isUUID() && right.isUUID()) - || ((left.isIPv4() || left.isIPv6()) && (left.isIPv4() || left.isIPv6())) + || ((left.isIPv4() || left.isIPv6()) && (right.isIPv4() || right.isIPv6())) || (left.isEnum() && right.isEnum() && arguments[0]->getName() == arguments[1]->getName()) /// only equivalent enum type values can be compared against || (left_tuple && right_tuple && left_tuple->getElements().size() == right_tuple->getElements().size()) || (arguments[0]->equals(*arguments[1])))) From c08769167ef3b172526de4c3c77dc47509489b43 Mon Sep 17 00:00:00 2001 From: sarielwxm <1059293451@qq.com> Date: Fri, 24 May 2024 16:46:24 +0800 Subject: [PATCH 023/211] fix test --- tests/queries/0_stateless/03147_table_function_loop.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/queries/0_stateless/03147_table_function_loop.sql b/tests/queries/0_stateless/03147_table_function_loop.sql index 90cfe99fc39..092f0531a2b 100644 --- a/tests/queries/0_stateless/03147_table_function_loop.sql +++ b/tests/queries/0_stateless/03147_table_function_loop.sql @@ -2,7 +2,7 @@ SELECT * FROM loop(numbers(3)) LIMIT 10; SELECT * FROM loop (numbers(3)) LIMIT 10 settings max_block_size = 1; DROP DATABASE IF EXISTS 03147_db; -CREATE DATABASE 03147_db; +CREATE DATABASE IF NOT EXISTS 03147_db; CREATE TABLE 03147_db.t (n Int8) ENGINE=MergeTree ORDER BY n; INSERT INTO 03147_db.t SELECT * FROM numbers(10); USE 03147_db; From 54cb4f2ac757d00b0f1ab7ebd2b5d871226512b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mar=C3=ADn?= Date: Fri, 24 May 2024 12:54:06 +0200 Subject: [PATCH 024/211] Rename allow_deprecated_functions to allow_deprecated_error_prone_window_functions --- src/Core/Settings.h | 2 +- src/Core/SettingsChangesHistory.h | 2 +- src/Databases/DatabaseReplicated.cpp | 2 +- src/Functions/neighbor.cpp | 4 ++-- src/Functions/runningAccumulate.cpp | 4 ++-- src/Functions/runningDifference.h | 4 ++-- .../00166_functions_of_aggregation_states.sql | 2 +- .../00410_aggregation_combinators_with_arenas.sql | 2 +- tests/queries/0_stateless/00653_running_difference.sql | 2 +- .../0_stateless/00808_not_optimize_predicate.sql | 2 +- tests/queries/0_stateless/00957_neighbor.sql | 2 +- tests/queries/0_stateless/00996_neighbor.sql | 2 +- .../0_stateless/01012_reset_running_accumulate.sql | 2 +- .../0_stateless/01051_aggregate_function_crash.sql | 2 +- .../0_stateless/01056_predicate_optimizer_bugs.sql | 2 +- tests/queries/0_stateless/01353_neighbor_overflow.sql | 2 +- .../01455_optimize_trivial_insert_select.sql | 2 +- .../0_stateless/01665_running_difference_ubsan.sql | 2 +- tests/queries/0_stateless/01670_neighbor_lc_bug.sql | 2 +- .../02496_remove_redundant_sorting.reference | 2 +- .../0_stateless/02496_remove_redundant_sorting.sh | 2 +- .../02496_remove_redundant_sorting_analyzer.reference | 2 +- .../0_stateless/02788_fix_logical_error_in_sorting.sql | 2 +- ..._largestTriangleThreeBuckets_aggregate_function.sql | 10 +++++----- .../02901_predicate_pushdown_cte_stateful.sql | 2 +- .../queries/0_stateless/03131_deprecated_functions.sql | 2 +- .../00144_functions_of_aggregation_states.sql | 2 +- 27 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/Core/Settings.h b/src/Core/Settings.h index a3d8c5f0467..97b6abc3913 100644 --- a/src/Core/Settings.h +++ b/src/Core/Settings.h @@ -917,7 +917,7 @@ class IColumn; M(Int64, ignore_cold_parts_seconds, 0, "Only available in ClickHouse Cloud. Exclude new data parts from SELECT queries until they're either pre-warmed (see cache_populated_by_fetch) or this many seconds old. Only for Replicated-/SharedMergeTree.", 0) \ M(Int64, prefer_warmed_unmerged_parts_seconds, 0, "Only available in ClickHouse Cloud. If a merged part is less than this many seconds old and is not pre-warmed (see cache_populated_by_fetch), but all its source parts are available and pre-warmed, SELECT queries will read from those parts instead. Only for ReplicatedMergeTree. Note that this only checks whether CacheWarmer processed the part; if the part was fetched into cache by something else, it'll still be considered cold until CacheWarmer gets to it; if it was warmed, then evicted from cache, it'll still be considered warm.", 0) \ M(Bool, iceberg_engine_ignore_schema_evolution, false, "Ignore schema evolution in Iceberg table engine and read all data using latest schema saved on table creation. Note that it can lead to incorrect result", 0) \ - M(Bool, allow_deprecated_functions, false, "Allow usage of deprecated functions", 0) \ + M(Bool, allow_deprecated_error_prone_window_functions, false, "Allow usage of deprecated error prone window functions (neighbor, runningAccumulate, runningDifferenceStartingWithFirstValue, runningDifference)", 0) \ // End of COMMON_SETTINGS // Please add settings related to formats into the FORMAT_FACTORY_SETTINGS, move obsolete settings to OBSOLETE_SETTINGS and obsolete format settings to OBSOLETE_FORMAT_SETTINGS. diff --git a/src/Core/SettingsChangesHistory.h b/src/Core/SettingsChangesHistory.h index 23f7810835c..53871f5546e 100644 --- a/src/Core/SettingsChangesHistory.h +++ b/src/Core/SettingsChangesHistory.h @@ -85,7 +85,7 @@ namespace SettingsChangesHistory /// It's used to implement `compatibility` setting (see https://github.com/ClickHouse/ClickHouse/issues/35972) static std::map settings_changes_history = { - {"24.5", {{"allow_deprecated_functions", true, false, "Allow usage of deprecated functions"}, + {"24.5", {{"allow_deprecated_error_prone_window_functions", true, false, "Allow usage of deprecated functions"}, {"allow_experimental_join_condition", false, false, "Support join with inequal conditions which involve columns from both left and right table. e.g. t1.y < t2.y."}, {"input_format_tsv_crlf_end_of_line", false, false, "Enables reading of CRLF line endings with TSV formats"}, {"output_format_parquet_use_custom_encoder", false, true, "Enable custom Parquet encoder."}, diff --git a/src/Databases/DatabaseReplicated.cpp b/src/Databases/DatabaseReplicated.cpp index cc946fc22c4..f5aff604dcb 100644 --- a/src/Databases/DatabaseReplicated.cpp +++ b/src/Databases/DatabaseReplicated.cpp @@ -936,7 +936,7 @@ void DatabaseReplicated::recoverLostReplica(const ZooKeeperPtr & current_zookeep query_context->setSetting("allow_experimental_window_functions", 1); query_context->setSetting("allow_experimental_geo_types", 1); query_context->setSetting("allow_experimental_map_type", 1); - query_context->setSetting("allow_deprecated_functions", 1); + query_context->setSetting("allow_deprecated_error_prone_window_functions", 1); query_context->setSetting("allow_suspicious_low_cardinality_types", 1); query_context->setSetting("allow_suspicious_fixed_string_types", 1); diff --git a/src/Functions/neighbor.cpp b/src/Functions/neighbor.cpp index abe6d39422d..62f129109f9 100644 --- a/src/Functions/neighbor.cpp +++ b/src/Functions/neighbor.cpp @@ -36,11 +36,11 @@ public: static FunctionPtr create(ContextPtr context) { - if (!context->getSettingsRef().allow_deprecated_functions) + if (!context->getSettingsRef().allow_deprecated_error_prone_window_functions) throw Exception( ErrorCodes::DEPRECATED_FUNCTION, "Function {} is deprecated since its usage is error-prone (see docs)." - "Please use proper window function or set `allow_deprecated_functions` setting to enable it", + "Please use proper window function or set `allow_deprecated_error_prone_window_functions` setting to enable it", name); return std::make_shared(); diff --git a/src/Functions/runningAccumulate.cpp b/src/Functions/runningAccumulate.cpp index 9bf387d3357..d585affd91b 100644 --- a/src/Functions/runningAccumulate.cpp +++ b/src/Functions/runningAccumulate.cpp @@ -39,11 +39,11 @@ public: static FunctionPtr create(ContextPtr context) { - if (!context->getSettingsRef().allow_deprecated_functions) + if (!context->getSettingsRef().allow_deprecated_error_prone_window_functions) throw Exception( ErrorCodes::DEPRECATED_FUNCTION, "Function {} is deprecated since its usage is error-prone (see docs)." - "Please use proper window function or set `allow_deprecated_functions` setting to enable it", + "Please use proper window function or set `allow_deprecated_error_prone_window_functions` setting to enable it", name); return std::make_shared(); diff --git a/src/Functions/runningDifference.h b/src/Functions/runningDifference.h index d3704aa97ca..fe477d13744 100644 --- a/src/Functions/runningDifference.h +++ b/src/Functions/runningDifference.h @@ -139,11 +139,11 @@ public: static FunctionPtr create(ContextPtr context) { - if (!context->getSettingsRef().allow_deprecated_functions) + if (!context->getSettingsRef().allow_deprecated_error_prone_window_functions) throw Exception( ErrorCodes::DEPRECATED_FUNCTION, "Function {} is deprecated since its usage is error-prone (see docs)." - "Please use proper window function or set `allow_deprecated_functions` setting to enable it", + "Please use proper window function or set `allow_deprecated_error_prone_window_functions` setting to enable it", name); return std::make_shared>(); diff --git a/tests/queries/0_stateless/00166_functions_of_aggregation_states.sql b/tests/queries/0_stateless/00166_functions_of_aggregation_states.sql index 85f26d4e206..62297e4076e 100644 --- a/tests/queries/0_stateless/00166_functions_of_aggregation_states.sql +++ b/tests/queries/0_stateless/00166_functions_of_aggregation_states.sql @@ -1,5 +1,5 @@ -- Disable external aggregation because the state is reset for each new block of data in 'runningAccumulate' function. SET max_bytes_before_external_group_by = 0; -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; SELECT k, finalizeAggregation(sum_state), runningAccumulate(sum_state) FROM (SELECT intDiv(number, 50000) AS k, sumState(number) AS sum_state FROM (SELECT number FROM system.numbers LIMIT 1000000) GROUP BY k ORDER BY k); diff --git a/tests/queries/0_stateless/00410_aggregation_combinators_with_arenas.sql b/tests/queries/0_stateless/00410_aggregation_combinators_with_arenas.sql index 99091878d90..3eb4c2b1b4a 100644 --- a/tests/queries/0_stateless/00410_aggregation_combinators_with_arenas.sql +++ b/tests/queries/0_stateless/00410_aggregation_combinators_with_arenas.sql @@ -1,4 +1,4 @@ -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; DROP TABLE IF EXISTS arena; CREATE TABLE arena (k UInt8, d String) ENGINE = Memory; INSERT INTO arena SELECT number % 10 AS k, hex(intDiv(number, 10) % 1000) AS d FROM system.numbers LIMIT 10000000; diff --git a/tests/queries/0_stateless/00653_running_difference.sql b/tests/queries/0_stateless/00653_running_difference.sql index d210e04a3a4..d2858a938cd 100644 --- a/tests/queries/0_stateless/00653_running_difference.sql +++ b/tests/queries/0_stateless/00653_running_difference.sql @@ -1,4 +1,4 @@ -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; select runningDifference(x) from (select arrayJoin([0, 1, 5, 10]) as x); select '-'; select runningDifference(x) from (select arrayJoin([2, Null, 3, Null, 10]) as x); diff --git a/tests/queries/0_stateless/00808_not_optimize_predicate.sql b/tests/queries/0_stateless/00808_not_optimize_predicate.sql index c39f1ff2ad1..d2527477dbd 100644 --- a/tests/queries/0_stateless/00808_not_optimize_predicate.sql +++ b/tests/queries/0_stateless/00808_not_optimize_predicate.sql @@ -1,6 +1,6 @@ SET send_logs_level = 'fatal'; SET convert_query_to_cnf = 0; -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; DROP TABLE IF EXISTS test_00808; CREATE TABLE test_00808(date Date, id Int8, name String, value Int64, sign Int8) ENGINE = CollapsingMergeTree(sign) ORDER BY (id, date); diff --git a/tests/queries/0_stateless/00957_neighbor.sql b/tests/queries/0_stateless/00957_neighbor.sql index 8c40f0aab47..ac26fe0eae7 100644 --- a/tests/queries/0_stateless/00957_neighbor.sql +++ b/tests/queries/0_stateless/00957_neighbor.sql @@ -1,4 +1,4 @@ -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; -- no arguments select neighbor(); -- { serverError 42 } -- single argument diff --git a/tests/queries/0_stateless/00996_neighbor.sql b/tests/queries/0_stateless/00996_neighbor.sql index 50b07242eac..f9cbf69a836 100644 --- a/tests/queries/0_stateless/00996_neighbor.sql +++ b/tests/queries/0_stateless/00996_neighbor.sql @@ -1,4 +1,4 @@ -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; SELECT number, neighbor(toString(number), 0) FROM numbers(10); SELECT number, neighbor(toString(number), 5) FROM numbers(10); diff --git a/tests/queries/0_stateless/01012_reset_running_accumulate.sql b/tests/queries/0_stateless/01012_reset_running_accumulate.sql index eed653cc629..09bd29de185 100644 --- a/tests/queries/0_stateless/01012_reset_running_accumulate.sql +++ b/tests/queries/0_stateless/01012_reset_running_accumulate.sql @@ -1,6 +1,6 @@ -- Disable external aggregation because the state is reset for each new block of data in 'runningAccumulate' function. SET max_bytes_before_external_group_by = 0; -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; SELECT grouping, item, diff --git a/tests/queries/0_stateless/01051_aggregate_function_crash.sql b/tests/queries/0_stateless/01051_aggregate_function_crash.sql index c50c275d834..a55ead8a2d7 100644 --- a/tests/queries/0_stateless/01051_aggregate_function_crash.sql +++ b/tests/queries/0_stateless/01051_aggregate_function_crash.sql @@ -1,4 +1,4 @@ -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; SELECT runningAccumulate(string_state) FROM ( diff --git a/tests/queries/0_stateless/01056_predicate_optimizer_bugs.sql b/tests/queries/0_stateless/01056_predicate_optimizer_bugs.sql index 6ea42ec32b0..07f94c03e10 100644 --- a/tests/queries/0_stateless/01056_predicate_optimizer_bugs.sql +++ b/tests/queries/0_stateless/01056_predicate_optimizer_bugs.sql @@ -1,7 +1,7 @@ SET enable_optimize_predicate_expression = 1; SET joined_subquery_requires_alias = 0; SET convert_query_to_cnf = 0; -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; -- https://github.com/ClickHouse/ClickHouse/issues/3885 -- https://github.com/ClickHouse/ClickHouse/issues/5485 diff --git a/tests/queries/0_stateless/01353_neighbor_overflow.sql b/tests/queries/0_stateless/01353_neighbor_overflow.sql index ac168cb3305..8844cf514b1 100644 --- a/tests/queries/0_stateless/01353_neighbor_overflow.sql +++ b/tests/queries/0_stateless/01353_neighbor_overflow.sql @@ -1,3 +1,3 @@ -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; SELECT neighbor(toString(number), -9223372036854775808) FROM numbers(100); -- { serverError 69 } WITH neighbor(toString(number), toInt64(rand64())) AS x SELECT * FROM system.numbers WHERE NOT ignore(x); -- { serverError 69 } diff --git a/tests/queries/0_stateless/01455_optimize_trivial_insert_select.sql b/tests/queries/0_stateless/01455_optimize_trivial_insert_select.sql index 466c9aa3707..09a93d94dc3 100644 --- a/tests/queries/0_stateless/01455_optimize_trivial_insert_select.sql +++ b/tests/queries/0_stateless/01455_optimize_trivial_insert_select.sql @@ -1,5 +1,5 @@ SET max_insert_threads = 1, max_threads = 100, min_insert_block_size_rows = 1048576, max_block_size = 65536; -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; DROP TABLE IF EXISTS t; CREATE TABLE t (x UInt64) ENGINE = StripeLog; -- For trivial INSERT SELECT, max_threads is lowered to max_insert_threads and max_block_size is changed to min_insert_block_size_rows. diff --git a/tests/queries/0_stateless/01665_running_difference_ubsan.sql b/tests/queries/0_stateless/01665_running_difference_ubsan.sql index 504cb0269f8..19947b6ad84 100644 --- a/tests/queries/0_stateless/01665_running_difference_ubsan.sql +++ b/tests/queries/0_stateless/01665_running_difference_ubsan.sql @@ -1,2 +1,2 @@ -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; SELECT k, d, i FROM (SELECT t.1 AS k, t.2 AS v, runningDifference(v) AS d, runningDifference(cityHash64(t.1)) AS i FROM (SELECT arrayJoin([(NULL, 65535), ('a', 7), ('a', 3), ('b', 11), ('b', 2), ('', -9223372036854775808)]) AS t)) WHERE i = 9223372036854775807; diff --git a/tests/queries/0_stateless/01670_neighbor_lc_bug.sql b/tests/queries/0_stateless/01670_neighbor_lc_bug.sql index b665c0b48fd..599a1f49063 100644 --- a/tests/queries/0_stateless/01670_neighbor_lc_bug.sql +++ b/tests/queries/0_stateless/01670_neighbor_lc_bug.sql @@ -1,4 +1,4 @@ -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; SET output_format_pretty_row_numbers = 0; SELECT diff --git a/tests/queries/0_stateless/02496_remove_redundant_sorting.reference b/tests/queries/0_stateless/02496_remove_redundant_sorting.reference index dbb8ad02293..77ef213b36d 100644 --- a/tests/queries/0_stateless/02496_remove_redundant_sorting.reference +++ b/tests/queries/0_stateless/02496_remove_redundant_sorting.reference @@ -478,7 +478,7 @@ FROM ORDER BY number DESC ) ORDER BY number ASC -SETTINGS allow_deprecated_functions = 1 +SETTINGS allow_deprecated_error_prone_window_functions = 1 -- explain Expression (Projection) Sorting (Sorting for ORDER BY) diff --git a/tests/queries/0_stateless/02496_remove_redundant_sorting.sh b/tests/queries/0_stateless/02496_remove_redundant_sorting.sh index 31d2936628b..661b32fce72 100755 --- a/tests/queries/0_stateless/02496_remove_redundant_sorting.sh +++ b/tests/queries/0_stateless/02496_remove_redundant_sorting.sh @@ -315,7 +315,7 @@ FROM ORDER BY number DESC ) ORDER BY number ASC -SETTINGS allow_deprecated_functions = 1" +SETTINGS allow_deprecated_error_prone_window_functions = 1" run_query "$query" echo "-- non-stateful function does _not_ prevent removing inner ORDER BY" diff --git a/tests/queries/0_stateless/02496_remove_redundant_sorting_analyzer.reference b/tests/queries/0_stateless/02496_remove_redundant_sorting_analyzer.reference index d74ef70a23f..b6a2e3182df 100644 --- a/tests/queries/0_stateless/02496_remove_redundant_sorting_analyzer.reference +++ b/tests/queries/0_stateless/02496_remove_redundant_sorting_analyzer.reference @@ -477,7 +477,7 @@ FROM ORDER BY number DESC ) ORDER BY number ASC -SETTINGS allow_deprecated_functions = 1 +SETTINGS allow_deprecated_error_prone_window_functions = 1 -- explain Expression (Project names) Sorting (Sorting for ORDER BY) diff --git a/tests/queries/0_stateless/02788_fix_logical_error_in_sorting.sql b/tests/queries/0_stateless/02788_fix_logical_error_in_sorting.sql index 6964d8cf47d..97741e6fcc9 100644 --- a/tests/queries/0_stateless/02788_fix_logical_error_in_sorting.sql +++ b/tests/queries/0_stateless/02788_fix_logical_error_in_sorting.sql @@ -1,4 +1,4 @@ -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; DROP TABLE IF EXISTS session_events; DROP TABLE IF EXISTS event_types; diff --git a/tests/queries/0_stateless/02842_largestTriangleThreeBuckets_aggregate_function.sql b/tests/queries/0_stateless/02842_largestTriangleThreeBuckets_aggregate_function.sql index 254875ba041..d5ef564469e 100644 --- a/tests/queries/0_stateless/02842_largestTriangleThreeBuckets_aggregate_function.sql +++ b/tests/queries/0_stateless/02842_largestTriangleThreeBuckets_aggregate_function.sql @@ -1,4 +1,4 @@ -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; drop table if exists largestTriangleThreeBucketsTestFloat64Float64; CREATE TABLE largestTriangleThreeBucketsTestFloat64Float64 @@ -55,10 +55,10 @@ CREATE TABLE largestTriangleTreeBucketsBucketSizeTest INSERT INTO largestTriangleTreeBucketsBucketSizeTest (x, y) SELECT (number + 1) AS x, (x % 1000) AS y FROM numbers(9999); -SELECT - arrayJoin(lttb(1000)(x, y)) AS point, - tupleElement(point, 1) AS point_x, - point_x - neighbor(point_x, -1) AS point_x_diff_with_previous_row +SELECT + arrayJoin(lttb(1000)(x, y)) AS point, + tupleElement(point, 1) AS point_x, + point_x - neighbor(point_x, -1) AS point_x_diff_with_previous_row FROM largestTriangleTreeBucketsBucketSizeTest LIMIT 990, 10; DROP TABLE largestTriangleTreeBucketsBucketSizeTest; diff --git a/tests/queries/0_stateless/02901_predicate_pushdown_cte_stateful.sql b/tests/queries/0_stateless/02901_predicate_pushdown_cte_stateful.sql index a208519b655..d65b0da42a4 100644 --- a/tests/queries/0_stateless/02901_predicate_pushdown_cte_stateful.sql +++ b/tests/queries/0_stateless/02901_predicate_pushdown_cte_stateful.sql @@ -1,4 +1,4 @@ -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; CREATE TABLE t ( diff --git a/tests/queries/0_stateless/03131_deprecated_functions.sql b/tests/queries/0_stateless/03131_deprecated_functions.sql index 35cfe648c00..9247db15fd3 100644 --- a/tests/queries/0_stateless/03131_deprecated_functions.sql +++ b/tests/queries/0_stateless/03131_deprecated_functions.sql @@ -4,7 +4,7 @@ SELECT runningDifference(number) FROM system.numbers LIMIT 10; -- { serverError SELECT k, runningAccumulate(sum_k) AS res FROM (SELECT number as k, sumState(k) AS sum_k FROM numbers(10) GROUP BY k ORDER BY k); -- { serverError 721 } -SET allow_deprecated_functions=1; +SET allow_deprecated_error_prone_window_functions=1; SELECT number, neighbor(number, 2) FROM system.numbers LIMIT 10 FORMAT Null; diff --git a/tests/queries/1_stateful/00144_functions_of_aggregation_states.sql b/tests/queries/1_stateful/00144_functions_of_aggregation_states.sql index c5cd45d68b3..e30c132d242 100644 --- a/tests/queries/1_stateful/00144_functions_of_aggregation_states.sql +++ b/tests/queries/1_stateful/00144_functions_of_aggregation_states.sql @@ -1,3 +1,3 @@ -SET allow_deprecated_functions = 1; +SET allow_deprecated_error_prone_window_functions = 1; SELECT EventDate, finalizeAggregation(state), runningAccumulate(state) FROM (SELECT EventDate, uniqState(UserID) AS state FROM test.hits GROUP BY EventDate ORDER BY EventDate); From 07a24a8769d3b8efe13eeef3376bf331979ec5f4 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Fri, 24 May 2024 16:25:33 +0200 Subject: [PATCH 025/211] Initial implementation --- src/Functions/fromReadableSize.cpp | 231 ++++++++++++++++++ ...new_functions_must_be_documented.reference | 1 + 2 files changed, 232 insertions(+) create mode 100644 src/Functions/fromReadableSize.cpp diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp new file mode 100644 index 00000000000..f94eae36fad --- /dev/null +++ b/src/Functions/fromReadableSize.cpp @@ -0,0 +1,231 @@ +#include +#include + +#include +#include +#include +#include +#include "base/types.h" + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION; + extern const int TOO_MANY_ARGUMENTS_FOR_FUNCTION; + extern const int ILLEGAL_TYPE_OF_ARGUMENT; + extern const int BAD_ARGUMENTS; +} + +namespace +{ + + const std::unordered_map size_unit_to_bytes = + { + {"B", 1}, + // ISO/IEC 80000-13 binary units + {"KiB", 1024}, // 1024 + {"MiB", 1048576}, // 1024 * 1024 + {"GiB", 1073741824}, // 1024 * 1024 * 1024 + {"TiB", 1099511627776}, // 1024 * 1024 * 1024 * 1024 + {"PiB", 1125899906842624}, // 1024 * 1024 * 1024 * 1024 * 1024 + {"EiB", 1152921504606846976}, // 1024 * 1024 * 1024 * 1024 * 1024 * 1024 + + // SI units + {"KB", 1000}, // 10e3 + {"MB", 1000000}, // 10e6 + {"GB", 1000000000}, // 10e9 + {"TB", 1000000000000}, // 10e12 + {"PB", 1000000000000000}, // 10e15 + {"EB", 1000000000000000000}, // 10e18 + }; + + class FunctionFromReadableSize : public IFunction + { + public: + static constexpr auto name = "fromReadableSize"; + static FunctionPtr create(ContextPtr) { return std::make_shared(); } + + String getName() const override { return name; } + + bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } + + size_t getNumberOfArguments() const override { return 1; } + + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override + { + if (arguments.empty()) + throw Exception( + ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, + "Number of arguments for function {} doesn't match: passed {}, should be 1.", + getName(), + arguments.size()); + + if (arguments.size() > 1) + throw Exception( + ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, + "Number of arguments for function {} doesn't match: passed {}, should be 1.", + getName(), + arguments.size()); + + const IDataType & type = *arguments[0]; + + if (!isString(type)) + throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot format {} as time string.", type.getName()); + + return std::make_shared(); + } + + bool useDefaultImplementationForConstants() const override { return true; } + + ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override + { + auto col_to = ColumnUInt64::create(); + auto & res_data = col_to->getData(); + + for (size_t i = 0; i < input_rows_count; ++i) + { + std::string_view str{arguments[0].column->getDataAt(i)}; + Int64 token_tail = 0; + Int64 token_front = 0; + Int64 last_pos = str.length() - 1; + UInt64 result = 0; + + /// ignore '.' and ' ' at the end of string + while (last_pos >= 0 && (str[last_pos] == ' ' || str[last_pos] == '.')) + --last_pos; + + /// no valid characters + if (last_pos < 0) + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {}, don't find valid characters, str: \"{}\".", + getName(), + String(str)); + } + + /// last pos character must be character and not be separator or number after ignoring '.' and ' ' + if (!isalpha(str[last_pos])) + { + throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, str: \"{}\".", getName(), String(str)); + } + + /// scan spaces at the beginning + scanSpaces(str, token_tail, last_pos); + token_front = token_tail; + /// scan unsigned integer + if (!scanUnsignedInteger(str, token_tail, last_pos)) + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {}, find number failed, str: \"{}\".", + getName(), + String(str)); + } + + /// if there is a '.', then scan another integer to get a float number + if (token_tail <= last_pos && str[token_tail] == '.') + { + token_tail++; + if (!scanUnsignedInteger(str, token_tail, last_pos)) + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {}, find number after '.' failed, str: \"{}\".", + getName(), + String(str)); + } + } + + /// convert float/integer string to float + Float64 base = 0; + std::string_view base_str = str.substr(token_front, token_tail - token_front); + auto value = boost::convert(base_str, boost::cnv::strtol()); + if (!value.has_value()) + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {}, convert string to float64 failed: \"{}\".", + getName(), + String(base_str)); + } + base = value.get(); + + scanSpaces(str, token_tail, last_pos); + token_front = token_tail; + + /// scan a unit + if (!scanUnit(str, token_tail, last_pos)) + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {}, find unit failed, str: \"{}\".", + getName(), + String(str)); + } + + /// get unit number + std::string_view unit = str.substr(token_front, token_tail - token_front); + auto iter = size_unit_to_bytes.find(unit); + if (iter == size_unit_to_bytes.end()) /// not find unit + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, parse unit failed: \"{}\".", getName(), unit); + } + // Due to a pontentially limited precision on the input value we might end up with a non-integer amount of bytes when parsing binary units. + // This doesn't make sense so we round up to indicate the byte size that can fit the passed size. + result = static_cast(std::ceil(base * iter->second)); + + res_data.emplace_back(result); + } + + return col_to; + } + + /// scan an unsigned integer number + static bool scanUnsignedInteger(std::string_view & str, Int64 & index, Int64 last_pos) + { + int64_t begin_index = index; + while (index <= last_pos && isdigit(str[index])) + { + index++; + } + return index != begin_index; + } + + /// scan a unit + static bool scanUnit(std::string_view & str, Int64 & index, Int64 last_pos) + { + int64_t begin_index = index; + while (index <= last_pos && !isdigit(str[index]) && !isSeparator(str[index])) + { + index++; + } + return index != begin_index; + } + + /// scan spaces + static void scanSpaces(std::string_view & str, Int64 & index, Int64 last_pos) + { + while (index <= last_pos && (str[index] == ' ')) + { + index++; + } + } + + static bool isSeparator(char symbol) + { + return symbol == ';' || symbol == '-' || symbol == '+' || symbol == ',' || symbol == ':' || symbol == ' '; + } + }; + +} + +REGISTER_FUNCTION(FromReadableSize) +{ + factory.registerFunction(); +} + +} diff --git a/tests/queries/0_stateless/02415_all_new_functions_must_be_documented.reference b/tests/queries/0_stateless/02415_all_new_functions_must_be_documented.reference index a152066a460..0218e7e5bbd 100644 --- a/tests/queries/0_stateless/02415_all_new_functions_must_be_documented.reference +++ b/tests/queries/0_stateless/02415_all_new_functions_must_be_documented.reference @@ -305,6 +305,7 @@ formatRowNoNewline fragment fromModifiedJulianDay fromModifiedJulianDayOrNull +fromReadableSize fromUTCTimestamp fromUnixTimestamp fromUnixTimestamp64Micro From 97f03ad242b0a82368fd5233ffeb428c98f6be64 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Fri, 24 May 2024 16:39:38 +0200 Subject: [PATCH 026/211] Add stateless tests --- .../03166_from_readable_size.reference | 18 +++++++++++++ .../0_stateless/03166_from_readable_size.sql | 27 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/queries/0_stateless/03166_from_readable_size.reference create mode 100644 tests/queries/0_stateless/03166_from_readable_size.sql diff --git a/tests/queries/0_stateless/03166_from_readable_size.reference b/tests/queries/0_stateless/03166_from_readable_size.reference new file mode 100644 index 00000000000..9456fc6a9ea --- /dev/null +++ b/tests/queries/0_stateless/03166_from_readable_size.reference @@ -0,0 +1,18 @@ +1.00 B +1.00 KiB +1.00 MiB +1.00 GiB +1.00 TiB +1.00 PiB +1.00 EiB +1.00 B +1.00 KB +1.00 MB +1.00 GB +1.00 TB +1.00 PB +1.00 EB +1024 +3072 +1025 +1024 diff --git a/tests/queries/0_stateless/03166_from_readable_size.sql b/tests/queries/0_stateless/03166_from_readable_size.sql new file mode 100644 index 00000000000..2ec81b44b14 --- /dev/null +++ b/tests/queries/0_stateless/03166_from_readable_size.sql @@ -0,0 +1,27 @@ +-- Should be the inverse of formatReadableSize +SELECT formatReadableSize(fromReadableSize('1 B')); +SELECT formatReadableSize(fromReadableSize('1 KiB')); +SELECT formatReadableSize(fromReadableSize('1 MiB')); +SELECT formatReadableSize(fromReadableSize('1 GiB')); +SELECT formatReadableSize(fromReadableSize('1 TiB')); +SELECT formatReadableSize(fromReadableSize('1 PiB')); +SELECT formatReadableSize(fromReadableSize('1 EiB')); + +-- Should be the inverse of formatReadableDecimalSize +SELECT formatReadableDecimalSize(fromReadableSize('1 B')); +SELECT formatReadableDecimalSize(fromReadableSize('1 KB')); +SELECT formatReadableDecimalSize(fromReadableSize('1 MB')); +SELECT formatReadableDecimalSize(fromReadableSize('1 GB')); +SELECT formatReadableDecimalSize(fromReadableSize('1 TB')); +SELECT formatReadableDecimalSize(fromReadableSize('1 PB')); +SELECT formatReadableDecimalSize(fromReadableSize('1 EB')); + +-- Should be able to parse decimals +SELECT fromReadableSize('1.00 KiB'); -- 1024 +SELECT fromReadableSize('3.00 KiB'); -- 3072 + +-- Resulting bytes are rounded up +SELECT fromReadableSize('1.0001 KiB'); -- 1025 + +-- Surrounding whitespace and trailing punctuation is ignored +SELECT fromReadableSize(' 1 KiB. '); \ No newline at end of file From 6d5805d260977c47ff86ba6f1b64e5531b300060 Mon Sep 17 00:00:00 2001 From: vdimir Date: Fri, 24 May 2024 14:54:39 +0000 Subject: [PATCH 027/211] Do not run tests with 'no-s3-storage-with-slow-build' with ASan --- tests/clickhouse-test | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/clickhouse-test b/tests/clickhouse-test index 133d635f8a0..07e86fbfecc 100755 --- a/tests/clickhouse-test +++ b/tests/clickhouse-test @@ -1223,12 +1223,9 @@ class TestCase: return FailureReason.S3_STORAGE elif ( tags - and ("no-s3-storage-with-slow-build" in tags) + and "no-s3-storage-with-slow-build" in tags and args.s3_storage - and ( - BuildFlags.THREAD in args.build_flags - or BuildFlags.DEBUG in args.build_flags - ) + and BuildFlags.RELEASE not in args.build_flags ): return FailureReason.S3_STORAGE From 0b7ef001613c206485c5123b8faef13afbf4d7a8 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Fri, 24 May 2024 17:08:29 +0200 Subject: [PATCH 028/211] Update docs --- .../functions/other-functions.md | 31 +++++++++++++++++++ src/Functions/fromReadableSize.cpp | 23 +++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/docs/en/sql-reference/functions/other-functions.md b/docs/en/sql-reference/functions/other-functions.md index 12b565d5358..64ff22fd948 100644 --- a/docs/en/sql-reference/functions/other-functions.md +++ b/docs/en/sql-reference/functions/other-functions.md @@ -777,6 +777,37 @@ Alias: `FORMAT_BYTES`. └────────────────┴────────────┘ ``` +## fromReadableSize(x) + +Given a string containing the readable respresentation of a byte size, this function returns the corrseponding number of bytes. + - As the conversion might lead to decimal bytes the result will be rounded up to the next integer to represent the minimum number of bytes that can fit the passed size. + - Accepts up to the Exabyte/Exabibyte (EB/EiB) + +**Arguments** + +- `val` : readable size. [String](../data-types/string) + +**Returned value** + +- Number of bytes represented by the readable size [UInt64](../data-types/int-uint.md). + +Example: + +```sql +SELECT + arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KB']) AS readable_sizes, + fromReadableSize(readable_sizes) AS sizes +``` + +```text +┌─readable_sizes─┬───sizes─┐ +│ 1 B │ 1 │ +│ 1 KiB │ 1024 │ +│ 3 MiB │ 3145728 │ +│ 5.314 KB │ 5314 │ +└────────────────┴─────────┘ +``` + ## formatReadableQuantity(x) Given a number, this function returns a rounded number with suffix (thousand, million, billion, etc.) as string. diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index f94eae36fad..d4270de60c9 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -225,7 +225,28 @@ namespace REGISTER_FUNCTION(FromReadableSize) { - factory.registerFunction(); + factory.registerFunction(FunctionDocumentation + { + .description=R"( +Given a string containing the readable respresentation of a byte size, this function returns the corrseponding number of bytes: +[example:basic_binary] +[example:basic_decimal] + +If the resulting number of bytes has a non-zero decimal part, the result is rounded up to indicate the number of bytes necessary to accommodate the provided size. +[example:round] + +Accepts readable sizes up to the ExaByte (EB/EiB). + +It always returns an UInt64 value. +)", + .examples{ + {"basic_binary", "SELECT fromReadableSize('1 KiB')", "1024"}, + {"basic_decimal", "SELECT fromReadableSize('1.523 KB')", "1523"}, + {"round", "SELECT fromReadableSize('1.0001 KiB')", "1025"}, + }, + .categories{"OtherFunctions"} + } + ); } } From a3f80626b921d13a298b5ce0149a2908874d698c Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Fri, 24 May 2024 17:09:32 +0200 Subject: [PATCH 029/211] Update dictionary ignore --- utils/check-style/aspell-ignore/en/aspell-dict.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/check-style/aspell-ignore/en/aspell-dict.txt b/utils/check-style/aspell-ignore/en/aspell-dict.txt index 1c601bc200a..7ad271f1b3d 100644 --- a/utils/check-style/aspell-ignore/en/aspell-dict.txt +++ b/utils/check-style/aspell-ignore/en/aspell-dict.txt @@ -1621,6 +1621,7 @@ freezed fromDaysSinceYearZero fromModifiedJulianDay fromModifiedJulianDayOrNull +fromReadableSize fromUTCTimestamp fromUnixTimestamp fromUnixTimestampInJodaSyntax From c5b70f595e465b6ae62dfb9506ab595e656f8761 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Sat, 25 May 2024 07:52:26 +0200 Subject: [PATCH 030/211] Make unit case-insensitive --- src/Functions/fromReadableSize.cpp | 32 +++++++++---------- .../03166_from_readable_size.reference | 2 ++ .../0_stateless/03166_from_readable_size.sql | 4 +++ 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index d4270de60c9..02996a08fdc 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -5,7 +6,6 @@ #include #include #include -#include "base/types.h" namespace DB { @@ -23,22 +23,22 @@ namespace const std::unordered_map size_unit_to_bytes = { - {"B", 1}, + {"b", 1}, // ISO/IEC 80000-13 binary units - {"KiB", 1024}, // 1024 - {"MiB", 1048576}, // 1024 * 1024 - {"GiB", 1073741824}, // 1024 * 1024 * 1024 - {"TiB", 1099511627776}, // 1024 * 1024 * 1024 * 1024 - {"PiB", 1125899906842624}, // 1024 * 1024 * 1024 * 1024 * 1024 - {"EiB", 1152921504606846976}, // 1024 * 1024 * 1024 * 1024 * 1024 * 1024 + {"kib", 1024}, // 1024 + {"mib", 1048576}, // 1024 * 1024 + {"gib", 1073741824}, // 1024 * 1024 * 1024 + {"tib", 1099511627776}, // 1024 * 1024 * 1024 * 1024 + {"pib", 1125899906842624}, // 1024 * 1024 * 1024 * 1024 * 1024 + {"eib", 1152921504606846976}, // 1024 * 1024 * 1024 * 1024 * 1024 * 1024 // SI units - {"KB", 1000}, // 10e3 - {"MB", 1000000}, // 10e6 - {"GB", 1000000000}, // 10e9 - {"TB", 1000000000000}, // 10e12 - {"PB", 1000000000000000}, // 10e15 - {"EB", 1000000000000000000}, // 10e18 + {"kb", 1000}, // 10e3 + {"mb", 1000000}, // 10e6 + {"gb", 1000000000}, // 10e9 + {"tb", 1000000000000}, // 10e12 + {"pb", 1000000000000000}, // 10e15 + {"eb", 1000000000000000000}, // 10e18 }; class FunctionFromReadableSize : public IFunction @@ -166,8 +166,8 @@ namespace String(str)); } - /// get unit number - std::string_view unit = str.substr(token_front, token_tail - token_front); + std::string unit = std::string{str.substr(token_front, token_tail - token_front)}; + boost::algorithm::to_lower(unit); auto iter = size_unit_to_bytes.find(unit); if (iter == size_unit_to_bytes.end()) /// not find unit { diff --git a/tests/queries/0_stateless/03166_from_readable_size.reference b/tests/queries/0_stateless/03166_from_readable_size.reference index 9456fc6a9ea..0579e74baff 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.reference +++ b/tests/queries/0_stateless/03166_from_readable_size.reference @@ -12,6 +12,8 @@ 1.00 TB 1.00 PB 1.00 EB +1.00 MiB +1.00 MB 1024 3072 1025 diff --git a/tests/queries/0_stateless/03166_from_readable_size.sql b/tests/queries/0_stateless/03166_from_readable_size.sql index 2ec81b44b14..e8c333e2237 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.sql +++ b/tests/queries/0_stateless/03166_from_readable_size.sql @@ -16,6 +16,10 @@ SELECT formatReadableDecimalSize(fromReadableSize('1 TB')); SELECT formatReadableDecimalSize(fromReadableSize('1 PB')); SELECT formatReadableDecimalSize(fromReadableSize('1 EB')); +-- Is case-insensitive +SELECT formatReadableSize(fromReadableSize('1 mIb')); +SELECT formatReadableDecimalSize(fromReadableSize('1 mb')); + -- Should be able to parse decimals SELECT fromReadableSize('1.00 KiB'); -- 1024 SELECT fromReadableSize('3.00 KiB'); -- 3072 From 12760dddae214c8daaa7770e3b082765371df004 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Sat, 25 May 2024 07:55:36 +0200 Subject: [PATCH 031/211] Fix typos in doc --- docs/en/sql-reference/functions/other-functions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/sql-reference/functions/other-functions.md b/docs/en/sql-reference/functions/other-functions.md index 845e2ae5a64..2984cca81c7 100644 --- a/docs/en/sql-reference/functions/other-functions.md +++ b/docs/en/sql-reference/functions/other-functions.md @@ -796,9 +796,9 @@ Result: ## fromReadableSize -Given a string containing the readable respresentation of a byte size, this function returns the corrseponding number of bytes. +Given a string containing the readable representation of a byte size, this function returns the corresponding number of bytes. - As the conversion might lead to decimal bytes the result will be rounded up to the next integer to represent the minimum number of bytes that can fit the passed size. - - Accepts up to the Exabyte/Exabibyte (EB/EiB) + - Accepts up to the Exabyte (EB/EiB) **Arguments** From 664c9358ca144084a453afa0247299d8770fd332 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Sat, 25 May 2024 08:22:48 +0200 Subject: [PATCH 032/211] Fix typos in docstring --- src/Functions/fromReadableSize.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index 02996a08fdc..428ee769d9c 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -228,14 +228,14 @@ REGISTER_FUNCTION(FromReadableSize) factory.registerFunction(FunctionDocumentation { .description=R"( -Given a string containing the readable respresentation of a byte size, this function returns the corrseponding number of bytes: +Given a string containing the readable representation of a byte size, this function returns the corresponding number of bytes: [example:basic_binary] [example:basic_decimal] If the resulting number of bytes has a non-zero decimal part, the result is rounded up to indicate the number of bytes necessary to accommodate the provided size. [example:round] -Accepts readable sizes up to the ExaByte (EB/EiB). +Accepts readable sizes up to the Exabyte (EB/EiB). It always returns an UInt64 value. )", From bc9cfb058492bd2ff2ca50e5831e7172495f1262 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Sat, 25 May 2024 10:38:39 +0200 Subject: [PATCH 033/211] Remove fromReadableSize from undocumented function test reference --- .../02415_all_new_functions_must_be_documented.reference | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/queries/0_stateless/02415_all_new_functions_must_be_documented.reference b/tests/queries/0_stateless/02415_all_new_functions_must_be_documented.reference index 0218e7e5bbd..a152066a460 100644 --- a/tests/queries/0_stateless/02415_all_new_functions_must_be_documented.reference +++ b/tests/queries/0_stateless/02415_all_new_functions_must_be_documented.reference @@ -305,7 +305,6 @@ formatRowNoNewline fragment fromModifiedJulianDay fromModifiedJulianDayOrNull -fromReadableSize fromUTCTimestamp fromUnixTimestamp fromUnixTimestamp64Micro From ce2025676f71bc915807b57bb0ce65845495fc71 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Sat, 25 May 2024 20:25:37 +0200 Subject: [PATCH 034/211] add check for result being too big to be represented in output --- src/Functions/fromReadableSize.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index 428ee769d9c..685099b2398 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,6 +7,7 @@ #include #include #include +#include "base/types.h" namespace DB { @@ -40,6 +42,8 @@ namespace {"pb", 1000000000000000}, // 10e15 {"eb", 1000000000000000000}, // 10e18 }; + + constexpr UInt64 MAX_UINT64 = std::numeric_limits::max(); class FunctionFromReadableSize : public IFunction { @@ -174,9 +178,19 @@ namespace throw Exception( ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, parse unit failed: \"{}\".", getName(), unit); } - // Due to a pontentially limited precision on the input value we might end up with a non-integer amount of bytes when parsing binary units. + Float64 raw_num_bytes = base * iter->second; + if (raw_num_bytes > MAX_UINT64) + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {}, result is too big for output data type (UInt64): \"{}\".", + getName(), + raw_num_bytes + ); + } + // As the input might be an arbitrary decimal number we might end up with a non-integer amount of bytes when parsing binary (eg MiB) units. // This doesn't make sense so we round up to indicate the byte size that can fit the passed size. - result = static_cast(std::ceil(base * iter->second)); + result = static_cast(std::ceil(raw_num_bytes)); res_data.emplace_back(result); } From 6d710d06a6d9a51645030a0719fe2cc3b54b4cb8 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Sat, 25 May 2024 20:33:22 +0200 Subject: [PATCH 035/211] Remove trailing whitespace --- src/Functions/fromReadableSize.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index 685099b2398..69a6a3190e6 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -42,7 +42,6 @@ namespace {"pb", 1000000000000000}, // 10e15 {"eb", 1000000000000000000}, // 10e18 }; - constexpr UInt64 MAX_UINT64 = std::numeric_limits::max(); class FunctionFromReadableSize : public IFunction From 6db2a42d192aa60bc89e91e304d4729471fbd432 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 11:42:27 +0200 Subject: [PATCH 036/211] Unindent contents of anonymous namespace --- src/Functions/fromReadableSize.cpp | 354 ++++++++++++++--------------- 1 file changed, 177 insertions(+), 177 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index 69a6a3190e6..f5b646e5a0d 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -23,216 +23,216 @@ namespace ErrorCodes namespace { - const std::unordered_map size_unit_to_bytes = +const std::unordered_map size_unit_to_bytes = +{ + {"b", 1}, + // ISO/IEC 80000-13 binary units + {"kib", 1024}, // 1024 + {"mib", 1048576}, // 1024 * 1024 + {"gib", 1073741824}, // 1024 * 1024 * 1024 + {"tib", 1099511627776}, // 1024 * 1024 * 1024 * 1024 + {"pib", 1125899906842624}, // 1024 * 1024 * 1024 * 1024 * 1024 + {"eib", 1152921504606846976}, // 1024 * 1024 * 1024 * 1024 * 1024 * 1024 + + // SI units + {"kb", 1000}, // 10e3 + {"mb", 1000000}, // 10e6 + {"gb", 1000000000}, // 10e9 + {"tb", 1000000000000}, // 10e12 + {"pb", 1000000000000000}, // 10e15 + {"eb", 1000000000000000000}, // 10e18 +}; +constexpr UInt64 MAX_UINT64 = std::numeric_limits::max(); + +class FunctionFromReadableSize : public IFunction +{ +public: + static constexpr auto name = "fromReadableSize"; + static FunctionPtr create(ContextPtr) { return std::make_shared(); } + + String getName() const override { return name; } + + bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } + + size_t getNumberOfArguments() const override { return 1; } + + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { - {"b", 1}, - // ISO/IEC 80000-13 binary units - {"kib", 1024}, // 1024 - {"mib", 1048576}, // 1024 * 1024 - {"gib", 1073741824}, // 1024 * 1024 * 1024 - {"tib", 1099511627776}, // 1024 * 1024 * 1024 * 1024 - {"pib", 1125899906842624}, // 1024 * 1024 * 1024 * 1024 * 1024 - {"eib", 1152921504606846976}, // 1024 * 1024 * 1024 * 1024 * 1024 * 1024 + if (arguments.empty()) + throw Exception( + ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, + "Number of arguments for function {} doesn't match: passed {}, should be 1.", + getName(), + arguments.size()); - // SI units - {"kb", 1000}, // 10e3 - {"mb", 1000000}, // 10e6 - {"gb", 1000000000}, // 10e9 - {"tb", 1000000000000}, // 10e12 - {"pb", 1000000000000000}, // 10e15 - {"eb", 1000000000000000000}, // 10e18 - }; - constexpr UInt64 MAX_UINT64 = std::numeric_limits::max(); + if (arguments.size() > 1) + throw Exception( + ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, + "Number of arguments for function {} doesn't match: passed {}, should be 1.", + getName(), + arguments.size()); - class FunctionFromReadableSize : public IFunction + const IDataType & type = *arguments[0]; + + if (!isString(type)) + throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot format {} as time string.", type.getName()); + + return std::make_shared(); + } + + bool useDefaultImplementationForConstants() const override { return true; } + + ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { - public: - static constexpr auto name = "fromReadableSize"; - static FunctionPtr create(ContextPtr) { return std::make_shared(); } + auto col_to = ColumnUInt64::create(); + auto & res_data = col_to->getData(); - String getName() const override { return name; } - - bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } - - size_t getNumberOfArguments() const override { return 1; } - - DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override + for (size_t i = 0; i < input_rows_count; ++i) { - if (arguments.empty()) - throw Exception( - ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, - "Number of arguments for function {} doesn't match: passed {}, should be 1.", - getName(), - arguments.size()); + std::string_view str{arguments[0].column->getDataAt(i)}; + Int64 token_tail = 0; + Int64 token_front = 0; + Int64 last_pos = str.length() - 1; + UInt64 result = 0; - if (arguments.size() > 1) - throw Exception( - ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, - "Number of arguments for function {} doesn't match: passed {}, should be 1.", - getName(), - arguments.size()); + /// ignore '.' and ' ' at the end of string + while (last_pos >= 0 && (str[last_pos] == ' ' || str[last_pos] == '.')) + --last_pos; - const IDataType & type = *arguments[0]; - - if (!isString(type)) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot format {} as time string.", type.getName()); - - return std::make_shared(); - } - - bool useDefaultImplementationForConstants() const override { return true; } - - ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override - { - auto col_to = ColumnUInt64::create(); - auto & res_data = col_to->getData(); - - for (size_t i = 0; i < input_rows_count; ++i) + /// no valid characters + if (last_pos < 0) { - std::string_view str{arguments[0].column->getDataAt(i)}; - Int64 token_tail = 0; - Int64 token_front = 0; - Int64 last_pos = str.length() - 1; - UInt64 result = 0; + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {}, don't find valid characters, str: \"{}\".", + getName(), + String(str)); + } - /// ignore '.' and ' ' at the end of string - while (last_pos >= 0 && (str[last_pos] == ' ' || str[last_pos] == '.')) - --last_pos; + /// last pos character must be character and not be separator or number after ignoring '.' and ' ' + if (!isalpha(str[last_pos])) + { + throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, str: \"{}\".", getName(), String(str)); + } - /// no valid characters - if (last_pos < 0) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {}, don't find valid characters, str: \"{}\".", - getName(), - String(str)); - } + /// scan spaces at the beginning + scanSpaces(str, token_tail, last_pos); + token_front = token_tail; + /// scan unsigned integer + if (!scanUnsignedInteger(str, token_tail, last_pos)) + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {}, find number failed, str: \"{}\".", + getName(), + String(str)); + } - /// last pos character must be character and not be separator or number after ignoring '.' and ' ' - if (!isalpha(str[last_pos])) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, str: \"{}\".", getName(), String(str)); - } - - /// scan spaces at the beginning - scanSpaces(str, token_tail, last_pos); - token_front = token_tail; - /// scan unsigned integer + /// if there is a '.', then scan another integer to get a float number + if (token_tail <= last_pos && str[token_tail] == '.') + { + token_tail++; if (!scanUnsignedInteger(str, token_tail, last_pos)) { throw Exception( ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {}, find number failed, str: \"{}\".", + "Invalid expression for function {}, find number after '.' failed, str: \"{}\".", getName(), String(str)); } - - /// if there is a '.', then scan another integer to get a float number - if (token_tail <= last_pos && str[token_tail] == '.') - { - token_tail++; - if (!scanUnsignedInteger(str, token_tail, last_pos)) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {}, find number after '.' failed, str: \"{}\".", - getName(), - String(str)); - } - } - - /// convert float/integer string to float - Float64 base = 0; - std::string_view base_str = str.substr(token_front, token_tail - token_front); - auto value = boost::convert(base_str, boost::cnv::strtol()); - if (!value.has_value()) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {}, convert string to float64 failed: \"{}\".", - getName(), - String(base_str)); - } - base = value.get(); - - scanSpaces(str, token_tail, last_pos); - token_front = token_tail; - - /// scan a unit - if (!scanUnit(str, token_tail, last_pos)) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {}, find unit failed, str: \"{}\".", - getName(), - String(str)); - } - - std::string unit = std::string{str.substr(token_front, token_tail - token_front)}; - boost::algorithm::to_lower(unit); - auto iter = size_unit_to_bytes.find(unit); - if (iter == size_unit_to_bytes.end()) /// not find unit - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, parse unit failed: \"{}\".", getName(), unit); - } - Float64 raw_num_bytes = base * iter->second; - if (raw_num_bytes > MAX_UINT64) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {}, result is too big for output data type (UInt64): \"{}\".", - getName(), - raw_num_bytes - ); - } - // As the input might be an arbitrary decimal number we might end up with a non-integer amount of bytes when parsing binary (eg MiB) units. - // This doesn't make sense so we round up to indicate the byte size that can fit the passed size. - result = static_cast(std::ceil(raw_num_bytes)); - - res_data.emplace_back(result); } - return col_to; - } - - /// scan an unsigned integer number - static bool scanUnsignedInteger(std::string_view & str, Int64 & index, Int64 last_pos) - { - int64_t begin_index = index; - while (index <= last_pos && isdigit(str[index])) + /// convert float/integer string to float + Float64 base = 0; + std::string_view base_str = str.substr(token_front, token_tail - token_front); + auto value = boost::convert(base_str, boost::cnv::strtol()); + if (!value.has_value()) { - index++; + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {}, convert string to float64 failed: \"{}\".", + getName(), + String(base_str)); } - return index != begin_index; - } + base = value.get(); - /// scan a unit - static bool scanUnit(std::string_view & str, Int64 & index, Int64 last_pos) - { - int64_t begin_index = index; - while (index <= last_pos && !isdigit(str[index]) && !isSeparator(str[index])) + scanSpaces(str, token_tail, last_pos); + token_front = token_tail; + + /// scan a unit + if (!scanUnit(str, token_tail, last_pos)) { - index++; + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {}, find unit failed, str: \"{}\".", + getName(), + String(str)); } - return index != begin_index; - } - /// scan spaces - static void scanSpaces(std::string_view & str, Int64 & index, Int64 last_pos) - { - while (index <= last_pos && (str[index] == ' ')) + std::string unit = std::string{str.substr(token_front, token_tail - token_front)}; + boost::algorithm::to_lower(unit); + auto iter = size_unit_to_bytes.find(unit); + if (iter == size_unit_to_bytes.end()) /// not find unit { - index++; + throw Exception( + ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, parse unit failed: \"{}\".", getName(), unit); } + Float64 raw_num_bytes = base * iter->second; + if (raw_num_bytes > MAX_UINT64) + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {}, result is too big for output data type (UInt64): \"{}\".", + getName(), + raw_num_bytes + ); + } + // As the input might be an arbitrary decimal number we might end up with a non-integer amount of bytes when parsing binary (eg MiB) units. + // This doesn't make sense so we round up to indicate the byte size that can fit the passed size. + result = static_cast(std::ceil(raw_num_bytes)); + + res_data.emplace_back(result); } - static bool isSeparator(char symbol) + return col_to; + } + + /// scan an unsigned integer number + static bool scanUnsignedInteger(std::string_view & str, Int64 & index, Int64 last_pos) + { + int64_t begin_index = index; + while (index <= last_pos && isdigit(str[index])) { - return symbol == ';' || symbol == '-' || symbol == '+' || symbol == ',' || symbol == ':' || symbol == ' '; + index++; } - }; + return index != begin_index; + } + + /// scan a unit + static bool scanUnit(std::string_view & str, Int64 & index, Int64 last_pos) + { + int64_t begin_index = index; + while (index <= last_pos && !isdigit(str[index]) && !isSeparator(str[index])) + { + index++; + } + return index != begin_index; + } + + /// scan spaces + static void scanSpaces(std::string_view & str, Int64 & index, Int64 last_pos) + { + while (index <= last_pos && (str[index] == ' ')) + { + index++; + } + } + + static bool isSeparator(char symbol) + { + return symbol == ';' || symbol == '-' || symbol == '+' || symbol == ',' || symbol == ':' || symbol == ' '; + } +}; } From 28640e43234fd25f66efb71fef7fe9bf72b44b21 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 11:44:32 +0200 Subject: [PATCH 037/211] Expand the values of the size mapping --- src/Functions/fromReadableSize.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index f5b646e5a0d..b42797aa731 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -27,20 +27,20 @@ const std::unordered_map size_unit_to_bytes = { {"b", 1}, // ISO/IEC 80000-13 binary units - {"kib", 1024}, // 1024 - {"mib", 1048576}, // 1024 * 1024 - {"gib", 1073741824}, // 1024 * 1024 * 1024 - {"tib", 1099511627776}, // 1024 * 1024 * 1024 * 1024 - {"pib", 1125899906842624}, // 1024 * 1024 * 1024 * 1024 * 1024 - {"eib", 1152921504606846976}, // 1024 * 1024 * 1024 * 1024 * 1024 * 1024 + {"kib", 1024}, + {"mib", 1024 * 1024}, + {"gib", 1024 * 1024 * 1024}, + {"tib", 1024 * 1024 * 1024 * 1024}, + {"pib", 1024 * 1024 * 1024 * 1024 * 1024}, + {"eib", 1024 * 1024 * 1024 * 1024 * 1024 * 1024}, // SI units - {"kb", 1000}, // 10e3 - {"mb", 1000000}, // 10e6 - {"gb", 1000000000}, // 10e9 - {"tb", 1000000000000}, // 10e12 - {"pb", 1000000000000000}, // 10e15 - {"eb", 1000000000000000000}, // 10e18 + {"kb", 1000}, + {"mb", 1000 * 1000}, + {"gb", 1000 * 1000 * 1000}, + {"tb", 1000 * 1000 * 1000 * 1000}, + {"pb", 1000 * 1000 * 1000 * 1000 * 1000}, + {"eb", 1000 * 1000 * 1000 * 1000 * 1000 * 1000}, }; constexpr UInt64 MAX_UINT64 = std::numeric_limits::max(); From b6dfa25ca4315247de7b5d98cd712a1fee03adf7 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 11:45:08 +0200 Subject: [PATCH 038/211] Get rid of single-use constant --- src/Functions/fromReadableSize.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index b42797aa731..f59f7f92d45 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -42,7 +42,6 @@ const std::unordered_map size_unit_to_bytes = {"pb", 1000 * 1000 * 1000 * 1000 * 1000}, {"eb", 1000 * 1000 * 1000 * 1000 * 1000 * 1000}, }; -constexpr UInt64 MAX_UINT64 = std::numeric_limits::max(); class FunctionFromReadableSize : public IFunction { @@ -178,7 +177,7 @@ public: ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, parse unit failed: \"{}\".", getName(), unit); } Float64 raw_num_bytes = base * iter->second; - if (raw_num_bytes > MAX_UINT64) + if (raw_num_bytes > std::numeric_limits::max()) { throw Exception( ErrorCodes::BAD_ARGUMENTS, From de843aad15ecca04b0023f08466dc929f7c965dc Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 11:57:38 +0200 Subject: [PATCH 039/211] Use FunctionArgumentDescriptor for argument valdation --- src/Functions/fromReadableSize.cpp | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index f59f7f92d45..69d8f766a9c 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -6,8 +6,8 @@ #include #include #include +#include #include -#include "base/types.h" namespace DB { @@ -55,26 +55,13 @@ public: size_t getNumberOfArguments() const override { return 1; } - DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override + DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override { - if (arguments.empty()) - throw Exception( - ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, - "Number of arguments for function {} doesn't match: passed {}, should be 1.", - getName(), - arguments.size()); - - if (arguments.size() > 1) - throw Exception( - ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, - "Number of arguments for function {} doesn't match: passed {}, should be 1.", - getName(), - arguments.size()); - - const IDataType & type = *arguments[0]; - - if (!isString(type)) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot format {} as time string.", type.getName()); + FunctionArgumentDescriptors args + { + {"readable_size", static_cast(&isString), nullptr, "String"}, + }; + validateFunctionArgumentTypes(*this, arguments, args); return std::make_shared(); } From 8f42eb6ac726c5de60ba9b3bbb53de5a41939f33 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 11:59:11 +0200 Subject: [PATCH 040/211] Move useDefaultImplementationforconstants up, compact one-line function definitions --- src/Functions/fromReadableSize.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index 69d8f766a9c..6801516f920 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -47,12 +47,11 @@ class FunctionFromReadableSize : public IFunction { public: static constexpr auto name = "fromReadableSize"; + static FunctionPtr create(ContextPtr) { return std::make_shared(); } - String getName() const override { return name; } - bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } - + bool useDefaultImplementationForConstants() const override { return true; } size_t getNumberOfArguments() const override { return 1; } DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override @@ -66,7 +65,7 @@ public: return std::make_shared(); } - bool useDefaultImplementationForConstants() const override { return true; } + ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { From fc67d54128c63da174536ce20c0104e1217dd3d3 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 12:06:13 +0200 Subject: [PATCH 041/211] Do not ignore trailing whitespace and periods --- src/Functions/fromReadableSize.cpp | 6 +----- tests/queries/0_stateless/03166_from_readable_size.sql | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index 6801516f920..c0b46b98b20 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -74,16 +74,12 @@ public: for (size_t i = 0; i < input_rows_count; ++i) { - std::string_view str{arguments[0].column->getDataAt(i)}; + std::string_view str = arguments[0].column->getDataAt(i).toView(); Int64 token_tail = 0; Int64 token_front = 0; Int64 last_pos = str.length() - 1; UInt64 result = 0; - /// ignore '.' and ' ' at the end of string - while (last_pos >= 0 && (str[last_pos] == ' ' || str[last_pos] == '.')) - --last_pos; - /// no valid characters if (last_pos < 0) { diff --git a/tests/queries/0_stateless/03166_from_readable_size.sql b/tests/queries/0_stateless/03166_from_readable_size.sql index e8c333e2237..9e4cd7829da 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.sql +++ b/tests/queries/0_stateless/03166_from_readable_size.sql @@ -27,5 +27,5 @@ SELECT fromReadableSize('3.00 KiB'); -- 3072 -- Resulting bytes are rounded up SELECT fromReadableSize('1.0001 KiB'); -- 1025 --- Surrounding whitespace and trailing punctuation is ignored -SELECT fromReadableSize(' 1 KiB. '); \ No newline at end of file +-- Leading & infix whitespace is ignored +SELECT fromReadableSize(' 1 KiB'); \ No newline at end of file From dd4e42c62d062ab53d424454125acb9605d0cb13 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 13:26:33 +0200 Subject: [PATCH 042/211] Rework parser to use existing parser functions instead of custom code --- src/Functions/fromReadableSize.cpp | 132 ++++++----------------------- 1 file changed, 28 insertions(+), 104 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index c0b46b98b20..69ada5194cf 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -8,6 +8,10 @@ #include #include #include +#include +#include +#include +#include namespace DB { @@ -73,146 +77,66 @@ public: auto & res_data = col_to->getData(); for (size_t i = 0; i < input_rows_count; ++i) - { + { std::string_view str = arguments[0].column->getDataAt(i).toView(); - Int64 token_tail = 0; - Int64 token_front = 0; - Int64 last_pos = str.length() - 1; - UInt64 result = 0; - - /// no valid characters - if (last_pos < 0) + ReadBufferFromString buf(str); + // tryReadFloatText does seem to not raise any error when there is leading whitespace so we cehck for it explicitly + skipWhitespaceIfAny(buf); + if (buf.getPosition() > 0) { throw Exception( ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {}, don't find valid characters, str: \"{}\".", + "Invalid expression for function {} - Leading whitespace is not allowed (\"{}\")", getName(), - String(str)); + str + ); } - - /// last pos character must be character and not be separator or number after ignoring '.' and ' ' - if (!isalpha(str[last_pos])) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, str: \"{}\".", getName(), String(str)); - } - - /// scan spaces at the beginning - scanSpaces(str, token_tail, last_pos); - token_front = token_tail; - /// scan unsigned integer - if (!scanUnsignedInteger(str, token_tail, last_pos)) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {}, find number failed, str: \"{}\".", - getName(), - String(str)); - } - - /// if there is a '.', then scan another integer to get a float number - if (token_tail <= last_pos && str[token_tail] == '.') - { - token_tail++; - if (!scanUnsignedInteger(str, token_tail, last_pos)) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {}, find number after '.' failed, str: \"{}\".", - getName(), - String(str)); - } - } - - /// convert float/integer string to float Float64 base = 0; - std::string_view base_str = str.substr(token_front, token_tail - token_front); - auto value = boost::convert(base_str, boost::cnv::strtol()); - if (!value.has_value()) + if (!tryReadFloatText(base, buf)) { throw Exception( ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {}, convert string to float64 failed: \"{}\".", + "Invalid expression for function {} - Unable to parse readable size numeric component (\"{}\")", getName(), - String(base_str)); + str + ); } - base = value.get(); - - scanSpaces(str, token_tail, last_pos); - token_front = token_tail; - - /// scan a unit - if (!scanUnit(str, token_tail, last_pos)) + skipWhitespaceIfAny(buf); + String unit; + readStringUntilWhitespace(unit, buf); + if (!buf.eof()) { throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {}, find unit failed, str: \"{}\".", - getName(), - String(str)); + ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {} - Found trailing characters after readable size string (\"{}\")", getName(), str + ); } - - std::string unit = std::string{str.substr(token_front, token_tail - token_front)}; boost::algorithm::to_lower(unit); auto iter = size_unit_to_bytes.find(unit); - if (iter == size_unit_to_bytes.end()) /// not find unit + if (iter == size_unit_to_bytes.end()) { throw Exception( - ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, parse unit failed: \"{}\".", getName(), unit); + ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {} - Unknown readable size unit (\"{}\")", getName(), unit + ); } Float64 raw_num_bytes = base * iter->second; if (raw_num_bytes > std::numeric_limits::max()) { throw Exception( ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {}, result is too big for output data type (UInt64): \"{}\".", + "Invalid expression for function {} - Result is too big for output type (UInt64) (\"{}\").", getName(), raw_num_bytes ); } // As the input might be an arbitrary decimal number we might end up with a non-integer amount of bytes when parsing binary (eg MiB) units. // This doesn't make sense so we round up to indicate the byte size that can fit the passed size. - result = static_cast(std::ceil(raw_num_bytes)); + UInt64 result = static_cast(std::ceil(raw_num_bytes)); res_data.emplace_back(result); } return col_to; } - - /// scan an unsigned integer number - static bool scanUnsignedInteger(std::string_view & str, Int64 & index, Int64 last_pos) - { - int64_t begin_index = index; - while (index <= last_pos && isdigit(str[index])) - { - index++; - } - return index != begin_index; - } - - /// scan a unit - static bool scanUnit(std::string_view & str, Int64 & index, Int64 last_pos) - { - int64_t begin_index = index; - while (index <= last_pos && !isdigit(str[index]) && !isSeparator(str[index])) - { - index++; - } - return index != begin_index; - } - - /// scan spaces - static void scanSpaces(std::string_view & str, Int64 & index, Int64 last_pos) - { - while (index <= last_pos && (str[index] == ' ')) - { - index++; - } - } - - static bool isSeparator(char symbol) - { - return symbol == ';' || symbol == '-' || symbol == '+' || symbol == ',' || symbol == ':' || symbol == ' '; - } }; } From 13a4c37dbf9bd7b95e72ddb20d5a8a54bccbae02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mar=C3=ADn?= Date: Mon, 27 May 2024 13:36:35 +0200 Subject: [PATCH 043/211] 02972_parallel_replicas_cte: Reduce size --- .../02972_parallel_replicas_cte.reference | 8 +++---- .../02972_parallel_replicas_cte.sql | 24 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/queries/0_stateless/02972_parallel_replicas_cte.reference b/tests/queries/0_stateless/02972_parallel_replicas_cte.reference index bbb5a960463..d3a06db1745 100644 --- a/tests/queries/0_stateless/02972_parallel_replicas_cte.reference +++ b/tests/queries/0_stateless/02972_parallel_replicas_cte.reference @@ -1,6 +1,6 @@ -990000 -990000 +900 +900 10 -990000 +900 1 -1000000 +1000 diff --git a/tests/queries/0_stateless/02972_parallel_replicas_cte.sql b/tests/queries/0_stateless/02972_parallel_replicas_cte.sql index c9ab83ff9ad..083b0ecc5c9 100644 --- a/tests/queries/0_stateless/02972_parallel_replicas_cte.sql +++ b/tests/queries/0_stateless/02972_parallel_replicas_cte.sql @@ -3,25 +3,25 @@ DROP TABLE IF EXISTS pr_2; DROP TABLE IF EXISTS numbers_1e6; CREATE TABLE pr_1 (`a` UInt32) ENGINE = MergeTree ORDER BY a PARTITION BY a % 10 AS -SELECT 10 * intDiv(number, 10) + 1 FROM numbers(1_000_000); +SELECT 10 * intDiv(number, 10) + 1 FROM numbers(1_000); CREATE TABLE pr_2 (`a` UInt32) ENGINE = MergeTree ORDER BY a AS -SELECT * FROM numbers(1_000_000); +SELECT * FROM numbers(1_000); -WITH filtered_groups AS (SELECT a FROM pr_1 WHERE a >= 10000) +WITH filtered_groups AS (SELECT a FROM pr_1 WHERE a >= 100) SELECT count() FROM pr_2 INNER JOIN filtered_groups ON pr_2.a = filtered_groups.a; -WITH filtered_groups AS (SELECT a FROM pr_1 WHERE a >= 10000) +WITH filtered_groups AS (SELECT a FROM pr_1 WHERE a >= 100) SELECT count() FROM pr_2 INNER JOIN filtered_groups ON pr_2.a = filtered_groups.a SETTINGS allow_experimental_parallel_reading_from_replicas = 1, parallel_replicas_for_non_replicated_merge_tree = 1, cluster_for_parallel_replicas = 'test_cluster_one_shard_three_replicas_localhost', max_parallel_replicas = 3; -- Testing that it is disabled for allow_experimental_analyzer=0. With analyzer it will be supported (with correct result) -WITH filtered_groups AS (SELECT a FROM pr_1 WHERE a >= 10000) +WITH filtered_groups AS (SELECT a FROM pr_1 WHERE a >= 100) SELECT count() FROM pr_2 INNER JOIN filtered_groups ON pr_2.a = filtered_groups.a SETTINGS allow_experimental_analyzer = 0, allow_experimental_parallel_reading_from_replicas = 2, parallel_replicas_for_non_replicated_merge_tree = 1, cluster_for_parallel_replicas = 'test_cluster_one_shard_three_replicas_localhost', max_parallel_replicas = 3; -- { serverError SUPPORT_IS_DISABLED } -- Disabled for any value of allow_experimental_parallel_reading_from_replicas != 1, not just 2 -WITH filtered_groups AS (SELECT a FROM pr_1 WHERE a >= 10000) +WITH filtered_groups AS (SELECT a FROM pr_1 WHERE a >= 100) SELECT count() FROM pr_2 INNER JOIN filtered_groups ON pr_2.a = filtered_groups.a SETTINGS allow_experimental_analyzer = 0, allow_experimental_parallel_reading_from_replicas = 512, parallel_replicas_for_non_replicated_merge_tree = 1, cluster_for_parallel_replicas = 'test_cluster_one_shard_three_replicas_localhost', max_parallel_replicas = 3; -- { serverError SUPPORT_IS_DISABLED } @@ -33,7 +33,7 @@ SETTINGS allow_experimental_parallel_reading_from_replicas = 1, parallel_replica SELECT * FROM ( - WITH filtered_groups AS (SELECT a FROM pr_1 WHERE a >= 10000) + WITH filtered_groups AS (SELECT a FROM pr_1 WHERE a >= 100) SELECT count() FROM pr_2 INNER JOIN filtered_groups ON pr_2.a = filtered_groups.a ) SETTINGS allow_experimental_parallel_reading_from_replicas = 1, parallel_replicas_for_non_replicated_merge_tree = 1, cluster_for_parallel_replicas = 'test_cluster_one_shard_three_replicas_localhost', max_parallel_replicas = 3; @@ -45,31 +45,31 @@ FROM SELECT c + 1 FROM ( - WITH filtered_groups AS (SELECT a FROM pr_1 WHERE a >= 10000) + WITH filtered_groups AS (SELECT a FROM pr_1 WHERE a >= 100) SELECT count() as c FROM pr_2 INNER JOIN filtered_groups ON pr_2.a = filtered_groups.a ) ) SETTINGS allow_experimental_parallel_reading_from_replicas = 1, parallel_replicas_for_non_replicated_merge_tree = 1, cluster_for_parallel_replicas = 'test_cluster_one_shard_three_replicas_localhost', max_parallel_replicas = 3; -CREATE TABLE numbers_1e6 +CREATE TABLE numbers_1e3 ( `n` UInt64 ) ENGINE = MergeTree ORDER BY n -AS SELECT * FROM numbers(1_000_000); +AS SELECT * FROM numbers(1_000); -- Same but nested CTE's WITH cte1 AS ( SELECT n - FROM numbers_1e6 + FROM numbers_1e3 ), cte2 AS ( SELECT n - FROM numbers_1e6 + FROM numbers_1e3 WHERE n IN (cte1) ) SELECT count() From 5397cd5bdb29634cc9b34589707f9d0af44b5c26 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 13:38:18 +0200 Subject: [PATCH 044/211] Extract exception throwing to its own function --- src/Functions/fromReadableSize.cpp | 54 +++++++++++------------------- 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index 69ada5194cf..9405558cb9d 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -83,51 +83,26 @@ public: // tryReadFloatText does seem to not raise any error when there is leading whitespace so we cehck for it explicitly skipWhitespaceIfAny(buf); if (buf.getPosition() > 0) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {} - Leading whitespace is not allowed (\"{}\")", - getName(), - str - ); - } + throw_bad_arguments("Leading whitespace is not allowed", str); + Float64 base = 0; if (!tryReadFloatText(base, buf)) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {} - Unable to parse readable size numeric component (\"{}\")", - getName(), - str - ); - } + throw_bad_arguments("Unable to parse readable size numeric component", str); + skipWhitespaceIfAny(buf); + String unit; readStringUntilWhitespace(unit, buf); if (!buf.eof()) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {} - Found trailing characters after readable size string (\"{}\")", getName(), str - ); - } + throw_bad_arguments("Found trailing characters after readable size string", str); boost::algorithm::to_lower(unit); auto iter = size_unit_to_bytes.find(unit); if (iter == size_unit_to_bytes.end()) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {} - Unknown readable size unit (\"{}\")", getName(), unit - ); - } + throw_bad_arguments("Unknown readable size unit", unit); + Float64 raw_num_bytes = base * iter->second; if (raw_num_bytes > std::numeric_limits::max()) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {} - Result is too big for output type (UInt64) (\"{}\").", - getName(), - raw_num_bytes - ); - } + throw_bad_arguments("Result is too big for output type (UInt64)", raw_num_bytes); // As the input might be an arbitrary decimal number we might end up with a non-integer amount of bytes when parsing binary (eg MiB) units. // This doesn't make sense so we round up to indicate the byte size that can fit the passed size. UInt64 result = static_cast(std::ceil(raw_num_bytes)); @@ -137,8 +112,17 @@ public: return col_to; } -}; + +private: + + template + void throw_bad_arguments(const String & msg, Arg arg) const + { + throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {} - {} (\"{}\")", getName(), msg, arg); + } + +}; } REGISTER_FUNCTION(FromReadableSize) From 58774e32cc9517faa4dff0ff9704cf86edd9b78e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mar=C3=ADn?= Date: Mon, 27 May 2024 13:49:30 +0200 Subject: [PATCH 045/211] Disable 02232_dist_insert_send_logs_level_hung --- .../02232_dist_insert_send_logs_level_hung.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/queries/0_stateless/02232_dist_insert_send_logs_level_hung.sh b/tests/queries/0_stateless/02232_dist_insert_send_logs_level_hung.sh index 734cef06214..32e58795bb0 100755 --- a/tests/queries/0_stateless/02232_dist_insert_send_logs_level_hung.sh +++ b/tests/queries/0_stateless/02232_dist_insert_send_logs_level_hung.sh @@ -1,7 +1,8 @@ #!/usr/bin/env bash -# Tags: long, no-parallel -# Tag: no-parallel - to heavy -# Tag: long - to heavy +# Tags: long, no-parallel, disable +# Tag: no-parallel - too heavy +# Tag: long - too heavy +# Tag: disable Takes too long to be always run in CI # This is the regression test when remote peer send some logs for INSERT, # it is easy to archive using materialized views, with small block size. @@ -49,10 +50,10 @@ insert_client_opts=( timeout 250s $CLICKHOUSE_CLIENT "${client_opts[@]}" "${insert_client_opts[@]}" -q "insert into function remote('127.2', currentDatabase(), in_02232) select * from numbers(1e6)" # Kill underlying query of remote() to make KILL faster -# This test is reproducing very interesting bahaviour. +# This test is reproducing very interesting behaviour. # The block size is 1, so the secondary query creates InterpreterSelectQuery for each row due to pushing to the MV. # It works extremely slow, and the initial query produces new blocks and writes them to the socket much faster -# then the secondary query can read and process them. Therefore, it fills network buffers in the kernel. +# than the secondary query can read and process them. Therefore, it fills network buffers in the kernel. # Once a buffer in the kernel is full, send(...) blocks until the secondary query will finish processing data # that it already has in ReadBufferFromPocoSocket and call recv. # Or until the kernel will decide to resize the buffer (seems like it has non-trivial rules for that). From 025f35a5fb8544d10db90da83ad2ddc78f208c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mar=C3=ADn?= Date: Mon, 27 May 2024 14:19:59 +0200 Subject: [PATCH 046/211] 02500_bson_read_object_id: Reduce size --- .../0_stateless/data_bson/comments.bson | Bin 11686292 -> 621 bytes .../0_stateless/data_bson/comments_new.bson | Bin 0 -> 388841 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/queries/0_stateless/data_bson/comments_new.bson diff --git a/tests/queries/0_stateless/data_bson/comments.bson b/tests/queries/0_stateless/data_bson/comments.bson index 9aa4b6e65628428100f6b04c74b7e2369e547d42..06681c51976ad81f967a2f0aed4309e4429bdfe2 100644 GIT binary patch delta 19 ZcmbQT_$2FFmJKOPoI4mc{+Y}G1OQZT2Mz!L literal 11686292 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�I``o3LjWI-m>@*CB@k{GbE4#ua!w@7#u5Z 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%0AD_L)K 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%0AOpiqMXS&%0Z8bw~mUUxf}Z!|Y=F11sB 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

|$8KNrC$MsV=r1`3(|y zjq>*mWJLIVh5Ne}FJ0vu{DMnGymU-HlGg3AS3#?0>1G8gu)^+M!9pSXL)aLk%9#?|SjE`B63vB1D-ODe)x33*u;zL`RO3d1NedGR#F;0;! zpXLHpYZX6aHlX>e$tB~CIPV{ec75Jo*u)qoAH!?4=^OC!^vPZr~ z*V$_vn^Y1c23F8CkZHGFZ;r$-$sXcET8-8y2>z+oNELqUi+F?8`6Qg%eM-i>vWn~! z+CwBpNLs)Zj1sy$tS?$?Q+#mOstsJKqMjjSH57XmK_}vCMSZdea@cjERS9qIa+TV3 z*yYbAm@ZppygxhT0`ww{aNQ^v1DB=Pp!~jauNrw4w0Z!7$V~`Tg+;lMNeIap4>aX@ ziAQCUNkKrn&mu>f6fwzfSmH4mY2;II?~sp7&e_14iBiCjKZ}F?uz~JLKZ1l%kfzjZ`mm0H6B`9 zPzRD7xo2ZlB*}n8J(@{kk5UiWO;Q0mi9>y;y(%Ggz3Iq@Cth@fUI;8;V|=hA>=|}6 zk#rHN>E<9I2>n5CFz zFSh^1+DNPo*K`OHWHBk^ix?S37k#@@1(eqAP(LJN`JX!AwA2Y%P}J@uA}CW6e`PQ; zRPqN;dJoZCX=z|QxxbZgsfER*#L^QjL`@*DO5o^Ryl|cGadAMH`cU|=qm5evq}~7v z0Lef3unQ2NsZ%aVLkv(kX5}!@$lWzA`pqxcv*YbVfHkrYy}th?dh>_i@~Uj8ypI3g zhzYyS;MPXx80hI(r&5iQosWtcXg@mGOKJrN9rNKBSXy}Ix3u%vt=9ivK z7he=Eina~iAr!N^k~4TNlI<6)`3aXtmo@{~X(4Q%SdG)&U`_4pL_rdCa_HMe`E>=y zbR}gH&O@-Bg?1*79LqDo^H|T3MhlBST}*Yd=A`k#ZM04>((AoqB3t%m7z+l1wqxEt{0E37YcJ5 zY^FPm;le6d;bOey8csmsJ7xHitq>$4)J}whjWKv69;v}L(F$3UnsW|9?LiXI3ai#i z-9j33n8DyPH`&pd}ZVNqwmHW|~RuJNW4}qck+VRn_;1FBb1KbRLwV8A)9R#AZt7fQSJo9FgDL_@STGv5!Mb9{5GG zesgca&56B3=sX`(Qve6D9%903>!-*uGB9f{G%}lZNJuOc<&FVwQ^@)s7?%-}-G@eb zQZfz|j*DTzvF~r+jPF+3wRv%-_e>bD`Kce12f@&iheMALFEoaDp@MICDPG%`hR_`> zq|UtX|4KJ$Q<)kx(3v0(d(OxvFs1;~2^hplM_Q2P2Fj85_+G;q7hez8(q3k4A{Qfa}$4eC?z`d*|>i$K`VhUakwkeLvZqnI;A`P$B z9hfz2#TM`xcc8!?&N9;*!e1FUh#(@)R6>?3$32Z*kE3rZB^chO$}wl+IRl@YvDWIs z#UWC?l@5`PLNhB>5R(9_U>bu(Q4BF?2|z-MDZpXfAKvsc-r*xl6yTCMzC-#1n6IBs z$nA4<4ao%JX7m~9EQ(a}*jZ@dOlU?eu4X-_j^`~F7;f<6XgwKH*wowmKmNA+eD*mM zN*Up3XPEG@TfrDO28ElnADLER6=MuX%cTld@p`}b@ z6Ir!Lf$1ZgZ8n;0W?okb9lQvyT`K22;Vn__7~*#IL9E+R?bqx~fQ}+fCU1ovO4~-! z#~|V{Mqi8X62*q?AN}(UJg%lzHo5n%IW~f;@VPlHQS@&D?y@A-AC3BU=s|Sm_r!ce zR#ctz|Fe2-v5SHz^#Ahq=5cmaRod_s2O?-U4ljmohl`5h0HSRxPP|l-3JIi=%FqGS z_U5MQCRM57#u}0oqNW=}oPz_#IXI$XgW9bL0STfQ8*THpt)gVI`$g$iG!CsOir@3B zY43A$e!s6yQ}zB)8tT-!_w04nUh7%U8a4#O!rd+hKMX6fe7Jw1>%xxz^|+l(A(frP za>oZ$R%9gMF@}Ik3!xRcXH>7_^w_Z>?3Zdtk;&j57&8Xvnq2{YhLUS0lCT)BUQ>HM zIUtKWb)|@EViHGU)>WlcgH+TQV`5`t)Cq&OSOI@3kOE!;k05g?tj=3TKjj}CUI@Av zLyym1w5yxLJ4#*c2WL@md|UIK)FFftuP4|y0F^D%O{$UDbRC}P@GMSIJEYu)$#`Wu zB@qvrQfFd`xQOC2wpitho;HNt63Vz<&3W$E7oSA&+=rh|8}p%A6c2G2A`k^sKvJn- zJ>LC7R%#N9u)3mSe+onq0M?a7B{ttf12Utjz5fxP1cRap@P-C3Fg*MFPel8FcOyT&J)7&L1L8Az#T zsuz$Qhk#e54uy)Q#X0v4{6gIEJ$Tqo)v!ZV$S!KL;?YzX866oF)a=KJVigYhoWzZ* zk$-1^ZPZH`9K=+J!A9U}VK6-^^PpPYbsnQ-f0NT^@p0kbAQ)GQt>60bjRMX~PGP*` zz2?2MK?HOt%<1^mB_!HT(>s^YX*ZX6{9ZL*laf!je+w# zh()3|FQ5k2WtD#MtFS)VHJKbCOkXRPD~+ydq6Ee|Oe1rP_ylbeby)kw$8DsxlydfV zzy;YJ3}pe`dz6zJZv(%zJa1M(W3IwyW))dTUaI)QXSx0J2X?N@-E73^;0l)tJsRN5 zy$Vbei;EXaivvDb*?QkT@xl0qwC~AiN7^-G16;e#zV`Q9IPAF8AKA$mDk2>4fO%4z zQ`q|#xNE%0b03EJ>k8m@2ksQSMi8$-pPL$_dW$~SC<2#Eo)7fiX|q`pHAvG-j&!Iq zK{q>>oxaVf2Cv~Y1nuJ4e)juow79jBQNMTC;TYtGRt_|yZ;1G2d~hv})){II0bmYR zF*g5*n}O31aT} z6w>QJgn}S*YvmA0c}m6Bw&7}zJ$v2Pv4YahJv-rmArr*4d6Z2HsKp0D^gJ0urg2_k z!-8I_pjD)viO;|Qr%4SRYf1&f1*1it)X$iaW^peNOnJ7R9hE=pr=swIuCEQZ$GT*Y3zZ^H?n0nJqmQso zH%i2~%BVmFSuuZ(`;#yNW{Y-^o|~VA9!^Jzfp+FuPQEf_qE>>v&pY;2j2ZI{c^y?j zHfR2Cza!NTWy3>mN{C?<&OCwGR!L);??H+U_nV5`O4GTK=n3T!UGz} z&S`mQH^jp2%v6J#Vh6;Pf?pVJ|*%Wuo+57_rT%I{$%^1Edg^z90KSC)LpSxyDx%-WjT;2?!om6mq;3Djw26?kcV8PrBJB5bYFm7ae9 z7DbJY<~77;x+lt~L1x$~+m*0Qu3!i=GozfUoS?}Fo1@FhRXU87?YJ`^bMk37U=?MD zj^AOYnvh>v1y_vrcAR~KGA-o!9XLE0*ZNT`a~gAm7!)J8tKz|;Z^UQd-CHlADt|mW z3@lbsJjJENzOY57^SlyA8n$_jnT&R1uS^WQMo-`hHFwUxUL+$n%X+cDtqR2=tW^kD z;9KkGpo?o_d@azqONPLG2(@$*ZD5ziz~H70l?LQ;yv;&QkjgI8Gal`vdI&|`GNu|J z=0xt72&?eM(eY*{Z5BgqO(zvGX+!~JdH@bIKQCV^PC&PLyb|~`GXO5Fy?qNW_!SvBV(XVbNsc_JwYZ;Jz0%Vw0Q+t;<+I)^vW)!ETo43vW2@+ z2`1h^P*^#dlz&^dCQ!OW-!7%=&iwUd&!dszVdS02@__2pLvVRD4y!Gc8Q?>4HqHQ) z2tCUc7%A!yHBFOP+?dnO?J3IcJ4;B(dz>evMW{h$L(S1hjDW<2s z7z{WJ2G}Xiz}5G{WQjmj`A-+t)&KaCU-eK}WuV*6_n1*tVvwi)S#=;A>7&sD`svnY zUD#H{BrIl>>v%lpc#_E@32w4g>&FXql`5Rs6q8Ff4cc)uZ3+cNi#ig?gv(1Y!vG-e z@|!dN)BAXac8zJL&aL<#v#=FEi0>jz6=}CY$YMNe?H2rW3dW8|nNh`BgzwR2AtsRUo=pMb zg|f9Mxw$QRUEGoeyAs*vl-u^(ANOApz?U2;amStdZW%Tw)`(1xVUj!5Mn ztt@}SU`V*n?IH!JLdS_MDp158*|^-cz3MyvaxoTBJGsPe{8HscI(Ib=doDeCp27oC z9-C^w3r_V{aZ>NYt;j}mk96?c25kU#fOr&gq||F7bi;&XbY#RFrgA=EO-d><2q54{ zMCLF(lREBo0rg&X+?UV7gVyGh2*}QsU}ovUO*rh2M;)hr8D^HIEAc-oJZLqCR zdh0j0;IV3_9xaFcHdviTXeLjK{N^zett}HZqP}GwFBf7%skBD*wYu$HojbT)~Y z_pD}JB>_s2#D3%+)kG7ZxG;`f@|JrBDGWlp4(GeyCN$5Mb@>{;7WmV2Lk+XN!5EVO zek>Vh?YGiD(er7UP89rM$$qDyZQDS=49A*jP<8Tp%Brn3ABg{ROid>_Z==2ad zaP&S?)2y?1U)FOgg;_FZVgJLEi@Ok%MjeFE)P{B(vPh*`&-Ta0=7H95vr-mm2kynT zi0&M*MnO6Vlow!YrD0`{b`(TwdqK+VFBB!L!!OhMTx!ZL-G94(`^O$Y%+ zsD?0I-S(dK?5Q8%X=^220Q+ssH8UN{kezi_gOb7b5qdSy*EX$@E;}EnhUqQ1S7Qj> zFQ#71QfFit*5g@Od0u7BVNV>fCiFs-lqUS(E6eb+uRO`p^0=wmL~q6pV*$2jhHb-fQ`)EsD-6WL zX+Ro}E6;T_VMctUF6prCCCkWyj`jO965#3GP_R(t3|Rf%YL1p~Py7K@U@3oWJ1!8~Om1*g8F zT}AfZxBow0fk!BtKD+;Ex?Wbdb&Z0UADzN!h=Yk(r3nJr$_vNsLnQ-P#z^%-DIs&(e-i2=X;;YF<(?w%8{Sun==jH=#O1H?(8~Tv7vX z_}iOhzF5f^sr}DVNs*s-Nio5(5!KahugOBYu$biFwF>h3d)#h?NwmPMh0X9WowUeB z=0vIc?^^4?Pco=*R9;@Ib0frGm?>3X9cTu~MZ1P&)@~;; z=5RERzg!q=?%wpJ8}W2yUC;ZUtNUbzg>famO_~xi9AmC9Du>)PcCa&aQF!z41IfvA zb0JxZuo^uso~Fx9g19Hw2Vp)~q99)mRr3pp5{@JUiKTVMgCavEyDGPOoEZx0)3;P6SxI?z`G7fNzbL_U zrksWR4nuaF{%C=9CGCy-ZT_dgknw@x7Kg-+MQfwL5cxG{QBS9>(QU;JE?tUqb$2)= z5$`ipy#Ttb{6>Qw!)Nk_eG90iRVoxwn7?%OE*TZbG&9;{T*j&;(xYO(3e z;c072N>J~Ml4C)}7v0Q=klLdc!EgptqmJMLuQk@&wF-`f^m4b9CsXh962asMgci3< zC4NhwqPRrMNmRnbZ0ai9bCC1#!XK4;vyhmOq>UvotzgO#b!=C!x@tq4PKjjke>X8X18|UZU!O>{w=Tg<_s?-r|oD_AX z8}yT`!qY`cf2E~Vp4Th36lb6041%C=60V}F#^wjp(fg<4KYTtVR&oUGejA%gSThg7 zM;{i0vo*&syFXyf<8jTKkNc5=pWf_L-=#P3i*;JNo|lj(RFY798|BGS;Wr>}EX?_# z%roPlSEHwcBqP*^ENqr*#$M&z zkL3giFmL2X;;%G>$Rd_RG=T+(Wkb|WWX-z4lpx{^@8dD6>`8GBcqPa$(`1-dZN1XDP)XBWiF!r zUrNaH9lE%7EV=0bkw@8abNg4#qPTWbT+&t^L5TCK37Zw&z91A+I7e1Y2rbvtA6U(~(9SbRSpV?H@ zd6?}A zl1mAyr`=~LJlQQM3qT5oYrA{EY7_))0hfTJS^!n^dv38(Cl`|-T5IH0Z4yiP;(JfO z>Fl%dJY{1b_ODI$Xg(_*rbdhLavk@fqYbH|VThqQh(g$D^%}b%=x?=Z!87?-aU_sn zTQt;3?nhp)xFni%Y!N3~=?|5MRiGddOMnN83V$q9G>RKg%stc#a&_rzx+MpAE~`0r zo^~ZuMy2en%~>UQpAT5s8a%pGk2MgeENnIgTFw6IlA50piDH^9Sb;(y&~qChD;H59 zWT8>+?ENx7~u5l&~_mkX2i!kHBjQFxC5pi|$%UNtN_7>|d{1 zMT%zr01JgtLVVOY04L*WpI=RE%=F>G<@kVAcD#(hKUB+R^&iR5xWP4L(~abJD(;p9 zhLmH?m$A%Qs3g15_i3SuQP>BlX$WQ8HSgN{Vmwu8%709SLWGI;j7G6KPoT>PZ6Zu8 z09P73g{~T%O=0xt(X!krIa!%D3BZ}k0(4v|G|c~&#n$4eyoUjPn>jXB3sw<$V|K)b zC|I(bK{1HidD*rPvC*vdZ2V8B(cP4Uu>g50Sg@6Y=!i?xhA0dayW$GZ0^pSjzMQ~u zwct8^Z`z6A+TN-Q#i8pIXqbh1-aX~RPs5~!Q_=e}dNXCV7m~2>xD9&4bc$Ib)d5E*g9z>m>jiYN zVX+$9svGNAkgZKQ@(-lT6apcYMnW~_&>YVKh6{_`VV$10}M(v4T=>)(W(xU$vU+#XAH zWQ^C5iXUn8O~Oo!V$S`vih|r3zYn+fj^Q`~z*X`wg3yRB^o05}+BP^bpJ$jjZfup* zjGlrdfooQh>+UGTE8tGT1(_=>DK$hB!3Q5u!khq}qM+&> z>DZsS7ZQsm8xD2kr3%uy6n6t`;K?j1jM<-=9E3$cZUr6Ltc;EW?p7r{k}D9 zttcC5vHx`{I?{z;rbm%H%g4Smc?2E@@OGTPuAn_1z@5Fh<>AvwLM`bJZMIstOs>R( zDMSn-Z?^gLI#O++T{LUv)g%%y_3_Pi!h>(WoQF}?*x}U)BHIo=2_LHcj8+YSnG|rF=ww# zo$NFhAf0sHiIc+g^vZ+!f|zvx&tk_Z$>$mE6t+c6@UlV<=w#HQx$e1Oj-0T0>uL(- z2l(k!r)?@2mI8MV4_?$U+PE;b+lP69zFvXlg`n;$c+w}0fX=J6oGvM$K|@79%(W;zE#41%0i1LqZuV(iq& z{K$SrbS&j>dW8v?7C;lZuS|rsmkl^lEc0 zu3>HNibAqGvCa%;0?#XJmIcO&PeTO&<@D$~7EBiWG{dFb-w31=D*+EjQEE;>oRe>Z z%NM@zt$&9{D@_x;H`xc&Z?8u$*Zg6gc@%X{&%})b&2r zaLX6QMsZeJC9;x9PxYT-F%dEcLC1x8#?wh=)LY4zP>F>C-MV^!f(~v%pI)L&Hg;6D8nOWeMpq^#j$!dfQSGG~1~6Mx~w1 zx6$MbU6)y9%Y?d~&3)mW-3RTg4=Ligt!tY}et zqTV|g8TJ5%td%jujYKAYGIQ^3Kw4w9 z6zlZ)Jq$l#0{uuE;7QiofIYM$@L<3@GtbLAu%c;bAv)W3?=eph(ftlf>a_HqoCVRb z`~i89+8H8dske1ESqLg@{fzu3m zp@Nh?jSp2qpG=fT&&oSxXcg=5YNF5xVQgt2btHYFE&+jHOhSTLj9{>X3HU;+lzo$N znwpDEUPil#EQVV2%j>V?LBXZPMz>|snrWSqoROAj6-P4Z2z6LDFqb(_A(UHa3^pyW z3n0UQbi{5)P_wp}6%lTEGW3UVvMHr-Mmo4-k}5)JOl^Brn7+5l&AW&^zw6W;eaMok&hmpiWng7+f zFJgIAP;xT^DU>+Sw!mT7MuhZZ&URw3qW(jT5R)@5gSjU>_9P|?Y9y&T9m&6_49IAT z4CdhskM>3v0@0cX0ds=z>xxoX?G=4y8Dqt6MWLez-3%h-xb~N-J(zMbD_E{bOgA3sN%|W))Ph zNb*|+{(8+vr)rU@D2+>M-@ezEE`5~;If9`ExrLgKHo9hQEEGC`KMd2aJbkD~ckf4mJStgw}$ff^D zg~xkvw|X#nzw$r6_6%Mccd7D}ieI+&M)|d}dZHGxe{4TOC$#RC_6Gu!%E=@s09*Pw zYwVA@h;W6r?asV-;#3lfrFAg-lQNwLP7C>zqw5ui7+(WL?S~V{c0vGXU+BRd}6qe!3vLom{Nb%)*G*SzMNoQ zw!;ppP{=u)*FqYpZs$#f&JgPk@k+yvo2pX!aW!sU%%Z3qcWA9xo`3Q@qo9>unI$Bl zbRn4nnb55b9u)+;;m4kHH}2*8{BwC51rVg!UIt}i&h-yWgSKAr%|G?vsY@$f538^k z7M#}_9!FJrAtT3nvmyC?<&+%Tlom_Xr7j%$j+m{pZXwO|C=vm*)YvpVc3Mi5N2$E5 zzJ>v`I07LS+&fB85gbnZ1K*Fr0Q5wu#r7PFwpIomB7r^7ti3E7RCLA9Ua zrxOC$&^VDHMtqL3#<4vf5L;xZzi*7=_Z18}yUZAV3rk9eCz}si!Gg{nX^F`DZ?Z5k zle1AdxWU_CRe^+XkUeRnh3U(jpWbvW{dJA}XXjdNju|1}c{u94zF@4qzU^p-E8Wlp zJKPv)kF+a=keA`srQ*}I%ts0>=~WRdCAg-QiB=8Pgnp1_3Db>;(*SN}s2DF~#0oS; zFcY-F+erP0SfM-ph0p!q+duFmJX2{c#E*2-%(xKVjPF}0UPChWvUze;hfR^Dn5rE{ z0;bDqw~e07lMhZnde|7sa-9FWI-Bq9{4$ZU2umV>>v4d8)%x z^>a|@TQs(IrLmq@D(L?w@U1I31KBizAS74#h<$SQ1YU`!fsh*EzF`q1c74vG2YsRp zxBhR!C;-p25x7|su%ciNCPh8Pwc88eONri$fmgMzl~AFqxX6aXiDR01S@ARvehQid+{K-Bmr?vbblJ6N&dy5? zN?8bpb#z*lpQ;v-ty{tYq{B!-@JtV!tKhbU8M@Xa4l@K(F^JHj${2#r;@$;bhL)4C zj%c&GQ>Yl;zi`;vYf5@7b{v4;3Dz79>V}_k{L{@lrTa*`Fez0xhgC? z9tVLcq3mM2`ja2p^$k3JX|M6!vn#e+@wG6p}zutnIcuPR37AHV~JS3tuYybPJs z)aBBmcBD*-RojdD@vV%(%}MrC;yNWxyeNaHP~3cMR77*Bru^!=kGb?rJYFfg@e7p- zJ)KGgA_;d-kf0LbZ!1WHLkGcwi;0y7F4Pz)U57nL0YsGtHj{;6s)e>`9Ns}|GRWgB zfohkhj>9ez>Z`YRhEZ#o8?)$ zF<_*mJs|Upq`7qE5{71u9*UHD@lkwaF&GDy#}`5*e(W0b(f7>Wv;OJO&ncH@l$h;% zRW9VddZ5qsRa0YGW!6*hYoJ3+aBq$eOteQ&TR%34WljuC>vVS~fOg2QYrI;`p}^G-trt@e5`I?7uAt(9QhTbo}Zqz4@>q$QIW=kD%Fs;_Z+*KmIW&Tu27RRtk^3E$f7S(>y|AzjSi zpkm!Azk*^F<8~8;sGR+okQ^MY3t@huy(KBB(fOBqQ`zzlf)BZ|E1st%sn_@?R3&!Cu&uv4We2XxI7|{!8fWw6fi@yf< zu7tytLI_y8M78+B4Ecxtdd5QDreU#;CI!*!f;x1w)EK4+b%8qO-f?v{ ztRmh)0WG?wT+n{+``Nfx*6VWMgv_FtxGro@rg84MxTbiag1Ff0vYeF*k!I0URZg0c z!&(kh>rmK}T23GbG=T)f5^H)LGR%qA>`Jg>Vsa&$p#adm5ot41q%&Xk)tisu9y+(g z);=;f6k~lY)MWzOVAP9i5@P`j&XFsP30|on8)iG^4WsyUaAFV=G6Z72fIEZP^pKl4 zDYkSBhZ;Z&i3H;aByyTwV#TRNnt`X{$bM9F3wy%Iwntkyy}U~h4uH1ihcmbxdWA?t zlS4kn$a^DPlBdqUa@mDgQrR$o1OH1UDF{*Lz|Q8s@!(S+HL!sO}ah$T6Z z9ROwy+p`F{cHbvAPlH_TA&1A4O>x#Odk#ajbe-;bd}#riRP7r11g%Uu*jhss9E#cKg*46(Mn_&#a-|D)o=K! zN_W}GDhhU-_Do?fk>5tgOYx8_b|jACQe$F}k;FPoGOr?&n{Yb`FKcRvU6s;s7DpCA zt_+YCjHpF^v0`VKX}KhEgRSaLnmZ5VlFVg)c`1BK;aqM8>Ek$MtbrVGCE)x)+(;8HYHtDn29)9&t=Q9c z8E4cnjr6*7>k%8ej_o|=j&};H z^VAYcev0bYBPbadn)Wb?NX~Dq&51?PFuT^+tk)`7B8sWAvQaX?6LesD8!$>n} z`GPGHAs8OWW|5P+Qi~maP_tdOBLOkx@G1BtOeO)OG*(2LO&m<7u~#mpGd6tWco|Xh zm=ZBPRmDVPtYT^*yTsXMxx*V3A+;Jv&Q^1Hv;d23R;_OaeUETC`wL2KJc8RAvIup}+2W*niTZ498u3+H7mDb%>a!*qTS46bY}#92A{ z3h}XFJi}A=Z!gpAkvuCR%Yr%OQ8+ngMR z!yC+wVI?5ih+m_>lfSNDhF0NDDVjr{B1b%F&Yc)gy^CT(!NkSc!q_6PI2wCHLJZ!L zTKbZ9?Edio{Ug4iY%cwQzfP)w!;Xkr>gSCPt{;fvFRBKPJK~kbkX)&-uz$eK%Enof zipI#oH<{to=?bjLFiWZ47rQ^>#|5oPCW2bz8kKkj@lzUcipLB4n(dTir$jsD?^GvK zi;jzI?%DtQcSk6)k}Udxm#D}dg3G;Ah)&$hN&>w--dfja4s*I#g~`Eh!e_xc!mc8w zaHg`wX(1#09k{DPSyn2^&SD2CM+ybc5-b*k01g-j#_WW{=8zObfm{)Zz!1W_UUcm} z6vBVur*kXVoK0F+BwIpTD1+fiOxHw@Gh_4$GI%9!RaYwXt;N=PFrer}T?B(6*41he zIv}E;3bd%Ow8^{(w8mDfwbx-@xKHr@V=~X4rGIfpKfb=~@V5ht^>xqqreA>XTOsqw z)SXHwDX%*772NYqP%0T|DHq_?LY>g|4}SJ%7t(J17C)UY>%3W70uOrXajGZtPqbVR zzHx_&Is+15J@aurf>$=FYm}-6z>$;S1>F&%n}DZ5&qQMS@(Y$7&y%KVC2gYzdUV;O zlvXfMMN>YW_S$Cb`7liV5pJPJ}(MQFBz zq;!fF#8Uj3mVSh7Gm?s1J_7x@hqi8G^ibA#ao~Iv6?s@_&Jg0nLRdzhhzXJn82=%( zo>!}9_%v?TH|hbWqbBu{{$F9UWDgXY6=N@H`IPGcQMG!EW>!Y;832&joX$ZG|!@K)To zoUfa7s+LjO(@T{VgS7%u&^Iq?$3$qcH`Mlxvvn|0u&rKNA_glgjF=pznk^D^b#sBt z8JPRpOYv;A|Bda|X>VVa86FkLxl$DFNP*<+m|Osr%`)-|yX*$syBLu=gU*yJRUQ%) zp{5X7nBtm{vaJewBaHPIjTi4k5LR8_Bi)P@Q%MuYbRAh<8^bhYwNCRHa|?xLEz^!Q&&e)YK}Hp`}RJ_rk1(GG}2Jl`6}klVE& z2m0DoG=_#s5E8cuFbc)v>KMK zt>E`KrKf9cvdo_2(d>pT4?t5$fx`alCLkhxq^0tvklyhQUPRahFIQ9PhS_m*Coog5 zxkhudx>UAY_2^GNl$-8_C7Luids5knuQaO3A4}#6Df})LGXMfj!nMjQLp512C@4Y2 zW=%>*|F7xUjKNpB#nVwHYuBt~r9`>Kgh^fr(J3ZeO6j|{!_#PiTCl{YIlfabIrbZ@ z5Ggw{^7MLC{zmp94H@|NUSM2a~>+~c%7)*R+I0# zwxfGb-}|tL8o7v0q%}SZ5_>hiXTHq&b&D$I)h)arFLOsx^`Y8Pm}o8@Twp7#4t>Em zzy_oFF0k4JuOcJ)m%;*1D43>ffAHVmx}WPV>8(33sq1De2Tj>LTJPzDV#37_xzaF} z!}+C~(azzQDuAW;;O-s?PX!k9)hDQ=ub9e%*i=Ha6t@OhEys66QL)1EFyAXdBM|u{<|OGF>5SL@6?MeDxXK<@{FFK?40*5eDG4?sl;Jf z(non)f73$8au9A8y2GU^nhQxZ2`*TPVniLP2zi}RGF3K_4BS-)6eQP~2gs2ymvn;m zN2N_G7{vAK>A(5oYbn1+mB`PA?amw;;10%efdMjbgEuXy0Syu42nmWPXY)gtKr<|Vq@*#npZbyIWspI-U1TPc$BNa?(hL8L|Kt95tb?|xfWU_gYNi5yeUoJT8|w$ z0(EwoN7&*=HHC_~DCgYvxZ~N>Qkt5x8LT7>Rt?|?I^-MbD?z4=wKwPH3uRuYCqPna zq2pHYvf8$ekNWW_tRbVq!A8MjFzd5+hML_Jmt~rIAEly>sHu>+% zxV1Y1a4w^;r!uB2Lj$H9(s8xSOWM)3o!^T0tXNA8ntB4!KML4pHP;JxBdc9;Cy&>X z*)_qOHZFo?mcEHid>1UZ;6jqxH4abgwDWJ!P08FhG-<2_48Ev6Jd(-=iJg%07rc%iYjZ_&qn!UcVFO6O$RgOa#M&!mDMm*FmP{bJvFTlT4xV=V#`)wN0lnZYAy-F2@1-!DHbQ&}HdBD6Qos?bF=)zVv+bD|p3=fY*5;JR z#%8ZFX8?r)HG#=@Qybb*^~O!v9A1Z*u8Bg5N)*avxYdFe-D>r8-f41eVq+Clc-Gn? zT$rG&Xijih!ek+_<>j-ARjMwK)_6=p( zZrxbC(palkDr~Gz;#*hQ;T(de1tL2ijx>s^4II6^c2Aw8^uN(39+o+?fWL;ZGkx$Z z1ic_VBMBv^G&P|1XpT8_CDU_jm&2tKuDyPMk6oH0e49#(`2rq94QWAbQui5^hKEo? zR_pou3X+V7Bk##{!ld>SeZ(%4AgNlW64SwhzS!moSvkM8E2#~MTTPD^UD zb!TA-tYN0!TlaGw6$9F%fJl8wa6&K%Qm3YyfO?Lg;FpGJ-6@Xd8U=kh?BxH%J zsP2~-4))7sy6ud~yM9iYmQ|l@S4C4VE%p{8t57@R(3uG~Gq@vip@PL-k9$|rQ3(B^ zk3|$BNm4*OIf_9rD_RXD+R{r|yF^;3Ttc8v2%bj`{8(S<-p@bl%5QL`zs66eS+>#F zw$d>e{`R^$Dz1H{OovI)*$^UyDw}8mH?C?=z_3u?wZ}NDr}$ijTH#FLb(HP`SY@VJ z{w53vKLwE{0#F!lOiuE$&BP38%b0=sEoZ;$(GnB&lvh56$^`8c zw<#;wz)ZWASWt)X{kr( zk>>D%jWB2;z8e}8%7a}c9zXmNq?AouU@8#IIuHaYRAC*Xp9NaU*^7f42gmz#6t7F= z@aLERmi$#|j^h0)m51Q+>gL!~!EnGO4C7#d22SZ2uCk-puArb+G{hZJmITNe&jiD% z=fcR;`f^7(u6Yn=TNz^AH>`z*DYlAw0TJ$>SxnnEi3y&N>}Fz)fiTvs6o~0g4(1wQH_Y^L9xDuoPX_eL- zT)q&q1|}vV{l(}Bj<3}KTts_Sl`VM{Zv7i6khXFdq~+am`5x>XJg!2EVob906%W}*3|IRJ zemYUWXH+;$G+($0M+dbqtu-C|#=`R{`8CG1RyuiU7evIse12yX3mBrJI zIE#qFaS4zMf2P}xHdpIZSubXsgLcQNMr3{tD2bsJ1Z9Jo3Xs|4bNkKD+j0W7NR8>g zPF47l%4a4Dudh00qP1nB)`xFd?07A0+^m8;ewp=csP7`II-8 z?|Jh7dEle*g{4?!kFJgN7U%HvY1DWlBEUq6Uhw~*+uUpt{%x3qt>Z}AHokINHsQ0n z+&AK8I8(kFjeZh*kjg^u4m2)TT#TE9OeSUxFbNY@+iH5U_)xM@h|vLrdGM5BY2E&b zb9bri*!HEnSxQlMxaWbdrOn?pJ}}%u!UV;qE(>n{ru-VGN{mgbUiX_S2y&pxiRDU2 z!AQy#Rx*sZg9$ZUqV~i%SrZex2P12Rmu{R5#zy!Wum0h0zs?LujrhA$tM}>}iP!FD z_0gTWxMldHZonjTjVq|OpvCeU7N%q#kS`1ydw387=P}AFCApkgwavNbtj+zxte0^| z`*azsT%3WK+Pfa1YxxpBF6%v&7ldw~cn$E|3?1O0N70oYtsTk`rQW@0B}r%?X(Bd( znk;xUar#1`a5q~ZZ(T+T)Qu#F-oCCAQ|wZjh(4tD(v%OCP`?thfbf(EfR85P(2U^#|F? zg^0&?VgN&+krT@M&b#vqWOqw@jIxp3Gj^2et|zHP{vO|Hh*@jrxkr!*&#ae(ae$5< zS7~gULI$l{Fr$xGooyG9frA4buFRD)0#@rGHqce#>|O6#MGByH7k)Zb;yW|Dn{4?* z_@<1Gc4~(TOOi_8VG2%Ji#XqkPa{b1^-1xiM+%Pl@`S0c^YH7(Kf}YQYV_-!>%3jp z$q;=;i+OgPsxSNv_+Sl8IdmPhs>vUi>8HMp-Z1tSlje014Wu+c}kz z8C3i+s-ApUnLz@V$6a4vJ%0?3RT`Y%q4HoVVur>V?|Oksf@M2-5)D=~r{c3%&x&@< z@j=s3f5*ZKOyA@vq&x#0l8e|q+eu-hDQ5`8P(|)4jd;Zll#f=Mlv!q*cVYf#+oPZV zB&Jwvhw;;?N!dWxbM%nW`ZDzOrc4x((|WzqXv>vpgqyqmR;Bkc+`N=%&q|S0IATbH z@6&V(-n{|<2B1r!BoMTRPtYgfc7kD6O4T)E&+QL;7SG}-osabEWD#bdGho-nx~|vY z+ZM9(kw6uo(28*6ZK$;peumG93QtQsVj0i_m^6;FG&%t{n=ufeoKif(*BA!Of=$Pe z4lN#W)9cRS(#wV+*ce0N{`=d`zUy7O?$6+}P*`BjJb@oYso7S}UUa6HuEW6=h!o&F zg)_(hyJg^jNFN0$8K^drSzu8tP3>MYWotWz3Sir@%Fs1r&YsgY{w>8+RuFoxYRI4C z@(fOU-1P;O*f>5`A#=jU`BWs}C2a5sERA)43z#wpha$EY3L*lRZggo-TIQ8D?qdUk z3XuR<>gyi3a_h}|x$cswM+YB}e2Dit&Pa3LuCM9JZ^8F26@nZ}i^$0$;@H&|LF;>U zBfuSk#5*{2&WB+UlB)qbW4ydUeT!&;oHpQqJGEwc&fczMG^z{(1r!c)O4@Erl(M~` zhn|j!jLTiMD_{C6O0uMD^q>uzBiAzHb1`>)SEYF=K3t1^U=$L6;QRxbO2lMZE|fu0 z-%w(5mC4gETygpeFMEhuJ@aDTfnsAkJgw}CwdMQur;rIMtFSuwFjXujpmab0oY*<- zc8on@s!itu3^p6nVxjPz07ut@?_dST9wbpesqC5C- z6&lIR`+WlBt|`?Sl7oxsfwam=OUE?dB92Md7oL{_;nw3oEIzl|q1X#FM3yvRP-0dJ za{(fIMaxrPDr1j5vdnTYsTUjhIdvH7C9vP=OR?MiI6(XXwcOE>3-IzIA79AetoHBt z=>ReZZ5kjq;Y@Yb?D|iY;~ISCA_V)|q+t);sc}{opz(_r=G$Odsl3VR1|)V`o4j2# zIi5N3(y_$^{f{V75gSv-eYFBd;xwl^TK3563~mO)HO4Zu=@4AIj_3lJlG926LmUoh z)N-4GU#w773{C`V49#VKh>?*Vw0Pgk2?yQiN`3@9OR_^+Lgsp% zwhp$9pyWJb#eG?bHFEW1%}MID-g)YrD7tIVIc5=F-imySo0dDypyGJLl(Z!V&dQcaZN*l$Y95nqEYh>XwCGV}3yM zXel&COqq!y{oc_)fnCvTl5aj0rv~y`k_2N!KbF|Q06)$Py8W#^^~>M?8;X$!Dt6l6 zQ&r8>{_;q;C9Tb=yoR=E9K-$wkdni%r{VFhf2xX*eMR#>f3TZlQ3hH z{E3UtU{T~_GG!$cP)i3eC7llJiMN(B-_m$L=@ysE;itdI(+M5dSjY{^a`=w)Xnd+#gf?>#y~8NV>M2XD^Em~2p8)NwM*v9ZF-c(Id(|A zp4TvhqtLn(mtQLq;RDy)`i|#OXdK4UsZ0x!(5yOkCTfYVe~$|7BlyGANjmmJSMD%|};UMe|_{uoXY}eMm zebD3$l+(#2a$2ZzA`dvD2j;n?-ir^GoCsbtvyk$*3`jNkD;By#4hars6t4hAkNy({ z65QbGh=R>qB&i2q!q5=%CterR=>ppR?&EJ@SWx>uemWKD92L-UxWuyj`uS*i^gI~* z9XB-l+G`tHMln6ibo~cai8$NDY92%?f)qmQ;~!FgP50gh5Gauc$U9H&MfnMsJep)} z^Yn%7c|rZ+XXB-pzWGJEFnX;Sqx*enAH;|DW*t8{78mJjDY-^H{x(qc;I&3l83K&~ zu$O26|I9H_B7~gq$k-zFPYwgLpa44*qLFtmA&U!W=cW&TO0q+bEZG|8CKIAZnfNg- z{`yI5>TxE1WjbEzz54dwf}5jlKJ{!T3!HIbaMjUMXfE9XGNzBBz$i>4|Av`n0mziS zrq^`uL6&ezK9c4WoF>e*4=Ye7-R)I6x{5E1H;Vq zDxG~gGtyWZRU_Lzc*k^O(wU$Lu09W*N~_egVnX+c3Ij~M(nJOb+`>fBI>0w*qr|*P zQ0~GSc>3rs7U0oqf51OEwPIh=1@fWFg10a4idGO_N=Iz2Erof|Iz>o>pRd z)})Qr1JlKW3GVl#{oT(|E&4dVQ%b9nQfH<{ZH7keSQb!+8!1E1lA)k(5%$2SdQoyP zs0Il|Z<3NqjOF0SxJDJ03YJQo{yNWD&mDgGGk6G0si69jpq8N6vAz%`JVV3jkP|Y6 zY$C=SaJ?`M3%$EL6OhqZKeS4{}_p}u;&d72&7HjMj#gEqNfsR&LzBdHD#icixd zssg3e=2o`a7<93X3Ew7WEJHz>0%TO7agTQz2c2@5{5B#>u-Yf&octmYlT5k}2ADW0W>=2;Fj#;1#3dI3f$F7*Rqpf|ERw zW0i`_XW$E0-TfOpZYdgSB}JMsG_-q}%7|!aMM^^`;}Mog|5G=UNFhJP9y$=YKW6%n zuZ7wmixt*dRWWTHQ_-UUqjzc{J0e4{;UOG6x`6in_?9Klpn%Gv^9@OXRx%8~ztQ>b zUKI|b^X1G^)7p^F2*Ye_X$UGau*^NMyu<19FhWu$EdEiNo0r>X>ThD|r+52#XwFY_ zVFb=hQ$KD$;}hrINx761QXCvsxv${;W=mBVsc*29j<)$YJH!J@hQDoaFoz1iPOD=J636wKpCAIH>D* zEAH${b$gD~@jhVn!{sTX8!<}eBB{2l>gTFc%+IY#rwVQf=)w=%)_GY{b7(juuZGcI z`TO1WZ-4mNTngjKCBhg}VMx>q{MoFp;F+Dn!yeNSF!b|6V@xkhM<82OAoPV@lBw1V zDI~%pJA*0|Q;m%%$Jh(&pL~{8>|@I&h$+}Ts}EA2FAB{L2TKi^JamhO^(xRuRyU2{ zz-6@cO=~_NCDCOj%?3Tuq^)cXPjRv%EIuY$q~VTiBALK18#tcvBAl~=(U?`X08N@C zI!r_w&5EkXZqSh@p+lK*f?70z=_R`-B4khxdrmkCD{k2*hBP5ah4QbQ)Wlkfg`j02 zk8SG*{_+|;RPBK!I%9*0B$~l^t6Wv!jfs^Ta6r>Ky?pnTswymxTY{orsE5;i2`AAL z>T+Q5`IJiSbkJlP>V=68E#vb*ITkqAn3)$Jxr$*28vZh^=qfSyDWCr`$1;_Ax!0#{ zg96l{7TQ>Nrbjdtaoa#sF@&9)X?h(+yAP`@$b@92#^LX=U3l*F_yogzr%t&rb7BDy zi&D#O&|FnL{qw zxa&aB$=u+@`VnLFsoHGo)e7NOVP~QqVdKq*c5TPAmW}f|XcJ#ZoSw_+u!}If#HB;? zyn*di1Nh~11Y@egFPrbFoOq;s=LpGcOP46swiirA(_W{=7}#KJmtg7xQog#v<-TBI4)aK;{J~8xZ!x!7*=OyA%+D3Q4ZlYhBneM zb4E=_)fZkYj19oX>Y&nn^C{Mp;KU4*)Igy%(U?X^I&YT6=kUag95e1+_`<2H@Q}4K zUhyrun<$qRGdfB5hIgxYJ|^PH_1`0g*awy?j`kDndUdlyGYmH)tyqFW)Jo~zlhsSB zegQ_SuvY+Fhi&$*Z*T=(>Z~6GpbFRJrl)@V?z5Sfs~uZndTb5>g>@dB^4JsrU3)yd z5<3@%^!JT%{C*m{>xM%rrOR+@feZ7^?_@f&@b+492r#Gn=znQ>lbk~?1*>A3GGn8p z62;^Z2N7Zhfs4s27sJ*I-o5=yJX7sf{B*_{))P!1H)9^@hTp3o=Ho+`N}MgR6jFRH z0e81KU+S9;@6eY=_S9E#&yQYl(rx&_TFD8d2S2Hr&v0WN7^>nhUxphvKfc-57{J^j zgc;5L#^x~|lrtTyb>oRi_ZK)A5W{Z1q9}BbS3$4P1|CHqD9e%?Pq!)&R=S=u8k3TZ zrW7H&RPfTZrY*4*`VqOf?t1Oq{gMj*5mw*%(yvo-JrtL4P-}hVXd2!}hdVSl!G^TK z(e=}uG=AgLR7UG@vuQq4Ym7?#ttxMlp4jUzUFKs`gCH1G~|T90H!iR{IDs=zBx!!NsdSlQ;4-LN;p(~}s{z{b&>E7MVB&8WV0 z2_1Rky@!PMWU9Q=;#{v1qPOiDnX314KnEV)fh@gkb7ZQ4iR<$FX?WWkyVT~;!As$d zze7<3d3>mg#`>I1gz88H7O>gq=|#lr-8>mpT%ba*$&R{3BB=hZ z1L)5ek>Z-3&%Ke;YHKep5!mjeQWO~KOc4WJwD2l8cfkwI64 z`{tqrd!zs`@VzJ(-MM97j17=c(vl^pcl)?5tsrm*P~!3YEQw+foqIpawj&(&a4IXt znY-!EtC*jul~o+vsIp^J*#&h%oLfhnfJ4o4@wGR%M!`2Uho?1_;)ZXjwr#^__UIJP z9J)pf#r;t45_b(ur)e$8E_oYz$FL36Q$k|#f>Oh9@HF>@(>6UN5Ge6(= zp(dWLY&!ix>&|Bo*@Xj+VE~teFc?Ha#P}sj0xM|J7jd6@CU?!Yn4B44J`#e;K&;{) zD_|4G34%g9fF_TTn-MBBi>lHNMY>Dp%X@||wpyO6Qk&?zP2ECa>$}8uKBxEBpTHtY zQ}4H^4iP+bje@KmovJUI980I=k*UE61-#H0;Drj3;~refiW+wB`h&tGxyGO-0~T1; z&6l4h*BLFR5s}*JYtzUkWyf#u=@VGM6XO%+Rwo+pj6>DNSvVD1y2wb zR6pBMuQDU9h}+)r(pU6SkR?;5588NzToGqXkT>8vVR-QJ;SmI6T4b$6vLblBAW8(* z*vmas$-sc-R!O$r>BlYTY+^#H)L;v_5dh&8nPfZ`%p)fUv1(D2#MNRXeuZ&zF1|ev zAN?`ya*YFuI`z=TI*^11`;Mb6*#b3s5zKx#Q!>!?wC?9$}E^+>foF+9mI*Rjdr!m3PH{VX&-R)E!76YnJG6`aI)PJ$j8bA*F zhf}v?pFzQ7b69XA4l=f*=jIELLgJ$ll*we3`EC-Kv9N3&gJBb_( z(dm}?^GHxEi&53m=VH8!Z#5p~=2B4`qC712rjzz`e_3LF+nc+FK13mu3_Ce^NEL+O z5>!(^#%kB+jkViD5zCN4S*uqXNN?jx1!Ka5)@p}BVif4?VOt8ZOHK}mFH<99rp6OH zEOHR8Kx#PBtoBG{NDUf;JpgN+pkXYGGWO1~{738jQ}9@|$CtSI!`XJ39rMbQD7v!q zF2n&iJeGdGrd7Da&>DN49ku+)3O5UqL~Xp}`-`z94SGS4(*h!f^09q2vXCY(5so z&&gKiX@IoxWrGEF~y` zyqHV4?4zp?#lV`E_wZdDkf0RWSxTbcXf?CMZhh6BS(R`;oF`tEh*?-IycgUJlnyhU zy+WboWCBBBCh_gxJL8!rQf4en?1X?vRQVo)OR&_Vak3_5wE@-@M8vVRbK~w$__sU)a_=|vm^^jc4Vj^@;^oT69 z5)ffcEfZlMU9@gsPo236xs@O6EsL@Ln z$GWB3`>m-*y%8&@J*Y%%Hl{|!Hi5F8j$~3D_whJZE~T-qIfy~{mEiNMasTQF%@g+; zgubG@PKPg~2zLiUFfTtz20Z(iY!DU@9*SG?03@YG_a49Ea#5Y7B{HyiHN?R4kpjij zj&f=#mB_V+7#IT`^cqH&@>&H2`YLW0uLTSmo4;TgsYxpeJ4StuYX(~-Eyco`1n38* z^nwB~BGQ{Mve(}UqF{TKpMzLwjHFD=fRr2nO#7|57U5=KjLdV2t)ta*jXHDTAGgU! z^s+?r?{y>2qBLIvX?DYs1WD16k_07$bpYbAKb3+rKgWCsJrrUjG0heixEBn&CO#7P zOZ^P~$e1D`N5u<++Ctnf6T-H7uXs+dNe$<05A|Z?FlK`YTIfLZe7XP zI-tI4f@k5R&~Ldp<0y#pl{%bMrmPT#22wmK!4|xQMkXn>NziB*9`aWDM2a2spN^q| zGcE$kEw%k$VZN<)Mu`yrq(bEN`2&pY5y#ihXU+t3D12|8jH`WqwXxZ*R@j|PJ1t2k zuqwU9uvB(~=7K^wkVI%A;?TodsZ63#&M-ptRKc7X$U~Q|G$|*!k-S4qvRfgiqD}O@ zx8~sT=lm28Tvp_9sP_LvUKiopml-oH5lO_Atn@Hig60f6&t}m@9*#DheY^%8^s;*~ zu`yO6q5uoR1SS%)N#kP|!}e2tcao5?D~?v1LpEV*meod#x=h$Z6{&)^6t^Mz(!m-r zq{jC_zF1L~M2V-73(%+ZSxP2~bBmoDAM5#J04yEvX68!V3B0ywBzr)D+ZClvF4QG@ z*Hu@3O40+rq;iqVdFeZ!+W)5GfA*y>yz9^dXVsdG;2X_?2%5$-haG|w+BgVn-h^$T zvSk%{UOJxs)@2LlkV-_{jl~xB70+4m*}wiKzPh%gM2F_+iphJ-2Z$bQ)j1{?b?|O> z$a}za;!0zKUa4SmzJ{BfHZSgT!!HVDip|>$r*siwef$k8#55}|-CU@JCf?q@v|(Yx8i&CNogXu z!%!;h4c(BNZyrH^DMiUD6u(5=xSS@rfEjd+QJUy~jFB6_JSbL&+LD_S>EPd;{Pfji+#DxM&EFAY-n03ZdV?nNyc#4 zTS*)pd(y)@X56?G6a-jVeQNbJlqk`g#r!fI1!Ki^MxOSqLeQ44l$P^EDAg}{>DWq& zq0AcD2rgQq1L;V;m z3AKu^(5=z7eP8bVE|yd_cj=H#@0vAP?!osipe10-WY|hUGMU$n&Uuay1S7`!@gikH zqh*p;VoCNMBqvxyQMgJOH+oG|j67Rx6BJ#}*u@EpMs-#3?L=jj8TGsV{pEklPM;bJ z<~kw4iMlhHcw5lIE=OWN0-9>NM1U<`fveOBFI~U)COlGEd)T45 zndzRnz7DrgbZ=c!z~JGX^*<>EJKtF(-3Y1}7P^}kq6{)7rASRlJHG6F=0&WGm3+iX z$an(WR1wb0hFNU+wQ;(2%a%m> zB)+vva?)X*3JyKJao4aB3FuX|gjR|0AJUPMcTX@B^1Rw?=3?yic?PDH@?x@FRJJjh z@fJGIrFG9AKJyj&xUww4p(my7*WJGvX#jQ}j%C6kR&U9b2Ff0IrGg>47B??!_6ZBG z+yE&7iBY(9JYlO|%$CN|NtcX8W(5hGe>3#O%1h7xrZUR_R8oG(q(6cmaD>4s%l0$y zKkQ3=Zemv4STd!e1H()%XYcv>p3hJ&Wk~C(Di`KByN3raYOclk zdZ3)vuOA$ZaHWompmFsg7$><{L8ETQ{khXos#p9P)GAAeSj_Lop#Vs-(HGvzU}s(j z7~x7Ppo0clt%!Itm?5tjp?Syh)+2TVg_tVtM4N!7OsnEEfm)-&0;B~-1i38#>P36* z#Bxf(`>85RRzY`ziSSe9auYU)2S6Rtrsmklv^rtk;u9T6Jg3?L<|G}usHsR4eFkBk zwwF40B|fnZrZL%&BmfubmZAc+mjL9)WN-{GfIf&N;haU3qq&|F5}hgfHW%(Q|UV5@J;IrpYx-hSAPsoQRDXMT=?^K;j9W+)b4M` zsmu)0hAg$x7)64&QeD6p?k3MqQiRci;5H2*Lb(g)CXbAYTX z%D$WC_b}6M_NZGq))-6(ZQkiaC1YW4-+(6 zW2bG#h?eGL6)JHXKBS8wF9BEqjpNfh)7LeE zk>djIp%%2MabHfY<_{~4R`8WMlr8RT_&&cu;0SFl%NYfd*L!{9wuhY3k{onK3XNc~ z#4OlI6#vM`Q*3$OPtK6xiGN*UT5Z5ByFbruf(xmyMAcC65<>d5`2c;5KAiG7y&+dF zvCrW{mj`0?l&L5B{QtG_ZZ$9xO`khQ^)Cr@m;qGM0=x}HMV1vZV=WfLOruvNJ0U|8 zVK)seXWMb94U@q|SZEuemsOlvD70w7r$2HPp1-WW>QGO<`AFw1;?z%^#~N)J6r4`f zLY0wTst{7{!riOg_z2yFKLHmUr+ zQMJ435`3hRVX{M2T}Z9K@f5k?g7^fJYJOc=jpd;_Nx11>9%#vTh!7xm+on`V)1fnO zsgEB|OjE|VFVA$SwQe29imzzntiOpMCPaty5{lI1QUx7)9lqBXcTMt9~d4^*Fe&&VSRbdbNJ(Sdqg>;#U|y@Rp5e->!H4{=#dXMG-!rL?bU$5t6;oL%Rpl=s5PZvk<8`eJ51g`OHD$)i&`vY9CYRaF&Zc$P zz7}7*)TH`HawQG?3HC4R>wtU1 zIRSoz1=tkiBJk}Qp{ij{ijWJmLs0BH-*fJs6DdLt?(9^TwJJge$}=-8%aYFT#0SD2 z6iSKk^khK{IEB7wxk8ULwy8_9jFindXB4N{84y%zIy_Po6-yRZ#G8}FPMscA%Rgt$ z8=g`l@LpIVk^vP7*(8Vr9t$w62k#$8Tu!bZaPz|^wheX}&E|f&q8;k8F%7Ofg1((9 z@yY`gBD@Hkij4pcOr2?)CrSBNc7&AGT4j)o1fhREpsQ3Nd5RhOY(^=S1Y|spFtmBb zx!zTK*83rbvQGU&gR`Vqd+>epHJq2%@2dt}()KFzysT~Yo)BuCO#{J3O$xI>VJWGB z4EMO$C3utX2&l~y8Q<@Q6~cSblsSv(iYMxfO&}#}5(C5CxEZg#_qca(-azeF z`03o2HZfjkm-hI;WRvAqLA(3~?!ahN{FY_l9DqQ zll6F5_(NdoInww`HGnQ9!92QhuM+en&w0R~Ehi&cdrZl`v#ILBSVC6#qR!qA33%nw z|D^GQROM<#cBqb%XiRoMcrabQbr9N7cPZkEfhojjm)pN2woP?zUe5q5Zeke zS2|t6li&~vx1IbL65W22K92lXlHcv0I%^%pSEJH&>dV%oFH4%Eeb8|HA5aF^Y1bD< zo~=m~#9$Wr;7GN|lQSCtHK^JSS7;nVSzx%ts7e9vxHm<)S5X;j1g;JB-~+@paN#L< z4N=*5&`H50Ba|A%cd3HG<+#yJCtjZU;}=hEplC`)k{^1VissL8c?OTGbA$3heyrsw zr4CY^u4TaUV92cHQW%~*w`#?dSXXksA(DuLlvJ|HGMv9In9vi4YK^0yB2kktRc>v1 zpZUC1`zWHasQXPSB8|H5=SXrF45Mx@&I+h6(T><&Q|^ou!w%|hDlXBMig?c%@h90~ z&Wpk@BH7Q}He$zNd2`Z2a&G)47rf7XD3GD+oGTW7m3b{!l*2#!<#&aj`eTWr zT%iJEjrWY5tL8iAB7Ep_;*!u2U%Da;zH}&x99|j5Pyq^qamthF9Gke1L%fc06PBN6 zMGFH>+8tl~nPctWadK1bKk(DJOWv-FCqVDP4BPsusWHS+t|(8zugBUr^Q6%nA3(kK zY3s)Z(L*~iFkXe@ya1n~>2bwPVb$V&Lj;zd@PSbpptLL<3QNj}PwlXJ64^bz#O=3S zdislqyUJ?#-#P0W;-mQH1$GQ4S~1{`c`~Bde!vC1W0?aiuEg~et08Z9x}VsoK;DDD zNJ)j-=*D3wbu`Tg!ayK^ZU^_M#erpp>{?B0`7^F^$5lUm*xT{MWrv>}dY=l5psj}; zYv^6;&hb~eY znB#+jlLm4<8!J{0T!Xt8Nc1i_la!>$Y#6WLiJe;USFL4M;xRFeyjXCdiR_|j&S8t^ zbtQoV0HO`;xiJ=}E}6jWKHqHv=WlrSW;}U~y|bML5ooLXP z`Vg0sP6eY&Rce6$3o{~qLx5*gaS>&xVZx3@S!+@#@j~_$mI5dWI>^5)wW1%De&JHP z?wntauxqAvH-0*$wqus1#wf!SjqRYi7`H`qqtWT3=>)H6l&O)bfZR4}fCY!e(jBoX z7B(BR=FO+vOsiNsu|!2aGRup78@_k3#3EV6hcDL36O9Xz+zH+orw|Bu0brG?Q20>E zXJX64ISG)_Jn|Sy<#+h$RDqA?mIhY0XK+F$ z7`ZQItT%!V;s%bclM59P+a}yQzpb_L>71z?VWjp9F$&^tu`Hj!&en^Cto5}01GfeT z!1!9Ge=6P2FdJJaQzl>djvWtPeleb*_L35H__!{d>9L*`JSBWwtKU~m`wBn;Ujv-l zk1XL(738rScQ5vqHav6As?&XPg$c+@@+Lfz@jXCOJmr|jIkt!& z@YgU-a5EGfO^<5}@BlU(Q!WYPXS&6=Lj8*Jn%a49|N2=p9A}mY?^7x~M#4R<^%yj> zf+yaN^+$Eh<8Wn!SD0dzD;4zS^SHUYX!24dnz{)f!#GccnzF!&d#usYB);B=@E2#jb&9B#}+(<{N+*VCu z_Iwa4EX`7>;qBx16=cT2JWir1RFyI_1N9xlF?dX?I4`xagGkjbg)Yf`5EYb5l1AXS z0``EELIob~!tTrU+4V2aP{&P)mom!6>~!z3cWq}SdTA3zb~cNj%#BP^D^yD?62J+L z?8Y<^T&N(WH{m-M3k0;6$n=>6Fv=)zHt zZm)$i5DWJC>My?Gnk(^OwX*7KJ7#5;kYF3%s#Hnzq{OQ6=mTuK&H%jilDkJI)V zuW1XaNtG&BlH})omz=O}XN!l2mV&u21qqIiMEWn&AV7rk&uDmE*XzOZa| znGTPZVy6fTm3CJ)R_vs}4peeTkxOWVyv3p-6yu|qdgvxu-+obbl-CyW&6rNvkMS`0 zYfmf!X1mn3Z@+G>%pH18iA~;_+hm-Rh&PHDDx>+;ChL{P1g})sIiG>px-8#{(2kgu z*(|M4%bzxgM!_cPu9c$o&1GziHj*1@DXtt=NZK}h`|+P1s27`Yi4pyDb)Hy(hfR}HQl#uFji`vOJ;h}Tj<6|V za6oCKDGq+0w{MdB_od(dq;GHLgrU+gLpRK-vRs94U6E_Bj9wH3;vQKzH3M+&nehi` z+g@n>oZbO2aDVPn8u-p{yGdl%7T|w6735}> z64~q?`Wtw_L5GMZ~VNxb1gME=_zwP98w{ns6 z=ADb&oA%FA=;lhCXFcREo)w7WEd&VIu9X}(^8m|*c`~q3YvXRgro%vb-E~(vLVs?)j5_6ma6LslI0V=w58Lj!((T&?FqmuI}4}E<$ zWW)$+shrx9lFvTduV7b&VqkJN;k&Q|&;sroh3*_gNmNLJYcc*FUJQl-7o+Y{wa9T& zAzEcJO3KKrG+2$lpEB%D%*8dQaoZ)5VC3A~PL;Y%#l>=lrHCxie>Yxdd22Rpka;Gw zRLQmf!Ms5x_?K87R>Eu&4B74urVfpZ-j7SyoDmS(B?Kj9{z;N^z=Bl53?usyOs=e{ zIm_#x7+&;{n5Jd6*xew5L8!dh5&9daMsL6Sg4_NT%P1|5vSV)^jLXZ0hog6|j{jae z)*5Z2qP+c7&=8~Tu`2Ft68CE;p}~XO8^tc_c*2efe*;C*)V*aBln;ZOXFH@NtO%`> zf2TU?=jmnxEO4c{>)ZeI-4pQ$wIAZAQ)#}fN+V0YpU2C4ij74t`J*}WmebkEO}mFm zRZ+GKR*Ws4kYsfzlj)lEzWV}qzV^B+S8{>BC|RJL>@$-KB-QSN(K2ij8l0OE=pN5V zLDpSsSWM}&+Z_8l8zt3Z zg&${R;@6G-W|e~un6X^SXMts7En4O+4OZ&^DZOU>TG*dfF#tda+D>1f4UyAxF*SlA z2~M2_Yuh*2Pp?eV>o$TVm*gf~0BgSVwx6zo39LQ3#14K>1u#po%iHj+^L5mlGLhb8 z<0JL*3MQk@Y@rhIbYzCqS7fr}CeMgG6_}))g}hYeK~owUAi7LWxbdt9-hzj#J)uM< zc0iLT1u}@E^;I~#Aj&?8GIcA-qNme6WvlrCI8-;V0%wg_JL7AOy(~7UG3M>Gf(Mhz^fo6* zYS+&jQ6nOiDZ9)c9{~2WPjPhc!Z5 z5Q4Zp{12l3;&k4WEn}f_VV*+<l{H1$*{G|*eHu_SzVGpXkw7eTOJ5F^1+t{ zaxjdXhj1b;?b~u#torJWOMr*?W(^&*VIKd9KXEPG`sjm?>A|XM4=j=7@3L(u^9~R< zk6~7tdwYJLU>Y$QQ{EMg($tFDc-} zh=&;61-J-yJoG=-pH2~!O&7HDc4&Wf8pI5WfZC+-tS83Yv1$RCQ~^czy*P49dMwmL zz3mDtQfojw>7k+3au&%4lJv+D7H=5L0zNw~>9=Y0VgP_T8Sf@JG%ccVZai_jF3K}r zaMcUWrzq!?Xw!YFO^i5KG}GDF1lhxrLoLpZ#UoYOj*K}J5U1fGv?W;FAnK#$4TFBi zU@lmB`>o`lToRf%5RL^g6E?OhgOKQtc&*8 zcizTz)t+&*91cGuw@)m{10>wyTZ%Xdr>n6{udltO!hZS(+-PbM3v>=Ddd9i);jCzA z)g<^{u(9W&35lu9gpu!0w=|&n=pa4nAWrZBvKqdntiB*82bTaU2z|_yFIsfX&wD8< z4rb{B+1_UMX0;6xClgoCw9=pKn`E7m@Hct(kZg$_+r7S1)nF=G;W*cL4| zjS$3TG-vxr&oe2b@8YLZUF;kOM)ND1qvOq@>nCU$ZzI-fHLO;q0#aUuo2{Btji5PW z$MW^w;z^v~nCXaNn*DUa6ndz=rDyh4ZGGpH{zQ{mHm&@y9R)!C8Ygd0@zr+@_8@m3ZXCC(XL7UW;#rW?=~v@WMgn7ZzXm51IdBVoC`nts?WGn;A*Wg(LW~ z(>Rn77Ar;GUxHI}Gqo>Xcbpti`3F2vr`>qG%7L?U5N5G;v3!exdEGdG7SMh~%gxbB z=irRtvwJ=FlhaJ{v>62j-++BX?_~9J&VP$J#-4Ckl7C3rsuEWj!gK4gcli%j2r4T% zqW*Aw_SgP)tbJMZR|2fMiwLxZWksHY;gS-=VLf0*!)1hEIeQqI{NQX z+oU^0hoPEY?7Z*Ee_Dg*E493KP6YkQs^%2WoLPi7?=F`qg9-U{V*tOdfYq+Wov?>k zwN@PXBjOj9rV9zB_!*!=l0LbG>4@EPe%Dg;ury{QkX|+GBkXXYBopaM^=BUHGd1Z! zEtJtU>4G1={dv#D!nl%^B zmPdW*RZ`dR;1aj=^kiyR4YZ&~>j&y9fxgGun_ZtsP3VLZq#QPmO<~Sd1t0!u+-(3w zpE7BVQ*RO!b*1_QSdgqG(vnqUlLKGil{$jCH4ZkKPT#ZpQ4iaYFSdsVqV?2T zZc-Jb5yeE~v)~nMD2A7kfK{b}?E-4z{y|}pf#v{vE|;y(m|AiS9<*$((%~~yIhdK# zEmNO2**Ao!rx@y3tiBCra4x=KC7sipnbW7L_se`+LP;GjSm1c$YcM%Sp{h~9r zU@c|I&BM=C5i&e75n=#+I>V0YWddB!-&YXdJ8&!5U8P^V0EMBiuMmf`i!ImC2Id3e zT9K8&nI2{}b)Fxo=j|C%U<}68jkstsUJmq=^_xXg?=m^^qLc3YXFOo-kND|?H8zc3 z4DvvG40yb~uHG{hy#wSLHZ~`R8$1`x0zQZ$HYtTb1mxEfgty;;D9=vuI+xdt1oWyQ7q zKA+Q`=e>DV<_{^d++<4_mt21ob#LqhS!P3(bufd*;1@Xvou!pB|u-W4Q*1u z5>!Ewyckgm*`cJ^W;-(DL^wQ_e8Y%YI8oyYY&+*`4|yxI)(T7B?TbGmbGX=0gqa?D zWK9R*)_$~-9mee@nDoF&CSx5|Q0VYsT!3tpM6#XOEgxzueGVR9v(%|TCjbkxmCjBg zU=9pLbM_z{mX&u&_b~VwAs==Wf2Vj@{)vcY9*Uh+;>kpn}PTvnEW#>srQ^~fuDiN|a zt0uAAcF)Ntblt9BV8}ZQ>Sy5Q)kw&BY*F8Y)EB(X1WSl&QyK}mA{&a6LL3@K;G*i5 zI_QL480bo587%1W8Y(y-k=eS(9u^6pt`a>@`_+Nmu3lDb*_MsHp9ukc8ei*c!UJkh z&X=B|j_&|eZAifmJr-CO`)EXmNDQyGrb56!;$t7J=nhI0#nUYH?FP%~j^W_Zw-g!} zP7Z!rdeh?L^sQh|d-Nx5ymtAIxi_wCL;E%xk^cz3a_pWgz-E9@oK82Oc}54&h@*21 z6b94F0F`K|EK!p35LXD-&7ot!rf@wr*^a{Z6RnIEWwQd9aQSPhQCqziHi*GO&Qv(B zM{(*XmDc#H z$^kHtNK)CGlaCHkSde{(yL02rOfqh5`+ebU+QRiiJZpPUTQ~zUS%>e*iaoC4;Vg(l z5IvA)3CrYcf7->4ln%M2x@@J09l}HqR1Z_{^+oo)>%#9JjPETw*KC^&VkaB3dJtzQ zl$}XTJO@L^CSzcu$^K5j%d2s#wQev&w6uo`tb^57*}xd_7VZU#!G*jo1|5hhvv?a3 zS~F{{g%=XXus*RJ7sH&JzVkyC9ZSiF6ZBp0jmsxun#sgOL|85!Xs%HMX2DjHP8NSH zZWXwq@dP2ltr})5?kg3KNTCVp)!k@b^)aBs9%ZJ<^q_7e?m)fOTOA@l1Fc+*7VrR1 z#2e3hOmbhYs7Ir)(!vFAQTf5bo^d>XDKvS7N{dv@iKpQN$_9qhrY$3+Y9{5^7~DTG z&>{L?#)2|nmL@}9b1YV@u>$~Xb>>h@ptpV{XC*MQ&3axlrv0zq5w5vEXh zc-Nn?|9$c&|CJIcnPa%EUnN2!JlfumZ}fu0j0AvCE!y5U=(VZH=ER3iG&W9DCULvk zeSu6;r0_ ztbJkIT9tt1KOmgYhu^|RcSouR;66(VN94j();_LlKL_{DCnlwek`QnXK{6MlasKY1 zAEEc$a=wT_tY5rkl%@6k6OHbF71BH``JxK4AE0yqIL zxZc6sH9)EwB3<40>;CHL=i*Dt`q{UQ=t>C}jzR%F3Zq=%I@GpC8nrbzNoQ*9J{Rc< zPs6=kp^5s^{FpJz)WjR|AMk~&`R1=X5|G$#CfL*v0t0Pq!ql3gqor8zLqB{0!&PZ^ z-_!*&J}hibRC@*^KG56sqD(PR-!Rme8kJ_R^fkCsS!Pv9V7O4cLe50c*QfpH0T@UF zFlCP@z=9Pl9Pcr?HYF3=prRJaoE0%<{@%xa`^Mkmc`7A)dbVxQ#WU}kk<+$rRR#DM zK7VO(5<*0B$U|u>rxe))3hW#`%MlEq+$6p{)s9>i4#^rW#3_i7wDOS^LKUKV`Ugmz zk=+ocY^gFIgrrpm6PN_Ie*f5pz>5Rn9@;&_t5kyQk~;){;X$g$NniBAXg~>!9MMNH%OJmL(X5G&8mGM5_-NO*nYARc0sP znYjby$pCah48GkeIsz?eaesx$ zv9^Uz*|GK5eCMVOtl~cT!PbsTzC;O?47u6%I+YMn=(HW)cFW#sSRcoSE?11i^xe)Z zb$CEMNKk$y$w&cA60~p)c4wPJA}VE+U~xkP=@RVamN6yT;i_N;slLCY?Asu==urgp z1M@G0mA?#^+XENB@@JP(ZokG)yEC#exkPGc+8b(sni|Hii2_msQ-LPIalJ4Fq;|`r zRBo)iciR|$Sd(_|<)o{K&dYrv9o?;(W($M|F&JRo-@#9VUkc?6hWf5&9{ajQ#Aamx z{f(+DvS{o&!f?LoLJUNTq7RWvuUYHsznir~0Q$2_Vvx=BWE5YB zj#Qk?S6z(bim+A>M68Jp=p|&ka%n13I9R1{IqvSs@VCGbVKG!k1-vOq&aDr|10#fI zI~>^32DOI5GluIQYocoNfXqj@H=#B;ythU#M@q)(3zKVh>(+7J zsG^V%nLj*udc7A^AZGQiU7Kwqs^TJKuNN_`UoK8XREMglSR_O;uc@iG6|vSS>`zvw zG9e{qF!!-(;#D4kb4+ZWB#kB~lH~5)jEI!5WbT?2gEy6m&U!n84Rj0Y+w^Uq_dEZ@ zUcE|Bi6FB9tE*<9CUnajmE|4y`c=XrWkjp6t5VGfi(#J+{4!Hucvf#GXq$OR^}`7^ z&O4eD4?#md^tiHPJg`DL73;=}7s2WhRaC5ifRRn|s+d|1_HGfA=jBIVv-M!gv#i(d z?W&lpTX(^+f~%{pLZLC$f|!XkHy{<6Xw-+NL{!~!oXYTnxD(78dDW1YH*3T%vH{+@ z=hJuSz*0joSc{EHNd$B&hGi^80j9!Rrk*OXRkB^nA|xVp1FXUXLGE33Bi?k?AD7&S z=dL`qMECw(Wkv9GY-4yF$FuD*)MQA0Kjl39mI)QroA8mV^DznXWJQu*pVmW{q^qlB z50t46O$%Bh;^w*lKy8pofJ^*G)-95;S5fdVkmlmJ_ojb7`9O+;eRu6X?dl|sY1`m* z%SIK*yYQX1_trCNpLprbba=nTf_kP(EL_kYS#~pyUg^9nD>G54)RB8g?w`3Z0wEZh zuvPjd_^Gr!m(CIQzwJHTepgviBAqQN9Tr-<>livx%7L@8*kFHcz1BC3jbKx=FOv}q zYu*p0$z@<8$z#nmB_7UnhZ82ctuC!;n1ca_=+d_k%s(?3Di?!l^E7l^0hnqHR=s)R z23etlj=8DI8{n`PnDQ5%M>U|HDBkF+iXphUJ2Sr|Cki<%iqg<3ZBmJ#Vh^AcHR zT9S!akE>`@q|eDah5318hRD%sn>20iS3kMz|KT|+B_rUreONV(Eb%-+V1uKi&M79B z4_V?qzXtxC*E$f<2XK40XPf|h)Rq>uLsRD*kk}uICxspC)y?3 zYU&uYtyiWZtqWD5&cV&|QC2{zUWYlvv{Gr-$QUB|fAY!DKK9w`q;QxE+pVnWKC$RJ zdji5Q200k8Iej%{LANf12ToaVED6vG4XfRKe>@2R5ueohbabrU@(vZk>+r1(piB)U z@8B}E@en!=r|Si2WUJ69fiy+U$dRXI_sC%k26?*g|CZ!6<#W;W`rzk3_r)#>qGW&e zwrqqVb|}N}RyOJzun{|^mC<_OqDN|d>(N*~irJGRQz_WpVhm&xx4YAbt~*4pJb`t% zPRpV;122kW!BUw5x?}b#U3`o>dZnHf0uqUuOFiMrecnReuyRPr>%Ts|{ux>I75Ltz zx~DF86ClN`HC%&^=08lOA^H|$%!Y9*OrP^*!$(8} z*O!?{cg9unCc=XmO|9IZI9n5=^)x6Mk3fUTJUU+~O%pxgzurG4i!C`%Zri7Iu_V8^ z*cJ7W!B*pRk0MM3xYm~bdMYl_mdXhZJ-&6q;y{WXX0Sqw!X+54Cz!~*rQ}^2Sc)k{ z#)~nu0^3-RJo7T~u{udUQVxuyw@wF82(AP7zUqwK_v0xm58|iYRenXqLZZE^HHmPM zkF=wAfKHENPud229sIP{%WQU;{!Nwn(S5#juCZ`Uz6LK%4ur8 z=2P%p%c-57;T39b{-U@%R$E7*5ED&Mxk9yDr=-9V z0-Tr(Q);WPF>VT!gimaHxj+oqB+kH}VI#-jg(#D=hwg7pP?dwPf3j>}EUOy)DCs{0 zHCohvQVWCQ^?F}z0E7t&;Pw96h88CbO({rb9-_;MPIZ3B-f-GnKidkRDvl5%9LUx% zZt^f1J;R9x&E3p3jA(&Mh?-QrQTtI0uSs5ftAld)5Ocr#y|?bfTFYj}ZreTc61o9j zt?UJo4*^Q#ZX-$Y<^tuX;836zGSn3bF4|6upi1z1w1FW$3RZO#rR5}$E^+*i&l`Z9 z(<)i%-#9qZ@D7PoRAAqSjJHx@I!p$ z=YDAejT$VUqR!sr3)IZ+;bS?HShb5|T`S*`-^JqPbcX z(^H==0UxcoFjfaQRa7u zq8X>OMOiXs#7q|GznC|({U-5E`0tRG`LOvLoqH~T$v_Wb)mdnCBkXz2=m!YyD#V5D z&?uX$GY_pwgR-MP8|EO4lw9CY6wYy&y5ebK0A`x0UqGa+Ga#n`{IL7viQt~Sa_ftq zfU7h7fr3ydvoZVYrbL9hAQ`w1B+kT%6Z@P(L3v(CYo27jK?w0#w za|(t1uCgAcSB|u~N~sm-DMjkftUB%}0iZJ+e%weffQTq1uv{rM!)jxA&pTjf=VvID zvf9cYR4P=kZtz10lPd?&YMX{EQo*qKhEww33wWgii#nelYYm(3kVUn0?v{G$j-D-&{6iex0zb-EQF7%!V^^7Z5O3x$hA&qQT{e=;-7 zB2~e685oe4Albhn=-g`ay$kj}w29T_HFiMHTly%kk^;f@hp4=!w@bx*%}4N^?Dkez zB;GY6t%9v{PlLZy6h&Jg=bii6h)a?k7yJovGxvFsPz)yA+rivtBP-IwzTwPNy*YQ5 zp}|r+k|i#&LoWTznct+uIE1h*+--l@3`*>6_|A-?qJt(5%-n{;Xb&n8uF)!raMK2_ zL&Az3Ey`J}7deVDrVNeoPW+m@2fQ$xpdps;g4wie)hoAAFfS?*%wtqAZ1(}B-E7qd zs>e1)M;oc-iS0h1t9gmX=W9m!6F6Z65}oj#xi>5Nl0kT^8FPr(&Z= z>jslmkJ198TC2Gc18Xogp>L=$wE}Qvd&{`7g-!|1$(wAT1X2~sduye>6fGy_Jg{Gg z9g?h5F#&{;(hD2PDPgCawfkDKV~jx^%E39lCk%NIQB(79BjlHSzq`_HiTeH7oTI9!p7 z*jx~AZVrtsFH3B@U&X7AE_qeN43}qS6o#gDXKeS;s)le&$r9r)l{tX2vt6ofa?8TS zr(P@vE0=k#C#c-WCv+o60fC<%MnoPPott1w#`)_Gl<7Lk%eNj!DyjZTG8V3b9a>l; zdZpHsD;)^$L%4ZfHuZ;HnyPkmXJU+6 zIA$CO5Gt*5!>}RoDA*Kl{u;(+-LJ@fTkFRrFlxd#KD%lP_EhVm7%XZ4E8tJHry~%E zgFik=!Tq7)(&urCeb@a|uW{US>AyT#D1 z%nY+IYTjM9h!d9Dj+pk=Dm&nTb8^z%4jBecdT`{66v_)rgmPeteG8zHt!R!WNx80x zgWXv+nA#p#Ck)7i6QgrqYJ_R%k2dtBSncBB;4lO9P!!lB$FZm;Fd;5LO+`o0Kj~V^ z!k9r-e2t(cjSm3(Y)Y{h0OE@0rSdbAf6ttr^Z^-Q*!sBo$35%92ZsWL&&p%`_+~JHi7}Q5ILz4_Juds8m?7<%N}~eR@-Z zI5ROEGI);S;uRou9BH~CYl=kEBhJDXW503qycCiulUDVhtGnNb=P&C--2N<8u_xj3 z0(RSDv;$rNT3LHAfeS_R967985A-`)TRYr@vUF0RdJ8_i+c*TKBks1XSS8hJpSR}x zn{JhZu}UNrZPhwJF^z^C(u;6@BKY12z;NqP)>Ba726)JmZ#bx*(kU}Qn_D)s(qW4j z$#UXI7*sS0Ccu>3hN4Wiw`Ju!FBOG`B*j4jm#c(ANdSFrO!ShWY*P)zH0~;5U&3-6 zpk^wy<;;J1#V!i1gpb;8bI!y7vE{wcX^8n|L$z^CnM7T<6AgMRzRROjyxmwql3B*1 zB%#qa%RJR^=na5K;UYz^LeN6wrKueR^XdOY4;f#x#xfJfbqD_PbmH;KpYYS}j}BK0 z+Xt60lxwnjJZ1;ERWajRSMO`~)_7EAYl=r1xKla{cdJ>&?v1pw!2PQ3>k_gKa}=ZRESihn(5kb&lT%lN;0GJ1^l!x-^OrJ8x}VE zo3Z18?8~kxM=gy_lZlW9@?c2U>&Pw%caa` zNFsYH37Y8!n%MWpaAC6kq1-vv8;~d_(sByrLo%a!$|~039@fPNoo+t z7_bWiNYmdn|443O^PQK?S%^hcevhAa>DlxaW)dpBJu(U1bK7Yq@hW^EXE}*pTBhh6 zYK~6m1)|24NjABYkg0U4+x}74D(wXj`xj&I+uR8DK5XLV_ux?~oFCS{_C?7D=x*A< zl#|cGJ?n5FV+{v$G&;~0GSMp;F!Isc;334{>)9JIn#3Ca1BS77teJa8eK-TCXm5|q zNLez=CaimkxkN;YNWxqsV`m)jqoZj|C1;OqKXwL0!oH!EUR?0}1OD2EM##&P+L-CO zs&rzw;PgBw>J|qJ623i>d}zX2?kHihtfevqW0a9Nk*p41Ws}Q1#JYIq-1@4k*c(|I zH5Si+cwUF^iZ&Q+p(V>}#AjRD68g;pw6QEjC!q1!I^!25nUuZkT6MtSZ_a0mrvduhpvDs#g=OnuA+hNDY!6LA0!xUbQCxUga!T> zMoRmh{XwB6NUMOaSj|y{8qSybbbu>KqkX$0`{xKB@CW{$DI6M_dsi=RxbR#L27dAI zw=$HM9eccewF-iIatw}o0x&PQO-Tgh_Z>4Z{rJe9Y!@BgW(;6oL%cdz! zf80>K$Z4fatJ_5$8H?;$Kkr*yWJy(O`$^d%8z^qHy=-0N2uD;l$48o-;6}odE>4Xw zVxyQmEV^&>@<2tBcE1e0WNbmNJwi zf}vqC+>KbR-A$qf5R}`-dEcl!?O;mbv-oL$*R>gx!aRIms=I4DtwKjNW2H+`h+gTK zT3c|PIV{Xu*|h()hs?zXmW>nHeu}O_pfd)op>6Vbh>s25g;Yo`{WT3|7vOunSt`Ae zjBU?N-RTF3@dZN_h^w#LN?@Vvn(=^ba1b5p4ZK~9o&H`o&+aH^gYWec zeCKN2$O>qp+A82DiAJh@=+Gbo2XZ9a+v*<9U_l`!5Mx7NxFe8sR4j@zke$^mUa2{d zu`the?+x1Xs&j+9Qs#A}n|p#$+NKxDF(UiPDW zK`L7ZtoE|n*enOvt7MXZlpg?4lKy5pmMuf07q?ytx@lLpO&`1Qmn>{m{;5QW>tXn1qya7TQ($U50 zfFA=7f0N4_i0PG=#m3Sx7&0%?pm6b@nB9{-HZ=h#A6u? zM=;Ans{6oVS7FCHw^6%V(1!v#`2T|F(pSul2^^MaV9Y&;l+Iy`T1t1nVIw9Qt%tFB1@O+g>hY<9@!|*!t#7&aa*12dny8{SMM}(b zVa<8sK8ra%q%_T+$Q;n%NN=MxJXu{(pJ)Uu5-)C7YHN9=1B&Q$d~4Qv$~SMK@g+96 z=??M@hS6}UPy3NU};o%BJXm^6QQgo z>CIEDpg>9Vzf{yV`sO+_HBl&==dODf;Snm!O04Q!)d~_QOR!(7 z&8V1*V;(5Z@2HOtVE@Ts7(kBMM-u}b8Q7=sDP37f!3YvBO&B@ok;&B@F35Pe#2|!S zc}xc%<%er$`X{j}R}o_(ke))E>h7fVMfy1Ov)nJ@4;1CwFAxv)d0m|M+`4@78(2}< z$yVFXOGf7H16@d_!pIoJ#v14$-S?%>PkQKysRh6 zVw8a$jcUb!wMT`6fLl6x2fe3L+@NH8363g><8s;Z-8(+WCoF9`v>AtlLK@x>+hVW` zDQpdG{A~wr=SJMPl({N%#mG95R*5Mo@E_FQD;&vQvedirry1T8+hWbI&Tb6h_CJ-E;4M18f zN{(C>3S7lQYv8plL50}kn}A9YZ#j+*ztW+crmzu3h``Lfg?o4DRW`l+XR^QU0j#AR zGF+(A<7VK+JaT7v&rPn3dX4qiB94)wc)=an<2u~ilh+)r_sN@Yly1s(&ZzR#GA<+m zy2`xEFzea?Gsx`SI_-VEv;KJJwLGS`?C6;7n`Ts7$Slrxvfm=K>p81C28%S^)L>@Y z2A05kMEOg|C0#Oy4~Hx;49l7?VS-G(5CAMvs6Ws1njkgKdF5x`c_rmh*0gk~%7a|% zk~#(zV}4p&fTR83Az`&>Aw*%VGy7p8rp1lXiNO?EGGv>2i(nIJ8<4OVwpKjWoxS28TOi zE+2eAe<2YY;T6{DoMpunt52E zQ{mXz;#1$Tdj@V@B_toLBMUin1kCmwx5(548AyzCR1jPAFcAfbntv&3CKC|kw8bOZ zseMjSZ(KDtZM=Wo`|%(Z()I2B^oq>CfF&45o_b<){pebcMs%hldZ9MS3mqs1S1%2W z^ck)27D>;uK+TL4(2YVNA*63OB8uWSn3bQ95#`4Oz_Zj9$$Ie2_uTc%AG{k6Qh8Ph zRDNG>7}!dJdM~^Q##8(93GU!Qamc-qS2 zN`z$NO(mazyB)2rLN*x%Sy~6X+(^bwbk?nXF>V#TPB?-7gYuGkLSEK_2;gq%K3Qs1 z5pY{qDnwJb)EtXA39v*Y=J{|-q7jJVq`E~%1Han^GHd9$C;yxR`Ii!bd@!>ax=VnN zB~5JKa-|WQ(F?T^Ug$t){uAH1901h7Q8XYVqfz&X@GFz?{OO?w-W%i`C|Sc)`ih`D zp^-}5PXlv(S?so;WFe(`v^48Vl<|yCeNi5-Gk@k%JLgX?yyPGVtnyX-w0oLsRBEC| zCbjN*G_aHF88MmlqkVnqK6WMU?Dlp_kcJAK$NGvU@dS9zT5*#r-hiG_dKxDB@-K?`FLDj(&7$mWQL>l>eBV2skOL@izB#L<19dIxEtlg4txMr2%cSY zP37{rBJJ;Dmy+*A$<)5O+H11HhTF@xcuCE29idh+`cSaRu4JHgRu*wG+}{a#d68Xs zXcJcD8DGAZk+1By@a;FK3hjf-OMznx0|m*cjN?pWhT4ui$(^`yezbY&Qar#wxmiL$ ze&(Hf87nSpQk?*&>A@mQBwM`(WZOEfJES~fh(BTvGyE6fKK{iyWw9ea+HX8d5C&8` zwVeecWs0Q2_3fUs-nrjVSX9|b0NZa;5t1Q@!|~dN(vV$&dxQeCc^DLkMS6O@3^ zNJf`u5=y>|8m3II%O9zcAz#?HpU_P?${|U`e98B@@%=H1d6p%KFj6Vf21Bltro1RK(O3X(@$QwX z3~-aD9Fi(S)G2F{KQ{Llw^+j*KG9?EQQCANPvW&M^|MNtm;s;|?_#^_WoLg`Mo5+n zt=s-36&s5*J&lRU7LIZ!jEF%9#M1Ra4EU+7#aDKQpw7m<%LO7N#ZXfKj*T62QMgfW z$9i~77t2KN8Z|EN$^VvH+t_!|)=F)-(j~C)sZV>v^YJj17nEcZHcV9{(Ci0b9IE!z zC(}V2!Uu!*!GI%xzlkXxV(&V{9${FLVj2g5LX->rFA1g1L|aI6D5w>2{adz57hmPNvMBULvz^sn&3A#`4Ktur;~4 zAvwh!CBzpbH=R)DH0{6yMI4lwiBnaWuLfu3gtmq&iGK-n2+)MyC@hKX11S@OSgnW2 zPy-0lm})DOmVdr^F&EB$bI<(w77C|ieC_rfDjZUz#`9HI_6>{-_D9Z6l`^8QHm;XC z2!8}y^EYY)^7I0VP;92or&j~>={9jOl+?+>eOd$t8r>8^nEQYa7FdGeYDA@sRotp! zv+v*u;F0tdsfRM8BH5mV1_N7j?>l!d?gc0t7rFgD6%_Ng70uq>BHGGjG*a)!=@y;n z(jAl$;#Kr!;CTZXA~y~G3T_q0d_;>FbOY{BhWSLpk2T>7pcOe98r2xZY;Oe=$^I(T z%{sniXL;71kkXong6b0Ee?#WmvW${l_yW!w=yrmlG`NE0%}@r$V=Z zE*8#;0Z(vD4TVBL=emgYvy2D7mL>^ z+lQihG4}N@9=VIs`U-y98H1mxwCL-hagEkQ6&rvM+;aETk_+g0;e`&&aw$GE(vuJX z@--PqmLvr!^`kM>8hR|{H8ZpAOd=hB{YN~w=AeIr53X>xTl<3U&liN?HB_AkgxQD| z9)@q6%7Q}7XuWTsGkWk-xVPJ@Xt{&Ym#0h2Dljkt&$WcY(Xm*bx|)X|B9{N8LE^u~ z%UTT+jihmaaj}U}AYmTtG_<8`(y^nX&E)LO5#9B(&pxS2DVA*pvB|w84puaA`g`@L z=5RJM^qKg*b7LbYc@BVS?X0YM7Cu3Ju*xpW0$kZ;5)Gk@&|`4fvR#0r0_r)^xRfcp z0Y8z};0W5DEvd`|lHmm$EadL^u-zXZlUAW9+I8tyGpI}N!FSHDvs4o47A>Ahy*9&H z+`&?MHDwD637yiY^xs=T4?Z9cKMFprKwvx6|opfI^2wCn25LgjBs1>u37yF+9_Lp?(-oFiyr3{cux9Y=7ylUgPp8gW_U=v4O?K(z1o8pE7RhIePv8lfM$*tE`p^Us055o5B}23 z98N?hjQa007C5j7w4uPaxP-{sS#4gL1zko1-~au4m(tyS9Y5_ddZfyTj3fv)%qGSW zM`g-_Q88l!IN`7#E3J=qG=lF~eD>gTXt4^iMi~R$YHKH>lF3NiL=>)}Ux*_bXr&HBkrXNj@TUQ?%f}4 z5z&`TVcfB=>H{6?s`?}ckS@d_#kmy?iT$?AB?2)LS6fBCG} zoq|WN{1!j$w(}1vD?$~M)ylr+L}Zq%2Ai|*Z0tQ=J$B^%N?1L|=*zR?k!w#NW;r1Ew)S_*`>FvVC_ zF=%8OA<@?Wj32LH7}hqtn!bd=-aB@Y)*1#{5 zX`xV-HasJaq1+G=j_)zf{Wv%_005Ic*%u^Cjl(!dD*9;bg91O3fM>Li00u}03;~MN$j)S>fJ7YoO8JX9ySVl{ zXX9QJM;UXqV^)S>1~>|LbWa4sfIo!HZL)@=32`)AC(>f&VTm4$AZ|E=CYCG5QYA`- z6(mrQ>zFbQJwikzVP`UkPYXgds*&lh5}<%(WlzLdNjE8=Qq0h0c-v=2uaUZRNz%RJ zsVc*1HncZFay{7@^MU?DL=tMP#U>Y$cN(jPAewXdH}^7H+ygOHB{UPER%6V+HVWLEL-kO(&3*tCXB%vf}_1 z1bbxRfm#iKiG|H!%w=)^!xRenB(I>GhgUiPH=o7LOJ$E?Qgv~jIsCJ-Br8zT#$$nr z$PqmVQt=HcQ&Wbp5=pXjLxlTZt1Ljp#>dbzijDqKsxp#OjK*D=Z6HC^lw5?py9f(u zwv+`*cr+K~)+e3vyI*5Xm69Wbc2rfA0s`~|StwQ7_9z%peqUS5-*+I!TkwrUaakqP zsz^#v>0Sk4h|Pe+b?ftICpH1ja0=2qpPWN(UH($+&3iPH!^x+RYKo(75#dsU1&K2y zo0XWhW*m(IDWP@oJ+Sb-f8e0tvSS%`*kD}M#OXVL*M`G0DVZt{zo%sywjarpME{Mh@e zoABsmR}ffph%{ZI%~!U&ohJRkYg zTb5mfCo0>6z2jhYMKdiCZjxIiNh!OleTa@G{*sGC9?uuO$mS{A>};PZm$L&F=#*Cl zx9puhpr_%Yg(*zH$OePB*ACSR2_5#PgQaP)WGKy!Xa9X9^lnHz@l3==~<&^XLA3D+4I8iwb-?f}HoOxtP3*CWv_EyKcK8|Nb03Ts{y6m=A ziqU8`RT4BtDgR5VpKZW4Fe%xk4(#A7@I}vh)c-wJcIiB~1VSF27Ck++kU#38*~~-C z$TG4w)`#WO6=v!VT@XG8|6oT(cOYq15*m;=pF|L-ow;HmaZMvyv8Ql+0(_+v;{-Eg zd_!D72ADD8h6lzL9P*77)DJc-wCl$)Dk>=>PA3U>>p!T-*tfPaHgypl=}TU%!w*pw zNN-v3voDgd%`ObtvgX8%3X+ zwG!=!C&nXJm-3XqY|%lf>Hc&{;3EeK(!IKr_(0%gpB~|c;DN2}UUa64&1VT-$A6kP zZi9{4=7WJNH_T@QF54@)!^XPOnI6^LfCLPi)W^e_vID^zd7y*+=!}{QD|_okl^3&| zCBAV&7~{-nyf4LBL4*_EgD&ZlD}>Pe)^8|?1q#B-nc0N8*~r4g`_LXesvG#EtX*@e z|MuK5!uztr+jsP;k&s{P8l4zuj!sq=u5XP;!H_I98g_Z1Hoyy0h%mRFq4Hqi%z$j- zATU8rnoFc4oaIQ#Stwq}$(=T2=04a{TZ`XxuZ5%Yl*R~}k@!#nooTM!?{eDx{Qo!p z5j=7!h0(8aVxlSsCt~L1JQOqZ0mE*DWnjq{wK=U27==At_BzDV8V2*i28Xs3_c$%VF<3XML%gPPMH3WiwK# zFW$V|jS=9%!ct$nb-AAxI*`CP?v-GI-J#Z_u9-L)R!gMvZKIN_oAV^SAzd2MK<6ds ze2caBMJP|ee%fQQ&9>BXhH$4C zx85qM51h?NeH=Tpd0{H*bE%5)M0{VDB{OLUn{1DRV1=`=LRVh@kxSD5;q<5=_oB=3 zwO#)0cb@+xuIAMZY6A%v`x7M z4TaJD=hz`UDU;}!_nS5@I6&ul5!9(Y>hQw!ifX`P;`_XX61-{(Xyl4jdRY5={??uq7uv=6#uak>l3Klk4oA2KG7>?o zg4LDK08*{T93~`^4+u2&M}4wtSJcPs4tYxuwKG8mUGI9|e=p!@q{@r_+JDZec&Xo102ZW)y6i0cV!of`WeUPx(Q8rC9YleCi;i7+cu83Ru7`=uSw;c z1Mhrz52bQHe%e+3ElDbl+vlNcG}NAW#BqBcFLa>#!?;(t4eErZ@(YV~znyeSMf=Sv| zM<+%jo!+n(ir8E;F@O|qHhKgeInu=WHMPP1%JE0;zxfxJ?Em>|?!MJ5onLC~yw{sa zc=(bL^2-c02pTej7H zVvW`Zo-tqI+2gv!NO)|w3UJWDp<14%v}B&pL~%&O=NdHY(A_IIaJ97Q;oT}UCU9sb z??pd(bwP9V^!jj`azQ=91zxMIwQC)i4aGNKcH$`8lRnn>(+^$WZW8Mp+0iMBj3~UJ=9*O=lR#Z7&O!mED7WfpC8gsp$!QDWkQAzS4 zD4L{7!mH?k?UxQ3P=`_HtOY&o5hX!p$80H%ZA;*kLUf<*dZxONOlH0{yxD#Q-7fF> zQZ9b&}&`J2NIro_)ET7=tV{VzeIQz!_{kd5f6? z@M0E|a0up(`Et%_KJA(lxSS;=s&Q3j3fS(@hcduuKXoK+=%Q`}7c}KbpB{~<8?M|E zAOlld8BJa$EAO0i>s(%SIm?<>d_lTw1Q%Q^?87@3ZP$KryBuCA{tCyH_`bFRg(ma? zS!!Wcy+yrmN+D{Y=X9e(MSuUbZI?zD@k*H&eHn7v|L_5v5JqK|Y z4`R+Z>yC^J z!$9r|c0w8Xzw(7HldJQRFRmNF=SoMV1Wg3e<7Q$Ni)Sh9?@yF6#Pr{peg~I%V z;}-66PDVh$3pX`^L6liK5YkC4Sny36pM2HT4Ig>Nukihqhm=^yM|IU~Q$4CxN1>J#Fn)_onDstTu_I&HNm}o( zZD?Uz%fyr_e)jS=;8Rv)Xa6MP5QD*_Qw&ihXU$+FJaz17nUMkSNhM}ulQQ%QOCn3u zE!|y`R}%oK&y}tk7r<>lddz}j@DLSN!Q1`gCuUv%Z1C#x6>4qLa1jZ-jNeedW;44j z2C>^ndy(KO6!NJ6rRNkWHrC9%x>(io*2}`lc!3ThQ3CZM%`FNA-11mmm5_yh*>nMG zXmyD`aQ<17*Hfau!B4wHZC0XqSEv-GX7F430}YdPfl2W~4eV(DROX~Q-kHF?N<+9O zCEQ5WOAVDqoQREqf=49gUs=ASF4lpt^nv3K3@1hJrP>_?D^SJ)?cUqRzfPX1bOY|K zsz`(<^RT}Q2xXLANEo~v2TCw^?(=JCMdGy%+{snAJ?i1)eF5BT_=n(!@ciav^6D^O zB|$G>A@@*7>jdvsT@rdWHDch8!Cx-rUVu!tPGjJzR5J`=BB8Q)C38qzMQ(e0?d#%p z>3Z5#AC7wuE4ir)1~Z!!HU({V)68&+ySP=5#M=hM+Rs? z1&ag27h1$-j+7E;~QgAdL;sS{3~=jfCxd?8#xYK<)L59!yLk&RcaAQ}6?%#AVk((GI0;EIQj&-N*# z-@1%8z4ludJ`EaETBZNe49ke+j^zQ)yyw8DN+31z`NrM|6?~9dg;w8JCpuIVs0}=7 zDIp0{JT>c?vd5cUhA=K>EN)1*)L%#%tL(h!9e2;LLxJ}3BlG$OfoibrIc?ITV28mo-a-X687@f^h#>x?B__XA*U2?ard(_@1 zQZ>p-Dqqi4<21z8m5ura%+W10C;|!- z3k9_PYiJi43@~2s3|43&jJ4F9f2?sQ?E*ce-WYs1W%A?_>)ECVHkKCw*Pqe>tb0Kbl}BUt zJ$17~7Up6~<)fUWOFyD!vF$E(i-;%AeT{!z61ZEIi|UBGPCnsb6ctUYJ?QREo^^iz z2Cz|_LDR~5mL(p^l^S{;c%=i|ItSmn3xFhe**xy{lpk zcR^xmLJcSPPomeX{0=|uLimXaft!G!kEhpr8|d6WesJyD z!OONJ+_;Nx=NW7MmcBS&=d!~`M;R7qcBw5qH*6P%=o z0yB}Z49u`oBR02I`O**h?Ng5ANjH^8m%RU<>C)L&J0Elxwp$~vjrO}+rN{_$r(30Yz*>@YQdF|iTc$XXSu~%m~;*yg_bxR!AVWon5H}STyJK*?q_%Mtb@{-4F8kq4Ga5A z>(GzH^s@PwHR{@^{=Nf4xdOMs7*IRKOZ5%~ylD=;;fz)2zi3sC;w5;a3GT?h~S^f^6W zpb-9mpLWmszbXWxlLbJ)ttf&}LDn^KxGM{5QyVGne&sc|Rq0zqOPNlW8lfPQ0#1#G zwUPYBuxfcx+=u?BaI}E*GD?n$m$U(y4SPq-j7%iH_-)I+`fwiKP?=NWTmMfN{|GJ~ z(LL7AkczEeqZso%vcA=t+7LirJ-2wk|7W38%tEcby$mLHp^BSOCAu%TAc&%FpiLLW z5KVGP6Jv?I0J7{8auiNU_X0r#Wbd1^W zRbE8+m^HPw+JnuPDd!==$Ec~bI6#HJ?!cp*k2@K9Jqz*TqxYV}iiqmrVX`b4a0TB2 z7vYN+Y;Jo&QmIHC2qa)>ph(=Eweu%*FCOSE63u%0e}1Tkit|7CX}21igDr~FYK#_6 z7QooZp&DE4IxGpDhVPM=DYdT91{-*#90!0GT?&iO3cobyGHY{!C=XlVYg3I@=V5Fd z9ElSc{LSw^_l6rDif1U}=660+-~2wfj5j}7Jsyo<4nfGQt*iGnduzZYXi}NtwmAdq z|AD*bX&;4f;0~7^kW13X;Fo7$Bt+~NPz)5(V)>a5&9>Arez$kf$w3zQAWm~l($@G* z8%ZjZf3-{Nx(gTYqKhm$?swl=v96N0|`V8pGC-IG|9gV`(;VfFAc<{Q|JIDdh zLT2hr2a-I+EX^v1-ej$GB8|rd2v!At2*D-swJZdBXCSY_33;}Yw8rnpN9kh-Yn^`U za@%^qHOGCEaw}=h-f08V=~Narai)51UqeH~7*%v{6o{m_Ugcq@F3|lI2 z><&QNGGPPZR-@Sq+@T&0P>k8;W07pF1!O>v3?~Mls3WBx19>>^7SP_>L2PT8OX0kq zR9BK?t(1WLoqMb8OtTcW;@i4q<7<|}(3Rp{Tdrc=0_ss2MUz^v_o>@kF1=!CjGBs3 z@3N0#P?kD%vE@ZUp8O41{6yCJsU{BQ^bNVNwtoAdqqkF7Ea|kH+M`uioW8mUO}n|q z)JND#QNwvKlzu0@376s1GzCHh0ez6B(u|SxqZAr^siZc-Jz+6e6eIMK*e%vBKkvX` z3D60d6qMZ8Cw;?brdqS9EGZc!r7T2W_wM7bm%RBgC8F6^MMH-6nEJ>dS}3uRsy7D`8;ZhOy@xU6vp*^XB- zGG-+5h%}!#aKGcEcG6E+EgHK zr5V~Ip|f?C!McGX3oi;+8bks5RQ!#pF;j>Z8iCD$VX`(q&+b~?mk#~aw z9XX!cakDlziSA3oiTL42BQyA~Yfm68btz)GKHgGU3GcXo_d+&H=xkfwA#h*_f=Q9P zBoK+F_02oTJUr5&X4I73pB~yFevw@}K-zNbbx)8+mmgzI?OyvCs#_w%24*o}c*00? zG=@+}<_#VVQ$w5MBh5}+H_K!ihGjvp0W0z4dq-5qAcq`C+An4A1Iq=(Qtqh5?N_b) z*`vNYo-L=|aoDl=+RA|?R`icEU`6l8cX`KYa3raiC#i4JeYTzk*O)5A4AIipCC)m_ z6twSOi#}AqL^I5e8HL7Yx{m|SA)1nZkl;3Gjl6lMk!vX_34EUqSUAGolB&F$%>*{8`scmGJz8K{G#M!5**f^HrS0da%eY?9Y7kk zC!iUnR|(FZNBc=j*l-J{700~mSPnZ5E&EE%Z<7&wQ;kcp=h6rE;@-BhnV~yv{w#^% zW5Aa(K}C^-eXMC46Nz$UsYA83!;MCVIqEgI7o}3<7|u*)jtCxviz1o{a@>fTh(-~g z!f(V!(OUs5$6pZT=qu8!Mm}1)0Mctni3gc50TfEMLiuB0ROOz*x(pBhKRkWA3wn+k z=8Q>f9N(FP83DX$lu>vV?QCGUl1ERQhAD!=Fu{Tji@nLcGOWyZf>{82@U;(l`YCvT z$}jNKzVgF#<;+fbUU_xJU|(#v=adN^R9*uy-pN+`4Y+T)me|$b8a}h|s`CRf1j4uu zT+Jn0#D^VbDQEIiu{E1HKQa(0za_JA>loW-*^7tp5T$vgP2zksF6)Xhm?s!3dL~^m zf7^j~AqHNZa&cE|h8(FUB7Tsql2$D*h%w&sy=n>-k)&WbDjMjzHXlSQr8fO)J|cbJ z{*8?oxp>GIpK~@fx>O1;(Dy!rQV{r{5LKgy{xggf@7PjJU5nEQa3CIASwGPZ$$1c@ z*H$z(qc??<1U1*vJ&J`+7}tgU&N{6736#R`@YAmSFPsr6oP}?i=TyIkMcr^45xU64 zcr61NrYtm0no5xyj#0>dB6-+5;)^DLWWY7jB*~iLZ{Bjr^4!t329U7eAW)HL`O?B><5iCUYD1~yaL^yFgFN>vC{6KLk3?13fN>~l({k(Ws z6pp@JdFzEzVCaES*==2sVGsx)LdEDOm~6IO|CR%n;!#Us$V*i=0z>3P-0Bj{h-pif znGJe;0Y^pOQ63EJ{FssZn4~q?_6xh+lYOX0avsLPrMNi}NUz@K+`gw;%GOOX2aLqufGKI73ugEe$8YbEE#0e7|U0 zLNnn%U4ENia`pePXTS1o{IrL%1*%s2;nFd1cZj0LBNa!ZNhp>SrsUFJvvX!8K6sJP z4<3g#Y+E%y5jYmdAuZAgeLnpbg@T9xP#Ps?d}Uj%y6oIn;0sEF^x|YN$1)<-G5oQG z1v-bU?2brQ{k;RdfA^m-A9KY{C57yvT_YkZJ$9ni0wG1e4PxucdSu;b8zYcxjrUJ;qrxB%+ znFY?RSHI*_Z^n04{-NZp_oTOe%yh$#3-F!Y+R({3sRdI{J=($oe3uuzBJW_cumaKI zMajf$|CGjIngL?^n%3yBatt>6)V=?`4od>>;%*#y#^%T*fF4peWz_bn8p9pn+)$0&3eNT{JS zONxcYRyNxOcio4ccH1*4IR2yET8>k}asSt`4fL4rF>zCHKCg5%b2G#F$jYch1yBSr zWwcd>>Y4S1J&2oy1PCGkDIB7BW!a#Jq=@K)NhGwElOr9D_!9d@+!S3xV?E!P|Id&> zSb=1j ziPwbWE|58o`|c6UP0EG}?mT5i1wyyG%1$lI@&w_qJeNw&kfB0>maZ%Akeoyt$%ih z_-S{$y(&He@nhMhf}-HczJZa!{z!cZ#HE7;qt#Is-@{>gg-#9y#6!SQazrCsNa|)mmzYoYX-n&mc*750R;7CU5}eS7&Dg_+g+|$vh`g~L-7x4T7(^|vlbYQK?p^5>Nx+6elcV|pc~5P5RjOIRY@jjL z3gsJtkh2lFbO~iB2|m0nwZSc7^DocaBK?ge6N`6_=qr^aLvyMWKS+!5fx$6PLYSBF z?8O>OA$F~Umr6IORYv87f+uvRhISLEyi}=?)-^rlOof+>RL%?{Qm*7yw2@XxI8EMM z2GuwI>N`Wkj+_wYJ7FoWGicSJs7`kHP<#;wfgt~7{kNXwg$m_PYjHA z^6qcKr!3{JMJZJ08ApV-0t1+-LwkfkRxKxT5GrU=$FNc-TnW%n04G^XF!FHxF>6Vh z;_@?~iE!632RM1CtRiaOp>oUvBWybZ{cX2XGQ| z?7rE;dT^+dNZotcMUn;Y#ODm9JM76PoQ{Vt>#*LrF-dDl19f0P$VTk-p&Nw?qGbv8 z){h$1P$#HT4`qQ3w)Nru8gzFI z*E^BLt+-q4j;qx^BeGoVH3IPwbKI;8Cy*zdthJ8h*bcYIdA=z!ft(SxS&WEn1W|4W zqXbivuPyRqCUAW>nq{PlAho-IhFzKVd-bf#mecfpfS-05o~|+^&|T74i|I0`bt3=m zF96*UUSYvgu5{qRPr}D8By+&>HR`)C0Yn(cPqJ++k`jgKnWUui3XLTwb{R35^U(Xlr=a7i#Nxp#yoa0I|X*wWR>eTCV6ac8@9w6LQ6YXqJ{SyxBw@#kK-- zG}frz!;?xG!Rg3}O^Kn1M?6Lt zn@Nm0LwGCsUC!NQao##KveVb%VoVj<^3uKsc{pBaOWK=NT5LyI(n8U{3y5G8rO)-F z>7;@xE{@=0jc@^@LPmM91G~E#_oL<{aTX>QjEbar2({xA?3Iw@&&%1#w4%JO)d=gT z_Fc7VV9ar?rmC2kdjRltTn@T>C(w?BxoM_u!IS-r+)h;brk~XsprzKSBvTj)8r)1Z zazBL+@I6IBrbCyiPC@A_NJ%GNOd8^~@jrfX^!1cR$&`$p*|{LvT>u*8_(pHe(U7pv z1_K;Rw?VIUU~CL>U6Bq8(y?NaMPcj^8prlrfMM!YdnWCoD9|>ciE1(-x%RRYEY2)w zzw__f^fC&eWRm*Mt5hWj0hb}KgS#nm7Ei^6e(^LIk-WB(2zLqY)FQ7(b;(c)%{0D3 z!8+YGlL#7}ys?mxwn*KmjO2^dm86M?jqvXtlpsMv2~5bc&6rZGgwo*vE0f6)yVpNz z2Oh9AkNkI)33o^>%XWBI@&9PF9&Mr_xcO{A)zM~03FK#Szd;@x6P6Bua!uxe4Za%+ zOO^Ccm;>pchP8X9tWBWcdf_#gP33uIw(39-fJD+)SrEOdPsnR2JEFoJi~Jk%zEo=o z%^XI%40kVTeQYb%RCcbx&JU;znMW=|PxbI{^~8E>!(?BK;by_4mocoi1~b19#X8Zg zkK*RVObO9KfGDQeq>b!U9ziK-+nj*R5|}Uz7F3Yq?i*f(eJW{djBS_^Iu!OP*(s1U z0Ji*OZ$vN}5Lmi5_v3VhfdCf%`du<;v9#atgDN%hhduT6!{|sK#Ex*s+qA_o{2DWR z`0EZF(R*;`3Ou?KfDuOYMcV|H)d2X+x=8BD7AjH*zQs{HJ8}&z_}sMJ*A7RwP7tjf zM1#LpX0`JSZ^J1Lv&w->?tbD?#F8B6(w>ccC}|XBgON6n>)>grEtwic@zlZY=#>s6 zbQ^A7B^4I|f$EsRisGeubE>nlJwLHOq7)C}F^U=Az@AHy?9)ac@~>|Mo<4#Es9 z3QEOCB@!CUBCuE(WeNk@G-YVa%NTB!*F9nL`hTPldA4A?5I>?qq`U8FOiZ?*Va#r0 zz8KTm`d~k-axENCqobn42XOBqX(Cnj(|eWG5c7C$#6`5uAl>sFB?@YkU<^zjC>75{ z29blj#gk?tvG%eIf_eQ<$R@F0XDp+jQJwwGYdLGILV>l*>PD5-BXN28WH0z2w?h#U zPHh;)xss@kbQA=x!l!lHC@95{65*09$>t)W0oVpSQlJMAV;L)EEPYnF(7_gIJYOoB z8m2b^i8Bg5&1K{|Zp@0=<0*T+?RnB1|NIj1+^phZlw46y$A&Yf8(xo7Mle{6j8O;2 z@m+^okG4}r@)Qmp-eC?C*px;vxr4_xa**c2VXlxAy_k4<)jhvEhTbT#s4c`IaOuxV zG1&-7Zir+$WM0zyd_~8!ze%rzb04^B`E_Jf%Z{_$X|wcM^E6VmtmbK~>R(awd^5!- zJC3kCuqgs~f)xvwFP0$gJ)#xJ6c&^MW|>>|Um&4NK2L;g6JkJ2;L~iT^{MNv01^$w z?vWPGJ$XVn$dZ}VJ8d%jzABX=M4ZBD9dzpGSFC~O7{cJT&dQ{laPxAd!#v1)$uo1j zzS@j@#9sCMq-Z;`0ZG!}ve>n4y&VqQQr zzjFB(uK&Ta@gSw`oS)Iv&xk^>(WGtlB_ujxP}W1laHFm95zbAgB4{Z}_ug0Cumj&M zJKR027eKngAXkQae|h!#&r=+~!B4v~d^Rb=ifKCp*V@x2@O|_7F5yIpqaERAhR-a+ z#>0?3V{Vq44lt#nWZoVH8H>*1X_DswE2BKZbcLW znkP4FU)l?9*X>TsH#MQldtWk`v16V^gxio z3)#S!OME z>l%hJbuxVKE%?BBzEzQQf%*;dOhrsohf14aF4NH7uBUYX|^W$6c4k%B|)m zLah-Pn~l#y?-^wPgM;PxIpfO2AeMOhmCIwlKMjw{+b%2O|5D}gSjq!umr)=Ko5Prr z;+Z_N3!Z95iC}vnu5=)gvvKn>t5&40W4BXx1L703r%o^N7r+PJ6r^Fr+)H>_kru#o z?lc0Oc?@zHj6JpXdTCTHo8$Crl>ws&WB~hLJ5XJT_ti>UndvUk-obMAXl<-Di8%%x zWbN1B?w&aD31JaRk~MrNp#!+Xe7tz>u4huF`k6yCoss0yftJE5O==B|!9N>%^;`?e z2dTM$*h+-ZPWS5jS`B6Gedcd&|0Eu~varOAY{V`lbs_auDM;rYr?nvAXrxs;LD~UUj3uqtVg$^Y727G6i z^oS^ludqZi4!1l6;9w9FEjZgp@@S^+eGcq4Dbz>eQvmhhh>##>8=J&Db*h3(V(z~8 z4u6=EC?h%kkU8e*mc%A}r#ezgK-)@YItDFmy31GT*aWbKJBa9-vsFd`iBtzS%x^T* zMl?5A4X5v-g5^ouj*DdL{m=NfYblan;io+k+c;cR4$R!4jZLm=MzModRv%u2_L_R9 zM05+crb3zq9*M=F+}gCcOomq~SK*cd=|rOq!VR%%?8kB^0~y&EVbvkZ&DVV1+b+0Q zcB<~Xr$OwpDX076`Bnk3f_bbiK*};P-V2Q3F^QO7Ha;}*AOL2kty|xTJAMsrpQl^S zvLIZnjp4Pk(j_U3$Mej^NXsIpUHQS9q*MJRqbbYE9B{}Qs*MH`&o8u*3uEqcAN`!C zKn`VRXzhB8+5} zkvt9V#A)Ri?~qBzU}~gCD2wSd4FR%6OHP<&4v=Zm_+&{9s5--9K^?>q3K%W$hbd5S(-`(uM?=(*Vtcpa(lWE4DN zYcq>UzMkFZ|K?{u#fMjT@O}Gwo~m!2S;>i~;p`EfC|f-AXHtHR!(=-;^yfT$;9_eO zW-7u`hk2}^y7j1b_j{7M^u{`UeZo`$l6ifS)Q3&QqfG(Dcvi+gf}60N58_2h2D%uo zd-Th`K}D=Qv_uR~O9s%x{A+LwLyhpSbUX=x*_d9!TtB%qm6!Y951nXioT!|EyB85k ztF~HUiBZ2F8Jh<501gsC5*UDElRhQVdUO+r0Q4!mkEKk9r@|7rXMiY@iMRwF960;C zlAb=QL;{DZ1op;*o`}6L(1cv4Tg~wXD{N@7?8E^wQCTFto_VB`LIuao*-k*LOGCfy zI#pBl?85%d0|MeujXa0Ts4huk{h%z7kbzfX&y4Zk`uu7ybCfcCu*(LFF)f|%$I<-F zXVtvp7nkh+`D^aJ?fI$>v<^~T(tw>h%7nW%nkr4%K$~o;hJ`1jRuuLYY1W2cqvm0% zR76n@JXJC3*6D5_eBqP!dBJb-R26PJZFdsSQ{5mw_}lmQw~2zR-*KEjA(=rjAqNt1 zh306V*w?|e10=u@U<6Wl^zDQ6l!Az|tS+}CG@KNhu4f&+-??HFFDkK#IceR0dk*jG zeyOU!$FS~{czOrA8?(Ml>TLKu@fniSFZC&g8WXfYPXr)iSN%0dd{gg|xdUm`5?zy0 zYyK%7kj0XuqL{We@Q>Y1NT*dYXT>k54@4C3wskkn~hlQtCI$T)~ zPAPX{(6{4KR9pcZ3+;hiHJkvL?hV?n(szM_Z0q6QI?3% z6K9vq1G8EuzJrn>*lIVV7pY{}#*PV7U;u!p-ObLzFEL-LfhlHxp8s>noS~9=FYcQ! z8|f4o#8@cjN9AET@!M*K%GM!?(paQ)Fp_m<9LdH~7XFpsUIrvA#$p9Q# zo_ciHqYGx+zKi~J3!b%Xn9?pA?nYSkw~r-u0iCG=x)~q3jL--l(sn+B2+kEg#Um@Ad zp(Tp-vgE1Yq3Z+8?(><%Pk{^u>w{<|`b&*OF1)i;cpt=#T?pPRuNjuck{M%Rct#xt zv{(6|hHb)e3azkK&+ZDYo;rquv+WE6$U=`Dauv?0H|Li~Cu-##)2J#CZXAD5g4pONjSpx6rtlu1-d{Dz&Uh4A(7Y%-15McfrO0 ze2V%6d4fC>@Cw3JYccBE^3Nhc7tr0w2v-ZEoRJz)wD*dx?64{*MyP^$G2Lk- zthDb?z*t{)%wXMFUWrk@)&v72phTrPF5$VkF~Y+J+?tSA$@fVd&E6rpfej`N?ES-^ zc0&ebgMW6}916muzrCT){i|Y+ZE3yP%tc#dHP#UCvvgPQL){Qk6dN*j&weyyjGf-MZ+MHvYs31%Y)tdks*>; zXNk7ivkU`b0}f_dy3m=$7A??g*5=FHoLO##7qtMP(Ng;Xy|>kGaD;x=oExNDxlDp< z)O4kmHZVvge9u}MDc&I%!DJ0XQd?6zzxmfH#~X3)d;uBy*!oWfKZ~kSaZb3w-Leea z*LBKJRd_huX3ErU$sU6)w+3WMp7=!#r8@cCU_TK*;0nSlsBmV$@CF3GIswnai~drO zq8slC`yP7To3W6xQ;&8Hr3eZ}2c3U#$_tv!*t}2afzpu+wY9kL=dyp-!X+xbkK^7I znR`-A%K7FS}S{NbI!({gSq8ABOx@LKsS4#%eDAWD$ZxT;K(I&vi-)F%$|e`8&+&O9n#%ar z-EfN$cjHq~0$xsgcal2HTU98<$Su!2@TPf`&G+!r?&@tS3pff;8d{1?JHCsy|{Tf^E`R$;m{q_^A*B7tfgx%U<(goDnXL$Y^6eUb4SB?X#T`s z{5`+Fs`(0hU#TsenqK^L46yUp{)%J^cmu@V9)L6zao?)@w8fU`PMP{5T01t-2we|a zEs|eD@k<1J{JYl?Pcuj9Cg60{nPSIVl)hh}LrNnpR+A%|B$ z-V?&v`~HWWj%O?_K%A?>A!uIAQB_B`FpdhuyVD|!yE3P0ja`^Z^tej}^E%wSP#U4} zG(3?^^F(=rn36*T4CIy}RxVb9j0p?wP70H_fII@;AyO77Lp=+?S#0*29JVWoeYzMP zSiR==C*g@I&nVFm+da+P>sW04iVl7sALLnu@%+#s|F)3M6|=9o zlF}(TW@p!>swAvZP2Vgpv!XkmtMVblo#(^@-d+Btz4O>yhwG8JVR#&!kKx%umYw51 z8@r;p7q}q{*Rtt@PDPxz^fudH#`kJm<%`NJSKojX#Sp0Cf=ltP#?>xOseIynG z0+~oYplMm5k5gPhST<3S_%utfdY=EHmBZA)lH&+>y+dV3`vfV1{Zz~jMo+H~r*ROp zPh8+NBnWzKD)wp4iktNls#Dx45>g(?!?$Bp&)_q_p9-sj0TR)|S}M2aY66$`Yymj) z*bB*{;QzwUiIgC?PLn>EIvT@*e#6x8KJNg=PC_c3r6wW0KSbaEpD4RdlmqPo4{m zU8sgIW!d zg@Uul`b<>P%JpinG(932>*CnG@$jGb;nB)^V|Tqz#X)!8H8KewIReV!^jsG8k;xh; z3jTU3ies|4m>(##N;pw3L&VgWF zQWL0?rS9fj9$fJ9?>8xr1tpGoi^_u-sB0AMjH7LHor!_an#2o#c{q=|W|PUMaWA~op;{3?>-qTDy=(aJNBnlt=@(2Tf|bVz#)N>$;!lE z6hi*dObs#`jCZQ*&Hl{xxJW7@24%b;!lC1_HZv{iBKA7zv=W!h#>c<>E0D zO-@i>n^w?GNdoT!cEhW=f>^TWayjIwul@Z&c+9dc;a&eZLvpzQ->0=N#t0JRF}YMd z00XWOjiv+zNMm#6^Is5i?V318GibxG|g(u5ySibGbO=J@OGZ+ z6DkRoB)TxGwNVGeaZ_QX9_bf;32@VajV#7}%SoZh*&>C>n)>4NEe6SMz23-at3(CzyI7OR+Zv{Ea$bt<57!fe87dlwZR@~bqg(0{m zBZpvv*zTU*Rjk7HqdOUuQwGv?;kh|{0g`MxAPr#%t`nAIc0oT7#@jsXrfyV%NfBe@qs}k>r-N{ za=^A!j=h9xC#FW}c=ZUfk!27BRCK&JEmKU2gu{~X?bm5XB0cgILFzpN%TvDYXw_Bd#-rHg6fIcx46!1Gpqjh}X>afgbDy#){x zv1`P5VnCJxV58+eHF_=jS-UTuN{6sb<+r61n zyQTRgR%lL?$Dw6Vu0>8`2%)K#YwU!H!56*x+^@}gF21<(f)d@ZP4SW$w=hU{l;gOo zs}MM2lFdKi*0soPV330tvEMg9tNII_q-~M)YJ5buZAH|EwuC+N8ewuBK(=W30jx^> zTLKffc!G7HVO9}6+aWkE)KJvf#?7RFQq(fySYe$)9qYSuna#Q6%y%!NJ(YFH-Id(( zJhqART&P@Es<;oEXgRB^QCm|VMB9BwK1O!cV}GDZ{8qR=xXTd^$_y8JtjxsV~W@{kg3`uq$_hCK8Vr9Ik~ z;T<^8eIhYOn!<##E+EtSy-*uz4Q+=?CS`0e?=P$+_$$<*>MWXrKk|Np|Ca`}| zzS%drUrMtPD}Q|Bx9Hv~_u;4AwSHN}B3=d^PkoU1Xg|Yq%3v6lePT~P+TZ@dFsL>M zQ^(!fpd{`vA;=u6DElKFq?SBq)VKN0U@++?qf8l99LohU)O~`5trwQ zpKN0Da|^pNdS&E}V^F$O^`mkf+cWff2l$Q50Pq|9A^3T3p@qLgbBu4PFxp-*mr|1O zoZ@*=2ul%nAJKn?okT9Cws!k_CN)W{R!s{3Yp4a-*p-CN+jpaXmmlB=C)Xzy;PIijg6Z;dr2|cR6+aeF<=znw zraM;9Zmm=)if8Q9(ZV5d3Sy9+LT7+IX^Vu4sx}*uqW3mG|8OmfRrB3O1B@BH`@4gkg(qOP|a#5P@w2P*iET zE!GTE$QDr>+9UTCa#Mt99)Yxl;jzPidC*%atulT2ev(#q9ctOcRtsp}U?h&Di-=GL z(XufBXu-qhr%=Lo$bSZIUuOIDh1Q6bP{OdTb@lGtvv|%y;d!tQxc1k-zlON z0C)>+S(4}y*!+X@XaAHEC`);^&9DS6$M+^cYp0T!G1wyqAreSE%iP2bNHES#K{tVB z(Hx8uTJWv4Me=Fu5eRxnl1LOLvxXNI=< zq$iJm6U(UV#!ox0`Ju{>Y(qEvBK##<#s>Q{&rDd;FPE_KRxfqnnh9%`)1<_TU|B}3 zq$;glh=FSJ`S#&8pe*cm@o0?383%-x90M03KfyLETj!kT+<4t<@O70kBI-w(o;1eU zp~_yMR$q{63_#FHUa7$vaHWG)ei%2eO6~W_;iejB_{_u@;vK196z3_vCUCvO5j7<@ zAlQni5#n$bf$`r)BcQL4N``bn(rNSqHFFhuSSM=0UoftFtAKw$63z4H^XmWFyt^zcP%%ywuPJN7*yYfRz3 z1i*i(Ew^QT64LCiNcJ;_PCNL0>WV`hQ$%kS5n|W{we`1eIze`9{vHqBZbLRm=#e5Q zu(H8BP^VhWjhHRe09iNG=%}!IHbvz73e!^UJcYcRrG1Av!IE4ARLdZCFfvdOIY%}x z5@nws2Ip(P_vt-%ehv>)VXSIj`~Rqt%*bw457zEOm>Fwaj%SoELuUI9^8f>-ctJkO zra2V%qhypqmRb2)tE*1ylhl|2r+uw9LWq3{-F3jn*5o*OrnU9fWSR)Wciv#Fzh3Jb z2L0C2J7*<8l-`1*F*`-RBl#2uamt-3Z7Jb2Ybo$X_xZ%a?m?6Hg-E5lL2DZ6qrp(+ zl_DD$TqrOLu4^MP93i?qw>;sZ6S}deQWol0nNOb1K4sS%vQQw+f_BWbCQF+ozS`+h zTH$J9XsOmdgyMvAsZ*!i?MP*wn^=7RSsa|mc;%xK!_Ro$ASRah?o(R(zMiPP^8fMn zEns$5)!9d_Nb!b>7Vk$vMJqA&ikB*rOdu07xlIUAFNc%NVP-P7I5Qy`tcr>nt0+{o zNJXJu8tVlRD^w7%fJ9rBU#&*47JtdDR!zO)<;VYh*Spr<`<#4FJLhpmo@bJ9zB%W7 zdwuKju6M1y_7f^J%?C9xS?EQJ8?eN{$T;@XCHQO6%C7LhP+sZ6`Mwt)n~Q+zP>>4A zx`IjcYPvQ*sM9WDt{pMtbZCiv5$e&{s1m+%urf{=$C<`MsisuAEz{soog3eK-)a+5Xtx1R6I+1(Rm85M`i?iH&Vy&CUEpQ&_2Pj(XJWo>6q}R*Y2- zZ~VgOZCrK55jS`JQmZC6r-B$9lG;)Q<0L&X47;)4g1i;eagc!8o!Cz9|I}Y0t`k>1^>H-w z%1ymKX^C<9WRU+;setxqys~++)quTjneMI*a0}k5#1R-w8<-V46^R(4O5ag-gD3oA z0l2jtnPRkT$_4vycCRglD@AaN8iA*0NVZG2RyK;oW-kK4BD|$OhDbC*eg~g^^f9Et ztNQHr+*j&$80CkvP7+r`;AfjKS(@y!GQdG=>+%^|NhXk6dA|UJ#CNTYb}kPu>gF}TO5eolzdZTYUqy!ZGdq6I~M|A@6GH!SCg%urz>?<`Sh!t)jBXPH2dVA3F$6x%D|TF5tJ zM^0)$)6{>PMgI{WWZPc1XK!&dDzU^BtdkL+pN`4QKuCT*n zo;IBZ?)e-((*1ODBHk`(?0VUgENMWZ%(vlKmhlXw)T^5Ix~H}}-+BW`RM5bx1QQn( zZ%uDO7oO5idQ3E&wSs%aw?TXDX_7C2{^8-0F%0?Dmmc<^H)AnX!Enz*7fgQ4=KJ-K z%`qo#FmYCL`PM%siZuahFU1)~D4Ym&$aAbTEnFeC@KzkBgN}6dTPIJh7QIMLM}O#ooARf2j9tECYaPYdxTKAT7Q#gmL8W9(!ybZLi`u&pkeFi@N~( zP{WHN1gWm(ICo<1Cz^agl9z*oPW#ctI|g&ViA+nRTM(n4YdW47m*Y-1~UDt&!< zYia_$Lb8XF66>SC1OTva3v;|3kX|D4n{5L8}Y2u`76m*0t*xwuvo=Z z{R^o;!JKv!oj{->}GxXvK$%8f*uIJI- zZknlKyBel;@WOj;IT5#Bt2pg!&r>BW_8zPN3?IQPP;OH^2P}118_Qvv{aOP%6?v@- z#kwAEk8+r7DM82-x{YyU%V6%5BQw%ox9Ql%pJY?$l%aX-ZIDdi_ewZYnxP;|(6J#* zyA8)^L>3_WLWqao_>^Do#!9LhIQIB_LFUdZJ=d4uq_fE_AwTBMtUKe_2)^8f=r-e> zYtk?eK%io&84ZciW)6$eA{)PYoDnFJ8eGtcyX=T6S_R_+^C+v+Z+`24JQ3epwc~lu zpDvhfy#e32K8BfC!;#}T1Ci7iYnILJDdjE??cwz(gJ`A6F_y4J>;gYu6j9pZr+Iz6 zImh=Cmc05`jP+UOa1j$(VFC~Y-(&mpI~>5I+Vf^>@5TE zNByRNEF#acUxjzUWA~C59%-Z`qNP2=V>BF<0-1@m2W8DyE9!W7|pe`|201G3nK#<*SRLIxkicP_V_DA!=&;ik86kjo4#BjPSkc7@AJ zgQbmb$XysQLjfc2%6HS@fsoIYXirb0poj3)*6*m4HaYRIw-D3aKlsk8Sq-jLOk&;h zLa7ZC)8BhYV5FpP$A_&Wjg#>)oCfNY?8*xlA3gZKTdByY0_U~KBvm~Tl&of3&`U0IN3h9Iu})_qpoLqQx<;YE5R2-BCXNVZ_3n{YBjBH<0<@_+3c`Eje6nI;|@Y?fdC zfoGgW5mgi__AHZ#m{qO-*$Z!W8h{h9QWBCOUc1!T=9juKt4r{~xks9qYhq*u)on@6 zp=qLW0O%Azh)cx=Wv2@SdyNJ0*lj2dLgQwZE;g$|wm*B^ZR zODUj=gG2W$Utj^Tt#*~;hJZ-P>_v>xHc~#A$>ad+w4F?gQXMEfu!?jz>tcL>cL|y} ziVgjJwaP>UZQH^PG5a1{I|;4m zNA2{+j(YfAC5aIdI`Sod@vEh{-CD)aggyO|5QF?Y&h!btOgesPQS0=YdGf@`$9hsk z{!p|{QN7RxDqa#?(Vxk6^%*sqK2jU*tkN2?O|1!m1YyWMv4KQf5nE-#`f1xCyAz(! z_$!-ASLL17WaB%fh0~!AJyw9YpIfPhT4RIV!NB+7on@n~ChLb+c}OwiqoSf;auOIUWjiD+KVT8Rm_==_+SDw?6FNM~U$9=ey&2-r<4>U;6dC3#0#yQD<-(t{_bn?a79 zCy_WVd4G%KAv3sQP^55d5EPslOmGIBw1Gs6-y+YW+8GAW;Cv56Sww)6ia+>~lRo_> z+-YT^@e0X?>DK&@$8lokjreep$H`mBCq*SMW9ZD^MZ@roFcu+-D^J$nQY*zBDlCeV_53yrw>kzVOHgNneM;Uhz%{%a3 zIn}ltS)C_|m!i^?>+cCBPo01y8N@^@GdJ~7c&ABdVhcSj)Wy14J@%R7jxPzz*?rcF z_8mvdVJ*3%S7XnRw1Y6ZzlpozxR$LrC>YAe9sEci+fsC74@>>%@A6WF z^!S^ke34%y@-+FZoB-3rre`=SAogk47bk)vuu!gOeei?FZJ@*!R~VU(k2RP$GQP1j zH8xv6xruRuAu@K1jrx_w5U+G0GisO!DuZkQdebmfR7-F?gz-8I%n6?#cMD2kw-Aa`W-kwM? z3njp*0b+nQ2*uc$5{gfz#r92-94!sn3b@D_axim{Pxu3D0biuv+e;0vv%48)dr{4&m(v2QjKyy-FoLEQ|FegLAMd z%TSeW6;3OrMmi+|R8}sF+>%l+s3G@!S?r3YwUm%hfNiKN6li#R@8do|NmRvnA1q3P z>u(Jqw^#>q2qVba3~roP8onvC8-sfbg#j)&FspB%viNL|J>wa$YSAW@hD?PQSEx@R zu@s^jE=(1qbb=4*8;;m>KT{f{8t5x=%WAQ6Q-Y^} zPDc&2a4&fLi#S(@p_)%0?^l;|=BCZ#$~e3|1FXfH%q!^!H;l;Nus2D$mZv}3IJOq^@za%uuxWLd-{$Jum!-kY5oC@Q- z9g7#ZoAP%7gMeM>GZmfkuy;n^Susk;oRsUWXB$q?I2bSDqzkUL_Dfg4gMzyUKb;tJ z+ky&i7T>rmf{(EsDHOG=88aK6b?f*VB8Evr1+%TF2_>^Om;{lW&twer7Hrf;I2kR$ zr5(R~&sUjMSHh)Pt)48Je9`)?nC+K}!%XDmiBR~)>s^GgtMFEH%Cwv*5B4PhG9RnK z?!E|^8BNrD5=kPB35)J0`gE$4%3Iz6#Mp)`!)3G1_jTbTVAx7)F)>5aa-qL?x91}9 zjmUKLYqY)aSGzvi`;qf-`<2AUt0ghZNr1Sfr<>T2jKn?Ak^xLz@QnU{IM}x%J==-z zv~Yvqttw}Z;udL{PQj6-S5f@4$DMlvI*^SCIVu}ap4`;|)r!5f7UkoFz5&xi16ZEr zrS=YR^zrWy)#4l8^O2`Befu7MI!)^}hl=Wq$*mJZRic{Zg)Y?V75KiW?Z{gOh@+b^ z;-U}OEJkzr(eeg`;ITr-=#}jGTX=NcFd{7$c=z<4BVL8?s%)=#{Q@qKk&CydvR-L8 z${6zTYCdjg97-Qs1vw%I&Jl-vs>ifo6{B?yJzVf4ZS+pgIq-F)aooQa7GjKJg6q_- zaON4;8%JhVA3{8C^Yd=x*2>xs@zbd#ZzzOFAOug=KZzS}(-K_(ornuvXbD>^ydWIh zm84Z7YLU*OgjlaZNCs$Jg|QSdab0zHS)k?ab#2_SfJY(NNC=NMXMXji=M3X}L1`Si z*z>elR!IBlJJ8{kdI+C@7a=yVsldUlaqLUqiep&2*qTm4qbH?T$w~Owc+2haQ1k1y zaCYL@C}Vc36X^Olb*oyqdo{1)C`CZh+>piZ_}FGV?1LvfU>AX2?GY90f8#=~|F0=k zKPm)E@jM_D6pwY#eS?R}67iGHgMYNfSaXef+9nbPkjN#iOA@FBfkVzDMdG$Zz_W?G z#dytW7k%fMxWB3`#(Q=wq*SiJmm>B-AXpNgzf~!*M&#m#C4$J{vh#MNcr|z{L}qlZ z+gK)$VG&f3X=KAs89)pWO2C%oJ&DT_bxKb?TFI3_dWoBNLt1?1N&nhUk@Z$6(nSj? zvK#TGPzAz!Xi=JCnfF{3^e9i0OK_OM*fYjv)D4|!H5B9tfODi0zpJStyRphC$cjo$ z8rIRN;j|f_YFQg>Bj5M`Z00cAm0DFoeYa#tvRVBJfa9mNHj-xz=gaOuwJ0>F8{2fP z3;)ZhqN}KLs=CXj5L|L|OX!Tbl_nA>7$KT6cxG;DXg8sFGE@>m!6h4i#Lm{}n~D!j zN3&v|BZyo8MU@as{&mY8-@oABaGRB_?>;-7$*CmN0-?w;lp!B-W0DW{Y1@@9q(k0f z1HxTopxHA+^9;lDmfH~>_-CK77%6_L=$VaMtfupea#&W{MVgRoqTsYeVr}!@IKI$L z?zYDB-@P4oReNZK$-P(VVzn9&(G&Icm=u^uFQy8thcbidazY;ccFb-Fj)g%OTD@te zDOObkeD*a)$T(4GnWK7j!xHtJgFp-VDgzlV-Z>%s3#}VcP}4Mv_92lI`+s)JeJGKt zuI)<;i8yrWZKl0~EbMX63=j?GU(9x)82^BGF2zHP_NLN>L^zWz$%T~Y&_lMrl`LvR zDmXLhl|{GW6U)uo+SBG92_}O&kopxntug<92x{kfBiC=CpsHFCd~7=HXianLSQ9gq zkl>)MUfR(XUO^#8SGo`vTM>GrxxHwji{4rf)TP_Wpg;K3u!Q;mS#=-q6OP2ZlaOC< z`S?(DMd< z02NWJ#Bl?u#m?Gak?h0ETW;QVV1e!=v}*q?Cw}k?luX6^&OINNWSEN2+o_e&-a`69 zxi#0zhlx@yGA2A&HClKc74S%|1rbPUV78OFRDJ|Gi83#PEwT@$5 zr7ra8{dl)1gs>g6b$nU#~Is;j7!G9(w^t-~gzTxfb5!o*OSn>tMTpE({4p zc+9nY{9eA9kkaBCUiEF;|6LX8eCoVu)}+-VFwl55A9_I2ieF`FOW# zVrBEC`DMamrW%?s=Z?!93pJ1hb!Go1k;Hfu7OS_Y%$0YBWe{N1?6!U1=_Ih@F1_MQ z|BYL#{aJdbIi)uYcV*bQxEGMtbOPC0ka z|LrlJuwn|^o~sJyG+(E3hI9HLB)1kJgg5QnL`+16b)ej74vX&QR1MS!iz%|KdeCGm zGtfrS&n1;qD|>G_HoxwFm5LPGHHFl;RmG#*{*k->;}N*y%IfncC8h<6Zmd2JM5BUD z7`KcULW)@nmX;}0=dF%Zq42nZ+syz%ZNyPLV|((Pq1@)J&zL zoEY*N9{hiwvhjw$!QFSVWq!^9_n)qw9!~A9WSzks(GlVx9&DNHf;M^`-rHO3PcsvU zTqII?h{R_}z{MI1V851Z%>rcMW}uqv0`Ak$4}GK&4~m{vc6D@tkB+6^{rHEEeH*t^ zHMwQar?N%i+@0wrj%%G9o5_Pfts`?AtER&^xTzZnY{fTjDEpL21Gc59cue9=uo5`v zQ`wq`Q>Va{74P-;90IDjA@@KoCNg=B>&M}(~_w#ve}q?SVEU-q#|%uu;e z7d=9lJ^XMi1(gz7u>08W{e%y*>ZH;=elElVaT#^<(Mfb)l=H`#kYi(31Irk-vBTZy z!3B8p(qbA0%bVfp#!ywjBSQ%#`d2(>6gXsP&WJH`& znt8y_=Q@T+E_=$4j_;?6{1QK%KH;-c5%M?~w%nSUIrIeWN8*|dUTF>vb~TTE25(&J z&;t*+XvHmpb~?DWC~PB%MDiI^=mJDT*CMw{se%`L{VxN*vFzpR-~Jiyuc?v4>Rk2> z3%Kmh;5+5{SyZtaTZ(Tu9CJ{Us(_zGwOE^uu?)p55-NBESl(a(niq;kCsr2$+3-(h2!ui#G-e- z&z^~j#GaJdJ6ZRT4;H-+aTPepW~13OUHid?}A!M~XU8o~FV ztJ*9uIsXvM{(pJF&Skj0%G~?Q*`NlRaO~#LranlI`}D@PpyEU;G-oa&r1QuC$a@QdluZ_5=r83*%(4?i z0QP~!Y=^8+r*&P^cqo$_>HsWXhQQAK&QIQTECp7zZ@^C?A$_wj0-MDrgGjJu?_A45 zUrEk@EE3tNfEJqr^{~xb(p5e|qsu%E{C{WW5iA9i(Wv_nz~axIcR`Z^SW#h0w=J~B zusg;4u$mTuYQu{ZurQoKvJxP|GSRe3lst*J^_60w19BIQ^whCjQ%_@6amY_5&iETyl8&uc*gpU8$HGYj-RSn>WPmPQ^7Rnn zNw%>V%B@5hPuaa~Tl!h>EM*1~HPQSos33HR35SoCNyXz(z^ES~89{!^KDnUsL(>v4 zFS=d1lc`{FjcRrAo&LZN_kV?oxV%DqyCpuRCOC+0mQEdqOyl6?oVK&Xj0~>XIBR6) zoFQ8r$!M!aoG8UaI7RVNR7TE;IdY+#aOtZ~z6Kt@aOhYMj=fN?PD~~ESR9OWnjIA z&$Y9_EJkUv#XFl|k|U<6Thay(jPUiT75C`z*1>1trYfm1Kk8+{q`|EewCg}4#uY0I zXN3SrMSEl13IGQQ36NfvB~;>~A`1(V(nh zIfs^%pjo6c8Y@I~!3kfy={|HbRfY8*N|A`4*Q1ph#cQ6q-E8BW(Ikco4Ia4N?1po` z3LnbKS{uSAY$+nN*qaCo;>?R+gDq@6Gb-yu?yP{lx{^g4hozab${C-GSQ`+_FLruf zZ7`<4gkvGI)4%Z#Pkj?^zp};UN0J$l&iY}T%8d?<`Tz)lsmX0+h}OI;6e+e$&ElY# zF3L3AgVU320Ffj5B@^_f`M?Zg>zdm}-TX07z3Xwq&J=UTjVSyb<|EwVG@vSyjA1LhLdWI2=~e5nDLAx=rG`*x3j zGsXvqcr*KUCYSgpz;$Si+!p$(K~!=mcF^l0pxovi1=gqE{hg(BR#ijC{49`#kR0Jq zW=cy(p(iUfNju)yGLR1MFznig;yFIb)^fre427GM$Ak4bRBR8oqp6;$@Cq8p0Rj}8<7ykwZ~if z!Wgg29T~=UcosBbl`ZHYWOYjSt7|n=x#5H;^mJrTumk|~sRoi;es?^nZ_U*dT~+%2 zTZxX8tPlX*Qa-VWPDucuF~rxq5ZkT%M%#EIM*vGP>a@U>5#-bIAUnh^J^Yk;VO3TS z>5c7z%*>K(-K6-hj-5#iJFNWt_S5D_}X4KMK-3b=ZS!Mt1kO*+ji$1`_7dn-L{ z?eGc}yhn1Bk1`eP$8*nTQZh?*L5|ynE+qLzyjR_1Vl)tt0u1?vHj8nPQ|aNEzp%WW zsrw{RM0{@3^-anhV z$ynWB8*pQ^IolODBDHVqA^b@hu>q{XtT9N#*31Oej?hL9Em4niX0Hv7=e!Ipe#q+r(oRB?*Y=OeB68uAcly>e&d>ENG!nKA4pgA@2FTb1wO{V0O-}ZM5C& zPpZ%pKMmz!Sj2j8Sy15m$=F;lGrbWRS-5Qyhc;$o67yCX!y{*J-r5Z;x&&|6QiJ4* zWSay>`$l0aJCpxuJ3gLKiD)`i2l;~Md}+CY-{v|5o|2sjTon#aSxL#Q?)>1gyB6U- ztI9%q|5&<1PH_D!rXn3WDvE)PEkk3iY4iqRoK!dRVei~pk7e<2%Q&8#fC#(Nn;JWU zmuWMmY7yFz_aXB~{EG=W3H}wDlzy4Aw1EMU2|8xX?meN8@IKdG`|ER#!Hw5Ajjbci z*!wUEjL~cZ>a!SExu!YON-YnJW@p>$=pMrBUHIVh@Yc1gjRltR{NKoZdJ|X$qKU;j zJ$40f+hN|3VJMuHY)fd*Wp94R>`Dr*f`Z@sgzTz; zgF#r6J}TM|8N>0lxX{>W7v>_m=DlZH+h=NjjrXc_%<`}&7s`Z;bB<@6pt1ETTYbUs z3LFm{x5u&Uxs$)9iaE8GaWv;m*{%;kPwSs3^7|x|k1zVgb74(2?(^?7DL=P@+O!N^ zh!{t3HYtyA(KIPU;7yGQy*?L_{G~+F*1GF${>GOU1x8tc7QYt0SB+XBEJ!liF6v9N zc>&f*am*(xI_mTet9V#4AGIMOr%dD{05a*p`lbrpWMA(=ZRdZz{fM_>%{2}d?UdD% zvjWZMG`m+zUhl@YZt!vp@rR{dda|sXra2?+y(`Qz+|FDJLS`ZgOvOwjP)d{)$%q7+ zmh?l~CQV~Z?1Suo!3?Ku;U_-nUAuUXRUlqB4G|ZJTar0<@2`PPE%e zPATh8PCGSzMAsCdL0k=x__+tY;ARS@r^23|FTu>?e$=ZZmCy4F{WL~ru;f`(5{*PN zlh4o|@ALrdXWmXP&O9_Z;IJ8%E*v4_vXrszkTFy|G^X#Y%rfyH!F% znkqXmY-KG3QN#>_SGM~_PU9*WL?w`3aF+!ocfzh$T+Jl3s#3Z4L0BLVckD205Ip*|IlzaT?k`btUuzNc8Ms{{r6??ik5O+Db27BZ>L6NLGPTgF zP9?lF!|AFG=Km__(#+M21H#04|u2uy(94)3qr=CW{2#f$Px*MP|RDrN%i%3;=36 z$;L3X)%D=uQ5TNifkYv4a{qiXY5VH#Z*ThO%W$u?ALFMJLoLmUqZAGy2*<}^0(&Y> zQgM{VVK0g~o_4CoG4qW@nobnkBFrB7 zVratfi?3ZwJE-Cf_nxHXiqfAq>iVV!N+aHYZv|O{?9-lIqN2;xNPQ|1n#xtdE?D;> z{Dnh6%r6SK#w4Yh4{#$Z_Vy*}@u3cRIu>#`^1BzF%3jW@BLnxIDLF7w{oV)5+;o~& z{~ml;G`->>$1KbgoQ&_3eZ*^A2)2A}LAGh05^p1oZ)nLdVd6bb-80R0DLE61QF2#eTH(>KGZZvPMO-2xmaZVw?kQ)WW>@>iD>kllxDdT&_FJ@H8{Esw4r7~Q-52MmkPLz zfa{_RF)(SY8u1dEJ#i*o_;j zI(KOAIrHgCTnZn?clAZhJj?;rOWYy*=dEAKXVt8wyEKPkDQEZzDvvrW_|$Q@RXfUy zUqdlQP76LzJ&Uef_ z8uu%W8D5!-!hA&v!&2jF+dr%}0eORI_j|rg$J-9gf|NO>Lu|QEiG??bK`o;u3?Lea z+CI)=Zi;50PLueoj1jxFc^-`>MyDwfrn}~`a$6e5UwbyS{G30>?c+aY2A%%+by6&v zSr{&SiP{QDa#xyU?MQY!a)JE{${zJBGVIm2hy-#gX@gOCfwi4T^ z0eaL%Lncd09E3$U?Rv2ip;hx@t%u+8)`{2PYinyNbmYxiD{;#_!?2qls}-|8ya70> z!%YT{Vw6-0L9m^~4x7?AORgXrK)${1U>FZ*w9SjiCxr!ve1US|oI;5Vyp^3E29~8r zGTu-tV+uo_XZD=-0*)G~sw`?S|LWCvHGXJYD^!UHf; zlOZABROCxkA1^N{1N-PhcBB9>J90e(7d&?nk0M33jq{Ss#rUmJ~I$;XHo3#kDv zBxWPhqi{Oro8lK$QrBTlNxuLY-Q65~{4qDNSF92eUy|ck4@TxA3168iqetUCNQ&@c zV{9(tQp4y7iI;Imo)7;I=N!481Nr1h!Z#Df8vf1h7nTKo47^yh427oUzMgiiA^yR& zWXeWOn7_w?%Py1Qi{5e!DVf@X@ki(5_X%~Zh^}akjJFQ0h&~CICPqe4;M$D+lW2mN zI({2AoHXZDIllRPsle;-AxmSvULr-H*b#tm&%}*fy-ywtW|Pp_=V)-X+*8N_I0SwQ zYvqY*v{y3}rrAm8MpJ}1YN!6wr*`3Xs>T!V_3?C!Nb`2kddPrO)rQ#pfrn-Uk^XdM z!6-X~>WDw)vOVF?{6eRL*PBfqMjVq>FUx{Ofht*y*_0D8{eU^S@ECO*7%Iwx;IuWO z!~0{B5dY=8mFp?Qr&Z|G`?8(=-l=B@?+Sd^D%(MeM2cixQJ;ylnA|US9!P-_j8mXa zbZ5kSL_i0dv_<#J<;T*IBG}~|1n)@475EsfAojBrr^MH-Z`W^^UT4i>Rn~X8BxTlT z$9B%siJmvVUuMT~nJ3vY0tLV(66q3>aIV;)PnmRuEMb~V(uz8w;lD*?kx;;jCSA5X z1aeA>^NaIG|C@^Q3;c9CqrWS}(K_oawDZ=rgD_?4+_JStz=bmsw2ZMdXXX0@kr7nMTQFg9e!_nQqhY;Bd6bSe_}?xck4q zdnG}4ZGDAH__&@dGbFS_4xt*nbd1Nfr1;B<%W(6onc8Xin9E&&?+V+-<^_XwOXZ1Vu2dN-ZRnHqNLKrAgne7aCrm@aV*}71OiwPlce+5*H z*j>2d=sBU00d#qx8$G5zASj=58a$9b#Qbk&NX_vV`WG@i{cUgh*%Khn+9?$>{Y18w zc|BDr#KBn1Tv;K?E3BKGXl|C{t>oL;UbrHs=xhf__WZSVMFIctfmfL@R-mszUitXQfZF1Gj~|m1$v{HQah6=snvzm} zkxZ71@K_v#exraOBHOx?s#KuSCd(c?PUUf8GN2dHyrW3mEJiNxSP&gWd4f=h>|EOkCd@9I?ty>@!^DV|e0uPz#v(>^z38%gGa(-o?!mr{0MNL6) zlMNL+Zus^Wy&OxbIy+%+F&rhN`FqoDUvN2IiSO(+zTNtKnT8QR(b$wuM4U(_2Sf8s zVWlN$RR!Q=1Yy=^RBy~ki!7Ugg>8|vQ7Z%(3tqw*lX|NizX;Wa$d-Tffx8T-R~$gM z_iIwX`(t%Ia9ZsH^r(6uu%^+*xD9~{{Pmp9Bo2|$97SZ8H=G=iZyPK1gG5tV7ck^* z!LJC*N=jhuT)QQTv3C1(C)l@SSUwZbWH4IqE_| zh$MU!EGQyljv4=Y(&n}q04?tNYu=%5RT0%;v1NMerV;LtwzPYI&3dq^7&wzWnpDNq z4~pxqlgKd%?1cX3pZ5aXd!zBX zyXehJ#3N+GNz!GXf7sOBPy5|{dnlCe;-@p)`&I@D;f9uPotka~3gOX* zd7%q;&hV;%Vyq6cx)v@2Ie&E0ca)4^BZ)^V9y}e6aG3+GL^j@d%@bZR#?@79q1)?| zHkjI@>6xdV;@C=*5y#UWI_9!G{=p`5;WYEsoO)BjYjAJ#Qgvdc&>hd)K{I1+P)RNZ zi)I<7#K6uZ>R7aEfImQ}Xb&R8l*s08liza!gBqC5P$SDs@eTvfF9 zp$v@n5FI+hoAr|?C(db(wazJ{JudKCW5};{p&mx?Pk1zuOe_VXrYIaIh^~af3#o~@ z%wb=rewqMNIT3kt%57|bc3B=Tyq4A9qJj%E%3WdV`M?7t7wD~$C~XHYH|DsR&LF8@ z^!R-?>h#4G*lAxjvn42nU^*qw=^RXINIbq#7aDlln05NUpS~ALcpcs=I+l`Cif!s( z;1`iyGyM{O8%wpF^~sOP;0Bt4QdJ>#==KL8-{QS8=lj?XrH`u|+WsE{2Q zO&}Jf3E6U^x7@s{yXutTaZesZVTaUF<=Psk73A7SuNbwNGIQ%GB9LPClZOwegqIz9 zYRU1T4j%79Ugw_r%GYs%TJ4W2wCx9_wt*vS0u@i8J2MPd+Qtj)$K&|>xog|&@SVNh zAFJ|F>0=Pt6aW$R-6bgkoAbiq*drJ`hR$QBehbM48?&f>D)Pb1VOT2yJ48vY zhYarCF*5L{xSgs2?R$TmWw4aHqHyj{+rZ^I-p8?wY#nKw)f~ZQv#wnKNAP|CMtBb< zXbDh5V|@FeX@X@jZ3e+qe`!%%%6L%L69$v4EGSLPD5?jtw!L;<9}iNQD4)K{AU{{!*&K zPzP1Ppn;Kz7C3M8ilhxe%r4LlrE4I)d94ehc`e?)esTsDApbyr2s{%*7m!9+Q&G-v zb^FSJCYbJ81t`32#Eodz)fGK7kqupG(A4=9y# zGUpz{1KHNYgd!2C{5m&{MZZHUoK*UopG(M;Lv%+ucKG%meBda`lf{Bg)$yI-tiALC zSE54*9fjkF0}+#r+_ozXgalsc!oR#19~*^KLXv1uPteV2SCf!Q#p{D=|M9aeSS(93 z7!b(VL00ec%>xm-xuXgSmFx%Z7n!F}XQ1d5dEl49#)ZONcHMU`c`4&h#c^T#d{?*x zbT)k3K&!b8XB4GAG`e8YI*mwCl`8y=R_CDIHtkn2wZ`?uX00XwYsZd!s{|n%s_wgV?pRX|y$` zAq-({f6tF|Mj0Gv0RKp83N8$`k$NGN^@juv{S=X(zyV{Z6MR=VF5#yh*%lA z6k1@63X~)PX?N0``QA&qZXwoAjB{nfG8yh*N zxe+@#&`L8jR29<$U$6&~FAh>iWYwW@)f`yTZNkPAb;Qcn0(*K#h^i=;$H zK|8pwDF?i*bPQ;v7uBVqR5()BdYIHrVmd}{WD4@os5qJ;(BL#88(fe(Xu15*xHi$* ziyC{yx{&MCiT7)r{%XqZ0Dd}A_GA74vU>%-7i_T433lqxJ6;5Xt>_2%L#|4jXbM0K zibi`AeXS;<7<@(xiiI9M+}HPYF7$yFzV`82sP%UsRd3eUZ3TThmSzHx;RDG$(QHiV zLKi;vukcPFSOAtWjB|B@5m%0!Ly@*_cwH}%S zaiei2QzT%d@Xl3+Xc<&8NR>RI&_#8KCz-;7aWe@ghss;0 z26q`wo{fYPm0#m9Aq!^ZOfK2;s!~gG#UX)RSN-iWJAm+{3JDx52{55N8MVLG%uIdt zMp7AN#yzAfjY+%Gg-(1PA1eJ0s}74)I}9Up-Xmv2 z5QXVdI)Eqk90Ez3C6yn_8HosD#ZamO-sFFV6nDS)iJ$Dja%%Uhkm8dTREn?1x0*~k z(0haoIuF~>6GV`rhGvbyDCmRIgdpSf4E3g<3l)NZtg4ty$a)d*h*&JcLrMO&e#S%3 zJ(psrC?xND%7Ti4Gj!HL%?s%1>7F7oQyw3;YBXl5qpLzG=$2W}4C-iyndS&OEIVq* zSq(vEh0%=bN84;CC#$->C%NI*Y2EYzp+V<<_^8_D6x}l_H0Y@k9TUuxK^RP>nkUP4 znS%X(mFdkFJ{3-$D<)CUk;r02C<{t|L1 zL^1J-h2Dr1gj2Iai8O%9vUd2me1MIYNAYoK7I}T>V;gV4?bjAnDB80ZLeV~nFEih( zJW&*vmYMvEs~9X0CLH6jOStIfBa$>Qr$GU<<_Kd0MEL9i<@=^z35Yt9S72pd3QJ6} z*HIL1Ks@qEk&t}+ffLY*)nPP#HX&6s^?UG^L7#Cy#@gIH!(>GNE2 z)JLpmX_&}SDRME_Qx?7GcOt2~}SDnzB9pt+@+cFyq6)sI;3i!36v>IW;PaF;r zoqqU9&%Zxy@R=1NI$;4sbPc`>AxgVCU=pc95h${7_VP9fXQrSSf;BUwzfqJlD}@eP zbA<;u@X@$#%4Lv&Gjn=Cj(KBh5f-8xhfk3WbH7?~gCViYhHw1jBof*TUcKN_o5R~n$#?Tg)gGMMm%E>ZVI6ZQn9q* z&Sm?CWw($7 ziv~eXC)}{-X?IaBkEpN@pFVeAT<$}wZ~5q(%zG6v+pw(T1=@s6O=4H^g{(!b!y5-22F1 z*4$7Vbiy=58KweIW`2s=FkvDLHb>?J6(dx+t2yD$e>-Oc_f~a`{Jwq(gv9EKCY)w{ zIZuFr2Td*Da;&)2Kx>>XbrE{F&17lO3yItHEtwd&Xx%6RY;6xcuZi|%B#?iGDlXzg zn#S#zjE!JMW|n(xjmAZ2VsnbxR4qMkt51|L-L$$$;CGzA=!e$nQ?d1O->HSr=5zmi zxFn9N2l{VwmC7sv)CaX132MZj=&;L}5g4Rk2_u?0zG+Js%xi^;68JD})95!OD_-e$ zgQHY~$t)jT7~zgTe&mxd;9Ye_p-I8W$cD^U+X)T_U686B zaQNtBpfo|r`Mv>dEG&GbIv-GFj0Xc^B{CAki=;r3KBp80SPL^e^TPL^c?U&O#oCTa zBrGuE;Bd5@;ov7UC8m90)Toi>$V6jkj;H#CAg;h0`zCBIF|7%wJFsw$@D%pO)Zf|| zf&*|~5-Tuu@*bEHaf+q3W^hq;BG!Dy0h#r1jbb~4nq@q7KStsgS*_^4Xj!*M6yiGf zJ_o+|Ox%2}%IS|Ul(@_QX+^eUk?(a3%Ukf;@;0~G!G zEgbSSn4~;bcyDkHCJS;4q;*ktfw*9F921F8z>&+b?OflYfMm$u4e-ckpLxP}D88!h zSRao%|JrsrzHp^>o20drC6Qzl<&ZsSi^fD}#|}^3#xv%8SS$Om4SGznJv>-qW1I5}EETwXwKvQtYoY{>U7V z_hj%{XC@`I&PM!uDmD|3{%x|+@$~(g6zR&4>_+GJTNwqF%N5%-Fegzr+o9s?AoZ4YR*fuzO{S zo1iAAn;{`q;70X&V;Zk_0SwN@TUVL!0}&Y|SPnOW=38rOdi>GgV;$CZj!}2*%)q0`ZYMVN_Y^O;TYP5q-<|8DYlb*MV2mD#JO-J?c_Nqk#9y z=)jud`;rh|dei~tP?cRVuhp|>p0Z*R3_Aw6*84%Nq1LceF{tG`punxCWS;jc`4FBg{py6OdxQ_}@GshXLxCKTIVeEdx!msiCXDMK40WpH^jvt}Y7Y|vU;ttr1y7Z@%pM9zoT)b}P$1LnOIygKBJ$co zgURT03Az2+w2jp%yTt!{T_^=b%P&HL!}t8|_2*zAl^Es?3oOC6;(L49!Qgl|KkX9F zAhLQC=Vq@&iMUA>01ZWt{0U_f4agT{w)8^yT<@i4?f@+`=-h^3c5MIc^S)1s99f}L zK8~6#YAZ*k(Zt!D#;!#G#t6`)XK|!0x;W!X7mhi}14;vEr|ewMO&fQNuCcNq;k*i6 zSVY=AhBvuFuxcf?jMqJE*{^!_G}X@_604dOz_+bcXt-z1JrqS{>+=q2$O6fOBHQF(b)#oPIA`Wg_KD4Ucd@n%1JY7j-STcd!4D!3`s%3Yp?0 zwN!!^5YvhWj)yNhed+8t7ExpKP$$%Ti)2U4BVB?bCCtNYU3$bGn zEhBrYKsW`fRg$Q-Vx#Q~G@N7wYYTb9S!0ltuX+1zd#-#I^`&B}#=eURkJ36Dqg_^_ z=Y^J;>KiPJa=gn>YYcV2ZYn?Y$ARI@&I={Us|OH=FW`0yFW=a&0tNvQ#(EIG1~}3v z1tw!WWR4>8&6!9eLNVIYE`t!ttfL3Qi~NM%<%3a)Ii$D$+GD@=GD`0b{B&xJ4;^RH zJ&)%)MsVL?A4@8@BjX|Ynd_y1bc7|5O6I^H1;i5glzhUOm%QYpd*eH5KgCby(*8z@ zp`}gDV<Wvt)4V-6S7rHQsE%-iWJ}_9X=H#-KaBT75S6QpHA+N0e@T*Xh zwA0pMe(6)-5z;BA`9$vHE;_jJKe^=ND`JTc&8GeLw@?;A+TKb%bS%@LSpc)qusw7T z?D=Rnrtnd`dtDkc2Sr}UbN3L1Ftt2f1+Q7 zbPcQ~B2JqR%qWV2h1J9CZ3z@5$Fb|xPk-}gaO0KTCq5jTfkxAQQDp!UA57c<1MfIz z<2E2HyV8Y*d>n5UX#!LLV39VS*{!C>y^KSFMIWgoZW4oL_yCaz0gTOx9I>Y)m`?Os zz;%EG=c#*$?6Hy3@+5z|dZmQ|m5xP=3!a@dy@s>c{j9Gvj7g|CMR?!)b9k9=_2SO# zqTDI%ahIE#yOjl@lBI*S;ax3p=+uZPJIM_?D=D;-(~CuM;xL>v{U`aB(uXo`hfsFx zxaRX;#SPXtYPHkN_~dZXEAuooI=m+vSH;IBe_zH@NrR04ppWq^u)pu-NBeePY~b9E z=N~6>hKL-U00gHgEQZwRn;;jHFd8|G*N6xPVTE5-4b@tp+S?#Pa#vpeq%Z#oW6yIc zB=>>RK?4u9rs_SI<*A?`u{*U!?pwks zPT(uoV=7vzI+430oFie~<*1Pvexk^R6rX(#SqDI|YCotbk11uwlw2|aUoJzYmr)$H zGm8>7NNfJ-tB<%8cTm}n>~q--t@yF5{gc>>--cFn0h}c+bPCRAe6 z`Jzh^03=6~v?Sl^(Ye3g%s*v)4&T6CnnNICk+(yoBCSO}Lr&2mMNtSb`V zI_|;%2P9i^y-8bPJk};WkNl6nA3QNL|z^|;plBc+4|6}swT&d8rqaXR{-v6f1 zD$Y&b_h|{u!qwyyz)kx>Uo@_9dwtI5d_}loPfBD!#P{?XZay9_+SbQlR3w3bkx2iN zKel8iOUJb)wic=|sj9YMlLIR1v^!dVR>A%?op^QXs!+I*1Q$<#_rOd3g3+pq`@2?x zdk8M~Bb(!pFy<6IjW86B(`m-17d1E}jA;e0b)j>N_bc;e@_5K#At07Q6C;*cf>3ze zutWs&w2?BPshaRZ&Q7kq=IxJU(pP&* zMZEtfN$_E~+&_!K{oEOiv7!)GD+hhbZ~~VaGb2NY{5X1~tC=J3#oGterrSOuN`Q#A zVwFm4NlAPTG!d~ZS}5qZ%(0~`#O72+EOdh=`p)WXc8Exx_f|lc<1ty7*W1EE7yt9+ z=d*vOazD>!{s3ZPHrHb<)|`;$YeGm==Uv=6rA1M|?CjJ-EXu@S%fONfAq^ z+})<{N?{WTl2;KW-e?qwHbHzZ4vCMwh5!w$jx+b*tOx~C`;}Z8Hf>C2`t|ayFx9Zj z=!wo59?%K~Lt=lh3vI^(uemRG$yXKyZ;|>Ceyv99(L@u+hE8>Ctr!IA1PhOOHQf*= zBm%%V7dYSf59_seP=(Og;rSI5F83-TDE%e_2#! za#hM2!E9yWHMA!|D8R8rh7Qt*_H%4N#v;sv8cw5H!pF5+A2CRxqXkAp925`3)oItG z9{GR1ha0Xs-+JE{7e+v2;@8^52qhlg?3{O1G+Csfr@$W|r6bMH#6VP0+fp<7@l;Qh zR?w4+$g}?st=Rt4do90&i{>$goi5nV1~ILe9!?D=HMC4Pu#)fdp-guBQIEoZFp9w!aTMCnQ5Jr+Q zABi_d+ZV_+!Pt4YRS59nnTgkO6L0N46$1Q9p*8a)K(?HwT_+Zgb3w~SA{71-i}cRj zw(;Gp^f7{ysZ42H2i>Dx<3Oq&0gJXJn4T;$iQp&OM_-8Bsyg;@-)#~BgV$={!m+XX z8O^C}vztaEh%qJ-R@J76OX>>(c6i15{pfL)V90<@3v(17)Zy0iP zVjcmfedR^3%66^OrcIb4mYQetVv2M}sua`l2uXAEH!TGvt+yw$+zt>t4gHh#!ugpr%M&*d- zqVAn6lOKg7r3VF*EjWdQ86XtO$)d4m&&eIJEEbDie9@Y1^e(mIDvW1$)*LPx^8-*_ z8$m%Z)=kafx|@w@ztY9h8Jf%tWZJpS#H+jpX44}CoI%7FUk}4UYD< z6!U~xg+T*AvZ#On&{rYl;II7HJVVPNr=we^zIQ$4R7K+ZnGQ$dvd_>5jRi^NDYPsU z`51kiGi#T+kks4pZqoxi%+wK?8_?Avr)J~iZ!rQX>gB00k&;!HwVA8Qg~a1VHeG~; zSc94UA?7VyvPmk0vUB`VpM3%Dtx|dJl=3W?P%g*!s*%*{J2HewdIHg9x9mJ*PZ!+j=0aCMV7P7?Fv7qzBq_Zvqu zU#l@PSUc?n4|~r~-ubXEee^5AAbk+;UcG5kvjqYLteTZgJwmh0s1A0i62)j%rs85s zJm^O9#?#OcPcJmy#St-v*`>`p0?ZMrbAO^Ywpha|K3L3B2&OZrnPRyb#e4$ZRxPqOk513D$UrG5iBt^Rwys2pfrNQ2n~tX zG|`}t3==_5ZpxByphfmr;u(~DiCJPWnkm5`CA!{JiSsye;(?PM66#K(yXelRU4g|^ z4p=V^u2_do?&fTL$>bOW7Ji)ZYh)X%vgD1rksqHHYZjswJb@C1&S|FWLL_Bvgn05& zUfqs{L=@qqmNIO1e#cUG|N1X?|1p>PWBham>i^2-G|x+&@TI02XhA5q4V)`0itJ%o z%e*05hN(X5fSrT+30Z8l&^hGcvD_o?`1BoYe68eYeyHU#grm!?t)Mfubrh#iHm49V zx_P1(;-fN8Y5kqlJ%vw$TU7HYX>gg(*$EtZGiYvLascb>F&=9Q+YHuBMd4s$8#jsz zL&y)qSJ}piki?e7SKr^xZ6n<8eDME0?~?c|BthNIXjVzS`sWj1OLy$~^qP{iG^WzK zk=TQt2tqjDY{b69OhzPHH5I&!<3phsM%96))y8TZj(U9Xi>g%?Tk7*kt*_CQ06FC; zMZvbfI3P2%!4sI6UBO92JGh>TJ)!n0BJ%>9FM@D`&W?nqQ+SWrM{q?HV8psS!fwZd z|L$=%V83cg=FcQSR(~MDQRqwCc{qf~INhOvb&moNcIRDbi>pArW3y*0(|u{+G0z78 z%aAJoP1{tzq>*VwAw<&-qd-|oHk6Z^hEC;%K@*mXvZ4~3y;ALhgQKf)d$s?>Pp2*Z ze1WxU6TWkRL@v99NwoyBh2|8;D5v9t0~QvZxhPMBaFA=8igfhyAAIX^r=5r|tlf#9 z&XxXJDr zRM0A@%a9p?9&jz8;|_w-@QoD%ka3qCfBUbwV&rZ3s;c9j_Wf4tWBc1WEMaUAna%cq z4QzkK;_xbxn(bY9g{$#KFsXQgg4^)~aA$4luX#&t^UEoFs;PAFj8q2pEtNHLMXk)$ z`Se#i6Z4Q7fz4#3B~{McP4W1$+P1~d!2+s4>i&Bd-e7VPNkco(;=`!3tTakTeNlUUwrXLzeb-{1yc9lPojG;E^|&H_8Tl6W2<25*I*$XbHq>v zMncowiCLWE(r4wcls_{IV)L-In;2rXh~hF#sYz#wmorLmd**GEK3Y5utWx{d^S(~1 zwaP#4f3TKH)HVQJ2zz3zn8vQ!F|?D8f~gqk2DeS(%^P_98)6v#q?1=ZQd*RX8Rq3w zg>(lg+ zqqwu#29BSZ>hAa%KG-EXy&=+zLY*U>OU#aSaC-U<2ySUtkV@bdbFo>XBO-^etfeO& z?DqYC^Sev&tyM#$_WOwz3ePghc9m+q3-4W5B%^|s zR+#UgAsmRVCEiK-mBmW+D3N$i*;$k?fP3UEJ$9rn200muA$SeR%^^t0Wyd$(`3o}e zRV_06{q%-;Rrnk5T|L;@NI=(WYcwsIugZQHY5XcX*EK6k3{Ge9wDbo4!Q3Rrgk4f_ zsG6KeRQT*bEYPu5PK;<~U@QKI=X{+7fXg{9mDZd9VTJrOM#9C^PJT$A>|7h8d zDHIBjP$-@a-%JhFR4BA_;zEN5!#BG*-Rj+VFBGb%kEWYNBI>heBwjZ1rjF?1w-mmM z(nPrfVQEeVOWr=GQ%1&GhKYY6_M1lM>hcL&j=uLP)F@^z9l&e<;}%dbr{eqi5lRvG zZ27pgGHvmUtS7&isC6g)GJ{i|^c0qI+h=zCf)BLzxQYkv1Lo(|QpmKg)4^_@2-z@L z)&@M_Gbc|=RQx7XKpJkSGyEq{tH9I(?fL}F^lU2=jPQAI6yQnC$na0^9Lr>40l{tT zU&_KlI@>?@=o_agor-xN`;S?GzCJT zfIW=S|KvhWgip4M#0nuWF^6x9L1G&$*s6a=P+!&aWQ44-6>QOEM;|+_tV(rO0K1DWV&a@-W6@Dk&l<}&O|AtEK-155*b0c=`xA^IFBu|!1 z2s)eB9#3i~6yG8a-*}+Kch~3M=&`TQ`jsg-xxU zaiy_QSGrjH7x1mUe!Pk412HM94k`nu*&RqLeE*4{tAzm>Qt|Aw3sE`@=Td^0m|)PM zA_?ZGgS>tFU;aq9&=NT41}xupB5milKkyD7h*yblj$3Hcx(Z+1N03rl5%ns20#@VVv%gl?v!jDU{>C;0TCiauwC`xaedhDE5zuZ#Vl)yIYuCoMj~;O@$dwlI?_~%JmN+v$C{9MP%(ULqjxqp}vT@})`11R{ z=Fcgkd+^g~r_YjdvCVfq=7r(O)K5mg#?17_B0XlC?>rnR?7EAdDDT_5}h|_dTJVE9gbRz)n9zqnRgwA8>sEV zPv`2Nr`7ZNhUV04a?HfOKGYXiLL79NVe742r z9N0lya(L%=#T__|On#!+qzS&)BC7lPB1KZg6(6o5#(L(WPZ$ zO$dU}DN;z`sB)lbb{Jq%5xf|4g7r#i92ikG*A^*~WFVwgZh`bSM_HGHd^8Lp#yKhw zg~)atIQ-LWH>>?W{B(+Jsmx-bL`LKiD+{9zuLzkrv#O;Nvq=VFP0&Fj#}Ms3N$8Ir zKe&mMRw;i>8e_pK7Qg-2zu0#>7yrBpeOac(v+9Cwwq~89$v01?hAg^h|<5m^$O5Se_6xJ4~4v#|!xLWIb@WRp?#&s`}h0D6XD zAD^`(Ll)6;IXell?VkPfE0$vkRZThjmrHC5=YlT77q5$%g}&DC6Odqvq$TdK+CI#V zzQnSHHZ(@AJ|Z||+jxB$KBT0^VexxD;7?@ zF2h$wlcG8tIv{HS5VB6tXyjfK+ir2mbjlsACxTvN_VXf(5=u%oqWOmV+!65oU1s7ED2BxOpe)&b}PK zWm^o@+>HXBS+(P+7U%>qe}Oz1#V*b@(Ca0gF6``APZsXHV8CXrM$Woz)DQ_0pU zQvieD)>fOd!h8IQq_EIN0fkVGe$@3Z=f0$>lg;+8FMJjDXiW?@>#Mi5qo!HC-oP0q z-E7Z#CBAXJ_n#@4MZ1B6e3KCHWKPo|2>gE{_27~)+Q4?YSs*LSG{-cvJj57e8Xh^bL`wPD=mVXzYLe#wyv zRcEV857}G)(NNmaYjDBk-~4z#mtC<7ZT|*6XfjnjC=LQ8vlxK>u1J;XKKO{SC!{$x zH^=*IE&OV{b6IQ?;>zLMEVRISjR7{cDuE9y3C9v!r$wkhS{oz+08nI$SsZesfgOWq zU^Zz~uwzGjc<%lwaxI%mQb19E0k!Ypr&Cw{LPDdiEN#xT#yF~V2E8~T zvpO!YB9DC$t;Si+k*T?!AGKVP`wM<>QA92fJ^UOgcB8X6GjT)O3u8J!<{Qg z7fni3w|T;`sxq;5WzL#ZMLwIwhS^S0Hn$o4H=$sD!iCv4**hKMax$+OCnSkA!0NieW1Q~K}tIC&@lT+K{6#F2$>$FOA| z^_f>Jof@DF{sTXqO7Kc4!BM!hFk_BCCb_J^7ho+aY(V#eoo@1pXBF=)5|x0s2%i=^ za!ZamrFg{WZaDo1KgFk4O|siRrR5!o%gfO|g7Qv%C0gGxt1N7vRNSyGA(OF7bHU@E z(z3?z?j;0c=x$~?OtYuc8CLG?d>>p->Iyc?@J9t+O`M7aN}q}vYyr?T1>`*ivE*9+ z>dmL)n`_*Z-T6d)vO8P(=4X2MHCpN$@PW%whY05rf0uwM z==lK-c%nPK3t~Q@fc<&Jg3FZ2%3`UiP)5v?1j69-H9!J|(BPnx zm1uizTgG6nUpbrU9Cxgvm>s00I(tPsc%M(Qu?Ux6{PJHu6N{-DUA_NRlAyJ7;jB%F z>dB@B{jD?wS*Y44Z= zIXyhGC7cLl0Z=j0;G^|xb5W{qNfuY)?fr=%PJ^??74Ntwh=+zORe0>Mkd&N4U9{6U zXdj=tbmZ@qwmshI1%{}Ks? zq(2M}LE+GWB4>?EOkfZVTB(Ic6UWd2CL*$NFdt`Hif>8#k*&Yv6;FZ}M2UH;HBJfASLKTSgOGQm%fE(g;n3A)B zif#q*80v8Fs>VIG^>JB+D0~jxyuzDX?~o{%EP9-wA1m>UvGj7ZRN?R)pmFejW;qa@ z@978M8Pp-PhoxwM_;50eWUK)}Mm|JQ8IMVWvV~qLud#w0{fNs;AsnBWlI5t9q+V~J zw6N?n~T&OekrH5DEj7*N_T# z?Kb0(SLKtgPmiKMDRWl_0@7p!XrmAVd=kXkg%csoO(E__(Be|S|54CJ3J6Z2S z(sN{&te-2Ep-%o+dl}ZTjB}X@Oecy;`8T;ILyEEZOwH4RY(OjC$CsGZ@2BLxK zO_-;RXb^+vtur`;8nWAR!~0f!7q?z}K!vmMDMnPBWrN735n9(HH%19HaxF&sjmSAS zO-+t(nd7dyU2l=1VH33ZtxTgAfK`&2 zEMRyui(}wk61+R8K13V&H;8-rL&_+`8UUBakh=UJco31*M*V- z`^Q$t00uc$L-{I|TPRn(90rC80J9x6Is({g501?Xh>lAFh@ zAT5tzskkJ{0y-jrV%Uw?1P4MxldP#G4u^uB2+z3e=Aubx@la@8RN`@bjo zl!?Rgty6h~MwvJa^FkMLx(45A0881mCA!{e65}nT2UgdRA(@CGwF<(e&u8X4ekK59 z+et9sCB+(#01n@g41XJ)hMZ&V<+gaAXB*T^JVd;M|FZ3Ij{E9gI{qy@P_{CLe}4fb z#~8j0xv&v3z77nK#8MEuvBMed7_=-Lei)&I>7sJ0Y*J;d)ggcwzr;f)YOB;UU;M?r z@A>5j?xV(L|IU1KzZOr@FY--*-|;OSLvbVJMB-`Jx=@}=@zFV+W;_;qwF>t`3xty~ z8k4z~nlu8MwF8>cl~9CmH?buwm)p%xK_sbeS@!AZaYVGPz2R~HvV>CN*(RM*@+my? z%1lI*;(o23oCbKo$e(XsN|=(MaS-5^th(9wrtfvu1MJC?6tArTQH^w=Z$%1`+*N6Y zWfJOs3QwjjK-jH@7|KVED31IG?4jHc^`EK7HVVxp~-Ih6cTeb3B=BZS=q7{wg z2!HUhZ=>f-7r~Ea-MQF8*MoK;Tp$yU`)bDrYtBA@3DeXXdFM`r^yxq}+Xa&3PJHxg zJEbBu45IZ(FPNFG_f9HAMr6u%K_M-Xewi#%cLjoM2H-`&2z(`-cg;o2boUOAkP40T z3bB(6+?ooG?&l8w=Fcwp2i$d~pYyRc#M=-Ux0Uc*gVxx1>ak{lltV*pjs5dq7BM+^YK zgAq`(m>33n5$*dS!Wz`Sm`Sm_c+u8iy-`O6yirHrSf3x6fM#^AWdx^b7=CP6#@@Oj^ z_`)g~ssA@x+_iR#0{SP$PT3%qpbvci3!GL!;~)>p8!&X7n*l>=+aG_Q8(xE3uiD*u z;9im%LC6xEcGO-Tc`{zbe2(U(#xVRco@sNiu?>UhhiAI+Vho@CDPL_@w!&e{&)W+H zM<7crGGiA&V0Jh__;l;@$hfsbhmt`D=tCHQZ5v7{=jc+}IgXd(3PY5`2Osma%~(#= zEdK*XNR)@+@)AsZN`oVrByC1;ABT5CYvr8w*#wTe8t;wm!D$)Nia=|m9K6ZFv?~nT z)G5@&(@F0TP(B0oj9QGj1|XNzWr2CWQFp?NJac53;SHlR_0YUP=^!MaANlc+)~=fl zUhy_8penUI@IXn6spY)(oR*T?;LW5=-ts@~F(+j)>dEo395|)}MQcT31ud_#V4Lv= zJsA9B`fLEV6owI!t#4II&7H=@W*+)JWM{=K`9IT&w@t#Rau7c$|;DeDEEg(5` zWsOX5hr~Ektc<6d;u^L|@LCt~l-)|}Isq=!h3yVX(ZfxJPNEJ&(j^^9mB(`jxm7wU zCnbo%ybc`G2p}4;X2zw37Tq}dooAduSyXJ!Kj5>39!6OV6MzA1)lY+dvy>ascml3& zimSQM`@c7;hA!QJ4_I%=6vO|#24FRLZXM@dDj(6w2Ma1Wb*fpH3;^L^5k^6RVPXi$ zJV0RkFhb#?b5CTkarB;+qff^QzRrQ*tznx0Y+hn8Fjsg}7_b$J+xCsrfAgJF?v1rn zfsg|amq9MDD6hr0_j!3U+;NFGSm6##Dw8RS58Ta_Q*uO-V85g>1;1!&6eU$NaqBXV z?)?(kI-V;(E!%OT>QE!{jNs^pU-HR53h|+brcehSS$H*sfDv@hVX)<7TPy$&#RX2C zB>_KoEqn(boOLya)fK9iO6XVZ{Fa64AI&dO0O}nWz@mLM9kUl zU{uiTn-2`2EPd)b?wD7)u%=7!=2dJ8gvZV{WyZ(vXRqrzoG`1gjT1bP5jH`us<4y>LCIPG_0I)_QcJd#Zpx)p~VI};cuFp73bCy@#8r{msX|e+KpAC-~`%YJVniu#PTq42+NDE*;j}Ty`FNVg!%H5_d%S&*6Kl<%Z9&* z)t|ZeLBIVnSN{wAbUyEAXMeD4a2xje5W!9rEhL6u>{ zZ~5lauVE`;jT^~3b>X>^%KdP;7xQDAsX322Fg3Xyn_F;{=cduQos}CX_QQDdhD^tJ zuu8}P?k?B`?v+3<5rP@#yW61{$Y{8y%Me=90TjB~7?K76Ca0QWN^rAD03JKxS}lT< z38DW^LSZ{E-T$jk;GS!btq_sV-FhG{FGH&j+I7+TKamO>3>G8U;D*BE+0Ci(IUPb6 za{61m*L*CDL)`*P1#qT(E`gIX6_pAl9y|l0sJb;6}_s7)RP~{ktGDrjwVVp z+h}J0gjd3pM#n62t$xr+K~9HN)!E>Mp!zlu(zF=yUK^As5nS{knZo6CIb>>L)<>Z=pD;P8of)%A z9HG`A2YnZFNN(qgMn26)T5lPoc&K=43DNyt;nH~SteSCqPy&b_k-9xyQw zRxol;hr|2@+m1OBFVHZX1KVoe>U#Je*-O^b54e|xh_l^>{@w_u6l&ZykxU^fMNQMY; zRhceIYSdEWwdn3cCI_$h#?$Y>UDl4T&?}$WL^OwKU_;3Iw-wNqXl@8E;}A8z+=VXD zKjz2h)pqd<$p_n`PL!v1bt5rCPKBU`xLC;4lItSQaR-Uc@n#T2xHKfh6fzP6GdVZx zU{zBea%gt=(3~3Gef6SqtSrl(+RpGdAR{yd!tugwB;GicPJI);2Ntd4 zn<9<&`wk^A&mvQj>rY7!n@UI?F$A^+{Gd`jBXIM$@!EI2kxVde#yS9u5-r0jw z(qqzxVy(Pn#w2=xaIENl2aFkr-_DUF1>nNnwUs{h|K-|W8`WH~vF*Uiv@*6`^r818 zmc_@{9H&_{aF`AONjJ4x?&jhaUEhD_X=rrS<=uKEjOEyt0SymxKFx#xrOm*?Nya|g z)2w zwG%6(;PY9?e6475Pu)t}b&ewsLMfhvOA{lbm~gcjrx2l#KXv>zwBI!6H2gMP*C+8I z!D4EB%6JqBqGKrjj+iKyZv?z8G{9%tR_p=Hgs8zK;S-%uEN5E8rxxa-5M$0ip|3Kq zhWt){=Nq@4g!`{dd3}}(gW`%NoKbxMW%{&bf(A7>Nr<_ru?aPsxt*OELL<$wK5u3t zBN2V>h}%MMk8lIE!z;9A zlWb=}R{chNXA~eZ5K_(szreDTo_x`Rq1G+>0bWDCfx<;L8`xTcMcU;?DzNx$v^u69 z1iT-FEP5>6hn)D-Q*Coz)u6Nkg9|8!8OUL+Fq$Gcl*?=a%faw41;HS6NQ8>!wav5zFVi0uo>-H7~?>;;!bN=V2|iDj+=}@jVEaSD;QkTVLAT zh$>q%JgztWU=H&pUFZT#{{ud>*OPQr^o-$Qg1WRQ9F#n`nSarqY`SFSJ&D{0J%w{k zmJ+zSz$ayB_j3}ot;W+ji*hLm3}My2{Il2dsFtdUx(ButCN?=dQC~7LJv^D_e-Mam z#>)*Hu8o(w5Y$KT&Sh|cu|^d*T`t)+kWzsogV*84X;-}zx@3;<#0=bp!I5}`(V=FjTLQ=`?) z7%e;^>m(ET#@os5P=rMxt>w4f`tG@1$t<;d#4beo_EZq7c{7m&|_tWi&#jw4LIbU3hVw zhp$!@E<5FLISki$(B87njcNqCVJT5QkIXo0U4lOxV?Coa2WemvSy%-z`agC;g*0|t z|D*>j#~oElsETHWuiTr*@ecqUFgC|Gn(1n#L|pX z?(9^NOvFNqMQaTG_dE*>FR@Y?m9R|hCKfG#W@)yY7uWze$|7cwo0U)_n9TBqoO^J< zxaIoc{~~g)Y`pN1RxT{G8T8}0k;$Ae&{2;xM{VlQZE5UV3u<=jR`l4 z(B&0R5#9k|tODL%StFcb_l9c`D19d%vl|n}R9`x*6Qf27v4rv*Yz>{?LwQt;>poCS zsyYRH!$cGN;iqOs+UT-TyU+k@h6`ON&vp3DVr#J(ysM1E5$HywJsyb2*K^({`9{QfuLV#N}AM^KNkQGLr=>p>na;8&uUykLPhr>U<4=dh4i*O`Y~T+ zl&Tt#c3?+gdRq~EQA*f^6SPwEssTw}XdnUQg)XG`X?*80-v?$DGdy-eTyn;#v8gWC zlDkV%LtU{p`6&gbyyB9AL{NkJIJ%19B{qu#Mbu}XfV@!x0%R&`2M1_~AOv^kD|dbV z2nw#Mapimoj*Tm)w9tD{U&Hfl@LU6eljk4hmBtpo(uL^WhBvQe*IFc8|DU(-0JF0! z(>@le`b$%a>w0W}A`#0<!qZ^W+SI+2i$E2Quw2SOnLwCj7lCfm)AHy$M!ocE32C zW1tBwL%cx)N(`TYj2U!?hfsW`^hLQqw*2I-!&wKcEi6GiZ&QJ=QC>R1pd<58_~{!? z#25$9q!kQW0=87HRnU@~@$#iIrO5PEIT;3FtI0E-u|EM@$l1%1^>PXSsh&u)QhDl> zC+x`TZ&^C0SU`ZK7u?h$#UbM7;^!bSPPOP4lCOdPlbptXBTZvLvU14S7&ug%9~n9Gj~p1OSnc6LW08{00T2C0xyJoJf4IpEq8H}*KwKPY{665 zHKr|e6q602B1HyEix~$XdNG2$wTdkYF3N#_S#;s&Daw**<$EquQIf0Of4hBbT$Js> z;c8W7(mk71X^NbqsSG#yrX(xuBD0p9Br13i2HIP-uQwA~8aYd7#lcA64cf7VBG`&} z3;2-q{lpD2(Pm&a7`9{U>z>Y@w6fE%?zu)KNq4xIhe)qzPT&}viDGjB*14lk&#zRl z?2qDYb#Np1@ad6D@!ErycHmei2}wE^WN4;Ki(T8=&r%E>OycURQ&UW|c6k`^e!&(h z5Rw=q$ti1QBAflH@%Mg>B0HtTA!d63Wf|+4nD`sQ3ELhqi8W*s>w3FTL15S6wQj-8 z_55Kcv|zX`@eVE&s>8B8cAAQX5Q;tC5)j(^kT&Q49Z^oN0;cQuC%2|!f zQlH>33&7KE6eh*uFM0G}NLYR9?6;?^QD)I5^u#`-zX^PEd91zvz{YdoS<1F4-Sg=g zl*fDUne*XR%zIkqVYlb_N;z{$|K{mQX@HY?tb=YCWYtuL*{(}TXd6vz$i?tlL9W}&#b52%ykw!O53ggqQ#!8b@#QH!(sYg5Q}Bx1F_deb_GW#FBQ%N zALx&K&e|8B{wT(r|6QW{Uz^dpCxMn4w{#tm6p?X5F?&qe2)n@*QF$n~x}*3zJ*+YN ztASQHU~jXf#4^|IPP%}06cQk+Nk1r|j&~2>8zm~rMYr|BmkvsQ?C)?Roz`;8jEZg) zpEwWp5bAB65BL$a$B?M*02fC>Ha0r=!=zM9Fe`SMEoI2yi9O!+seGcGX5qIyF!Zu* zU&UwF4k*!<+x3ySotXeqil58O+*G@u%~- ze=`#TDCH&qPIoi9qgjpTS#S7pqYu5&)1ObLqDkn)AKz4({FC<@8~&d0s@~HmJhoi!e&0NQKTP;dd9>DHlBY0XaOhEYJIa3XQ}% zN`3v@l9bOt(rt{$&npw_m*Sbo^r;sFv!=Cv$w(IWj3k*ZUqAKZPrgYbB=# z-gA#C6bZql==~UNb}+`oR((L2C`n*iuS#pkEAdLlR+2KQwtM@O;w`-e@Kah?M06xM zL9AjHLio&c0vPfz)Q6}NYG8{urF*s=>dG5(xQwl<2?YEmu4e( zb^IIcv7_zYp+@@z2zRtysSl4O-Y%wB5%CI%mW&0#emG4w0Y`z;Ls2Hd-FP#nrWsa} zr;7+qG$Cv8HW7n8ZIPd<4DjwNomYpDwR<5nFFgt<8b1O}ATF{kPkqbFWXPI>ES>Jz zmVYvTU)G!)AM72fpFPSQi|&I+T8!zH#*kd8;DKI_7q7OulH7~jy^;U2F`i-)5{jKb z9K)Q?$rWmi@n4={GUbE_U`u-I0wDN*cuVf~$NOj+vk!}Y*a!aby@%0g%EHrM)M$v+ zmo+yIW8J_YX6pRrX)V3H1LXM&niA%FJaI`Ij9i#EK1 znkDi)*AHNK|0@GG#OKn+KeekZX!@)^Wlnd;*FJm{VN@Bhv(r{{s$y&$ZbJLe-?Axn z1gm1;N@K#VR1gn|9m!bbcJ#q{v!QauMAw#mF2MuV+KV*qI5lB;h)?y9?+I2!e2My< zByff4VHOYnQJpQ^wUQn3J0G5W>9W@3)Hw8lly0mbV6Cz_2oko@55;U%!kX{HYc&Aq z7m|Dq-h~{N6DoF7c#8Hrw!x8BQdne@2PLgKNQxg%J;Q8~^QYH%IX&q{H0zm;oHF;c zmx=Mba9`)K^MDzY(oK-kQp3|8l0Eax?-=fF^&(k9@-RuAfZi1Q?Y**_*OL5aIgWGLZCQNJ%kQD=4lOaL!&M^= z!{rrZ!La{kW$(bqU|)n|>I5`}ml_j#se;>m6<*zy!iOlit1hHTM#sG{AU?}3!3Jbb zL(I>6Tyr&oksu-7*gJ?;n0jU`>bxDSxFk-z?(OG%5?`oP5|2%`v7)`MH9m=?k*(pb zO?1HHase45FI12MH_HLQ<2!2bb?xu0P8-)Lu_Sp&xC7w%s5GQT0gbmpgc8MsTp`nO zm?@5}2DGuEW9=~sNnHB5H@tz8U<%afC63M|0WUFxVK1%(D@ph%&S7+86;~qU`WKQ6#`}z=?12+;XY@gi|wB7X&rE>mmj7T!!^k^EnlNhf`CnQhxM@{ZZ~`nA8{Pp8ZtH-j>} z5TCc&P(Q{)Sh_j_BZ!@G>nn`9?>g8;FTJ9@ITEbZhP) zykc6jH~R;-U(MsvY9-TKJD;Gp&%XE-u$$pNG&OB;iz17N0E?euTzyLg$MOlha0zo- zPhR99g?sUPF!scw6e>%GbNqtd86ct5Y?9~2Z^n`u#B}&CDM^ve&j|#iimTGlx4I?w z${v~$$!9?CzGJ^}@Tc(oYX_BBSbavsMVF_}fDbXmq!>2>v7~!s>}U{u%=K(*5GG4< zI+_EjD`gRcVgOY+q{HgX@^}=kDfwtOn!QiE|G$XU$_jWpZRzR5ad|~MI{gW3S`*l> zzYgR|Z@UVxc{5(xB{Pru$nC4f{>3f{GkUy{T{CxsHekWAMJ6I9ZMvlyi4Ij4*T{=w zdwBdf{z6=wR_CAls->3+|NgiVT{uZ~ff+M)jiLLcz`!#roM>a@q16DRg*C)g#KHQO z+K;4#xJN|}Dd40~YEGad=dW7?ORuoHEz8>}5E*9+79zwy zyYPsA$5$?+b$8BIMIu|b5(QuPzM?_EB*WN}JA}^}tfE2J;>{M4vrf+%)o!3J08`!e4hS@N9XMPTwmd zH7|Mo`;MdT*Lq5n%GTH&A!6c&+|hltifDKUlAmhetYVxhT18}E=Nmh-s5dWw#uI@k zET{GxPO{VckpG7YPBQWGUsr=v4p?%?R6Y|T6HZ!k$t0;zAd|fHJ7!X2a|RkWY&g;2 zlm&hJ?X)3(_Dv7&y&3mZD>;jP=L=NlW=xo`7GVPD69tgwMvykcfz=4Z6YVC}r=XEr zi3^cH#6s+*vXw>}!wnu}NxGv#jd+4JrM~6PYW*L6dK5)bhME_sC|E97g-j2QoTnr< zBdk%UP>aHahK{mV0768~%Sk$j00KLQBT0q@>Sb&YgGx=bkEB^8HO+$Ic%v8SPt+9z zWU;c&z?C#i^SR8=Wfe{@-$ln0eVj~n3s2|(;N}abE)uqUZiy}00y{eRRRb-M3jG81 zl|U-v?al7Kn4oU}ctj_|Xk%=As<+aP{m=286Lw2vhaf%NEK(8g@Px++3X6D{Hz;#) z*2D<|;tYc82wXP~O^_A^+AbtFDwk!=CX+9Jv&e1n%Ue>wH4INB%SM;x`jIfb3B&GCt9dl9$t?er8?Z->ot?o`Bv44`HU z6+5|$wh61GMv~z>P_|r8Y7`!0%~3%NF>&cPzx6}!YwyIjsXeAdeU@b=M^I457R0Fy z?I<@;0?py|z)sDor1IPFQnG!B@+c0Or}Rh9Ov0#42M_2SAGM_3^@;Ux9hA+PbR?=e z?+vR%K|;^7FJOrd3f2Xe^-%5@J?vAQaH;(Ye>ye7HUYBG0Gkp=w4gma0(SGEEkOO@ z8UX`z(9-tM%c}(0y*hr=DpGIx?rHNl;*$9M={Z>_WT$0mOB z_PgZHuR-nR-c{30SxYBSpXh<8_T2Wc5lXp z27i$YLokuNg(zPn3(Y{oq(@QBwj&p3D84Q$Wvq8%?jSroki#;#Dxm#^AGsUC7jAvH$kY2LOs8wqI8LKrEy~L( z9#K`30ANy^i8BCk>)w1*v@fhX$jFpKSFL7|KIxGvAHJZA?Us@EorW)7t8pTv z)4-a41+iU>&t6FME_bCaNzy*g!_yskE-9U!t|v4}*kPL0$omR__n8y`En2dr8HKB# z!$TLwiI2VFh^JE+C0)xqH>fZU#O2i(LM?b1pon2?l!ww_%XbCx>m7JA@iK6E^uXR^ ziw7p%WX167@dTkoSTLv=4n!6v0m0XAD(ah(Lgy)!ly5}L%rixr@hYXd@UeNH)$BE^ z7f3@13ss%UF{JXC5${Xvw@~*Yz&um{&b3Dcm_qX1)rx;Ir9|ArqNTR z?2|TmCp_c$x3I~Jo&e_3yOE;`Y}?Zj-z-LXrX`Zo!!ZoJ?45ntK}^bOPb<-e5xsTh z0;`daV7=3s!#I~O4UrPeZIUZEwO6iGh{o^7ix+~vMC}9r!(+5>X^>qCi_~4IWd=@h z0#BF*0s1=PFElWE_2mFZO(3!qQ)8FVft)Gr(O$>wP(|$+2=iw83B+*kt@c^y*-I3R_+!TW|NnJdc%Th!Jd4*+e0XshX?32F1 zyF0l=4ce*(Gk{?kUgt+Uw!$Z+B)v5z!BSOgn01!jY1grp5kv8r>WN2$0=O-h+7*vidX)XUQZnJ{ z$cZ^fk>dbZ0)cAiG_wA`VqVrrXc8(7coOEB5pI&_v3^#~yKEXWQVJfQNhl3F)|jKw z+{=1Mwq15}*1Y3AB;0C0!kd-)=2c+6984szrLIM5ZXJ>J+>>ASnp5#XW$S%+Zd4;8C#&}c zRu_fIK9F;s+7PSi{b7-vjGc{F$!@N~%a{4025%`76){xp94o3sprc_N4!1OqR`yBW zx#xD;JkH!O`aT@=L|Na2?6T5a$PMNCe|qX;52lbxmbUH8wrkGCa4veP>I=|n7Yr?v zVKCWL6?`!&3C4C^)CDt#>}CV5wAP4+7s*s9!mK!nAGdq6bf314Szv#n}1k z6x#OJIzSWSC-8}@wYw-^x@7ZROop@yB&gS;lzx9<`RH2_to}231V51#dLJ(ZZa(^iNjw#o`SHAz&vni>PLHeDqP0F>ZIR(Q&mu!17dSr$B zlb@qS7C)bkjs8((#QH6H8(HZL$BRY+p__!WOCVo)xz4>|VY>wM=LKz;i)vat{I~!Be^=@nfYkS0_2sSh^N7)!@kF=+E z2#=}B=kd}7>Z+~biq3`Po!peid)HEZf(f<&IWvjTq%Iz#n{0KuI2gye)(^t3G!a z(FlkD`r|og1|d^diG;@tPfS?YB|+jJY0i%MVK{uzZ5!2d5!QdXedth%u&gcF7T^+g z%|o#pwdPSu5&LaI3F)tT{Tf8cYts?t+tn6XLxwP;#A@Z2v?_|6g}Gimy@xvItRc-T zqq&^#QHn5;%$bN+q(q+zX{xJjLxI~>OpWZgSK_q$ceD8c==?cmlG zDjbrx%NeckHNoqUF13B+>#Uds|84f`mT9eUQO;6&FHdaY!#YjH;FTX%BI@WBB)^m3#o1#GER$kIXbJ`2|;> zbGNR#h-*{J&UW2t>oRFzF#e%d{mjA13$X7IZOJYu8WnWivbEv^|IXoS>Q}snN`q8Nn(|kc0s#v z>OJ3?{Um(DTFI>Q&W|Jw+E4KERujrA@re?wphdxru`nYnu$Od1MEH$jNYqpxs1OQ* zst9sfLP4d(q}~u+nq;Cu(M35rdT#Pw(}Vx~?Gt6%yDWs+I?TiHb!Xz(wOc=`I>OoK z)ryrTalhmug7Ql>hc5VLY>U);Op)KxKyW6g46B-W;I_VG#R^V6G9q#HDAPR#EJf|2 zJ@{~XB4l#Hfjw=a(W z;w)15p;mKvTJ^tM?^Cfg@Jez4dIxAWaD}lLOi~?sl7J1cFnL;>w|)Lb&0CFFq{MS< zKsy5f_Z!^up(_?LJeO9azMwZq9kKQFXkx*gjs`QrZZ+Fak68z~G>r&-+aY?Fuf?mE z$cVozjMXRX{xx@!`QUP)ob+A3VYE&*9RVQgl(vB@<=fj<3u`S@De=-b3l&uvd@^i1e zwO6uI&Lwt=?JFuarWsvh`h8 zF}e}qcC*&2D3vRl=Ex>W>wc5MkVNct{W$FZyyG_6FZ}!x{m6Ftb+;ziXwCClv8~a) z!Q=6r0pEG0F(y~0bHhjL4Rf?6mF-n~mC>c=3L!*qQAP!+5Ai!gvaK0oDr|w#kV?8l z(TLI+`Z0bM+z5aQYcFuj3T>jaDV<0%ga_q_zBm`$^Z~Fsiw( zI1fSxdW9zwrkgY=n?}n%@gct#{ccQqgwmj$3JC;#aOG{*Ri^__iZa=TGx%Jno zXk-}?J>^lRJ3%Ws19U=Pj)>u<(FM#14VS1~N1A9=BU3oH&^GmkkMXb!AxR3(6SC4_ zZF+`ca@!2)@QH#ieay8P(Ng~=c&Rbsm!@I0xBgCrN&O2-7IMIb5;{+tB~hO&m1JlKQbwySQ!DUWa+Xo# z2{>$32W?R+HBly=%RG68X(XLZ;#J|rGbLA4m`pe3Y}wO4a_7;IRc(2Rz;0K8k@(o} zJLPYCO0I#}^<&K>@!u$%p-ZBJEE zvg1X=q{&J*^9viNU)?(bgI7{(ou78TN%c*ui)0BTNXTo24nX%=jFiHY4G-eL(6-K% zN)5pLggZIgpXRF8b^Zm9r)1dN-3c7Nmt0*Bo-s)xE~!Ujd$iXHp*=ARhm_(P_SEy* zG_3Qsc`6;k&v}H*hLN)NxtvyxQloB05e+aU!S_NIhBhiuyU6A&k=4A#)1AyPUB!%Z zaYecFk`Lc_0lrfy=kagJRn0`ccH26Y36~6}p{&#(7I@0PJIq6MO1KB zN=(6tNnVE6Skg@-k8fRjts^0|DtqiybMmTQ)p=T^Egu8BM2gWy=F?J;pwhrW7(JX@(j=T~pHn zT_!Ge&Cd^4Ae*%ci7EX8T8XT$n^BQGvbIqs7h-8(#*DElhAC7Fqx49{98YE9#ibM+ z2}@WgO2a8qPj;(2W$$^P<;;5R$t807g<2imb2r!t82ZY=5geBo39x{AxzYf9;g#t) zpjWA4U5U3nN6vU~CXsQ?$J8yGW5Fjn$Y^K2s0_a<^QQzxVv3TqIL+w)75D8r$y^9V z%Gw>u0|f5@IoN08TSi<~E~2&dKYi#LeAn7H@uyRjY-t`l6IV7zHbb`cRn76?D0x2- z7xaMS@g@#0n>u+j$}`i_r)yM7?C3dDv6I{;zI7058C2IhL7>3(q(+=6C^k6^%s>28 z?qV-H4RYsiGkmjOR&3w)?|Ktozy~V5rvwy$pv2Vhs~HQ9YbmID&uL26^kL&JbFY(L z4r(ZC2^W*ernL?JKxa6K938O9m1zr-Yd}o(xhmZE{XZ?a4fj%7Qv73*-u@cxzs(3S z4mQdVdQSU-D+y<8O&q*?wwXC4m~$Y2jn1~vW)RUCTM;%j$491Bt-k$i z70ZQqts-Pt9h;@3G06E8cIy>N#8StXc#_kTM1SapDAck@s=!r?Ften` z3!c6N-=u8tZ;(=UpXL$ae*165t2=Hne5-eQ zX5q)4ZKO{G9%@KPX=ww}UKln>VbURU-rqwILXSo8?0q%8;0Yagye^d4KmXl*AI0~p zJ#k-i*>#Yb3!~0{Td;WBXH_Q{mgmF2dTu1tM~FqftAI1@yu^d{nPID-re2=Ns-P`V z&~f6)%Bj#MMl9Kkl{qCo(GldX(warFq?q6W+B)?9M?Q}N`U?JZ+RR}|K=be>*hd7& zh0e3wXnOTRqmLJ+<4eX=Ky&bUzE3Zix%IGWw6!rA7!VZJpS=JSSP6z5%_SbZ<^vC3 zi+8J)tV7v#Y`TU0_Ka^gkopmP=F-Sq$)V=aG^#8l_-vv|EZMp+OoNHWjP%l9^0scd zQR%6(Gn7&sfsc`=%wJJTKO%;5g0v~+6kTk|NnSTT_yiaDk!bH}fxbg9 zYel7(UINGrli@foR#rt$2Z7!GZhhY88Dw~T0*qVSwBUzvKg2ah9n%n zCVq-#1)ruYF@lXL$hqI??t241zIGS>bl$QpA){x+@Mb?w%_jVG4QKTYvzz@`e#swC zN59{!_se3&JRjP{154=0lX)>(Pd_Ab6vIU71P3vxYdbXGamByDxb}clHImC8`s8qOU?6IB96VJ`!&YGL@GW$kfFt03fDXh1?DmwQ?2v zMMXzUKs~ZjfFRu88duvk$80aQ{Ruz`zD349o-b2NNM#LEi~5?8qnnSQe zCT(cKWzJEbJKk;&6_Pe|;qppjom`oYa@?gN{3_mdg&gOh|L+Y;x10EwM|QKB&xZtIJr2O}&15hyPSxW;5O-3LVM{5IhFSW_C{{V# zhhqlfNRC~-lMr_-gsXRv839#hbM*LtoDOEdcLAMy?*~`^gaRtzD0e+u1#~DbcfqY9 zA6XpbKGuYR-|@r7v`U+|Tg`x7H4DWi6@EKhAT^*v@9sxE14&g9r8+nt5w>MJ2bj$e zwsC)eQzR*8#KeU!o`*8S{A36)hqx||IY0h>O>jC(1fBl)xhf8VvaV4~&yRK-;!dEB zIbdFx_F*%*SU_C>5ye+^Bg*ZhL+`_1qhCg}uI2N)&N#UTgI#E=wnSlqy1Y1&C4#^& zX5~N)E|#@Nz4n5ya=?QwiJ!GJ#J*rk_8g$kyW#>$nd(VUeybDIUnG z+ceb~a3~%W8RGytcN2R8l1Re?lUzD3zu&F@y8J{@40%AJN)qck};|;w798W>GVSm7QB$8LiAq(KLvJN|c@yukBuGT!SF8{Kci$Qw7zB$y zEk@cE=ks{=JnfB=0R(rT(e@Gd1@(}Hm-{6C?k)tb<{D$2`Ci=DY|b16bpYCD+_pno zu`zc$DGi9r@W9NWSOZ3<1wx<8aLbGCt}mh1lyo%iIwNV#TvXJ1;qEYV3}Ln-<)aY2 zm!c14?&&SpbRn`bwZsm=)yTnZ>6|HYv?$aGQzJN=t}q@C&0;6KC4`@d_*Np5vnj(M zb+3nJLzF~9E5CZ@y=!G-lW^ci#`4gmS2P*(J5o!aBI*6yF0^z~k;$=L- z8VX)*4Uljeig09@fz>TYYCb}u zU5##hXZr^|xT_i^+39@d%(NPDifD;+x~0wpYgL2=baIhOqDFd%a;wbxv3L>P06Mne z?Gch`%7YT>#0va5L~yhjr4YP?&qdqmMEP7)d$&D%@W&KYN#SExS0<|c+hFY`*Nsn> zWPtYz9>s#QuH?17#;a_iCDRhs9^6uKaPj6Joqp(PyqQxlb37lsTf&u zJ+`kNyqU#V`LS|gU|FLk$aOpGaq23plFu(Gl+{pY>A}S*<_l!d3P&M=6(gMm>1CHs z{_`6suOH%1r=84KdF^+M^Add43OoIaS&ue_iti)_)6E)4;^1NZU#U?qrcC&&?f}r1 zg&h|A(}&$vX_AyVmukW3r04F zFD^Er@Mv%;?@a#I<#_#9zW0P@;g-sp5q2$B6`2t^GK=o=d5VBDSt2MJ0|g>(&(GLX zP*yiIq@Ch$6g+Uudf%SrsR=__-xf?Vj$J$E$kQ%g zPeGOJw%N5r1;zY`L(|0u(Btvb!HH(Gw=n=uhey}!Yiz~=bOY0>A-gAiJ>KO^tsw(m z;hVvk61zYTqUtS9Mjm^36)&QTA~Ie8F_T9S6lhUP!VHT7=+I-MEL+eF0js7eu+zl^ zY@s#xvgPQ{p7efvtx}OJ&vZw}#sB~3$XyoO@R=*QH%uKNVvB;T43sS=4-*PtCSgP5 zKp5ICC-R~Qb7-yGvNEi#9?Pu?Ej@0TSy9YIa`Ow{`ghAIl9ID+cG;fK192H_-e{m& zx}y!iMOdJ}9)+=K^#{8sF2!qC_z=XIVt78fzxpS3@1Tp1U>4KIP8L@-yg=8D_eZD%Qo>bL1b4P>~MdLPP$yi@z!VR z0Y2)3=@W3n#^$rq2_%p4d2PI;1Cnzqm43^H*;67z)NgLytt!?Ril6dZpL2Nc83aDH zl8raJ8fq6u^415KC?YAWuK~d=%PPvG6{UWe^wjExFo5a_siEf;hSM$b<0xR6e$xD(^EAt?l6iWY4wEEc1@FXlt&z~rYNwPtWrkblA=t4InkVA z&841=s0TJ*q~QK_DUX*Kl>f+A9_uTGhz)TLEL3%_Iq`UI6lOj+{d zR-GQ2ctWMbU3RrYzI~#sCN3F$+12}3lid!;ZY3VA2+TW8EV)xKqeU(AH1267szW76 z##r&oX$k)o=F{fZ(6u3igisk!TEPhm0X>ooqZ=Up;slXDFc;j3dw2g}4Bxu;ze=*M zJ{24x;{Ger8_D-Zys4`PZjJ^aK3hQv1qfq{5>mEfD-Yo!(}?gYVXKwo2^1xl3^)2e z5*~GFT)yL(e_|n}w3@PBr9tQ3-E86Pm#GQ1682;NV_MA1hD$88gEcgI(F!y)txjH# zYp=zNwUDj%uai(wG|N&Cu}hFMK2+vLnMPT&tdfegK&UWC*fW@9&^cYGp3lW`*J%@{ zY{GXc%^wDna&#jIAT^phJ_Xj-iF5)V%tPS{0{Cl^{K14zq zFGCH%2tcpqYQFAyI5^{GzRtTv#=>B;G|_nE&jgJ;F6CjC_!4bsG<8AMf4ln0GAY2K zZ)YxUyFy7Ho1nUzI4>{r+GIXWRDE`-g0L>ftCz@%<`mm~{z(Rs)aQ6u(yk78ASt40 z{Y`>+k@k@8f$00q8l<9_T>O0)SlWYUbp;pCUEjZQY!$v`*_kD~vOSq|IaA(5QFRWpb%WwGqz(^e-CPg^SaFat^31(7E@`EfA+!1{Yf`E-00%A& zstghk)-l~pr|54`2)&$zFz2F}v*o@MZ=xv53JtanQZ)s+T63U&HcmQkr3GE8DRPOe zGQ3nl94s`%Y!~BInqx z)jjoQi4iJ+ScsNL{iAaerW&uOqQL|xX2V4;6?&>>Y zgvwMh5WdS6;vKqVA0xk zq-{|BuhbkI4YAbgWElo=eeWOwj}HD4Q%kc$K@mIy@$$Hn&tkc61 zxz)1#tj*M90Jp`gte0teItZre+*^tWBq~alQ~evBiCF6SO@HgjDs5_lxhw7xIm$h34s468c@R` z=jL}m);DML_qh2QPX_Od=38e@KVFHCTqp%LYKDA&%^6eX>JHkx1RpAYPtqmXe+@Iz z8gHieL6xz|g178355L*AJ`1x{7r}k~|8+9k3~M~yyHf=#<>+RC!pIQOT_w87wYl!%9xb zZGu0pAhp-w4VP2jHCh&2C%v(`}0a#&1ZZPleU)0 zc$Yp3B^8SqhwoubPY&8h#%16bj5k3O@W`hUWd|WisnrPwiUx2e#QhE ziQ_aiA5G?SA~zPJb2Hkp>UDSS#rG?llHB!=GvIixrZA-8PF+ZvS3+PH_BVpIJyHH= zu+VfMe1-n5xLvIeX-3bP2yK+3omkNG*v@Vip_Uyo`cQ$qjb~vlo9&PL)*Z}`Yk$U{ zPV95#49JEbM)y(xJWg?Et=N(Z;!b#jRu}hJFWh?sa&f2Lq*3@4h|J21>S_id zx$m^S$Gwm@&w^Ly&0noIe;6(=07hl$W-(64#ENx~=VW#U^b#8KI$--9V$b zV5C|xI+41eTz+@|=0n@hp{H3~BER>}u>7L&N3o)N*aS&3UoVHEypjb%_7Q_uok0DWeM`>O+hk993F}^zkovyKexh(Je>2r>M8bn!pNQo?M zxhT`OMa_{xG*E$@Z;m!y6QyH;7kHKgFI3ROi}0o^37rE_dg@_$ra2+2Q_!SX^s@TA z;2P}@brfxWhjO-^n%=W6fXn|u?o1kH%oyifdeFH&RHl-(TDv}}%ET;e5toS9_sPO^ zj=gFYMowvQb7LQ*Hi&4ePBlqF!-&m!2qy+73U4$Cbf`W>y4@X<=f=`e-a&sD#9_;f zwBjGQJ&YxFK zT-k2hwa#!&cws??B9el05%+`K)Y1>9@g1>XK#yHRx`~}Mhg)%8!x8%ivnEXs9?TM* zX1(3I)7FF(vsO3$*NF>`pi-6WtKaq6nMt#6elz&>}ysAhS>5l?g`{ zih{6D-kuzU-~@d9Kz(9%as~VPC%l8DwUcO_%pN1} z7EH9S(01q&7G{-*RWcpm^T+CZ@h%xsbqo$w3sT9@EhlNE5yrp|d)O={I(o>FsA4&R z`26Ta!U>1Esn(ynn2Ojy7?y8_vQo$V7+gxK zScp?r<;54!q%MBV1#`+HR=-r1AC#PpvFl%FP%!U>U{bgj3qe&BLM~7yN};-ka9%^2 zSv3_AOrYL^o(Y{Eiq3Nw3E3wT$|?v+Jvo~Zzk;_hjdCH?X8+Tpe@g8kpzLG|zOO-hp7*C~)Czzu^siU&fu(9$6y1AFA-UaOCV33X63+Eg`%SYe_@A z(y+r4s<i!*`{^P+~qfbkFDk<<4~!SE_XUfTU6}~!2IftpMC9H`1rC7p}X$Rp8enmlFs3& z`dK&xwfOAqN~51wDi{yrA0MpYc?sYg=R;B?Dy!ra{!T(j&Ot!A)d#oqL57mMKS*8^ z!peHi)G$+4WhcgFKTy!4g_L6UdCQ;9xJQce&n+p666|JREcHR*U@|ru<`yATn5GPQ6v4=vF2exU)j8W3 zgA&t|a1~BUJ~Q!$=8&!XE~v9DT8iy7qw8<@!c8y59h4%%UnMhIjPW-_z~N2djgQ5P zaNZ2s82Hl)>O_uXS&rJWyh?nBQ9rB*Wo|)Yj4jDd>HtCMq49oWB?@DzxKH7cT@Rg~ z-4ePm7}MeBpdBbsSKfcH9j{(u z?azVjg0at2GtUL$>vvNA3YkPD&0{C27E3MiR^WQ5sBFVm3>{vdX&;np7|aJ;w~J}P z9fv>varDo>$DdB{kXa*vGunW;PF*ilP%rxEC3KyB6CP9u^8)dk z4EcpqQ=wL@N#v`)(oilCQ-V@wZ;U%LzvsK}e(LpdYQcjg_xuM{4f4_Z{nP^YMQo_k z<}YhkWpzS|?+!PB<9u32^NI{+IRB#&D-%Hx9;)I9L85rtBGlzK{PKWz;0u)P`rdV4 zawYq1F`#uHTq6>dns@e{z1<+&3FoF@Ev&6A@XdCv**Y&6re+Q8R>ndfZH#f2OyCK5 z59?-5e!EE7dTlj%FxQfUUwGpenG=^b2K`axL=>l|3a&urhyr3ElIyvGwne2%B>y7b zHcQ2&r+p+xjZMvD4`=V7g^4(*auOhg!)`B-gAAdg`?Df9Y=QqSSm z_(ER@=HA_9c-TX)e=d9LYjiQ4-sR6KL-8(n<`alqAjlFJ67QlHEZk3j)_`LetD~T! zji>C-%c7;m{;cLjO5OW94>ifr3K@lO0JjZTbJJcvqyE($o% z){!SlJ~16Aw6P1ss6YI!x7Rr2Obs_STPCgPVUr%ilt(jcxe`RH^u^^^)8+H23HVlmjE@q$e^0S#S0bS51T&carJ>g zWi>EuGLsesOH0*-TN^o`wo5~%T7n8n&L%NF&NA{Cktje$a|1(TRuagwoywB_Q7}W6_%r9O~>v-GOOG#XCt`(dK=`nN(vQ1oRX*4#KKxH@XSHS;E-arCu0O2jyw&vSB{k{Yht8BpNScYm zF?_E%cht6o;9)*sgLd#JsaEKHsmcb4NaN1b&q$b@b?BL#(MSUw(Y9&}iEtNXC6iuX=8^SFc8_T*O0|UZlvF}4NmZX0!iGlyT zWKzaGIKRP!Wa~Cl&O6sqBxLx6nfS^O#bY3Z(uMX2iSj`}q*j1>|%|~3zVWF~u z^lsaP&XKX6ap-6l&d3-=QEcOAIzOb2izB$$;7A~5U`Bbdf?+X(DUe5@7oa26gL(qN z%^g|OqUMIcMzlIVg9WL+Mj>m~092C5ALJSY8^{cQ*Pa)?0i~TtH+4I9R9JdmDfvso zIfgw?S@zZ=FTl;zjw#W%zg2zXa-BF~a}j!GvT1VeG1aOfS|HdsgKHJ!cqv{k_=pLb zGaNYHLBo{synUi|LjLYTi_~b4&)PwKxhYJ7fn1|{RP8lai*zr3?hGY$q5Qg?bCc;I6pcWZj zz^bqYQT;O{1mdYc;EuywIBTEq9|tnDlpW5u`-w9yoOk1s5wBT1gbA=Xio%5^pu%Kp z=9|I1psiE0Rj{n}_*CWKRM{D&Rg=uR+&@tt1Oi$Y0!k|3 zuLX2+WGeMuDS_ZGPWk>NOWt`eH_O#{&R*y3K3Q*8!FFo>rb-0mI={+r}pGt42e)cHWCg$p=;u~rV$(0K7 z<2Xd(;`XWG>tT*rFqR&X4k>ch9DIh$97m!R1)n+x} z^P;iVmE}8$&~;$Wk<;Hj>)U+vW&1F8KTBms)^1sI<8Xa$a}WotxVkZ+8^ezq>*U83 zbd9viLK!UbN!NIs9=DCo;4e`l6d)>`RJ-#oB$ajI7bYMehJyJr=Wjq>lrf+NERdvm zp}RkVD=Y6Rv1Z*vXd>@i)o!`?pZ@u7+(lWV@$ToS*jTr;wh`p@sO6_KM#G3B7$m7SsCC4DZA}_3<+$l$*FNz z3QHofm>yxwSD}|Pf9xyqXsI9S7WnL4ILVEO zBprKaoI${J#T)qE)F4L^E|#rNe8*98_Uch3fN8E80*A_%Pp#WHURY3tk)QS`=JwDy zP|4%6XtYE+!L5a+BbQ9M zZf)X(uJ$mVa2_oNH^TzP2QaExr6=fmxhqx%G{Mo(pcV{nI2@ss=C%6gT#i4R?AfY5 z$Fs&LFCneunCx_bGT`6Xm15N)VK}^bkim#=4TLPFVs!!dNk`T>4R-lCM?LS4`1ZBO zmKcXE6K9lgMOfK8Ff!N|c#cuRRbfIeRZxaY@oEXOg5dpj1p$zzaNmc*bGO{7Z~jSq zB4mfu3389eoqnb@x2qw)QYB!kK)cn2_P+H>m}_;4mg$Uv28;J z$g^A58e&S-ja<$gEFu#7hJ66dI|2*t%uR3L`RM0knvi}gS$E@dOK(Fh}ka`)~igxZ0Wf8DVZolI|HXwTw3CP zKQc3tMQr3dDKTX-%Ky7 z41Cff5Fb8AxtL4&VU*^Da@|og4BHOh!+V$8Eu17cDj!68AWC6ce3qJYkg+bKO9n4~ z^=Q)sjJX2$z>Boy%U)ul2gplAz8=^%t5-P>pX!Xd&4SL~fvc)G@qffSAl8^qkt8X;vY-QM zJqgl?McOD68M9=JNhnEd8N&k&ktzk6B%Qu-O2e_ZY`pRe#A{71q6MSJefvH5qGbob z?tWR)oR!TH9{$Tc(rFLc6Y)A7c-BK;Pu`3nwJIX|65b$7el6M3hCA<@6XHa<&_q~i zi!)R!xIUkemM$sUlLozvM^*M&gz8erVxg;I!6RD#g#FB$Wb_+(z;t|d?sHoM6lBSq z)Nb3zO?-tzfTpNyo%o8BJ@7-bv3_v!f_`|-;l3)8Bz@kUZ7nH~uQso0TcI-}g;5oq z7Fmg;am>@4mw}?OS%&$j0#1kCjs+sOb=A7_EpK@q7gN^G!vA#=7Pdi{j(cWQi&fU; zD0OM?ONMz|V+04-{0`HuLG%yJ(*su&HVN)5$WbH{t?H5&CF)hV5yMFZmP=kn-Cdo! zE|L8}NnP2f$X2n7DB@z=e)^w&$DQ}3iZzuibX9A-HPNi|h|6XnuSH!57aBThUIAAz zm01~drZ+2!RA5AC4+3F_a+WNpzz=wM^9VB+)Pgj*b4OGFquG<76SO=C0&w@GN+&Wy z=p%>7?KBjZOXTh?-`uzeU#@m`iDJE6B|=kMHGmUSLDkn+!tai^H#^v5hNtu7NQ}qE zv97R+rF{jj&Mi$)i-0`j5O9&&ai2Jw7=h~ugRni9X(EqoIxme(gdPB(x=>5{U)aP#O9m+})dcV5JLa$V~UzS1U3s0!#15(Gb&rBVZEfe1=RUIcz zsR3eoY9EYV?sP~hAz7i@H457Ie`cv-p&%`l?6z58=F3!lv}3lECfIi0j?YN_u;fga z-L{6Afex;D98amezTPtx)ob!9QqLKJIaRSE3T_!XQ;?P$wODw>AsY3d_f^ndBBKCj0sjrCOP= z0Nf1|5Z%adQ4zW;E!c)Xu@XR3b0Uc}ozk9W&3^c~&{aPu#a(y2q?43L@o@Wx9)A^A zdX*hWy8B`k9jV)8(6 z<6AEtemX@{a$?2qH>qftF|S68A(lCzBO-Av!~~n<=O8`t^9n)W61;TbXx&m}x^cQM zUs|w4I;`Bwxq^}TmUajS^cf8t9S{InY0Ip)07$IV3OC>cIW6~`t-zQ!zjtutvG`V{ zJ$!FYI--I=xW;b6J~X^I2B1Z$Ft9oWd!2Z#f$|KKPj82 zX{Fmx%#+HBA=Y9l;~cFm*$iSI6~NA4&k{JAK?R8l0 zwV@pyEaYVSTO%XQ#%2smSButfz-zIXBBw#6M2;^!Vy<7Z(uLAeE|-kMQB)&wS0ONT zL86oATELXDq>KF;S$#-s4ZcS54E#Sd$X3<5EVkE=zU4ex0}mqUVT|7u(N`8z*iLbRTZ&-JRoe`AJlf2~Gv|lL{w>=qO6%4iQ1Kj$%jflDI(0Iz8+|F#iWZwX zu#sUpxa}Ktl?_vI4X&Ow6>us2KVVk}d#@452F1W{%fA)EN?@h-*?1wVZ_-swMT=vd zJq)u&#t*Njq=o{TC8j>O_xeUT< z%$7YSk0>M2YGPW%@ZLE04?2@z$!rd|>_KObGs0BZSUQNT?TyE@= zLx;QFqKm|Xi#jSHPGw3g&g@Wsl=4I<5oo`NI-qXId`S%@^G@QM)dTqrpLpu+&p#dC zq3oE@-8bkBGZ*g~<+91C`aCoU#!WLaAvNL!9Eynx6>eO{&ts6jWVEi;|xmU z@9~*SxJjH_3njnvJ=+}&f!C!hO4I*JEHA>|eO|8LKggE1o+P$F@>tGfVZH>!o^7$jV) zKEZdwcGN$+kum$#Lb`II4%XM4^sQ%80%dIZ7gPdd%iSWtQsK;*)cC_p#*G4|A=fI{ z#h3AN>4SyFP9h0GZYRT#p0!E%aKxfeUAK~lkJH`@(TdDaT%4NkQ^io!vq0++ModSF zh7g^OKIev&ewbW#u~JR{pXEIRKi;$R*SMdu^Z0guBPr9|;pPyw)w39oGD0d7dIE;9 ztzIuw5aLyM?ZQ}YELxtcKa#kN)b#vCI`iyz&AiMSNtaJdGVv{%8H58E?F^s&7j$zz z$U&5(bSxPe{6p$qZf@H@+jTdS`BMJin@QQ`q7v4N7C0Q1I!=A{4%zwDo9dZXf+9)ZXE$JxW0ec(D<2kX5Hn@H8OpxdYN;8PEMV2pt#1DeFIV z%||JS7nCFgcVvPPRXH_?R3 zK+Hz|7HB7cu$!$$a`)b;X$Nc>+Jv;Ms#F79GczjZxzt1HrQDpQ3DjNI&zF6MqhPhA zCBn0fwU5B%xj1*M*mZY2eu{-|&ECcUPtKZbHTxQy$2qPuEnIBi?`wFMW#es}eT=!R ztl2{K2u=ZP2;*9UZrT!{6DN7Ov$%FjL%DRl`X0`R+u^IaOsO=}U|^H%BpO6#qP&%F_!Em4T>ml$-L#GsaaLsC47XDn^bm$95LxYho^!7Gey?Dde*pM)y z+v6?&_@mD}j4~*z(cGo>IFl;%F?_UGSRvB^EXW8OWzeGwK`ML>fff4_Ps*-$$+6*p zh11Kj1d%U!WfvBz8mgOas*IG9G*~_cAIU^aXfew%#I{{<^-Zr{^B4-Q#U)vC8n4648h27T*RQQZpP zl%XrUk`l@bi#cnj313iFMJ@n5f(!AIr7OPl3fx7ltOeV4#?G)1x8u_n+DM!&YEic< zArdBxSYR2Ml>;3+fIHAcML7B>N)V+(h9V9fWpKo=B%{JB@r|x*@=+pu4Xsk^(Fd1- zj=SIco3$UOu*&wt{8XJBZFL@?;W!+9_eMB&M;vtYy?UY1#|stkDOW46kV;C*S@O=_D;I`!kx7Z-eWA=A$`c!K}$w~=tS_y z+3t(GN(=FEm-@2YdK4R|8i^76ecyThANJC5mhJlA{Y$-Xn#;T<8&u#{Ku1#-TnPv} z5lQtLIB8z1paLHn)NFeXS3u^)}ijHx`^`H#zO&O@I1EjggAY|_wn;IcDlp31Fb!wWlu@XnBEh5asWMwjBn zs~uv44e?z{P4Z*G4xoao=l`;B$wPnyEo)@+iiC{S5f!CZi7$m8()Ptdb`lUkg_LSR zE|b}-*F8zrQ7JKDBneS@!b&X_A$?^u z0a3S|e-Q0JDHGBBI6$eGmyIo&5o?K3*<00N?HrZdMUB!tXU>Y{cB+rYwQ}v7fA;Fz zDaw*#DR=)#Mai*8G$~Mjfu@F%>|z%j76QbF|?CIWLLXPq3C=$i;qFlM6LB?n0~ zdV7*oUYf>{YLkH&8hht57BA-pMPok*nSB166VjGfvOjgt!Ky?=<6uEYoAnhNIk#3A zTmu(_^>X8Sp@Kvt>l1~~-Lj!)YXcGjfmxR^!vPh}kv=;lvS4O3Q6@5zsumX!MNe@y z-Uj=2>NFEyfrap9zqD6`(8rvr0$_e47u_jW{ootVhiJ+ceeB8hr>f`*H5+ycsNkwr zY%anpl}pI$kZ2#bCUoHnNc{@2EXo6W^Z{BaWwM-a4$ZNCZ)*&l+VD=&^1e@cl(AQS z^M~Eo=wt3*D_P^X$F_ZPxkER4R-3Wxf;KeX-hy65H0AdWwWikyU_8Nx@M0i1R`GTA z#qZgGq{Ko?Zi8yfVj6*k6HM-Z#nlElGqwfVmGxeEZ>PW1Ey{SPF3wQ)@J%m&&LK6Q<)0!A>-0GF84&n)T?#DJoNoTPFYhrE~BV$`&o}Ia2SO zt%>u82QO%@YvGiwHG}>A*_xy}E+SRci#WASE>^gIGEmBI1bHoAoNXWDPKhyZ;c9Z^ z{MyUFmR5omo7T}aUYcuA2_!XEZ=x_+i+enlK&;N3ljwlUUR)Vo4E+f}J2T`PHNG^~>m!J$02GyMoVRK?LkC5-prDy$lm%a4zmzs5~2ZWFqzs4Yy(9RnogR zM$Owe8ZNEC17x6#KK$Ibb~ay2`B5Bv{#C)TL;OSmgZA2 z*#&dgPp|3vTbk1u`_d=-l2llflsUIZhEu3sqXAR#6` zB^yNBanY8K6O5F`w5O`1*h`C+;(ioNMwpGrU44GlTBa7ilszAP1$Vq+N4jtzk*XEXr#bB{=kI`N-a}8`#d*swB z2m@ImtE3PCfi}`fbhM?hu1H%xz37DR;Jegz<4>nQdbTPOJB=5#Cz+||7PbzUd7!y@ zsCq?Y3EKgEdu>=2eJSq5r`}XK&=VjPvt$>Z86@w_NR`?G$%7a%NtBtvp&cLkkYs)qVVVJb zg6OWqIRb8F%uF}%0>{R9p@NhCC|;Xa+_i!sv{#l_rN1Ki&=X>${X;4UB2X84zTwK) zvIX!zp`>BPHUyjtIyD6-kr-l=wjWhk7uaFnU3&2q`0l0j;X)M{jd)R$sr){C&j$Xu zQI+qZs%PM&I0;CLlIL6O;1cyBYi*D@Zc1nJ6ci@Kk>rj6O?Yk;d$}hU`mMp9h{?^` z-zZV4dsp3Yo3xKSxx^Y5<<__flxa~Yqy;uK`SZ$Bc`sf%*Ukq{WhRChjo9Afrd!U8 zJ+vB6=8vrmi;OLs9nTz|YZyEg$JpYqC)9DhHI>Lv@wNVPQ%Gyhy}8(Ig<+pqEhUmP-|Etq-s6(UM~_sMNFV7}9)` zdyhcW#iT{lEl1OCVt%Xj)2|qmEif-E(T1gZt1RpbSwK zHP-933OD;1ynLb09=on$8)r(2SW1}ZrGNhoxh>wh921_!ApZsNq0p@i;AL+k<#19& z{EGk?%}=G3(BBpsLu4T?JA>Rs*tg|pgV!ygM}AU?_*Trg_~_eK6ih)qfGf5V?NV?k zNTN%sVvLBmJ%n-%HPHwzMKk!A5jkR6W1qgI2ws1kug06ERs0DyV9mqPx}Kv>4p&1DBr|G zN1aKq;Jzg7v#U*IN41neM z{ll#mVp|n3MFt6msA*(;L0hYADg^JMsFJxnkRq|E#;z2#Beq9!>*>4oPi8Dp+DM~} zj8T{Z?k({ec;NnjSxlLbmF@J^4V4LH#tsrTC8fr+WARhjG6$-@S*7*nV|Zak85u=L zO_9e15EyJ(3tX8R8)7nI5<;{Q0wm13Ts;&|d8Wbi#K<)`A?|ulrUlJ$_7G=K0ipvr{#xiuR_?<9kPOLjd`{OIn9}V1`KE`- zp7S{+N;8rx4PqNA*{vWuj>nyFS_vmhtsBR4Zk-G?-Ov23iY+nhb$j@dq(ntR;wmz7 z6%2Y66bw)+OjgDAS7z?=9;S#H73~6|vMnA2647G=vT$bT`%E4A61X0Gi-E8Vth*vD z`0|2J_23>#`D|Ok$Ms$~Te!Y*G;K&@Ha9dl$%cP)C{-+vy$dg1f;SA(OvW^!HU@Sf zI;X280C58aQwqy-t=j61?vc2uQ_rz=wmH%q4sZe$NsA*Wq-DxQ(@o`{}l->3IYbO9U^$Wl2=NGfVV03?6qo`^s{?>9=slIygY<|W@* z`_2P#JGBS!r_-NrQVFuac6MtJC8o~FY*8>?`Jc>YZ^GMl^w-AM53AGyfymPe_tAg` zmSms6jx2=rk&LKSzh;3Zuzh+e?D#kU#@J^!ya3=M=W&q zKof_#j<@@xKU))fvK=Gsk#;4L?VWhT#T?EvsUy`S1UF6zPB zfg*l*SEEX3=%?q6^{1cO3g2Rmfim@qt5KMSk2g3-{ptydcTyi&ohd=Q^1-(FEJ3D@lQ7%#9*cNmTb{?k3o ze2FE>(jXhf-Jn0#w^Mq?Wq8MYaTh`#hi2VnOV*ohg{3f%(zCL!$wYh!YXOOr_1vc{ z{@aTwtKZ^JX9#*taxaUUqbSht%k4AEYHjQX-ffVUtCVF8MT+h;LuohG`2U zLs%;Zhc`u?E3{~WKdlg_UV~3t?QqL8K1d_`uEo)*)NY~3gMLVb>x~BUxd7hzAui{l zK!h38wq2c35SSRLm#fR17wqVlLng|IEn9}TpCv$IOTMxP65M@WJjj>;gjwm?FhA-P zp8r=UVuNr_U`UHc%>O9zqy9KWn5wW{LIL97N6DSSd8@MecN29pZ8_zO2ma_}YRez- zr_&i<+F@GzM_Vq$Cn>Y%WU@LCk00m)6w%pmjxZ~9#;KMC;fB8u9}E0r9T>HC)W>+^^^z!bncg@Vy~Qw3mTs_CcCav+OS@&=MlMt^miORI%~*g2 zV?n~GIn$sfGo)_BCjtuzle&+h5ZeW{g^m+#*d$n+r=8={T<3ufOuib8<_j*E2x+#c z*X48Pf=`V$D4(7Z`D8m3dl2gCtER@YzArL;NRd$LY)%Y-syZ3#@z4q~IWSR$>H9L? zr7Nw97448zCLTQki|zrC5SubVX+{8m8$|D_t_1gXxS;8<=Wo1)`&agE=Rpt8LP#0t(OJw;m6NG??qs z!Sfz5{1JSS+Cxfo>B{`}$EP6LNg4F^Iw^AkoM|wHlf?Bx1zTf#SEfViXCMMmCfo)= z9TP-U1IFM@_leHMsFfjFM(cF6M2hdGMqa6L0qlLq>sLxlKDa~x+j9Xxucb59G<8zN5C0}25y20b|7>2R!A?@$$A zax-4N+P;;{K(doTzAkPFLd9D)g;v2-l%$XzD&e5X6BuHpA+UWmwT%#$z^$eqsFPqZ zGAc}3yrHeBfJp9f%YYVxlM7*t0~LYbr=1)HFXR&3{_x9>orAln{RDqHJ&CO(WrIae zbG#pKH`U>qDMolFJg*i`U>nCWfhuBrF!E?V4-8{S16it;|+FtUAI%Ku@b5yQWs*G~HJ8R6GtpAK}j%7;M1LE4T_S%y1$^ zf<|%%W-MgtSHr(S-KBxgBWPkVAaQFapHp6fE7fv+@ygz&uf#?k(Q)6@%%DPE``iL3FM%ZycW+R*bF zU^BA?xko3TA`%NKB`dHICq_;VLg%FoAWvZOziR`N#-B4aXJ*_`K?JqsCNd#=kwl_~ zUbp|tlm7A+d|gDAeXZf+DkFBO^}rIKD*$UTZbnt%KnP)Y#T`Cd@zT|-2pScg<@Rp= zneX$R`CW88hE!7MkiwEkO=rvyRVAK=1467dau336@;$Pm+3edEocCjVn_5{9(x>$P z$xY(^ds|2s;SI8?2Z04VfLv)z@=66Q`5a!HvJGJ$6?W5&#juR5M8y|3LWDLS+!9(7 ztwA{B8guRN=iUlUU?OCtfrZ*88Qvy_LbE6bY@4d~D9f zH(4EM9ml9MGd6lceuADrQLAnpVJ9L|C?gA!tP~?jkBjTz4IjIa7_V%(-<~h2x*Uqj zJq%q~LNVx8^+fy-?}RcN5DJeZ7~P0-OZwsX+Uq9=up(;~YAXkgU=w7kG1ymIbJ~$t z{Pt}}-u96@ytDt)c!NS20E<|1_SL_*qpZNhiC%!8gj>PLgUW&Z}@lR%*d=HkeWhi1^_V}EvkppAoeR4i#_N%WtjXYfKd-&6d@4l>pn*lvL2cNbw z7$&<(tr&PNlK_pLLqa$d4X6Qk;h{1(?CP-hU8jAHxnJ$kCD!xx8M`Y&1E~cEgKO$6 zChj&vb&iLUiXbuz4S(y?9el1n-tV2E;S|xNk^fzv(gfVEqJ*eIe>*4nOfVJ3Bg#(5>jsLT%={3 z>UqUot90`w1SOn;$p`%5okU;4*dMQd9`m5m@}ljxrXO8`(r{s89(~9J4q_v|twb2z zfERX2Q-EVx_%X%?ByifnD#l}30E_}@p6e3iVXg!JpT;leKx#i_s4&yb|L z7rj$rHp!Rx3>q8w2>ralJm4i!ffr4}*Q~z(O(#)gWi2juCgWNHq=F%`37mUBFpB<- z+_*;V+W&Aznr3!x6IR8*ZNtw5KQDGC?Hn1T$#h7qM*J0oNav&3Mv;<&nZZ2iXxI*< zp`0INgP?$nL3pnn99zmht53xq;Xt=P=m!=t;h#Zs{e=uqPj!zt|piu|w5`rv)5`xtYeO|FEi=hnG)(>}VMr zV8?Q&-~5R_X_hu{Rvd^l)CJCJx1&v$j~s`^$%RHgE>s9C*WtBkt}la*#v=+MN**)C z8rT7yDXv3LtZ7A9XVqxwI!SaABnvU8_z~VS0!g6vdKcY|y(wNqPhzeI!w4p?txvw> zxXbX>OLfRrbTW%x*4&67vl67$;HK0JFZ4XGfSuJV6(n{k-gdsbIi1Q&aDi5@U8L$l ztSShdQ9nr)!#&v)ShVE=@FvOHiZ@#tAZ!EPRrY;Kpo#Ryyp_vj+tE+jv5a;yXfpQDTT5k;htnkI2#LRF4yO_hf(fw zX|QQ*a5F;iI0s3p2;(Ze(wi%c2$FOnPtcVsOi5nm6Yzj_WvfjD%6Zy zq~`QMTF;U3Pw`h|eFhU|&*Yv+;>IkREU#4KqzF%)lZMMTK^){G$2CmjH(D~}R! zuS3f;5Jfe`HRP~|-tZZ&Myvf@iCAniD=R)21YK7|uq;&|3IX->;Y{;B9Q;s4RX&MV z`xKru0*J<2FIP}K_@Uk|nSI|fBX~W#eH9i_Z)_$cVGC{3rUJyMSX<;wR7NHU1z@U| ztCW=M)pt9tb)jv&aoxQ#3vptJ(EhBtG!sI*213h+)g@j_PY|F2 zC_11KCPr`gL-e1MU>Y}xj` zwHcHY>9})9EJi^{gSmK{eP{)a4QE?(5!%<#Iz!dI)3Fqg*w$Rt<3?+#*e9 z$zN+$EIEKCE#@Eh9e&cfSK|BE{$^kIb?*TxG;)|L+Q5n(py^5YIXC^I+=8WFPw z=c<7x9@M;|5cfPP3SU`ls3V|fQLfyk)0Bue+I-MB|z}Ng_MnSF62DBB6o4x@r%Jl z-1wSvfBrN|q2wTzdmk|)Qn-bm#{2g&2ii+@_QsNP|CVH~vhs*H1=kr3_*xo443uu> zNGifuL?^T(EU(rXm(Z>}VasC~o6-ll)Au~Kv@80s{x82%&g3dN(Cpqvst}pB zVw(+GJ#elj8zZ88$y{x`&9*8ej-!>Z6-&P|mZIu_&O;JZcdNPm@*K)6L=pAEi6?y{~=lyFQHjs1dVw za3uHsFBKj;2OvE3RurgJCj1j^oM7AXE|UtZ*tK}EU?-HO6$pj5aRp>(ghvrIF;7F- zg|k>XTa%O#bRq;VQsNfB?AD7mlNClzWvI+^moQmjF!s&V6F zr?hN$t4fP|>=(B-55@o#qvr&+DGXr49e!NFZ!rsA&dP6wm>fzbAFWo$?k(2R>AzJa z=&x~-i!@Vc_NGx@Mo+oM21Jl7i=yrs=cIm3y3Dm{$sY-_BJI|aYKR-U>(aol<-(e`Nh?1(I;`Q)@`BjBPwR{S%K(s#Gqogi0cA6Wmfwio{aBVw#Mw< z$Ekq0ePiVS7tW9FTgM?*AA)b0YGC*sCyrOi1iy^e&QC+g-ihV+lITcxOQe)ghCv?* zdSe6$w4o9O7p%_CY9OwY5eN)>p2LHKMSeN+Vo)j0KZuOkbTw3tjE{y@tV=T(KlXtm zuH$H3SvGy|6I767c30tf!)>9RxPL0xISR220Ko}ojQdw|`Glig8H`qX+frN0a{e!G zZvtm$S)PrbiYU^mX>q~*pjL1J(YgR_g-IrmgoI2M0=Nw)Gbb~X%*=^rCL}{qLtVhC z1=K1EDikXe3&ahnRt0gv4I+FfTD9PAKh5SAt;_$q?(4pv=Q$^Df8U&cXZrgYg!ASs z@BQA(bzk@Lg!aiR1rmZYf@1<81KlVJpRceruE zys063*}MIcl>6-b(i>Z+;P+P@{JHCh?CRGxW;igo1a2Wrlg?|}ULM5s<9H8d`3byp zai;=hezKVMMoyd>KGls}6iAYv4v!PP=n)}9SuC3}-vk67DRx(RC4y+Y2R0nh#Yb-v zky<2xNpr*eaVam%B4d=ES7L zvJEGy&|T)k@t#+Qorp}yzRQB9gQ}EN1C$-&KStnuzeeR$4spEh#E0Lr++DCFSwt3VA$J@-TkQ(C~fHNEPoxMonAMw^S)?k1}fw|1k;CcXfjMz4gkFv18sv&PZS@S0=;94B6 zMhViKP0=qXTT44{Z9ZhBF=TM|ImY3yr7C{N=$e~;{+3mgQGbPuo?FVO)kb{~hjOCf zBV@#^cr&VRgPR&NJ?RQh?ON-Ri)C1(g(Yl~ovG)^A(9?*xKDGrgOHEXyCU!C8}XB9HM=^H0}oWrrTiuS}^&yx&E zx$r1?6f&S_%|wJ!&3rKvwsk|#W`C&l^>}N)nga9hf-(&|wHdKIn~8N*ahFoGZ4@0e zO6+8Z_6{cNaQe}kWb9W8|K6aO>Jcs=b}p4ZF8zH5f)LlmLnpqiAHTg4u^&HQDo01a z$uksaqu3~XlkTB3kCf2}jYh6*^l!N1@WNCpZXt>-PAYeHhd#0Mj#|m#No5Vb#{nQw z65smSWv`%sxHPvr>@SvpSpHpy!K@Vc2{7?tIMiiSaH)q#_cpwDQC>h0@+ne3OHW{_ z(FYL4mmurVznrt01QFa^DIMIf!`7&`6s_W6US1J~uDFatWlq|8=Rp?Po>w7}C6Wkp zm~~^ITxZZ}&jFnFOsAOv8Y726+Bq}ai#Oka&n+k^ZyS$^QLY6ELvy3Zj#(uuyYpP6 zlA)QM>b|Yv)#^IQ*icCon0AmQR1XF9y;kNr8#J{%nx5yNLTaP0`uNAV&a6gv+pR~w zMwou-EMTPW@JDqTVGHo!Rvi4==qdg!#Cr##EiGI&YE5~qEwd}50H{&oOhY8Tyay18w-_V*CpA}!z3kF*wAgd0=_H&COMrz|$u9cRMH!;t_OW0hvEBtLIJ@T=8D23nSPxph~ zASuxG%Xy%Q80UV+GbSXJ;}}FQA_hQa0ZHGa$IE#kB_3qhG3GCLnr|SaLci~2&*FKq zpqZeSR|@^V>0vjIamOR79V$fx$t4w{dkQr_bLr8);Eh+-KsRRB2{*r~SwDGf`dl=q zqqY|kpz8$qL7P;;9Lz!rdnJW8WU(VY)1jlyQAyAc>SCW%QwdrK*Di)^F8_jYYQQ+4&rFNWGg_i58nWTO0vt0^$)a5&)0%PLKYHC&Yt0IlRe!@$$OX8u4d*@b==#o z^Rgr{_diD~G+dG&!*{MS#vW44p|FE2apgxL%{wfIHLL(%5WUS|5!O2bF-WV#nZf6> z{Ziek?nbDmsp$-u1J1lT1SO>Rr3*4(moks^HzN=7{}1UM`;{eopN$)-9af=-FE6C0 z&XfQ7pzoKDlOA4-@3hu-MTm$OUS(tbvGcZajs}@(u(A-MCn(`@T5!^dV4g5>Ntrlc}fn3S7vn^a* zJf6~oSPsAOp!MIH4I762ao~X;m}4`o3h<;H!bp`nMt@F7V8N?TyY)XQfr`BoyWSuPu=S`912ITE z>Y$y`>mO=C|A7-Bv81Kh7@rj}a{DVKfRE#yxt5PqBxi9_U4U7w+rdq$wOAnrN>8@a z_6{}~U@c|mo;-1&krWuZm0l6?M8Zd2q)->8{n+J_nhJtzFgq5EHX*0Pkvlw)jD-01 ztiI#*U%;(Y9j3nPVu|liT<*iBBk1q)B)P-!B4`x62v%t}mgI6H+Flc=1IY_RdGrx8 z?{y`hbIg({ke%av?FLK4QOb)@QY#Qt$75km)Omu$&ELB9`%l5|sTzLX_2vVuXAxQz zk^o9fIK&G*2;n{W&c!6Swq+;ML9P*c1z(yUUC^wGy5x(>!6N7i9V$6}tDSY+ydmfC z*6>JfYWbuN4{OZ7JyItf+5d`@HmrnyseJ{1x>JT?Wn4I!C0p8g#-Gw-I1L#vKD_itXh9QRQ<*l>0BCUY)44mR|Ok@m+O zg*DDx*QIKJ^GK}i6xakp6kYO#gj^lGSj5e~msr<1f2S)_=n`ee5@}z0Etg^Og(*K$ zHzR#<$nBojee46Yw#o|VHIf_Q|3U_8@MP_&(For(#Awk+U>HVI`fPZJh~e+V+cWE| z)I3sbPkE$9PE|$8qoW5bHa14wM&QcSWi~i#Y_gV*WV4<_!E}iOf(*!?69T&F)bIBj zby0ER)2{bPKqRRaVyReXe=vg^y6+l8gQKt+;Niyb;MO*pU8Z{x6S1Bt5i~xfw-!x< ze2XT_`YLfxc2V+_xpbzM&=PT4+}9XmGEqQ|<}mdnn_`6^27Z0sWiQ5$sqMv|?m+Yb z3Bvq#dkm);Vr|F<);_0`y0Gzc1WGjAV!Q@()n+GnPq1$oACcXNAcY-AU>-%(6`U|J z*3>i`VHuhVyoMSMz)yO{DNjhDOhpa%$NOvF{PDB!ja8>!?D}9fjlQW-oCU|7=4rN- z$QCLu#F7VqrSCI@4H%z+AW6u{m)QCMV&WgN!nIeSMOQ9?B~#pl(O7P|tk zlmwUHYo}km@Y(;ihUrbMVzPJFhv!KMZ@~8z9J~GC*sNo%G<}Y?0_Ata=7?O-1dH!@ zM=NMf>2H)hiJbWcOnzV zLu(W_m6~CL`9iV6PTq1yXK%LbCQVg@V=WDX1{L>x@l%h!%qYi-Ek(ONTHN>i8U8zP z?>Sar2^b4ktWyPAaaxB4jx|Vt;$*kENhSyl`wtfJkVl0BAc52gI82zO<)ooZ@sv3n zTS3t5GQ@P$B_H1OZT!v}7X@_t$B+H5i0NPP?Tg{u&F|$Wjr0RI9(QfQjxjHa*Ti&w zu%PYx5k(pHW{ohElUDCULyitpQimX+eja@*TDsydr=Uy6B(=4?xb$f5bbmB@)B{-& zuJLfeZYlbHy}1R!=ZR9d3E#QKD*U-xXg#4$2icHL&TflIIb@RNXK*(Kt5k>qX<^`t zkc73rVS9xQ7^Eni$Z>yGV7FtSu;^Nl)KG!|30`(-9QEWQe)D{~>ZewS&UfumbcB8VJFZ7TIaL-)fAGUJ=oA8zTsVlzvz`j|>NsEJ*q8tC$}8}jtG0RU`b@UeMM$HX zWA)`2i{lVNqBB{QMwO-kT-O+G&h&!jF2h@uL75NE?1D5QtxZ#FG9R$pU)r!o!|^kf z@vo`UC`&XPR4S>4>~oS)WNl&K&iRllbsHRb@Yyf=1Leb2ecd)#tfiX=`J9JuU8;$8 zDGHc`PPGgN+6H&*RHd9k;C0xNN|33BwiTdOz}@4yoNr_?aPyvj=W@ z8tcooXH{s)9TJ53+ZOzX&4d(7fz0391@6D$X#4-WsUtGy>+zjS6QMxYR?JO@rWG@yH0C`trU3$Ol|9%+3_d1DnJ1 z5ZI3Q-E+UAD6py}3cit#)q+J5Sl2$j$KeW|CPdl8Hog$q4!qe|`51pm)uNyp#Q(ET z-?ndL98Jiri_Y(e9%lUoGNN}%^ok}B--6buXC!zflzO|o8lEo@Kc8lrWtbk_Y(v5m$2&Pnq9|NPwgCH&E z$`?llncPdTC$zQbOew0~K<)xsk=+L;>5@9?n@iR%!%wc9F1a^KcD!#$c za;YFv-e7+O#N9o0dOM&}S|kEtUdBhKkmA7vaE%TrFi;+Ldd-_I8F~Q)`GN|S`|3Ok z@+0_OIDo09AN$1622(={&j~lQLZsQ{1pE{Q;g4vO_8;n==^ESxJ?@>R)b?VRLUyN+uAk@i zYdkJD+mn9r++W#-!C&FGccaa(OJ2ki{S9QPl@k?=3{9r}7-=4Fv^Vv{DNf?etJnp} zyjd++>J*g?dUqJ>g_%wc@(e=c5eGbuwxFv*gXA@Jt}fe_bP!Ca$=T0;@E6zPyK5D@ zy>|Wkyx;b_@y)3zOA$ZF!=MxsES5Dfc3D4;HAyf@Q%SuTwxK-K8>j8X=6&!Yk~k}( zulB9RVK~X(hse-?5|$QnI^^1!SDsHf{TKdpt4FcKv>y+Uleg^|^a_?)Et=YKVQ{@& z=mBMI!}qPwIwT|^Sr|e((q;GvW6^aWM-d*Gm{MSHzmyby0d!=YEz~iEFdL9J>q>8N z7F^u=6~Fo3pX}kS|D@v9zbh3Xz?}12AH#?C8EeY>$Pb6Xg9%ekTa7Tcx*re?;uMHj zo*=B;Ekc!Y+rlBZrdeIky}*vA)bFGn*D8+o-1Yr=yw_`aubJk<15>-58pr}_BpI0U zBi~A=vh!SVv?J2LB}~bNyyZT=o>O|(fGry}meHXM&;Bto$U?P$HKk5D7eUV|W1$$w zJ^B~leG!FK;S17kb|C!7b>5%G{$1~=Q49;Ea!yjgj?S$W35Em6+I;V$M|p#l$=5z95Ub<; zCV(|KnJ|?*SpwAUPx0j*ROfwor&=_Ta@U$PnZd#;*<>;~oF#S7XMg|1rTF2s zD*yend3H%8px61b3j9d>u_h2loXJZhH(r1_Sz+S4yrKkSGP{fzmXeJGQ1oal?1^Qi z$4+E5{Ez?;En^O#TugyQrs#z-dZz=J zYlb<VZQenC(E3!5#amQE{6wrLG1qL&4EZU+)K+ z1Km0ePLA)iggWPe>9{j67tE+ah8FFqd>ttVeQ*)_^>x8_b@DX(Z&@*O4@Fj09<55gfUF;I5%D>7lJ zXpZh4(+d`>sKtXQwB?v35n5KCWoFJPCQxoz3J-&I54A`-Lf3A9A_)ok>_7g8Z=mz3 zqDXfiT-e*(D$mF9jjVFI&PT=|#8VP`R3AH2G8+4`XOTFNui6H*JU9^|7Lx4r-lc1! z5vqqH#RRM5Lzl~DGK&l%r{j}T#IIfRf8m8!UYYE%MTu_^*tWbU|+`sj!6T17=#bYOtr{m}mnQIK%&cZN1#e&JxEV3z9^ zE&#I@B@a-glhsGtk(Z(lf{2hwz)Twjc9fZ++ptedSPRj=Rvx_55J@2ah?(4)hoM+Axx z!pMP3pr3&&qYWIadFuz;gBx%C==iPIZJ8Qezwy=^+mlnk+`X9AC-7M`7TT4nL+w_n5&674Xuba5*)rL)eCv@V)W>JX)Jc3HXy}7ZSoIsRTy? z?aaBHC`wf|+%k8*@3c#QhLw^u2VMfa? z^?(x2#k&`?bH#7bGIh^8PzS}$qj4&Xru67YX2>LR=*`(UV;fy4Oi%KNdPWFBN4*wNV1i;C9^Kh(K}Sk>qz{)hP-m#G8K23O zE4q*27K6$Vj(2TC$$HVQ*Wld{0=yso=POXf!f3^BnOQ1Nv(k>U@yM!*WZvpPMdP#M zWZD-fSacKECT#)h1aCkkVNr6(VNd;>kK6HS6%7TueS0ol>9Pj-oh8loByeAz_@gW~ z@)8;@{ZbE#M0~TjlR$-7ku+IMN{%t}G7^zW3^4>})L!J~c%v6;ToZv1>6?M_7?mIy z=OC$zD^kv{7-N3PVN+q?MY}M67e6DUcjlw6{{55ahbuUs-A^ms)jUY=B7ASZ7~<47 zg5`24VJ!bOOaK%>lCT8DbOftD*dv@(1ZFARv({3!?3Con=#oNr3)>5+T>6>+`!zd? z;Did>@(siDVq4UwRnG3pNo0pDv==Z<)X$>wJURIBoN;w}os`v)_eylL6Oa7?VZ6r3 zkOlzbpfe-HfR;uRgrDri`{=w=u>k84oaS><4Cq8_g z`nZw&0M(O`)QHeG?HUdO$U|ewJW_FkUOGf^&GR-)Eypja;#PN`P(*Q@A6;KKHZ|JX zTw>vkco{43`En0W|3mn`MULRR*ga)`?g2soSY<&vg1y~HBeRbw;)=S~JW$E>+=JC zgtMliQ$*gsP!uIZJf!EJgxQY;C`0JcKoY6r!sPP#@vym6C1+V&!?)7a%&*srU)+5Y8dVz;juC=+D zpfo78rNqq|I)Vcg0zf4guq*}T@S`cBizst`R!}{eZz6`WLPmP;nw(M(E=ei#9jCvO z^e)}`-P@mrJE(mMf4V*LiIN_74KHg=*4IqtGX+Q(ZW^2BL@rK`>9JC{2yYH41mw4M zvGB;zABpq|U)kw!w}hdJu{Q*$(;O4eTFDA37G| z!tksh?vAApTM(%so!gcVz5T`bakVPv(I@Fx%4w%{)>mNnZ&%7`7X~NnLJtyQX=a6X zv(U*gC6bO?7U_B&58rN;E+ysO5o$R4z5$^Ip*w7W!*0vR0Hd%0a58WTI{h5Wu3%)=?VgcA5Sk0XXJ^CG!k6+&3D?Bu^ZnL?;2-t9g` zLLl9FY7@OT^#LB*gJ%_TFi*fMgE+m-uJj-ZPH6RYPo;@pC<9`ezeeUma>b6W0Z1)S zTKRNS_(-Gua-iUNOgGHe6tqKPZi?>=;at4`^VgFGu5oI++r9XT`gsx#>%nWR@0Hs$ z*$)FgHgIS_6yL3hcvxS_ku>)v`7mIBS?4+}X8SE#DFrk-ywxjj zCcQp5h1Yvfr@zHpmpTr0YQ-M7QsZbqhN`fyHY(ZK#FTNmx6u3v=_`oOw#`It6%v7* z2wlQe8AA#fi|J z@;ZEDALq>y;EB$b3G?bho`Tj~MT3uh`7l5CbTbBInr zxgMEnNaDd$|_0XP+VTdgN~Qr6sL$phvUVKcoCqqrv}*%;(f8LfHQS4 zXw?LY{MWrnc~8`SKpVCJ_eE!|InmO^c9ii`GNYjwM?Xff+p@cGENIcdq+2q)BJJW3 ztss6#>qi%UtM4w{K-EV0-KR@hOn**=Q0o2d)<{R+jhNtx)aEal{xh zFJTW$9!z5uR3k>4B_XgdR;N&M+ozhx?&DqlMTN6GYhLg2dVK4`@tF0qj9C3szgQ{#ZDC`WP|PZsN+M7h+A-_R$h^`@f&nx z3FrAe`YyQO&Yy0g$f|m-UMP_*z~xi9I19YMnxWB&vEc;n$;)oirNJp(>OnQ$j(4vu zcc!u%R)w#E?2oWwBvUF#X8JiQWt?Yb3Y9!GrV={hQ_$Gz8c`e$AZNlVyjI9(^w9U6 z$c+?LCx+~P(LBqC3F(?BxF=R4dq1CXGB1f_Z{=pTGs?wS94#f`Tqd2d*InZl@BN3T ze#*Lms#4z<&#TqE12>pxVr3gC^uq>pe_1J#5kVE$QOZez>;VhRFW>>~7d@$ln6fOE z$0`$$i!dIbCB$>Z4G((KmH3@i2deCTsl>w#UCVLaD6|j%2Zj&aSU68Y)aI5EsQDl; zWp8aQ+wtDhe65^ngXY<}dxJ#=BzUU5d&}5TJ7Gf2gaV^w`!B#fid(_L1Cb}6ihNIF zmFcQ`t+BKbcEM4<(e6y z023B?t zNs0s^cKFDevGH?KviB&w%43zGLwL0ZAG-r@Tx_l4_WX@ZMS|=K=}^^SDoMT|FKV0@bQ2U3K!oxhVt8Dph-=u08w_zj!8oS*_wYliic^ zD2~r1alk9^F~taF$^uhr57vG;GqymqAfOsUn32yc3+PAj26-}9&I%QnbNA{(KxBu z>OqDK#sk)Jh`1HE$_do)O#^K-Z-a{(!)tWuj{8zEF+x6FJjihqU!F;niwU=KIQ zg|dS_(_Zp@=9`d?njVzlKn}{V2IOdIxHw~@w+y+36b||9OP>F1O5tG@QrMb3SM=QX zVNXhOWg{M*+96{03m>i55Wtas-Ml;e{hPdsszx(p%ewDZVJN)U6=^ZCY;rrO% zyk%>S>1t1$MBD2iIxaW&SbyefjbiFc>MhD7g>Y+qPmZ{O0sKkuy2%y5hsy6j5uiPu zJA$(4*ma7#RzMOU$Qb&h<6m&iOL_D6;!pR@zv94WK8H8|B7CD6f*-X^f&%k%bYsS# z6fA^M4mnTIW299C=OhZ)AFq)a9#{AO^n&jby;dzD+WpG%{^sbIuwbjN!*>>qHW3rL zT3AYSYwj#Lc1{k^=R>X4qaV&7sD)H*=hl%31o1WI8&Xg73iE$(C^1_BIU>H zJ)nhYytM-@b<`p}Aei?vEG2eQ>7d8*I`=RUM>r81{2Pz&iSxfx;*6JCn8J>m-g(IF zyU)WfsI907eQ%UWkY2+h9zmA)(Gw6OQwkP#KkX584 zO_yjctBNV)Fy7Kng)nb=$rYRb8uwJmRr<+A^gk<*rSrh&b{Y>k0eQc-+6oHQJ z7Ti`(K!UZxr5LQ@2DgMGOE^?G7nSABOGXZiWgoGx$KRxKfN{YZK*o(Cds?Bzb18B3 z5JS%t4L=EYru--5bLqc+?-Sf$U0YnCY?n*f*rc%niUtcqVw`wf8W@Kf`P_OuAK^0; zO=M?@ASsu;`9N75?wf4Il|_p`3Ap;B=i3;944e{i&HA)b@Q7p56vrIa+|?lHij+Mx zH7Q+(^`{h(sLq4fl7IclxAx+eYHTI!c2n0)AE!yKv|Hkn9Lg|G*EA+M=19Sk4qlEv+MuP58n?1Ju&d;h0;r6FY4UkDP4` zVp)WC3Tssa2xOQ00mFl_aH%RvXvl4^e${;&D4!~y{*Tg-d6f@a5c84@-jSgfchLq% z%(q7CiADlM4yT81iC`vSi0$Fr!PF$9aPE_wGN9i!`k)f@=iD+gtHMhuO@QQ6y{62R zkV1zr2VQsjFE>+|-^8D8bGvHZ%YiUgV|5!i#TD*OQ?~Eh9 zOFl3GSEN`e%SHQ!D#}r!HzXrIE)0(_nSZIX&S-TT`C;fH{!SO)5|4VxTP}M30*0rG z4ez_J)uWzAaWMZ2AP797EGGDTJV|zH;4aE8U=l>O&_Ec-;#gMpq8haXJ%{>0^GW8j z3OMEZaPK(}K9t;Y)nP`v{ZuFNj?#xFj_l*1YJmkwgh(5jgV;NYD?Om#alBcr8zKu8 zXl?ZbA&nqQ=JSyZbv|RdkdCH0_U_ZC<`aHYL9);iPyEs|r?%|JH&-o3-hG{(_&nY4 zr}3==?G|8_w^eAbHeAx0k#=o6ZU(>5I@3$WypW-JvI$m^uan zLAcht_OQ93&&oe3L*~hS+NNU3T<+6kAnr`JlvhFfOm08cl^ZmTQ%AHE={MriW*7 z%6$Nr^?2_W=3!n66 zzkowMTf;s0(>C54h4~^nI!;ZrK%jB~2t8S%aKw7GpBP-HE%|mGW`NrAYFC6-Jut_U zuhs9~|3G|y)%nM}KPIi7mz(}Kd?x^rZ_M(D&u(bf)xu8Y2jnvfu$_&QGkG& zn4}`KjkT&n|hnB8{%( zCK$tN!4+6oXP9qT*%w1H~5lb@p#w_|U}^(D4-l`eZ2}8r7!ysgpcj zvQt2IWpI;S=|Mmr!nZCi&P+ET#o|my>S3-vk&?nLn&Z_?!h3cRUO@*GAe}fbPb?x% zq2wIhAfW8a225N`I-cWB?obQC)gO1~Q~N2n@8VB)l)kkv%;xk=8^f!lsnTo}y-{Oq zn2V(tx_e@$&c=I*Gs@J74mB}?$! zg+@K{(uOiLqjK=P65FMj^rq7j7Z#_8UnJNu;Ub$8)18!*8?(}cR{C&y;ZT}Ozwz`> zUy0vcIp^UAT@kyZKPSZ=>dg3-O*nU;BkkIibbIwDfzJwg<2`$s)QoqEtN`=H-;TSm3%EgdR1huzuFbD>xUluNixPY zw%~N5l5a>b@;h^mcUhNTY1^v>If?|K!xP~?Flq+y0@$@acbPbk7&DVm3JHQ1p_=^* zS=G8gpM`m*r}W09CH5i1JfOCX7S=GhV_$dl%!47UT9v2v(_dHuTHWGg)xy?zam3ye z@p_z3KY@PmQPk6V>-oMKpU|hF!i30RVHvBs>tN3<`O4%|A-x!;Foc|I8K#7?U;HIY z->Eu9Yf>Wpjj^z7q2T&0sZzl6Rb))8LR{NtUNm?gesm={^<630{c(A9D-9IUQ8%Y1 z;HW`D47GZ3)Stv#z0cj4_zc4%ht36BNh(p?u*vB7BJ(NVYuS>=C?hC*bk7`L(}wV^ z^S;nsAaP~oJvipqGDeGT13b!#I~dVrLSfyMD0&1?D9XeU1Gf*O8@mm zUne-NKF^tYN^!K`#>IDB~(V{?Ht`cPl;?(#$4;sOEDNsL_^*gsBwZPO6Br ziH0nC8x^BfWUZnGS3oR01V~K%0wIff|Ma^qq%8ibLKc2z3e$=;*zY*W#T4j;Ke?M?0y;W7ZzFT_4a^xE9LPVT6 zaA^|BVN`-Pk79r3Fmg|5Sug5z1K!?eL`&!s0Wix%+L%j*JGpT6h2k`YX+kU!95E`P zoB``hrl#3mDdy7}Rl6K}B7teaE@t1}zyugJXsl#>uH`C<$0(HMhNOE&FaE1O3a;YR z@7;dR3USq1Xg^A<=uRD(N$Cl3RSTO^28Tu)0Eayp;7xe%%GlP?b#MM~t)Qzx9{qB& z(X2yMFepQT=$W|kI6BH*X`eDcbd$$t8q-5(W+WRv0wbfIPBQ}}ZDNfVxYFH1V2X$3 zwhp$Az5f%wu@!ew*=gb@M40H1VncLmM_Ut(XGtA*(G zw2cR((dIT5mG@${=i=R<%ZeypCLrM4jC;%N0)CPpeK+9&B56n@`*uN$ZuCHqVsbd3 zVd>a=9c&3~x;ah!ABH zDvh+00ioJSdU%pDxv|I~dcLqqGb<-wJhgXT?8ufVr0)mG60Q8;){*ie-K84g%_e*K@Zd``?%CxT!w3Q0Vx&p+jb^g*1{>DG=z3okr_JtUJ* z->&gqdST6{U?bS3@y19`V&cN-b!-_9d{U^22P+dt(ihA$Cx45$#X2%Uwr1?0DkdD} zvK>HO^9Z@##B|%F;`2MJk|be!`UbhVAY+ooNzcsQLxPun?LjXhz^qm5FxvAck|62b zbqyS(8{V5B009SQYK;zZ9ab-)iqO{v3ts@P-z@5+`Z$Wo33uZ-=?Eas!$?7Tf{;+R1!-R4%l1zWZcnkvoU!z&}18j zRT`@7u_EvRe1<2jIU!Sdqm1kwVn~lQLF$5F6H@f00vhH?su$9P`?a0h#m4C{Gz}jn z2CF2;64VM6y7&G6@H4Kutv$Cweh--k6{6ksN26a8Mzx*?4n_pBMp@x&A>zO~W?i8l z3hwz{4qcpRVspuva_U%aBafea7ebp&XP3{2Mreph8G!Q2w0kOqcE#QkAK#?V9#bJS zKYfFCxeg~0R~}(a6aWPQiGT<)Gu(>_vPE}sta}QTA}9=AO|TnaoUC0VS^^o@Qp=qO zIGi^b)`U_%yYTX?B0NKk2!zIA9xG{We6g9dsjJ)Ly$}D)&3o|^YY(gt&BL=(UkB0y z^ft=;-2L88-iaykIev}D2=H1D7>S|Z83kiz1%|`}C}W9O=$*@I2TCMdvc@1*999BA z#x3JtLl3=oOc}88#-SlQSN`@@r&0_@R*1n*6PYg!xe{M1(59#^h(mfiy7U?5<)4x< zB!EYgnD-^yY!NI2Q=6W7M1{%GvO!TG1OpMmrLb36wKZFWnn_GX_=TAE-2Z}O zY|%g!LONX9GCv4ub?$zu`H)>)>_=1R$ z`6g7L@e>D8Oo>fT<+6!58B{|&hkx_l-#?vNR6#K9d9=jCMB}VR8x2;SNgBiaNONMM zF}QWK31+DmAM+8s7dJXKfmENxOZ`M2MNfO9?F)JdS#OD?wH-R|FcKUZ+%r@a=D5WIdp;!0Z*te1^j;hWW-Sc<}?hsr) zYXsEbbQiUY^=tqF82su*WLMzRaQ`3-4K^F6X}dW(N<+NvFGy&H8cPBx6HUf_%RQ+i zWio_c&s=$l7daE{3%;!GlVB}Z=aD-Jr5YW-X!Sw(wY8t&PdDuLBVOiKHsq^fbwrS> za>HD+Hv#hlVd+UJm5RSObgC~MNm}?{tBNF_9Um2ifGnSM%a=X*n=BSq9SpwbD5=9- z7ve6v-*j`^bd7|ECIK-UWsfuhklKZE-ejRv0am4+g6J@$9ffNQM+}T(!UkEW*-4Z) zE!-b4hqyBiVf#-?&^$ zO-h18(9A=R#io)eO5!!&1dPWF0)Jcz4t)R<@tSLl)8A_lu~N2IG}pM0)S_OLX;d~v z&;xEV_BIsJ-e8Z@S~DCOUHp+3JpFqVBGZ*_yL+0HkdOf2ZjMi}eU-%d4t#j@xXM%b z{ku%MX4eAbz-8rG1LLnj{lM{}h#6ySMKen3<5^TJe^3ZaRYI>Wr)nxfKxo>951VMe zjY6t8hhopuB_w9Fr{Do5K9chpSWhw87#*D0(r!0qce>v{ODY%P&5NyOVi4JK^Mb@S zKcs+OaDs+)0F;oqM1b?HveE?08;CcFxl*`7Lu`RM4xluBr)G%a(vNK0a3X$ORV{qa zGb9Qc-Ll3xW7yYlz&PYadwurfkS>qw@sZ1OhmiSYaP$fJ3*O<0Mrkrn+8S-7sR}!1 z#3>?AOUc^%nF=U`WaWuu1V)VRHzj}w`W*yTksB9Y(cnUeYx^yeAABM#tM>E?^EyW2 zA`!5#jnxv9T-sh=i-WdO7wD64ZDcDvZwoc0CTIZeR-7dU_>ffTT_!qP!X(1jS$~7yT05>nRDReC!{NeqV;E;;))%&0txYLIqqVKql|dXzfh)7g&-O}0 zAHdQ^wzkR#fp$`ESV=>WL+; zp9&vy-yyf{pE>V}vvC8p!z$$F=XkJIKBq0XcRWOrV{7F)I2)XIn8=Qhp;a!tG^WhY z0RZ|m+BtE})ISnK*mRe}FYma1I`xq;Y#4tL|AtJ!Tw{pSgWAp`U$OfCQY6o+5XlQ< zb?g;H`#?h3RG=wzd4k$*Zh{{ln+?vs!R57$8MObQ`j}TzJQ^=g+soo@H#9aiM_>Zu$AE9IJ#Yde zcg?}E;o2D|9QO8oZ$9h`@4Nkur%Gt#jMi8#P9$W8<)-2hJUok9b0UWk5~mQAzQJ+P zJ+~5fAl0xW*647{UF+U(sPaklW-=EnaD=*cT_&SHdDQ4J_=%O-nlBcAI4&!Z+P9E-AepAAyPhY-}11Gl84PQ4G)}ik0++B`Q<_ zpdv*t^WpplDnd$T&AYEcv~-t+|MPj(f~3q;ZK8R@=bZGj!(MV1epuCk(R#DCC8{Q#`?Fub6gb*l*>|F3#=MkpiX~7X!b83~b+v8aCePgsywA)c?AzQ1 z>4~|C@pQ=i-e_Jko=8QNS7D=W@tpF?khb_k|)Pe$AW^Sdt*x zjG_Wh&;Wpx-YH&buTg>ngynJD*L-g2v)GYa)#bM5g}QAHv#pw0kIg=1bqL!@aLN!k z5U|&?^3B)jt}n)?x$#?CRv=tPVx;!;3CXZ51H9Cbc|hrA?0-p>)F9Yj5KVxjqnV#gEc})G-^wdBsu;^Zw1zcT@j#y z!8xJov8|qFjgEWm4JY4<-(HEO&z9;is;?}PusZ%5XC6+ra0X!ONZ^mj*6ft$M#<_r zydQqj5r;TEQ-yNVAD(<^Rbeg-Cyzo^sBMYKCy*|iLx_El=c_{P%7!G(pjCP@>0j`O z=;^IU9vuWMm4s&PdH9zuKMOy-QnMNo)x2c&cYI88dk?;Qt&?cJ+#H%~;WB~j5Z67oAN@s} zsMw94-R+BqvS$4cXG=mj+yUaloYE*e`VtMI8V%xkr>1t!gxIhTr2WG7&1i)(@g1K97;FHTY8)W8WK)23}Nr;ExegzNF z)?Pn@Sw&+arL0Hbswebl*xTw?XA{rAAtT$44_IfOK&Y-j8NSjITXi*o-U=rwzJ?+)0Dga==;x`WNu!WyZdTxYSdzwbd*=i*giHn zJl1Yt7h8K`RtpyHa0xK)iuA^z7voLAyt4T)g(~O`o~SBg#ozJFBB~^*-rV6d0yF_t zTUsZP+ayJ4uNE`o?|OEc=-V`b5sqia$(MYD$1m2Z9M80r$ofR)wB_@T-${Q)@Wo3Y zt|Ia(rGj>#14%vE+)=B+nu26DPAy_tX<>RlAR@Dkl+DKN-gMO!Z(&MQwW(mwIl5h@ znRBy{Zs(!8%}?SJ*U7EW1u$~LDFRmnE9J?!xl2J6IM1%g5^gtwIXp_{P%Wy^cXV+V zh+~8@OeqK)WuK|7y6k9VzR;m=9`~#+8{)g-fnRyZ%PGD`SGb%RiH}*=9Hb087f5#R z#K(ylQ#dwgluRrheOMF@@?fl4fmsxu=Iuw2Tq zLl43oO?YDAr}#KFq&{Ki1(8sv(uGKl`ug*3VNIfv1G_*XAq1T3F_4`D(j1Ph(YfgM z?1z@Ynr=FZ&J5&*4^7#7VIcYxH`Js~_Nj&B_}_fDvWO&qmQbRs)5+kM73hISKlVu^ zv#L(k+w*r4*h6r6VD5(ZcdnDH$fBNXYLIefrCl~p3th2^p%g}31v;2311LE}n+G>^ z74Jd@C-%f#5gi~Yv;YpNkrDneH0ap#ZutMR1c#$&e58E2#`- zKFvX?)!p)Pfb}vnRc@UeyznoYmmWpgR5g^nB|DtC0z5m0Kz8>xg$Gm7EiVHA-6 z-`x7nZ%RVMJS(($eA`fSGYT%S3+6C|w}jm2TF~YqU{dyX#PQM0OcB;%fl_caT_LA_ zI@k=4)rO)vudB@GvkJ+1+h0tK28bT~ik!iQ^p5-0f=Al%o~Kl3*j17qGmkmk&b0Ht zBtvGa>I9Q~a%YP%ddY@Re!-Xk&2V=-grZzWQq*Cj>84mjJn!Q8z{ zXJs_2HH;;)Fl4}L@;Y$speE^_JWhh}F+`Ls8Uc-j*{da1 zVUKt{=M8{9eZ~mdCkK~i{zy!#D zzedAV{!Ei`T!u9RSK=A*Br_)&R53ANc zeNW8f`>s({&^q*9?3 z5x~&x&-R+dP}A)Al<-H;%!oF3m!^QB7K-$oEFJ@`NfAN4;Ni5lfF%#TTJTTJhjZ0* z?PUC;8?4?U+00o!6Q=n&d|zLCXmo74iO~`xm%VOdUK*~-8hy~}Ai6D1ca?{+PL7VC z&LUDMn|(qPW*CnkK2jHQw>O)w@J*@4X*{s;ygc(0nI~RAhx7VyZ&j&RNb%w)54`#* zxTzW^B)X;O8~^59ihqaiGru7littCg9nOi~&h8ujI{MI9e`F&c$i7UkWb)HupWg?C(%q?&HBDjr#Ibzdsx=VuT1UqMAJm zOdqQB7QD|YM1})^M*RmB8%Jae0`gY4u*O9Kp=?Q#5+s+LSGW<+fmLL25Nm&LlAmQU z(`GJG{frnR^x~-NzOd4!svlXQ7hlYnpl=d`=94q^C0p8gQ5&Ht>ifJfILZq>iUpVe zsZCKaf-aNZASbJuqQ{-`DaW{4_@x4qyUE!thcA+}0kYPly&7;^MS;#sl8C+RrEsWJ zJM2p@{{rr=_H+E{HWy!8M}|Md!s-0YMF$Zl&q6Ys(C4)tgtG~6H^5|`BxVu7Q!?=I zG~DRfXGtw76r5-H7*)gi=|N0A2#umw2txKw4^5ZEJzqS0_k#|hqpjGNwdX5Rg*oD> z!!|yEZ(C}NG5tVc?Zv;U@Ml@DysN|!sM(=i@dk2~5p5_R>QV~Ct`^X%ba<}0pVE;~ z6*2&R~t#4*NjGXpxebrVdAwv)usI zsb$8Bkl7rg4-nk|S^gsPT%#33-Q;#Y=e>`A2Icv<3VD7#d!mIV&oww+tC;kpCz3Fy zbfE`Hz60-F#k!Z6NjQC_pLD{WhnSo-R)%5-#UGnU@5s=jAoiKm0vYm-rg`v=GOcpPsqf z=-m5P=*SOCaah9z4)Ozc5Ooph2rmpy*o7Xv%lQz;;$#7GtA#)0OiyqCMWx>EC(-#v zo5`wtt)YQ~EXI_VyNycdkdejxkimsFzkBLL{G6(DH1_;hGO&m>_fsulF)Q)y#y+Ua zR^b_K=hi={B$5(Y8Ee)2QG<~H=YdK9f_d&zC3_V2cFp!Df9Q9-H>Qf+(fFtTEB8hi zy_96V!PjC@yG#^_0v+$5`Ua!LQJSLI~ib z<34)$trS4j0-T>^1z&`Qy>Xly*wG$V$NN~ZVC)>+&=|w=l3C5Y#bYH2bGp^i)n%j^ zw*;BIi(7VyV-wP#fQic}aOkRZ7g-zb*z`Xt!JgBkz7!u#F6+`%41twmE&vj=7H3gb zj^l_9A;8j_9Dt1Oyy)4t;YMmpDpcs_S%n}$3=Lqe3v&ZF$}^pWPCz#l*Dy1{YdtuM zPvY%;Vw{BXQ^p6tZc!3e-Vy%lD~)S+v+))&lVU=D5Ucr6Ko$n6GC@jFI$l-NiY?K@ zH$}igtcH5VBa86H@{>iZQrrRLe(*<&+3HeTTOmhZ2RDyJi_l3LgXxz64Ms}ZW+VnA zWMFKVBT*8>GDITug=`J~5f#D;NtillH4C&|FXSoGRa&lRtM-xjLcWy#f`xlPOX~^9 z;&l4A5F_5k2+vWeMmk?_!GAnz$qAGxH(hqSx8F%O{}*Js1HWL6&Hm75xpQ`OCdMXg zJj38jA)jo$5|PbXwvf3RW5{%f8Oa@ldew%)E9ACPfdWH3iW@msLw8`2=h#XkSIW(w zdg29E`LAH7_xhSW0_a8PH6LqsAK~{nT!HQ2N)HG4g(7kR#z4@=W`WTY6kB%S+)1C*{8{wi@JW?&F|~%bG|t?xq$6>EWL8S* zU|?^)`Gz;Lgj1_1=I*_}l#e~L{f#CLb)K2xEbIujgyltrlwXr;O|fVdt)!b~wGAWW z_X)gtDR~b0@vK>DNe}e{K!A60_CG@-A9iudFqF>@4mbO^`5zzlOAa6qq+2q=cBC|s z-(k;4(UB2FCyQO-t0V7;2)*E#_dNLw+Hl3_(B6aRU5soUUu=jFy=QPkUH}3FGgrk; z#|dx*l`7*)ISK^^+KuZkS&#G$fZ`nVPgNc5Gvl_ex&H8VB!a6t+V&oz+ot99H((w~b`D6h zHO88*J%PWJM?Me^$jWp8Y&J&yYyoqMRodgnb zux}9)g&gk&V=@#?`VsZ0uU$o_#q zJ4sSNrSB?p6v#-fAw)Fry@j8=1i!ULD!dD6?e(2==C0;mgIA35kG6-8L z95N7I8En~=9*m4U-a54^I?|IiNHW5?3Pc7eLmx@gN6#)AGrU#H%5RI|$8rSfkXf4X z3$>{|>s`-Th+j~9Mn(K7*2~SqjbDv#&CS&jYf%rAb_7kEU9mL+Epqn*Kt_8=GaKIR zK?h8YiZGL?5A$86EP$(reJo0_8>t%z9-4)4-g- zyODS*!dZDvV@R|>(;=803!eD?J1Cec5cBN9dfLsA0}mx)6?U|-VS4n|54Hz4-ult; zTd&(PHMoA`tv9wOr`X6ai`n527>%jOg-oeH3^I)|HWu8rgQ#fj;Mulocj5cIeLy+vN>buu3JnKCH_o_yHI$dh%9djIUV)ROU9{UHO@SA zN2}u`r$cd>Yjx{q;ApD|R27u1YYDm&_L62A4o_xuj`14v#^7zLeakE}ozLoo6l6{OCAJ@6$c9&-VDGXk7XoT z2+K4hu|umY6c)$;s_F|ItXv{ygMcBF=a4g>@~0g1sa33T*xM)JPk@!KxA1y$k127=MrN>~ng;gH__^aVmJThF@67qd#XB@V(+qf65{3fzEzpW z0On&g3qLQU0&LiB06tnDjAN?^cS=804ln!_EB=vnrtU@2rjRT3CW0Hmk<3mIDVUYO zt09^*|LXtL|AV5bXgJ%uyfnBu*`^!5=PmfgGMIGv7zm1Fvv~?r6fgR_-JmnT1 zE@{+@wj&1hU`D)Nf*|Lfi~cv|wZ;*dVuw(+J?)#H{_i@h_MSFxLLq5t20~TFjp^~n zs6m2+{fXrZDTE_N5H~jiY2ocCVaOH5C*&Dp)W?G3q1Jd-ELY{8_?iWGU33N&<9QW0 zaBU%jCbF&-z=5sFG@|$zylo?#1WpZVO-;<|Fx^lL7Hw4bmA!b7FfKIGNw@@CX-D}u zk8XW1d@(s~w)_*63s%tG-h4it{NO@#0_` zFZKY1*W!JPW2nOK7jal?fcVQ2^Xgy+R%S5Aa>;nQ?jy2)b&II2dFKzTobvn%i}1yf zb9y_ZKiB1LWL*(3qNaGvNal{Iqp3W&8ss{et7E4alIK2aR^f9FgklnsTI7dG3b3R4 zREFB@m*ISK&IXHutl^9-tqPME{o=9@eF=9`HLkVyCDMWi;qo%#m&tsXD6#FPv1xWP zqxL(?Bg?~$7`F9>Br71sG-Ci6cs->^UFmelQ5D%RB^&vU(^W9>Rq!1Vj>8A%ol`Nv z5`x(Oz6&=WL_z#nh5q=`JF@J{TJ6SYw@ZB#E{rwCCI?4md9r9of{opPA*?JUipuH) zq3+S!VVruPExTxRySW7hW2%X*Y=P5=ZcdL$a00R3En&E1K2#AlV@?jk{vdYzl90%@ zVqV@iww=%#EXQN!iEqi>C61t<7$|Cz&sG?mGP zhJY8)avSz0a;!=H1Sxcc-g#&@KWmvcdu#y=;f8{I&a;}G?U07L-4`AAk)g*E_E#;j z-Fr@!+^IC42Br+Vd%!o@h2DF>c~tvA?&D(R5@IoRi35+5F6hA{2THsbypy;)&x7m+ z;c6OMod6%hY3#Q5(HmbSgqOAh*=r!P@P^Q$o8Gf(gb%c8r`z5c$$|;=9Ib!}!(uO2 zmW0=Rj2v>y@=CrQVrr|(Ak4{2jElkQx~xRGBV^l*I;j5zNYmVGo}0^bi$Zm9>B*Co z-m388A-!(G;i*niSC=v|rR&kypd*cps{Htfsa9z(#`< zgjjO3Wq5Miv#fJngVRqk`_|~Y`|;x|$@o`EW}GiPb+mzXI_=g->Z}$tW>P-UnrQXJ z*W7{+ESYxUFy1-xAyXB&^6{}DPt)E4#OoM7}rPB0)Y+%U4QYo=3_Gh}AoK6Fl>r+=pAu^dT5uaTw2 zy1~%4MmRof3?jZ@qVztrL|Y^No@mL*@!F3pmogzI@Bpu~ZHsMUQR` zOl}S$UT?=%}$5=N&ek|vIVBq)LXoqe^S1c;KW&;^)J0Fm`cP0%{tSa9Xre!ZH)`wjkdBel!tO?Wf- zwvr^vzdG~>KQsjf6;r7e*2IExbBHV2fFPjq;|jW{kb)A&P@5~hw`I}W@iS`2;P$)k z{9V~qt$@YzT-J8VVvoR^h5)mMnpi75IXKz^kJ(ef`JeFtOFOIucPsOej^}jE>U*hr zVWF^}G!e`z!kI6ppuyS5hj2*=4hk74skBxk`<$jxXl8L9NHfsqr-igG{=sjqw85hV z71Fw*a8HyLsBk2G8B18TS{E>zfD1jC*&87%w1fw}naI7ecAReqLWuM^m2sRBP$zz< zmyBw$HNilsEEWK#IBr!gZR!S4W+rZKC-0=V=J&7N!^VZGlS=nqBY6;9Vc+mj6Fl( zMg7mJeh$s3YHCK0Ll@J7FnGIon@xi`X`3=m(%I=RdQ1(n<82)THi-IIm=;*A!}vd71FfLyX&Iu5a{zouwWae+n^Qlv!y|NM>FO|qlS_3fVb z9C67CO0cTVcEdbLkaf0oaCiV!R(uDNViAy_(s_am$2}_P=n2b$%>V;_BP{ru(4vaJ zlC6>^*3u0Y;39MnQV$SCjPI-Xi)7K^1F%`=kqADL=|Vj7tR3sfH`Umf-yJJ=%##qW z??f=k{2fdeq;^8~pg8JY*35q?Du-6XCUc&Gqi&f%N4|X<_ z@I~lG(y6oR3ZZ?4`mvyvWo`NBSOiTdSAk$7vO+>x)ZQWC>3G=Wu`d|=(8K;aDgCRY z^k=xfqD|n7QynH7Xd|16t`=gYsVbA7)_QEf1xRg8F_zewmarQ2$5j)eW5@|>Fj@b>l4|RT|2x& zm;Oys;wpp{5EAFTXRu6=3ugjk*jO55#Ch+TL3Doi1~V?gNB55nP2(WMs3ZZo*_bgN z3S2aD4R(G4e3>(v!VWsd#56d+xIR=M`$2y@n~QZfLX0VE<0az#y8Kx zkE?V>zQmEEo-1Ymuo$@(Hemmw=)Wo@Gl@%s(_`3oG`In?RK4WO@4|<#wT3jraNPX} zC~&N@)EHAr+c@gO!n8MBDOei4$rX+ox{BgOo^ubGWSHihD2C|ZZ5*B?Y+LwuIwPgr zA*k)&X+7dGRG{zRPq#Djt%MK7rPDCG2(qqAeTY#fb)|RZc?sUU25ON_BR|LJ>$4hi9(6x4nQ{6W@bhbwF5`Xg+$QYf()?3TeB@u z_o}l*Vs%9B5y%KCq@2j4`i<}Yu8n6_HJyK6u7kTeS5A#K!YG)e;c4(k4?+ujVldy0 z_ePS=MxCtBS&ySx0X9Rw!FkI>{y31P(9BMZN8z+!M};5ugjQvnbW#3e!$T3NSWhrn zD-E)bU?ekS847dL>1Q2z4t{LyxfMROSS2{noStdJaWH93BSMr=V{91uGD2tCQ_BAV zy!SM&4ha9~tr;bm6SmJP6I2VeYjmZizpvcGlc~IYCKaNXa}l1%(O}X@Ewh>L4Dq39 zJ$l_T3KjnDteJ+;>Nmdpl_%l%R}ySrk~Wc=oO7XZZenp7SP6T9r63~tw3O6gaX8`9 zA1dPDt`Q%Rr+PWvXctPc>_Q4uZj&%+4+14hmF$!XdM*S!vyxjIF-|iI3udV+gm?H4 z`oG6c)yfvNFVCa!xDzc}Jv>vBYmy?l$10e?WR00UJBEA62OlU*n(ai)PO%BEhs_^2d44Uame@jV*;I8@Lf4r3F zt`Y(H=1()oxfk4f@U8Gosx6ZwQuQj-7#1yt%ZEYboj z7c1YAi5At>GS`qIy9>yfYe+D~!R=T5`{xZR5(af6ps!{P!x=ME4V?Sl8b>=y1VoO& zj%|gvZxcKAf(_n*cMgnW1B0nowCoeurb3>9L#Cx>n%=$$3CQUeS%w^bZnRwyjsEmZ z!T5zF)QeoayHmo951~T~?svpb-h$s*V}-q2G+&cw=3ec#>{6q&D(;(=fo~N{0X&!?Ce6wE|9KnSi zQbu|VD1P)MqUMwKu;+(rKNe3h+kl!K@tnJ`jGmmW10WKjlLbbUd6<9*jHk*XSVVNg zIN3#evq558X>56@D4zDko6k6l30-YJ{&YX>`y@8j$k41eH|KJOquqiJrN1Dbl$!Js z-)de#L|KaNm;jO*drz?C-=|quCTs!QCp4p*aFG*gifZbKZl*5#oiF=`Q(lXoP}#QW zYd2ZX$LZ?pJJ-#zqzVm!dmlzK&G2wD4Yu%f6TuMDpc*ukk6-*icfa zg_JB+}hjeax z*_n%8OzHe}g>-&V_?lJ=`AuiceIni#$5Kszy%}vx_t+rHW(G2F36XjIPHG0{33?c6 z!nR2P4JO*1VX`AN4JO^28Di;Y#=VP(e|$+mhhj=TkuAI|aRmS`*u+HU(mLV@mjI5O zX&*S{mv>xF;hk6^ykBP3TGN==N=gH3%*NB6;3M!pYp-74ZVY28_~@;0C%xzwu>fkK z3R?KZnk+3Ko!gdzHv6*rql>Zt9m06-zsfqaFBU%L&~>@xmbnwZNt+royWzziaL;^9 z-YOQY?rQVR_L|9I`|qXhX=Edg#4w!y8G8o zy8PU4`~ttF>X4Rwf28{-vp&~Hb4Iv-6F!@HRqT^OhGSdlae1q1JTA;LEhVJ~+kKdjO8t<0Jd*6jGAWmhD*(k5hbNYRsC86Oj>aN9m=Smks$v zKB~;o4jC!>wne4mTOc}im`=b6Vaq$-nTE+yW(%wH))DwZbC;UPa!*u0=<2uGnKl)( z&-)&b-S`}fi&P>i>1uZ*{*}}mM_bv!U4yUKCFj)%u8*lJkudjQ%QzA#Z-}AHSiRB{ zj+;l`I2zCM876mCve?t*@;UC)6IXFXS=GAJeTPauEYIK+fEmWQsv^WRUM!DR=)vRM zgpW>cG(X2s566Ikl97`Xc35;4yC=8A%j^7U##cs4@9Yy5hB9rRFJ5B=m4uVsa@pPFff6K=+63G`Gl)47oCn)Wq$4{< zOsYFzFu^TZhZ%fRvO>J(T~WFPaMz)HC2_0TaHkR$L5$89DheW! zR_NCi*B^edg;?jWHjTUE)6V2(Ul%t);sZLgEjCX z#3&`JnjSXh5X~B+J~d$bP?EtG#6P27dRsZl$$YM;t)@zT`Vfl*u0-~H>~V#J7L2^* zt-qs$IE&Vm)b4wv6o}QId63X5d~8R&w;yKSCEuw5Jx@>d!_k?$b%~stq!-IKQ#Ya{%n|ARCjV6FrNOU z?Pr|Ie5k6`V&7vWCkyAY53DuGySFGSw~i6M-h*xY6W)4Si!=T9cvCcu$1WWRZYa~@ zUVh+Ga_2Yr{uGr6l!R50?@N1`2cQkDas?@~Bo2l{M=nWD@>moHo z-N2;gPQ>n9>r?ScAtItPg0|G?h8`U*bF(rI0+>a1?Q$`*O_~L*VPT@2bOWR@@-={S zQQ~9mHpR5)u0=pE#*4(kK=uhEUb_7DIst7JTfOhtta4|yNUJpJE4Oy~s2ROJ*uv{Q z_^2E4jeQ+a+j<2BQ}XbRA6Oo!rE0)4CsbI}QP3j@JX3=KGUdHJb zJ?$-hCEh8n!6o9h$;8rsyVZ4>j@mM%A|e`jLAB(=cdjB#)p`(O77jXxzr~MCUR-vG z2pe~Q^N%iip{>d}uEOqoAsk(Hoa?t}9Orz5%O)m{L;Z$$VK!>>dY$!4>MYF9!WbZz zkbm%hxED(bRIDhtK*tF|966k3Vv4G`Nr#{1gpGmU5DyobovdZ$-UU+fv7kJV!Q!22 zs7tIF>Z^|H=)dbbP=gZibkS&~tqk~+6*Wu$0NadF9?8_q%W~5`z zIQ$Xx0>LmQaE+t{)FOL{n=K*(+>nI=#Zxr;pAJ4HYRC~tasetLNOoR&3KU*Q?$V#% z`YZM`Roa`ch9i((JiHa<5GG>WS{f?HRHJEE2G{FK4>~u)k8QB*Yr=4l0H2O#LMsd~ zS&~5lD@E-yQTTA+=>|hvqs>Yzw-YD@Y?3cTSEmE+vtRYGRbRu;sM?gX?=R;g&b=L9 zrVb`V>jZ_Y^mCdmCLyO0k6g)+rtAxg!`&7^(A_9*UA42MM+wr?cZauy7jlSTZe3RE zLUy5CyyKTYT127nl$>rC{8vTf0)tWK%D|1SlzY+#jWj1F8iQNWcGu{sbk4jSj~TLH z?_7?*5qdfzt~eQ93VakgkPRv8hs-9dk7>T?T?*>X1>ljymstZ=xS&v%dk;STNTXOQ zMqKxuD9O-RPHkdu_5nw+(^xj~N>7KeexOA*5Ltcxq#pgnM?D|$TCDnlL7(6oko2Fl~yn~9LVvg1YZ=*V_lSBQ6tM<2Y%kZ z3+`DWrB4nu*|TBC*NEn;mUZp(ErD}dvUg9zZkK^#i5(@N>P@LPDQ8%L`**Hhfhs_M zma`udKlc`<3}c2-zc=Dq-j zOlXpq97;d}(~#T(tS~5`qlX0bg%`^Z=cd2?>Z^~&Z>k!)+;_SJawsm((eB?n|43pW z9QK5w^DHU`*dn;2K?A8mq7-vWfj2h=q0wbdq&VCqVf?$0YvIb{FBHidRS}{cPgH(r zSg6mvH}8Jn`u|Q^z7NbsR1u}HPyh$>CM?Vd#eo94{^{9~A9p@h!eX6J9C}7Qg1`}u z{I>G4v$#);7YikF57-Jnsgx!gV27(}aX_sn4HcCkIK13al-jPc z5r(w(zyC?iwUk!H_N#p_l5P$bA@`)=babBuq zO(TXO$|cSzro2SZqR)nGCU-$W(rnfPN@DY{v-@~wvHfc2v$rgHIwf*ih5Kn__cP~3 z_#aCspT<|S1%^QkNkULD>>sdX8h$tx$|F)aj1)UVHA1LM;o1oiAx7z>o1~|y_+(Kc z7Ca$oL_;Z9k<7c)y;UaaXt99VzaxHa?)W_RJ(qv}bUO2j+0%U^lIC27z&kfeidW++ zS2xi^%IPk!{ll@`*MSd`@)Wd8451@p`hk?CDdujdfm9_P8%YE`rOp~{`tknn%xdES zaqiXTg{f#|M`v_=Ild~^Wo>)YEi=Scl(_$lce5-_pVEM1@0Hm zavHa&dUB4{8S@x`6pCakpsjmyvdG|pFoNa(MyGaYqpL`P&m?i<-n7+-*)1ZV+kbef zvw!=;!&us^YTMh_l7JWm`?&0*fo1N&a2$>oZ39RHr1oqC^J)p^D!fmv2nx%cZD!29 zoZJpS-He_Fc7d+7DS)`tF?As}%xu=p$xvjMUz3VBbr!}SUrCC=3^k;)2X*_GK@3Z@V!j{amhJLaq+&B^wdg~UidW^PX`a&&m{ z>|(Fkf6CXtg|DhTq{4G-(VZ>8<$+P=R+|w$@qZaDvsD^>bG(GTz;g%%IP5pPt70czoxvIlpDJ+uUh2Qx9~-@O#e%RH1WHIA7ZDi37Y z{Nv-doQ)qj|1+}`F^4}2P zs;CDPiL8B#%Ke59!dh6boZo8T&r7Tf2`8ySt}Y-sS#cSxToJ(V4FusVQmU<{?~ z)`N+dYRU$)3U?FGgLyddbig0uosE!W=q9AHf`+1-E2QVUshP#7H7j2#26c`}2_Q*m z@!NzXLwbil?&WL$1~+19Y`3pDS339rTwc-|Zl!WP?al`a0He`HZZK;}6Q|o4GP|fbr7DK?}6eaEsRtH^?tkA#sD;wVNrjF@oOs$F8LzDI)t-(d_hGl~SJk%sW>EUR_kZ>YT+ z@^U$4Bpk6igmLV1@4kgWv37KYZ$4kbU}_E`V+6uwi+l-D(CjlZxY=HwO@#WkM8V7) zRXyf=?qs`&2<0-k(dITpq#zRg?y4iDxgRlX*M5sX-A=@pak7D9No$&i43~mh-^5E zS@n_K`JWQh`S>tRYLRXT<NjA=y(DtL#;#)AhmtAUiPe{}+BQG9NaK&k*1 z%|6>-@{xzyy`Ng4C>Kakc>UBSR`_B44Kg3D)huN|FFMj3$B|dF3f@1L47en3ji})g z!q`(Pf{JhIuu-ql!Vr%H^@@&c#hVOS%)cNEWpE%wKmg6bpVSNGi6x=%j=;>@Rqwxg~*Xu$v__&faRc2NHy z3C2G)RwjtabCis)PENRm;Z zgaqet^Gm+`*`M8vUsL-Q{&e5`+jR5fO&4mGtN#D-_TF)pRaN%*Ga+V1F{cs*F@UHz zGV09Gbam4WovUeK48`lJqN}M~v#RGB0cXyR4Ic+cPW|0DIaN*`eV5h?NQq-VNw2O?{mYA%MGkGaZzv4 z;+QKR52!btjRS-$o2Nzwft9w-%#A&dCA}ZFcDytxn}ZS6%&m;KT`CH_wKwJ)vYa>$ z?Jb_Q;Ifi$ndN18%AO>1_b@-()#sIqWF(>x76Llx)!)49NAS#z&6Pg1ctMiP5ZHzI zZMCHu=qN#>{FjL^QyL(_;9gu>W-~DK3iGgNAf++Y$ku(N25Aol{wfb+!ZyE-@8X|T zJ*j$sv5N&4!M%qFw?5%dw_=Lkv{mw^4@$?_@3k1VJTi967*A~jm(?D`5skxh13FhZ zH~e|r>SV6Ml82GX)Fq=TLPgw-<+`phqrjTen<$h=X2mWQ)=VArMR0?(ii%oLODB#S za30J?&#K(tBjo_0DGwInJL|=7z13^5j@I285YmSvzIkCoui7fF!)X&q-=Rd{W7C}a zQ8JL_I(Qp#ftABRU<@elAHP;ma7koYRxC^gqnzYjLLTu};2r&63Aa zn|Pvkw>$nwamVvG&^H9bO_PhGf)eSI+Dx*7H&RD)buuCL27<<_ZCh6HRxIHlXGz{c zg&o5PP#)vg)0~Y*M12E-QmY25f-aT|hW>QaqbQb!W8`l7gv3G`XFa|Icm&hwHuCoFaN=R;`v%v;a|6|e4&`mUw!`7Ro^QCJE;Qkqf&Yf zq_lo71GQwT(1;Nz*Lt<(PXuA>hr3g^47)$T%H~^`jULD1X&&X9gRAU2y8tA zc4ka-hH<^ybM3EUp-SF^djWOXAJIO7v4caaxkBOfumP zf356>J7UsE$mYtA9Cy=xJZjUpuA9Cl*~~Lwz1n*t*p6h&ba>UN5+MpoB}f4%Kvrj~ zeQBzuR`hkoj^#w|ktS6&79(f;uUKqFNJ1j%?!QNRL=LgQ$%erEmZ49`xcL)^4c}k7WTz!3@dhRF1GeK3FJI{ zHSjwYSyR<@wpSL~l?IA)sM?m?%(}?Hq^IDZQU!qn#RO>-&mSR z-he5hFTyJJqgkaJpjDZ6g20aY^!Zyazv*+7$MFrW`8vtN;C`D&v18{8_66aLg*;%0 zMY*B4hRs2|HW$Tlxm<$Vg%!fsonb1_-83JXWvNdDr~1vJ<2>Ga%?&#AWs>Rw3wC%6 zRL;uSJ5;HYs=Ce2FuK`H{)N{HwYu>YUp?|-ijn8@bz>Kwh&Au+T33%txvU|A+f`hK zRZc0-tRzuAq;*#0Os1#U24*cea6&@KegOT*2r58}w?b}ygV(q0)sggE+ZCblGIO&+n&ea!dIUmIlT|RiqxkxG$h+lg|5&r?k3arSmu(ZgbeHKQVYEA z345iBE;y!7GCHR{F~!t+zd-NlEohTqOfhmF=*?T9Q|Eo_#zUV=ooed0{U1q+Oz5KN z9qrDcJ2XmEKtcADzU?^-!MNHh<;-6*bAtZ>05GOeNJcyB{JqMpBYv;*Lj*c_US$=b zK-i^hJJNtPEv<5DRmzDfko6-FA;AKwfk(9G#1pOS@Ai_XvD>Egef;Z|PAV+)cmJ+L&3-+a$}YT}R%EFCE~%%*?6fdrPb+euuRv_bAX2 zXY}PpSc=QSrvVzVb3QT{9RY560m`XGI67sbknySkU$-{%N%xe(8tN%xq^CJAtBG6`>>01_PYlnBm=?U0~N!)LvZ4pUeA#4Yxmz4wc)z&BpA8||- zDY+PEWYmHj6P$VH+IAse6TsPb) zFfxV@4sDrB?J{I=0q%|lvSdUoagcw^7ia_&DBS9}WUUFNTxZo_SFmkfgs`Z{B3eO9 z6EI|$?_VxKa<9N-^{rlCu|A2A*!B0^@s)l`tRZjT?Q_qVxA&vP6(MK>8}RD99kUq0 zQqAz=xj@3*QW@s$$R&7Oh4uB?yJcTxq>+&x!t1jAqbvu&muCS*1W$*keMBB)s|K2Y zg_eLW7ULtSQi(Y251w=9=TkNfBS3angR0OFjMm>aCgx5)yFFeG zTcI1p1zy9@TwR-kl)iIRWmqLgV2UWXMm8#agAr7MbeW_Ao0N!bF_*k0va;AD&B$RS zuytBx{DBOr5&|U@qB!<#-&p!&isE|w>oTm}K5~jI*F4Q*_|C&6fTl6coXGYQgeFUa@VA$pC=*(O^NWAQK;#&sd5b-dBuBflqkJwLF zYww+@3JnDR$3qNWtf!0+kIl>*o3KL)9oyTdrV>_v@${ewF&Q(!74xnUsX`O3IPb3e zKZ%EJ8WynoAW7;VTt1Pf$YHelNBswHXeD>43#1Ha%+wpppDQtA*NvZHexO*qsiF<7-#?9wJ;p zj{&g)>IsfpZrue z&@VQLARf&G#s76UJ~vt*n{YfAKJf+noCSMMDg^bFBr>PZ_ z36H^UC#Z|z!>|OCiZ@TdBbQVe;`5?oB5lGOD_uqZd*%pT&=^&|cHpONZ-~6avg-tTJJ;f-k=miiUl`sKHcK zKPBE-p`e;Ljaq2?`sR9A_a=-lojB|7rU^VrrFVUf7W>p#pylIx+ z-NsC>D$eHEV?TAPU*V~mPL|vKq*@ffU2K$@M!i1}j6}f;oZgBHJ&58H_|3JMI8{Br zP+p&+UFwjP!76Mc^)&u1^Y88r9%e?_fL0?JdC=Gs!N>zd>XcWXJWV#7XlqFL>deQ_ z{M|)ck0x^dBmQ;!*?*MK4!|Y!zD{-sYcoQ^#K_=j<2xpMiacgJ);}Uv9R8I3x|`7U z1K0*b=+csoNR&GdD6yab5o=)DcVEk({^3lj>s(h8x=gDde>t)aKQ=9Vt%5b;?}KbdK~1>YkCZ z!lWESe^b0?$pGM2Rz^YzWg={`DzYa3Yp+{L9F+EZ`a*^=q;lYIH%~kbkJfr@gH#q5 zGg{o9#a#6+|JsN92uoPJ8axdf;4l!o7hLio+%n~Qk5e&2zybruJ+5dvHG^TFr83(wuuptsw{ zCsB?G%z;(nF3R|UqLdkgv`=494I0= z`phd&=6*N?Z5e0?<%ZoCU&02$rm;!8mr0B6Nuk)(C>;7RGL3G5jo8y%vdV|zx~59m zb#x5qdJi_n65w)r7=PUnXFbFu^o>2BS|}jdQY$}3Q;s#c0v6Y$1>3O9-kXZ)^fn5* zbTv*olZsTTWC0;({CGD}eE3PK~f`hTWoV8`q}*sv8^g?Cz%OrA4QNo8vI^PJnBkeyXym5g-`~S-A1I z07b+f8ex%Xt+1J8HJ+=6i5+9=GupmG3{8**|d>V)Xqr_e#WK&1<>uoXJ;8z^--lM)@05?SkXQ48<2!;F^`~T zvx1`PuHs4?F79FLkpn@M{U~txqEZncWH1e z_0+NXUpJNDBs(z2fk}x3$PzJa0TQbrCm zwx444#MDMu2}_k7x>t*Po1;=7>6MWQysU0Gr#`+KU_g=XgJn=_cJ8`@(?QjuiM7+ z7;`WHlW#QuOzT1qHo)Xtlbpjjs?8xP9r@;cX1*=8Gpt%A#J8bTX@T?K$?Aj{VLh-I z+vj1~nRJO=S;=JJ`>{NH)S-<|^OvEJSKjoE7qa%zIJ&zQT!!nK1$+(~1CmP(t8pKh_$Y*h zcRuL;YrhS7HHYaDN$vKyJP)I?A~bV%;f9n|_K-O9QfdGICe}q$oK~eT6>Ns5^~@om zU9PgAWm7Qk{IaNSe%o56j4BC%oVso2|1hg+#4TeI2ve*6`43mj(2HQ?o(j|8nPN6` zu7b8i+0rv?tdXZMDnkIIsoYMAru0&qU+>780vVgz4uKr|>Sb%6iYIF|4074+v-s|g z%S&Pk?|hBu4Sk^#;!auH9OKTxkMGFCC5zE0hg9?}k;^<&*4~&snLY^WMZ+xwT2c-% zfS3{EMZL5ruOL(F;JEb@Ns}J)s6*C0kHTtbC*JMz+3v#ipy3Zqu%}~0dTx8TKR$<9 z3}GOYecpqgW*KLByglJHIun)NxLJywC2FWR4)bnNjI$(KsKt!}-lk$GGQNT1SZ=#; zuvk~Y@MU6+B2|#L!e3b;0WGBY;vqa*l$^BGKL`w>VNSh*p>#Jqy6=!5VNs2Z8qbv# zl5Rd8K{m@2#K_oZG}#^u=bvw_qaq)Mv}yV_XO zV5sk=BBfQC$9E7N&_BQ=S$GA&I#7U6HFJ+}gw}>7aA1DRbkAy}7;-KGIOX@ryIlBm ztf*Daz5^Pt#LFZ;_M9z)F_Dp6F@n9*(@FTV z=M19?cnM=j?NSfM`~uv)T(n?fN;e{Z$v%im5TmLi!T2l{$NxlaJ@v0{oGKq8wa4Tt zs}ET}b%*Ca`Sc?naT*?`X&dS8YBJM;NP&2Lefljhfn+DLsQ@cAO+)vR%?>Ops+k-3 zA4_Q93xhH8FH)3{|Lb&oR$F#Gin5&Ftab#OIGDJs=owF3@+9ZnB?F)NI0g3`{Oiv0 z&MMY74>JM7eNE$+U@u_FLbFqMJU^)%utf-86r7s5X}|@&{CXQ3_W2>Lwd=}cJ7g8h zUG|^{?KR@7;kdrtXD`TdiMiK!kD7Z;qYM?2IQfU%F^vI+P-pr^OxH~DHq8FyIhhHN zXb0R_#eHZ|mdy?ovzG{PM#OgN8%iZP;LSZKDj6i-&5zu}KuD3%Es_Q3$pZxhw;Z7ge+W03 z3rja0@*6$yZFjOJkcP?syWdvp9m-?#)>U3LC~nXOS1X3{e-x>zwfSU%oQ0iB2(ri= z9;}TWFBO*=eI2Q;PG#cV1kS>LCW9Zck5~w|r>>%!)$^RE)>w5PxE1d@=ae%Z0>x-7 z9=&6MrODz^zcWf&R!rL~>H$-=#tNbKV#g*8D=;I*@zjA`wQ9ny7!kVi-}?0$dlrqO!uC6ZBoktnaS5?UuBKp?DzRwx;#h6^7PvPvy8w_jDzW6y|1SBW`^hZ}Z0=npF>y@xjF z&-*LsjbL=aO3Xu_Dgi?f~C}Fe) z6re8Fd=hSv7!GTPt4g^fXJ}UGrzO-riJVN`dcjv#Hh>?7pSb?PtT-qV|n*Dgasj4F?KRKiP9kTo6%Za zrLRy(E8bN8Kjd_u_TW|q-Nww}GYcRmmP(?CYOk&a5YBcPX{a6SMjrXeO;z#`_%Mx3 z3p5=J5(NxYhZ-qcj+063Pd(?bn5B&(I$!~%rDFSGm)e}oN3<5fkl>lm{MDcCKnWh% zplP3#1i8uOgeicRju8}x;ZvUmiNVyvVq|`{1Jcu0Z`?z1 z=wwI^1`5#TRGxIqOTv}UiP&e^vi}n2tS0|tNq&_)XY3SU7@G`fE!+8=k3JSp-0E+T zmJb9q6f`y69_?0#-<#}2l2g;TFgRfsdcX-E!*4>>6rI#3>&45;H1)i&pTc0uECC|& z2)i-}1aR69ina{TN+>)+c}e7{{(d4!5g_Nz5g@h-rl??pND7Reu{R{P{T` zhkxCv$0fCw17*6bT{@mP=oO<%N3iW`e7pxqJqPziR;&FWgan9rD5Z6bDX4Q(*@}0i zthY&jfgwX{9F47H<5#u%Oj*SpIf!blI_7s97z5b{+P&&a7hu&d#_v=RK`w~&L{X2h z5Q|megM4oc13R~qcU6C4{Jc3iHN3i{tN@VV&q@o(K4SH6|Nh=_JW%7NU7yn{Bs~uU zY6B#_4ZmkSny$5#5g^WG)hgLPV^!C6o ziCzSaU5eJ)5X}{jnL3zNjMk6wuUj!LTL8rv#qT8A$;D$a$xD%q@gW=0-T>JYK#iml zajNK%*%Bc)Y$|8GKuWR1(Vq_8*ScO8HN+VoPi#JN8(INCP7aMujpsNt%eHx85F9-( z^kDgyV5v(Dya5yIUFm=EpiU+TAjT^q(&G&BHMWb?xk{J-vqtZ)v0g}11d@RR1cqai z$RG??X0*sy15v?>^y`9S_YEbUf+%{6|lwQhZ~^wu<&SEne>8|6qO-J$a=P; zmOBm}hwU=i*TjOFVJ4}VD$^Eu<(=jG@MdxllL46u9`fhN;fJ!Ff7S)(a9C~A1mE3X zlYGd&pNO6go+LgnHIsmbNN9^bADqGGJ=p3wxOI_bMxKkO*LC;JXH3jU+v^v3!w5yr zow*!#aIpNN90eE$_?;i43){MBy>tWXC%x((t72Mb!4nqz==yT_*AKqmfs{wXF{8V` zQORRud}d_FEvpe*?DL+h5wFHCF7b*%)TR8uN^jT`orkQV>g9v)B5;KmbV5|(IU19- z>2vPeCToa`cqVgWqb$CQNOIcPLUk{N<%V{gx#Cg#kH@1m?iTyzf=T0F@rzs-yAp@A zWeHpjeXdCX5AV$^@w}-ihUpQz(^Hs)pe~VF1f@=fRKvQ=e5h9Or&iTbUD3oNn+=g{ zz54PWbGS?EDGd(gTM`MoWKSHyT(VmncKASC*}^Nm9CsML`Lnorg9jZg)c1A68EQ(F zcC=f6uhhPxIur{lSCA$b9=(R|D85GLBm=$2&omb$;_z!s;39`DMaT4Loz8gI?OxHp z8jEP`F!s6XjBN9E;9W@WHTY7MsQig@I$s@$Qa9k3%zAv)_?v83AW9CwbvFHHyti<< zkr7HSCF&FA?)&FqaixpPu`^FHX9a0rL zMK0=xxs}Y)1xLot<+bbEzZw{(yzbs$eAh3qyk3RhO{gq9q%D)Reh7_t(ol}`W)5m= zM$EB3J9r&T81Kxag?gfUSV2swMI@s}+u2WqL|RKv_{#GrktVe51Hj2Lu4qpVA<4u4 z!FN=LND^?5Y{M}}BZClpZzGbvz@K#&ln$3u7-nXz2t}%$#$eSQjyAXa43%~8^uagg zE=3qdITwlH2{7EIkR+p{`7g;gCjCpJ86tz3{g$Qj1e(40%(cB?nBg{raZ;OAQSLTL^U zc2j^Mcu5Q={4Z*_%HNGz5#TFaVIo4YVP;&S5(R2VX@tco^kwhb23$%+o^HEJWa#Ai zFX4szI9PE=@2J0j*1astePV+r`lX~t?pbOBoypA(q*A3a{Imyk`8;l16h$07_VhMv zQiNF4KjqZ1Cm6L75cyVZoTzyAE%&1?EDxz&S(ve9y9n+mD`P_!MWI3p$NkqV8bV-( zQc2s=6R$m&$P+2WFy5k!%uq<+vo6W{l1g0exXrs z2#OSet?GNlvN`d@>V(oiEiXu67$5x#us~Mtp>f~`LV|GgfdG!|^Q|XRRl0fgaC-q; zF(dsP!8@{8ltV*m$1Hj3?ca}OG|o@?zm=(Ct4klVW(?Mz86C^|H2XI=Z-0<1j$i9R zf@kCQHPwiKphSx?W~T~#t`Js=A?Ov^pd`Quq%c^0g`|+h{M9U6h6J-ggq0+{(KcQAUs5X%#s%+cz(SFbJa&+H4CERPbL))z1 zRzfsyFG(8Lk_Nodtvy!K2t}>o$)3+7;Y*1t#JT`(+n|1bES_w>=HEvu z^CF095uSAn*|G2VE012FcETqC$Vgc{B>KK0X1bNv_9`0)VdFTffC$-nE@T;I$Y9r@ zcl-bk+-^0sZZ5zX03m}jDTA`=$_Jb37&TC1#JV4@Q)^bpnvzv02jV4xn7wGkp6udTw& z3fl&mS~r=M43<#TmEJ+rAgK+M2euMv8}N*IkclmpeZ{T6`hlDA1Wlv$_T1){%RXgl z+vKLEW$)mH9+v$&{ALD+#DyNU4Z_4mhD1x4;$giCRc2AugEEfvt?_0CEVdkr0PI*= z+UzKu++5VQNJvW!shs(RC0DMZR2oL6?77`7r7~~I@Jjq9HgS49z^g^+RQrXQsVZn> zc#XNmisu`m4g@fu>M%Z-CAkslNlm4KZZsFu3>g=r<8|t{U~njCtfxukby%mxuY&5=uWX)MOoc>EZdsAt3&m9&@ zT0{830o#b#k!GdXuyEwv;5$qwKnPiLfta&ghy+!a-1G;55kn!iUvk{uW4XlJHAEXf z8pIR=wbM3|-2Qg%5NC^OOv4_={_we11Yd?b*RnWQ`t`m3(h(8G^ji4o2(rd@>7{!R zuvnEePUHu|vt1q+^CoQ&51Gjj!VQCcpZhI^(6Hxn&%O1Y$y=-h)aF3R9e^{KCDPH% zJ~4A7+PQIU5L32rtp{;@0AIbXBz@^X@jZYPC{xs{gh^Wx<593`Ims6G0y`?ar5*6$ zSW|hH(|t0^csFCpm)9Hc%j{owJYNdmVG(O$ z^MpylU%32mJ=g{HAjr3ppnP@VjTOO+`eT_iH!|Us=n};_iE^@K3n85~-+j}+eVWo~ zs1NVC--1i$P59-d8l-8uf`~}e*0EixE=9mMN=(WB2&%9v%eV@mj!KoPpykubHv0Y> zYK;Y{s<2qjM&(m|OF%YA zn9&OcQZUT=HLC1maYS;)m5RZ=&f~*hD?X#{bMAASqFm&sl4t3gf|GRIs zLwXu^7VJ5!I3qPp;fuP)+nT9a-&A|%|HpvaH$oswFmA|wkb<@s1-%NP&mxKRzmztq zT|v3GP5wuZ8B$2Bylh}_gN`-h%{->`TcQT%_X{X*dT6n&)^{p`JP{rVxJKzL`BeN4?EWSNN)cV3Zzj!4cxiMvUM1uxBb!1~* z4(!mNGjy#7a71Y>!FE2Ja+^t>n^!z5BqFciA5cMtVT0)AVcTK)9d}ozeqR1`a>68< zc{{|O#rdr9IoKBEfd^1B#$O?3O=xuBKYwue>y%c*NX9*nSr~=-EPiev=CSid4t7}-3 zZ#5JM_dHo*Vo+N%GP`3MsEH(2o?S#*t3Ae@0-Nw`BR%c7_!REl0P7jSs^j1r>zJ$f zI(w^79W1&{L13B5e*rw?AWI3z^u+uYVJ7^V* zW(n=O@i{kremTX)6t5dm9VfBf9+%ec*tl&vF{a52n++9SDhxpR;{e;h6kgvJ+Zb zP&y3F$<{}O3FWc#lDHAB*MMN*i_~5eX;}#5tf?>EhNsy#_4w@ZaqJ5skaO^xPS1cl zv651#Xk|Ke2FgY|^z3pQb0C|HUsa6Z>*TB;E zz5ox`;<2gSHsRyd55nb8k%lg@P?Fxe#E6pXCY8t#)pa14+i3+=BTlvEj+7Qb5B`bj zAh#RH+ME%bh!>lZBoejmp7q#e8~()hf!2-q*Da3KauEwAjxqcud?4H&HjEEaE$n#cBKwe*ge;G+|)S2VyMF*xGh-V3Gg+es1Eej^JgQBOTojo zG8l$s3LQmxLeJD*l}v zJm=50mNb~kM#+ZU@Bq$bqHvnHDwt2ZKCWsL*p8{wu=@dHxKMb!{lpaJ5DktEx1Rc> zd%XFk*WKg4KKzZqrx)>;$3b%;n}t1)tW_7gu}!56ma^!mA<}WsJnR^XsLZ`2YAfSL z;T0oi6g)yQW(M*b1rEcQ)@hd#%;IGX6qQLUA+WMH&?#$?~hA-o6JPr6rjz0B~^;6z;NVa+6eL2bqX zcy<&S+DpS*+N)7yF*S;gN8qyR)UrrLO4I~y)to7f&BGQuq%GyLiuceC0)KaBxXO%O zw_yOiOXtkjZQAw}JY?&8_}8roTNYS4>+zebSwG1#h^6nfh8Sf>ss;EVCZwn<($f-C zdgw*r!((Ze-sWi!zLHC8*v7GEYQa6lC-KW5O3GWQky254?%cuOpn_-_DoIs*Qonxn zanQg!ThKa6Ah9veL$|r#N~&TIz{9XHF(FDOgyQ@#f+=Ko=J>r2VVG^&Gq&ehk{!eJ zz$g!GnY^W&W!ka@QDDd5*yN_^_CznS_!YQ!LkU2#4`K}0X!9D(ye3DiC#I9f4bR&_ zeQ;^q_3nl!Psy6KFm9=P$|KneVJ;Z*IQ2nKxF@sjrkTlmwo4wA*ZTGjl+{7Kce2;B z_VM5-KJLMJ5S*<{wgSk6Tv8zu2MEh7SFMWd@_$BxtESV$H z*5-=jTt%W(Rv1#aV(1;~{*h96L__S|QEA1j?LoMuR*-uH7m0)JCI^QhjP_(tg`#)j z_H`wNw;BZnFcu7s{Hh2X@LQg^rHdfR3s>QuqePZ)$Nq;fle+WF?Ng2R(87#B6?GEb zQSMc*y!yZawhgqN)F7zmOHjn~t}X*ZQ?ng?9j-4k{JaN+VIQ=G0)a000vmy=ojfuq zK(jn12X9@yeqJl9oleQi67h9(g@?$<9E3nJdNJ(C#4G~k4nHFY!uGsc?7=Nm?B-uQ z|2Gs`>qq$49glo0w@GevY62|H@$^0cec2J?BVRW0^ByGkOx&7P>d055T7jmZ6|P?L zmPJC=+f%z2Ibp=I+}s$;+rH+6XRpR@wGM7j44)=V^tv9~J)7L>!*FeQq&;~A2_X<+ zgZRH&C)z!+hwS!PRP&(3^2}DT1mmECx-LP=-kCX6YXI`BcP+yfUVc?zH4GLm%Gmyl zG2v@bIgkN{Oiq5*FZOf7ck9s&GC4=a!us=i05ecFeaE8|I6Jcuz9U{d-HL6Jn*yx~ zFMImtp2kJL3%A41YAYX%f&o}@KwVpSaxnAR;pRlB??_s2n3y63%;6j6)E6?dD*>m@6K+4VcnxP8m5VB`uy zb3i>0_2hj&iktg=6m66T63zZ^% zK?EEh!9HFK+dbrnm+{L$rp#iqQ}RNwEVH7JfEWPdA?;Uk ziUp#j=Jlnz_6O|k9I$#>Y+b1vHmiy@oq5=6Xxx3STl4aNqQ-GzV7JEkENRw)HXzCX z`79mBsfMMCl?r#dUBMyQcBKcWYTfSf-!;L!L$0d085E{yn^)s zlu_3ey+GH}xg9(RoG6D?y5n?94J3uh%wvU(3B5D3=~QkLW*FcN|9bHsK7*%jY>Dv6 zz6av+DVso9&t^=djHWqU3vXz=xAx!<;MR4q(bk)Sjm z1+3;~F#u4*QdHkP72ZwZ#QrxLxZM9$*$Cep&IsmQLHF=$mL2hn8}ZOhM+olm>A&+U zBHLKcLA9KRsB=LpwpZXmwSwe2JJR*i#_5fVo|;qvBT#6EYLE#T(zp!$i0sUOwai$C zhhsC@VcUH9?J(g@ep@#)4rdHM=WjLraa|+fNGU)WG)R6J5nD3uZ z6V>-x@k7-_IUCk)=%G61?a%wge^N5XHAv=DdeQU8RXp|9vm@JQTf{tBD^gcf>238hSfQs@^MqZ#jD!YoQb&?9xNWJo)zRnu5ARtILFli|~xHB=X zBQcmKqHs>3Tj%}go!{9@3H|~9x=rO`NsuUeLC&ywkpxP%dlEEhqi|tyYmY<0_)@Ok_s>_Wjy>Acz6dz@%XXG5 z&07g`N38kyjX!%c1w>HXts9q0Km>kj;2i1NnLs?Ov3Daq>`QpFRD$%*YWFH8B`qB5 zQRhkRF$)+p-b#HR?2AKR0*@UhMH4fnDk3a9q55N1i>Z~MF!C!@5JaIuxvHTKxDr;Y zXHwH=0Ysr*t%DzX%F$Rx)2z@v|4}S!$uRhQ&=TtbAmP93tZXB=!=dRZY(So4S@ZRh z-m~zlP#DiL&8@}>*~qw+ToQ^w^&Hb$S4+h=Dov<}Y2V{jWF1K!?2hIctKRy5Px~ET zUh5wlbjHX1QD=?^rp0ReR&SghE5VmKvq@J5r|imHBGxapYL4Mp=QUP=_&Pn=<@MIh5k7#4%>+M>E|33xpW8JD>W!Xl%b3N>tiXDCKXQ`lRqPwE z(I`niRlr;%76XdjnVHTivU`?VtGC_TodWD+aUZb+nuAu-aw^67J2rglNIY4K=eKmf z+3%EyB4Kz3SQ1tA4ibkqfX$^O9|9qz*Hsnb>mq{|uTjj3@dQ>;@o{4IR$&Ad8#7${ zz|d&TRR<94JN%-L1PQ64U;v*QqeU(C)~<31GT^S>3w|;6=Z0^+=rVe?R;xi|-;>C= zO#s83GImgJ#0(zBNW2HH2wnVTr zEl@h+y)z=teTQWwb4da!){*dDapjM9uA}`ts$u;<(E3?MI1b%sL!f$)&rMH{l_nuJ zHMqJA4ue*oTd&kL_meo@gS!z)%X*_Ttc$CRw{FqU123>V!g_dlB??kCG+2fYm7FY3 z3JhaRbv`kKc` zMsLF}F11O;suqPetQ`*$BR+I4pG8OcP>-l<>fr=gMKif5`!_`~MmbE%REu^sGz%1K zJCPF~8fQu~%B_DVU-XSXo3yj1z>nJj!Gc%YFi} zBH763^rq{MW=nr#Gwuyi8A>Ilfv56dIZg_}V0Wn7cQdxt6#~LRBUL5roJ2Iu1Glm)S zoVXCjG5>Phg+IlEHTHt|6efye-sUS`^DIf@)%eoYwmH0L2@!hu70dE0|MgjCbpq7R zS=A-I0Z2)3pROX+Om?E?hxiGYX9zNb&yCMt_G1!3tyxb^xu1oaqSwgI>gm z+@??8iwY*%$pC%r`}z8O*W5TdLQiS1e;8pb`G; zkvN$gtyjhWxNSpQ#z#_`G`BeBMOWtHg&r#fBmBvPT1;v@YsUguKwD;$?h?njOwD-8 zTL{P7aku}e=&8xo-+Ven_RkF(`1>L{+m`vG(`wbS61~vTF?s}Regl}ZG$RC!|pH=S8F7+0RVE0!J(`67aDiad%pkv zzhE6r?bUmIE)NOP`5C(M-3k$e+fMEgr>0gpH(?%}IH@RYl|-Td+EZ;j?$~P|7HS4B zg%XQPEt2d`hDHny_xxE5C`ienSjc8g`zya2pllkDUZ34_7p!XCd~MqJ z?te>E7f}9{ZPb8?8K6o`)E+Ybs!YLT4vjE`)kDR?M$n4G>cG9gijTE|B&{vfh znR7Jw8zNiw!LOZrPdt6=H~80;>hAqJIWFdH^Rc~q*S|#I!UYk58SM3Qh`5!GTgM_s2~H7Qx!qcpcca>$;{!gewvml25{5fLRNH6>ZMjIFY^9khT2sv1cyu(%{oh(c+$FMrIJeoZMhY>wJ{u%t+rw9aNzf>hfc zRMCC$DfV=5V&%}(_PIp44@i1Mo`IgQc$=5*>t-v7qE6;jb%_Nz?3!^*dw~~oe;gW< z8Cnzu>9ftqC_hBhl(?BL#BRGG>N@v@k3RYLtMO<}=ezB#<|3_|+Bh;jd&~A)%3}iC z#0J~L!*fENyPj6GX)U*RT09qi!*E5m?klVlL&lCdhHki|GFC5gcyrjrQWV~~8=`x2 zA*KZ|N>#0@p)UAaj^@BCz(6@|vFuQ~46G~x;nBoX(tbmm4*$$qx3#k?In}b;1^M^{ zYST)%1DqH*Je?gC55cEH$ee~oklIZSj!t1XP)YAG{Mv`S8-4QOG8R$?R&`4<9P6< zJtcepVLqkwonm?6PzoCWOBxBC2ki9_N%E-fSR#jWXbcVYjT&m;tE+PAXTch}SRozP~@d0+yE_k?$2uh3?GJm>SCu6=+c^&#B3Qae2> zuVgVZh!FdK1P9plgNT-8cgcp%%3K{51Tj{P_KDt13^=~jBLFJ7UZ6JW1r0=@csyA> zyOC9;7sRLOJF#%#qh9)>FW|YG1~cqkE5#zUwGfRj*DjOXSaw~mhTKFHcq^t+fEHe2 zGSPL4B)OTYacI5o5z~$XHKtQlv<vrJy?2=^;X(kzOz%A?8H=O@AtJrZ4c6abwFFmq~-FSP;NZ-=2*=J*tA`+KSC9*3> ztx>)_Ew9Z*o18X&Gj3nOepQ{k(gDwf3#}GKz$DdB6Nsx`*(hl8?Ql~$P$#se%IFF) z+Ub>4)C}wz4Gz2C@LD_Up=(5 z;9s7(#R!%rcQqy<9)R^84^!^o&{3$G#Gd|%ZPU{j9XyB4F4vwf>AeHrwkYsog**)n z_<2rVngUv4v!Vv-nZ;l!YWa?WFwi&V#+SseW3)Uzrm6`u&hpCi*Zv zfIj4gW&}_lLIe9S!+0o9G}~B6pc95R#2R0bR-}=>aEw@=WAF+)2z0=vl1KGk`+8U?XNq`>AHg@v{@5c5KCygqqpPP z_G|$!?_3*o;AAlj&W^8QnbJ6wdR^6j1KnVt6L!9rh5!-WCi~Qrci-!^3_y)E$aA#d zd*Sl&=y@1M&l^+}=j5!}!O6%;i7;2)%pn%y;TjokT1k7NQcr&V3<(( zj2~ep1uRkwvEXG_eeENs;yBe{0z|%#(t<7U;wV-r25lPb3bXLF(E-$2b{gak_%Gy4Ej)ipxnzI%{ZI(-IhC2iamm(W*(}FX$Y)T15 zXHr?#3Xdtna2%J|D>>I#=FU6qzld1AX+!(o*J+st;PSF5^xj24Wm|~tVW-!aY>!RP ziCVtyIxX;HxO-h0^C-ub&)!L;+SY-nv1Hq>sX{0E2k)%hplX7Nz5CpA0`wMfNMC1^ z1L=R-WNv`+O&Lk_c4Uz|AN-;3ZNkGhjq}?3M#+i+X3^H^v2oOPij!qAqs>oI+nE#b zeBFM@iYRcY_p1~zq@E|eVym%h<7)Z`gJ`Pt%-Hp=0hr3prDQNlD{7O9 zky&)U4kn{8KHF)MJ{`X%LK~9w)YE>u*&W|}_$y`>VO33oX!pKpA?(UU$%gdh9PJ!! zmtI>mvc^@+j%DwN!)xl|P@QgyI*uGj9VR9TbKoIiB$|3R(NihErN%8qJOW201U07< zb8Ev+5Bk#KcVeZlk<9mf$c$nU<^TFVzw2Hh6(lfRnXPD5$($9Cil*b@;ds%@=KGRs zjt5d_{L6fx`Wlme^|ufm`_l{kL(a8i_0HT^7`zG^h=SE4h3xwJZ#aVKLen6Vz3-9A z-3^!Lv1{wP&q#RZ;A;nrm}2%pvc?McqNIfPYqfEwM*lL)i^8V2n7-}7wH4| zY%PbCM=N14AXJuWJGvV#z59XRW!~MicW&?diW!0=#8kbN=)0aO$2rlRjkU*!7)R#j z`rjpSybCwNoiT0J3h8jXw!@N`D6x3;R% zQw(iUoGO_KrMdClZ+QMADWHZ~5_``tO0x(Cj;;TFP#(1EM}%Y=&dtZjH`{RdbHGvG zd$2_G2Hd$kx`jb{+jb{dT4odW8bzRbGFAFsMy!meYND07F|N+6(W4(?rorgc5*Qme zSl?r!?jZ}VqTV2}*jo`|IqzK?Z~7h{u~975&g?}KJNnje7zuDl2<85`tv#`05Mxj6 z^Eq&WAr+3KMx`C~7ki~p8YNmrje6AbCNlhgY=T1H2K#SQY!T8)b>(i`h<6#w0wWMZ zt|dILOsi5C$rKD^h~?x5{QkF}pjet((f&=^a!0P=udPUjKrX~x%usiHLAto8$1oA|NTNkKInLb&(y z3n-`;;WuR-$yP?4qz`n4Z6WPjf&!f$ni|rXOz8r>sam2VRY)IPMPhwN8dtZr?7ZLg zXYzSkJTSZ4Xuhz3LU033(=_1K#-U=&WQG78gwV2fB($-q>+>EaYy)afw7Ci9X`h>wcw% zPzurS)*8%ehEk32%0x3Ej`L>@J?x(-j$<42!T0N%INH7>hf~#fwQ8jmk6*R%)O85Y8Ad2 zV)5NkWwY+wY`$a(BK=juMCg=Sa>_{v`A7OT#rud-7ya|kUqkt^SFYRde63Qa`Rx=4 zeYym{3~E9Q3;c@yqwREx`cOTIv;v;YBHgtzDeX3K%S2dT&R*AucPW^P)e!EfH8^Wy zxI204`gKCH#Sp2BiL|3-tATkgn)vml6ysO%uUm{?mlz3&k25i1haUDpWmZKa1zgaiC z7|;r=X=Pf=p<_otb*fYB(DfTBAy6%mKmt)8-|m~R4n}D=f3nbmZX}-fbHE?7QPrh z44Wj-bby716XwE)bYXCq7kXIuzjNViiOO!n>fPo00rId;nmQh(Y}ob@xfOeoV#(JA)I+ADOaV)E=>`nPX>Q%#pGp$QG!QJEZ51CwMH~ zqUfZIghFVFPm2DP7;KGbSn0O%xO~q*;~T7C78N0FGc-YHA zZN5MIo2+^Qzr57>D{lb{>JR4#utO)ZE3^d$E$T_S(u4G}I^96q?yO>?#5iDq$thNT z^3khL-OiOa?cA+Kz#NBjr-$2UqL_v@#j6%-@^=kjgTHTwJs==O8ef%u8K%k}yiQLa=z`9MIe)YT6@(D%f|1#v zSN#8m6i*#L^4>R5ibnuNb?eVBq(7E}%{TV`5Poxs26l*;rzE;ipD99?T8bLsFDdOJ zl%TxiP~ax3Z8&LG0HOU^!HRq*zdiZ1+B0_v>*m!HzviZora6aue_0D_o>lH8_)Tj; zu?~}Juad|5wTz)68 z3T!4oU!|MvwrU+KZ-C|fqP^GZ)SgvKi-FYfUkGEL!>Ncp~ zNJst#!g(H^Ac|AT(?s(qyg+uA6ss~=8LSz(8gG$8d&^p)EYYwQtxYPBv$-ZCjr;@% zbWmB9F;wNuBQAW`LuE}me$OVoRn4|D8f$kwvnGk#$&say<*{01j3tuFLCua_H|Et!!`KX zrjsT1?$=rgYWv&Z;2IC&ASA}AF5Cn%G>*X%J$2p$7|kC+=NWGBQz|Y9Z70@2HXJkuU}Z??%ANYq^1HPb>)@8t#+jc8NCWO51=2Z+Ta?oqk8Yr8Nhv;%zgovVjg9+%@+g?fR@OI(&0DME^^;`a74!nmXM z1k>E6*vD``==?hJj>TS~Hl+v9{|g4}azvOi0y90XeIewZ{Z!%U*;E#9&AoJpa@kuB zd+4Vr%7(-8_T5UNWMvuiZ718e+_n!kf3iL2ZTmsnvsZ8}yVN=~C4?ZD0`XP}b_5bQ z81p}HUASGzs(It8iWYIm7-wDt>z`Fdm8J115Od9QFp!2!E;#UqYw1^-s;m2aKHEXK zJdXqPLo(bxXAGHdfT%KsupW5d>cNw2*&w=t;~RVzlXbW_-QMAM{JV>IEzym!FK|*S z%1DK zSmh}O1EH6rVMS6Y>wkBO*$|~oBr|=9g`L0Yd8aJGFEq`B+;^AC@3c<`_!$^!pD{IE z#$1q~9m3-Ilcahmks!+V^DjEm4 zi8t>1q7xAm3sfDzJi3+lqnKv$a@~@Fb%q5l+xzaiz~bA9-|dfF zx;WNM8p{+I0Xr)tkkSz0LlZ$+A=<#0IH7sLYhZd4F$-Gvt4>0PZq10ww9Ibeq@D;1 zpGRhQ6A$y!ERgKbv9g3-7uEzU zwy`SOiTm_TzzE2}iB>ofyp6hkVo&uz%;3V`7xnA#O6>ctj5@ZQJLoy{{TEL?o^olj z9v@71dt5#qgvoSP*I8QFJT)?i;{R5R4eh12^IqJ_KDF=~@-#k=PKlzyRWk(vSKm`l z+K*6>2W>%m#+z4~Qf#gxHSjdje=b_s!Tl`NU^Zu7wXGz-BdllpPu_djeeuMt{rJ}% zbRHr0o5%tGy?6;jM5I@gNxzWab%lZtC<;NSOPEt?JeSoV&-r(!!yWCahxhnw3&QyT|S z&_-*++z$E)Ya#i|{!g?*np8* zVHHCz9^8H$6@b4kN9+X~Fjo45!w8V$k$fYwE5%DuxroSY^Z zn1SsROCLlsvejf)$4DN;7ALfkEA$PZ4=X2M(R&O}F{Kz996}LjZj)@nn7)L&nbz8D z60aCjJ%q`&VPoZ1Zf{?!S6Zt}dK$Wv`hozqWT-5*rs?Q&GfN8i;Z?RQQJWPj?2}37 z?;{fG%OL1dkyd44WP9k<&R_lLm*-(gt;aO@r>E5ZiBm+EjZ9Axz2?3Kfm%)yMaf#1 zda$kY@w=mYx#6qz_K^!2Oi}dM9G?{(svPVbv>6edr>{q@bm&uygj*Yfq*T zUyXm=!SPs0lgz^jBU97eqXjI_2Ar9}q?DP7sb2Ez0et0R-<2AeC!)Xkbar1SeULS` z%mEa_stzMMsW7NBfB2MF7?<6Y5G-1-H8CMrQ`MZKD*>;p24DGd(^Px}qzc=0Cr>a) zC_Qc+LkD&ny=Zxtow#DiX#3a%cEOBcHh+TMzMt%W!=v#$twjw+vQ#2qihRP<=w#nI zjGhl%cOQJX86OUUY3gOe_T{*5rB{SqM`Qi%K&bd!yGwb9iu|L2{(P&df(Wfd+5i}1 zJg&LdCfPx4kO*PN874bm_nB|SGh2YY;b4kzX!cFi6P=FG(aj3~jN%KhQs~g7t=4Ha ziHxH|yX|6y1ju&W6TqyDq0NA&*gYGC#*ib4@6CRV2ifsj4{n)$2J5CI5q}{zI1)Yz zVWLK3pl>BwJ5a8`QFkHI zLvVSsU&bkCak&SnJ_X+pJG@PD8Oz-VStm_2cBZ$EUF1$bUHXU5KJw%Erl#>e`<|wy z819*x8Qs?II}ztc#S+M=Y_^XFx8UO*9{pn6xylAX#oJcyp#Oy|Ks)Nckq1TF3&RPw zxrm(?q|5eP%R_6F!#)WimsQdmrVpyJXb6M3BL3Y5|WCL_#TZM?z5=eS#XNU37(8W?vT9V8;fXDsRNLfvBPYAOe5o@4BX4|BtiZ zWe-}5GdQ}P(5aG^Wn7#IiBU{Lqf_H4D@H&Y7CESc;d_x3tK-XKu#NSF7dov)l9^N3gw&b>e&iftsWmGN6*j0_FWl0P(eOcD5(-3(1pa&%jYoF(*us1I> zC=yhNK%vfYc*?tQ2+C^kMk3CJn2tT@rNn8MBfbi+9=abW1Q3rtI2O8V%{`t# zC*JxK{&l}&pMG!Ab!-Aac6>+Q@ks9zy|ICHi(eVs#4A1cQ@-UznTut`kioXn{)iFG z7po##B;MJ-0!&LYpeC5w6i+NsvThgPEf(MRn8)p5EwZtla7U%!+}1dPKr%EsF*cle z5^=r_Ek@yOMwfb6{^xM_5)$DK=ka{i)~W!p%9fWK6&}qj>}>{UsBNLVU+Oe*Th-`m z0)P@IrFMmfb4bG|N>maEYFV)O+O49TiM@*+^JBUQVIRj^UEx$rcjV0~c^TFqQ7QfNzYjFNAT#zNb z2fwx)IT;;M#~7nvTM-k0J;Sc?R!aY1*EVRw1vGXw0Wp!G(__sZSkz|3>MfSqWmmeQ z%V~@t#$k`7t~@4O@!7S1&l7(eyOLil`7qg=zp26T=Fi2q_G^J!NuURSPH$zmLo&2~ zu|m`Un0V*aR4X5y(YeJY#f#9f%GjdlA*`HHpb!F!a=ONicl*QQ$KdIjHpTDr@%RfP zlTrL=CjVyU3LIV+w3s27nH3J|I{O~s4}x;cEfXxAM9~*~0F+Ky8}L%R|6K$BchQr% z)`mTJ`(C<`@BfuttC!E6Nx~W|?eB1%P<9fm9h_064L1M1VxQ7lP+?+-4d<%tdu1(+=^ZFx&e}MK0E(nO(BigZ5GU^0g&u;(r*Q9aD%uq1 zEv-!GpuxPVJl5L1(jYTIfFIz+{l2WYkV>?HSEOgh^LwIr#0(FcSvh0?JPUb#sEfWn z-AT3tR-syuolYslcI6H6kD=84Qt{mBf6b+RlIKkl# z)H=Z{EFamG9xRX1S_`x_2vy=W#v3%s76p#AW-S!~W}ZsycEP3@XxX$MTa#P~48Rvl zGiXLMJRKDdLyu|M?)i;g4>|1|c-|Q66|H+UXv-Ulw&38FG1i7Aw_pNt?Vs4Mz`~GS z=s`-a!*8wg~VtXT|KNTNa zL0ZQ!=l$h>?qLU_HuWLCNm5~HWF@%buG4G|!^g<>My3aGBpP-FAF*kA49%ajqcgoE z`s5YGnyDCKIZkR2;Mx*v0x}tSb|5cA+BJq|`yO)h7u*=#?-o{M>`2#iPH}ta=``2`r1IAuW)$9&8|x52tj<-PcoUOI~J{_c&(;t^ZqlDl8` zTPu^mPUy+L^>7H81(Wa~-^FZYwzqu@B$w8*ZY;o+&QLmS!s-arY#MdcxV-bn}AQXTqoRx;;5{=NVTdM8l3A2==9W8 zimC4i{WEL`=*T~+GNWK4Em)T(mn(K`KG?=1H|_nX51Dbjt4d(RT%6rcDvM<7KMv~RcG_FQ}O%!rtuaQE9yjLDiQL z%F6fP2i3DVphIa0Xu)H$iI=(@>4ee~+$92*!7jYfQJ3u6dn8uUG`VBn2PD3`YhYhdD~>^HtfU230xc`_`o*kNnY$hd#vA(J#Ka4m`Dq-J!#7>`h+d)Rfe4m z8_ zGo-8u$d;4ZKIS^KTOvUhAL_{xkBFeC13|HFLGGSA^`y^P0}RjH=?-Zh`Wq+_cUBZi z!6>El-R?42A{O|A(b%p<+DJC>Ds$E!6d22HXY$b`EDC7!hHHut9<3vTrQ^!HvZ6jh zch;QynMbngq;Y43A2mb%YBi{JSlTTi(XbiW^w_3Ny(rEz@s&%NJ0_P;&jCL`{F`nf ztqzoT3<-9$L~dM7Jt_q`IfQR8`ZJby*7;|j@<%T3DGiG7Q7HoZEYz6-%=grhjdekf zC2}>Vv}Xp-(6t_X$tQ7pztwJ#$Hi6)M&DOyH;nOw{$-hTn5`gr&hF#`|MdCQ zBn+FTp6;uT_TZBHj%$x$mvXF^xS#7C+-M*7u-G$jXJPbXr#kVr1rT#|g80Rol-!?H zeL7J&krC1bP;(tiiS8sLekHG&z$1Lg#-zB;ANY_9R}y$PO+DTB@6vg8Klo8>s5IhL zPbRmTdd(&;Zayc z#pa^O^V$bIcOxF4X`tS|Zxm~HIuUu^>0`NWip<$WWO}&J!>Zqbd)M+c1i-Pt<`AdQ zIl{?O{$Lvs*KIxyPD;mN+-TMvqhCW8C+hxmghf5tkABswEooq*H}(9Gh8#XF`*bEn0I;%wU0CS{HI?XNc;Un=jkW zO%1IB8zRS#DqXVn;69v*Ib6J@>5^T*q1n99gD$-kznLkjoVizg%lJ3zsW$Zr#yP22 zt4Jsk5TZDuXUigzAvFn!MyXQ&;IQ~RP&tx`V_w*#8-=QUTJAD zpc;^>G?xRg#BP!}8Z>DSbtGAKAGoPtRUrsTFL=k~Xj40Gcku`R0gupFp706Dq+-`i zO>w;7)OaiVz5mpJO&tta=_sR z0Th&%0}%Ve<;JE|q+@2Ng|>xzPStZtl?Fml8=v&`L zUsfQGhu}Wj8MSe`jXvKUN1Op1)Qhtv;>oPl)f?lA4LZ1mn<>yZs_Ir{2$e!rEMoPy zTCZ_x1mh+D^Tz2ePNm}ggR2X7OP(oj5BZ(7^~jg-K+Hz=$j1Z|wJ(hPK8$a6Z0!is zO1>p2$!GU)qq%p{Y?7K$<$V;j0Dqt&0|@Tb>?|`-D1Jn$lA4-7DP8KA%aVY|3_L`3 z=?|7a=il+*jaxW;?kg)|12~p!v~R`883p(d>dx@v!Et`vL#Sc{T)*)+9OVU{>-m^s ze0bQjN4#k++hdWo3j_>8*26txg1xdwRHNCcrY`!L&bG2W9J!y{Y_%X3 zWeJF1?##ZKdK+@P;ePLbEDP~1mJ_?3_g`eHblwA)%VC?vFy?1$XiFF?VbKgPaif?n z^&mgKu;n`AGT(lv5xf~&o;wkcvR=>gI=i0|W_vk71fFeZU{N7H4S-q~6mZ&$gcSS!=T@u!6N_oByrmTP-%3&>-HY>4*lUek3tuogGL`8i z85%G)n1&9pfUwlYDZV`%kbN0$UymtV^zNn(c;SYKWw}b3^prJ??5)W|W5euS!uNX2k>B+QJ|dIeZ#`5REkCH=ZrYK(>qJ~rKwI1j0t4v@rPG|NX`XS4L&++f;eroW zLfTQ#bwHieO?pXGezU2_`6|KM2-xuWMrm! zO2(1-RF4&cy0P!Jzu>tat$%0`)EyT{P@l)|t?OtbXQ=?&pf$0J{5X7E)k+K(gi&p< zNWoTYq-9qiZYt_m(rNr@Xa*dlXUPc((bncA2)ta3=rKzK46z0iE5(=ZWWELD3UBJ3 zjo8`!*Vc1BvHNRSN2B2GynupB!${cHnHU-$R09nPdIv z2<&pxXx{(|kkeCVgnbf>XyZDXIkrykz+ig&{0Jgo4nvMN z{^IB>d5B-r0HytXk|UXJ$Pu>G?proBj^QF9MKawy`V3bFvCkP-dT?~F!p;4Li0iGU z)}moX1-R?|xvSa2mEIYI2GK9?G${(LY9|PR2rM)Dfkan1=nW)MGK4B#ggnl?;9Hk% z!Gkqn-2D%gJS-@VPEDX_uo8(#$qoo8Fem{RupNpQdXNTT8QwaMC^V74`=4@txu?yxVO#`n&ozD5lvM~yXJJ)?tt4VkV7dv93B2jtAKYrW zQ_;g-nK88?#S4G=<}E8J#fD?D_djf*t@GvhVe5&i7REd%wzQM=6cr4QZDuD!BRyt_ zN-Sw&Ijo-*W*t&m0%H<9frFDX3Dpd7+d1?h6u6W~pz7or+y8CwN~AQMS(OJf?S!x73m_#VqP{$f z2y$4;z{IV2)VuJt@A=8kD32z%@bCpRvd`c*&E?ou>x!@O;AK@OXm~xW15|MF7}YI_ zq`av}U42T*)t9IGiyV8JGQdC-XPuUhgbBHx>t9zyL;=$UckBbc)Bh0)ZheCyJ+iVZ zw3uKA-z`$dhvC-Yk@n;fYy`(%C(C@$1k+3GyF6s*)fn&)F)*_<`4AsOpGz$L$f&|r zFf**G`VOmRZa0*M95Y*w=4e= zu(TSYunkP4C8{V`QHdVqZ<_Tu@dG1xV!;7ff7Y9Y{CPLb1H)+OFbYl=HV3u zi-#sWg=-U!L4YqOhgC;C!zuna878(82gIaw%HC8ma2*3IOtr#NRiBgy3-U6p7Lm?v zBCIWB`AQGe(CENaK)YuEECROf%Vze7b!;xRsyx z5FK{l*1A!k_%o-|47@u_Sy^9(PVhpcf?!Iu!UZr1SnBoov`FIDSow|HKk@K?!(%jY z*ZZGXOiwFEj)4KDoDm-IlT4Uak3*@f(QmpJ$i+;1O>Wree9J0k)ey?;Q+){uqgHxF z*_+lN3Fl`zygZTs%aI7!>TfJe2I}&Kt2S9z`9VkMyy2{?UVkQ@yQyJe|C1y#PE0-p zTQz29v$>dhGL5nlXzLlYKKA18pO0IW#?S#FvxA@2wlF%;>PQ>+3xO$^;*B8N&P-E* z(6NX~v+DA51Y$)?mHyqoB>OyiucIG961YYG(rqS7ikX}OzO;{H<~L7eoroT06Wcup z&%hDWy~Vpzac{q2^3L(3mAl{$HhXLMzfQdg0cdDfcuISxVNg+5L%0ibxZ;dQ9P&l{ zTGN2Q{mZpN=3=x0ID*CF+|||fin+lOhYU^5Eu=r~*0UqqXIq!xOBsX$z=r6ffuhPo zOEDSmei78Rq-7=nI7V_KmN$f=5M?7_LAq4#1}|Rp+>t`1E6SlQcV#qE+M~w+&(BSn z7NNor9Uh(f>sw#+2MVx>4PIRY*gucwlRZZwAU&74wKDx(-AlGKx%BxPK7XCC&1OWs7;-L4^W4@!27 z+-r6ql!XJPTfywSk<$j-<2?I#E`j@l5*V}p)kanqj8``InrlIHDyb$BWzcWI*lKd6 z_9s{icA*TC7Aab$s7wWQmfS$2i6bm<*SYWe%#-k7tvfde!H2uu5trxd6pIUrEEpu{ zT`lG#8clvBdB)+`L|WnL*&tYm7x>4l)Xx^T8ki zpHf#)Rd@_ig9m8{x#rN+bS&ZY>mDYwJtPagkjw%|T)*wyM038p_Ry%@U zaRZ^k_jbb<*R=o;00Hz5hj8G1)Jj!nbZ4`U0~r1OiCXSUa4#%?rH#&uOWy5`iQo+{@J*{i?)fwC;ug@% zvyDOT(T2ECVSRt`H(vS6E6&6dweH)X`ezj}tVFEC1`{;2A;%4$NHI+40vg(I zp$9R%5%;dQ+N|S0kPi{{oL?Xki8jb=`Kqqjji%jNV8+&d-U*F>v+UaZ~R$VZCXMgdH#*QA}AeeI{7^W(VCU*3B%WTSp#?YSFG3foWa}vwbr5%^! z)_~fMuYf!vl06_+Phsv{e8hhoLqtox=${SjQ z_rGHSSI!pU4FxbJ50j|~{eh-MA*#SXnh6UeheDTrvmnJuddQumf91XYx-;r>%(LQI zXu!$OedVdP&7xsO#r}6n4y;>-2CPRpX)EUIg$E$z5o*m+6R-8)2wsibS4R=n`s(<| z0iL)S6DKoIf{1husE|Uj5LcJsx}U{!4O1kmPs*ioLq-X^=7Ni#F@hzea^oe>e)~Q= zTGL#<{pT&XRJeV*bi);lEfR?6vV7)KU)EAJ7Il`woYT{J~r=U zB)u;_ZSzy^+vz2gUV$4|IRWOy1b;qbB%)`~IEnz@SOf5TXZC`f!2gf8HvyBYtkTCz z9R+d26-3km1>-20fE(^~(jg1kItd{POr^TJ(%tE$LUm_pM2$NL3hF4}8gXMr#Gt6S z$3Y!*Mg>L11qYWAW>7($kt~k<-}h|acPsbz{QJ(6_IYfCzJ06ickcPldCz;6Z^VfW zbszBb${J+|&_6*?9c+&OH^$#~lkbHl=)3qJo;+=|gFV<1>0Lg?u?&;p{`!06^SH{|XpC zM5sU+6^;7m5^uOjZoBw%KmIq0q+|;BJ=RSvBI!(nl%8sKqR5qk1VfG^P8-{ROEK4F zMzeApdAtj^uRxZ`)d;Vyn2vBQQv4KaM3M%6%No&>kqwvZRFMSz={g9bl{Z> zUJF^&4~g^67`9}mxj#mdg%%gZxJPvcwp#~?*xUDgB}$QNpIrb-Vj>8~SkcgD0S9E} z#2j{5kkxxGc=DHf@w8>bgzx!`is-?(JRj$HqEx!snT#VfM1yP&2u#LcXJ&mKu0ce4 zq6?A;gM7GXUmpII`$jDlqUeSA53~0sk1*3RyuvHQtxZS(11~6L$&bPpz!Wh*=zC}T z-Ov99_jhS!)^)mcve@&rWurd7({7JOlt==}nmHQ%a;1WPNNKYWNScO+Hek{TJyLQq zvb#7GFT8bF6tV}npgfCZGi1q<94*9*evkjZvlYl#OF>DdlA7y7+781xIL-_bD=;)> z#IRMhM&IRl$wRIN4XQmd(L#|4CrZyO>*(^k0w1wN(>}5VoybYzgICw8S`9YDa%XUx={d~| zpoyl(vmJ$qB*ApCfm(-yeGf|y7aTTI5lX~As-QHXu4G4k`r$QcYAl(ee9t$Mk}Y6{ zo+mWqfT50sva^rQu(7c@g0h?$k>)O_%W;3N?8p#86~T!=>h znWfUQd?gkwe=mhHAP3+hEmm?NTzS+@|M4sep$t-fCldm&QfuVEgBD1iVj>OdY+=r; zt4J181c~Ja*@v-+T2TGPAhRdf<30L(4N^Sh&B!2)EVT*@fj^;M;syz-p+8NgQ2jae`VDVd+0{w6`?rLr@-?)mO4n;cG0S^+F$0hp{IPdFB(qozpGvj!Ur_|XFrKC3>dCI|eW~rBJ++u}Ay6HqCJS0ryGQub;=(8=W zp0H^tqo&mSqZBSYCBUtFHEd0hr7P6>$>aZN2^H#TB^&TZvn-+y;(NJn=KnhFtq55V zWV!9J2x5Sii)VP3YIlNH8k?p{}E4YWcC;^Mn zE&1th81;wd^;{ZWikJPx0+|MoBj^Z=oNGg}5s@@m>~s?6ji34Q^Cs~$HKu2}Gc!NU zL;y+{@hi?rLy+Q@T12218iTx0K?MJV@5Jd5q~Fy{%ZrQ!aiBjA_d=AF6%-5oC?Pvb zSw+hz!I(QI(F`B}t+E0|%?qm7VC}uMK*RoI;nPk`iX|Wn7KI13IBjJG-}(jHgm@r^7YCz3Bq?l-SDhaFMmA+^~4gb`c*EdtzaJ3w3^%6 zSQDvikBjUe-6OihwJDQIw@i)+#&{;2kq(B5TyZML0rBKf+0#yX0Tfv^^)1xSVZA7$JkR+QSvDV%_SA-b;cGTQt7= zFj$apDl!DHbPSn}V?Y1qxBTTSLZgS5n5DaCRe>(Tw*tR_jCXc03#ekJWvev$(SRT< zIO#?*z$kUI*gf-5N(V4^pq-ZdW57bK62drONKmy=iv(O@j=b;D-#-UWR(2}VJ%3bz zkla><6q2?*JA7#SdYP(MAB3j>b^tLg`)2IgI1jnH9K!SV(9$DLhxhB#{ygyu1 zcsgtli?!T*S@y$qW9N5%@N=S$veEkY{O|0^;hmI&uzU*M{PA=rh%i(*p3veNQJ#?! zVA1Z>C&9g3*NP79d_`X*nomekdl5*%bSOWbVpz=x2o>bAx#2@+K4&Rq!z0DIQ1c!e zR>FOQ>f#}^O>o?ms|fea5Psd*EWfU>Z?46i3(41q*%S4LOYyu_Mw%+|oEZd1jI5L$ z({_F82$Tu_c&hFcwh2|EbA#GFd5?C0&FstkvlE&~8`4E~;~Q@NCJ&{oal}=($PP)S z=Aep<{KgWglyYN2wyRLl=CYGQ%K#y8Mk!X}unEWtW95)*LULpZy=gq^GW|tVv1&3` z^%MG~HdiwIBdIMYJxhQHm(sjT?>dfk31xi!9vipwSk{l~UUHu^VR|LM-eB+H9tP{Qrzi23WNA@V&4Md=FMO$8m~xK9UONyWG@@PTO5 zp);E3YQ{?;SkfJCQU7YAGY~|R8w}*-s}h0n`!vHA<~{RwC}}50BD&~; z+kX57kCN2xpYhz?yYXSOv>RWJ?}AAdQ;a$q;nrgZAUA__d>Z-NHSq=g!^F=r21a=# zsZkTQK1*3ziMjkSOS3v|ETNdb_8ZRo*FQ)S<54A+=;6Bd!||w#aWD+B7%1AsWU0=e z8*p|BgSqD=li+x4mU zT)7%Ts~uG$xua)Aatu^Y2XHSORGuV7H;+h(Iqr!855lCQ2)91kY=(QLuY4ZGYWouK4~}@Tj%>lt|_YDjD_$FK$oOSB*p|B(Y^b zW(i_6<7l`vf)S3Wm)vYQ25$#h6j>HmfF?&>4f8!T zKT2m5>KE7FbLIMn(1ILWvQLgvHK8kC+64NoFK%@vkY`KBEm2iA@e)$;cBz6ZmkLj| z|H_iF)|{lvZLQjd+&G$$B+X3POb}oOn0;@N`SMSf4JnZYwv}%&+pNtfc(%6~>sLCVuK&mC!nnvsj&WY>70Ca+bH(U)=iYS26K@J6IZ zkY(kDTEs{zpz))G{TU`Ex`mx}9HhY&6^Z^1bee#GWMCn(j4DVWsi`0X5A@>24%TQt zK$E+Cr{r9YJLezuwRKob*~zVY=BgZJtF{o9VU`%uJ7JMn@UaO11w(q;ljH3wQ5XZ* zUdb;McBlG%t6@#?fd}y((*~UGqv3XDEO^nZl!{!L9Q~VNt!&qex5_Z7Z{Lu0q&5ye z^1BxZM_e7z)4=s3g%o+5Z z*%FYxYi-0ab9v&HtfO-!bI#cU(Y}Xzu}%yVY~)}w1rXhi8QOj%jD^x+6jv8BB~y4Y+ynSOK8LaqF1tBTf7r7=hUJvH3L8knGUcUh zI0R&=S`iW-kKeL|4bu`)={-2oIsqemhET5DsbcF0O8Q91LsURoZttZBQB)B$9Q_Dz zhxfK2hNchA)Xx5uNhB!JvC*9LqAY)eIug4=$t7ms z>q3taq60jitDgjsd`Oq$$^Uuy0+yiFN{(sX^L*98*_0y*bl`PRXN8_$&tt2mh}_io zrTu3eklI73Rgx4o%5$YoL*9hO!bLeEyo_><2%a_X$Jji}YPpOKzw+^K_zq?CL;Q5( z`xmH;9*9fm$FHxMNW)%YhS@aVKSzr~JZq2YyjySayLjFk;+yxz4 zN~_we5(f(Dqq6!~v-EE8<9nIwx8Uu@=kwH@qB31o6g} zp~x;Ci^~|fAeT7?$u3uLW;}dprKX;{Pme&L;YY)gK^BK{?*NW{ti^0h<^-@--Q$j9Rn8} z+gD+>QLTe;7YK>n&uK0!tHnp~<`x0@dv|G$6nuS0&h5KkBfhToyOQ(17%K=dOZD`^7!r3f{5vp_VDPv*>!L3?6*J&BhFW+x>HnKIRke$Jf^G zEm^lscjK%FoE?TUS-L_cHuH`&M<$5=D^a4a#ElUZy8;UKQnHDp9DEsgWwTr%h`iH= zDxnZxU=n7RuC*#e0iL`S*;0e1DNGPlV#~k#?j8M4!Nb)44L{wR_%wa(ia^oKwz!!R z!-_yL*bhe<&t&?ed$m4%4;?V8DDY(71*&6rKouAc&B=-6^ki-l^xwD_!(6^$@7Q=& z?Im1GS5XWPabgw7=cj-@oIZM!#zaZk-tJl%+V+0o$`))AtyBVcAskJ?nLi zBneLg5s1;g^#vFVheO&5B;lxD;~Z+aR$;9Ku**2%Kuxu7Rd`e!OT+^efLA5PDx@*( zKSVb(+w3R=)&j;FsVa#VrD`Tzw8JoseiY%Tfc>4{aNeuGyNL2AsiWL;R@%|0wQyGO zfel_{V3^k%YK>vWZIuw1>8Xr|@1(UteBPb%S?W_D9kA4V*?d=7ogrJK&6#VhH>-DATQS$1(+3zdNfj1Q9-j#vIK1H`Vu z$2zHD_TSf}W?SBB#>{}Ag44^COiM#|k z2+d9)jbcxwq(5F+@B%mX{^h7k@c3nI;ClvDt3+xe8u{v##t^Sm z*kQZzt*57c7%^ z6AiDsj}=sS2)w71Yo+M%JL3XLIfLcW#^IDQJ9OncPJ14OI2ZcY?QAz@Ta%5-psCgj z43Cct1{F_8B6)XYNs%_=r3zyF2=0bBbP0m{b-PiR8S;_@u<|6Ji-0>|$rL);_<@Ky z1Aa$n1%<&Wv_{4!In%a-t}}7Cl|$Ih8R?mpic?F_1~MV4RHrSjJKL^l?-{>_+dWFb zFssb0v0_|3WW=mirw7%|bNB)qrK_IGJP=3Kv6$KvT9s6f6|nO}%r##5#NKz1H>&lP zNYG}d9%Kpr3%+d~-ZV<+rF4}u2U1l}PDCJIV5O`@-0OKDzu)!6fgU118ImA`o|r!! z7vr8W4~d-c1ns&Y#?$JU+Wb)rUrVYg=x3AR_9cD4B`H}e%Lz@Y77{7qOh0nQ^&TYX zqQ{JOPY-3-+5|z=tP~YqkDEmqqY0j!7-agw6DkUDN+zMJxz5qM5EW1Be`QTm8dpK% z(BWXGvcU9v$ql2-2^auPhbX=Y%i5DwIjenuvQsP5Q?Rzly>5MT|6iyZwFi}`;*^S! zIicmK?yaw#?qo&BB!hnAQ$!u3jCW0dBAh zx}6wqI7^<&Iun5+!3SOfq!b~$?m$+;Mazf49ZiTdE#K{;*!8)0yl4ZSruHrTblWwX z=Q}$Z#cI~^?Q&%lGz#_Trq^iFc(b8w+j^<`T4kaA?Z%>4Z5@8iFjmeZq#zl#5^rusq_ru zEo=1)5^-)lfVv-&OUa0a5@T zk&L#zA!7mIC|Tqv5cq>=ISa4cxxm&*Ig2kBQp+<3xzNq29@>BJW^S9Zxnz6J%f)bz z_s({FC$-xn%|ckNn+S@*8XFaXCSu)!3jr-2QI^i=zE@CAE|p9QVp^px04I>x(vN)6 zO()BU5uO*^ZT)xX(iuoC=cyXZ@&n=w76PepUTGlJFIOrU4${o4Q#XTQRDWIx35-Sx z%jshctVRpwLbN9VT_+l8Vcyim96K5FZlNhMO38%{I6@l1LIUlQ%7}t!MgMw$}ZyEmNthQi=ynR2zM_$*h0ftn8 z7dMWlCvwB?LcHZQSO3=oxrg@Rr(2P1Nd7D-5(m{Tp`kSv%F+ywA;P@C+}fKc1{o6a zf_ABm^Z&3h7gl*9h~Cu^425A$Z~5|tU-Gk4=W&8c?eQf$=yj?+BsFyht=-a@NMs*L zP2E30GWdOk-SckTs-Tx1Fw+p#d4L2&z8vx=Zn?`p=w`@YE>aG*0ktR;PFEYTBPvHE zVl`d9i3-6dzAy?tP}ODTW%wEQ{`e3)Y3+q2!nr_&!;nwT3;@~Li6Ww7@Y?|-Ne5bJ z|3pz~8!axC;+5<00ZMj8J3dhZOUklDTU~1ZvrVGql|U47idTv%<{q{ViJ?#jBZ(3G zDERJU90bT7z1f0ImGLtcE8A&20m=oeYAVWRf_34Yf8LuO`af7jjZ=EMx73?ec!JE4 zk2yF8E?5it75L7~GRLCfNY%e&zj4>aMUGfqjMP|V7&T)7lc|=)wzMoT6{d+jHzpzI zbwDX&vJze7LR$RFSG@8Z3h6~9LbAgbav{B>y=7vkfO}PXjcHz}umL}h??ke{>9s)8 zb0yiLEI3iAh&O1^L0ZS&gr=dio3oPtY|>F-a_VsZZ!yGIQdCGkob>gPXR;jep}ptfF*xUaF!y z440R4Z{piVTHF~keFkz>!II%Iawho$(;ie^A#9Rg z!wAym0QnQdS}PSLV3EkG6wUJq|{Gh88S0W>|3Z#|cq z7>}TYRUdT9kCeO!Ii;Mu!%4yb)yX8fgeP4-mz?#x4>NqMoe16N_H5aC56khWoPSBi zg7dO{3q29Hj!(`-PZF+ywBWT0ru$0VzCdPt#kSALa9=zipFtwEOmL> z6l-gG9NR?oEIR*Eke_{!rM+B+QBISNNIC!F@9zF@3an%r{hljyA2F*uO9Fc%KUy5T z>%8(1LgYl>9^O65f5luAD`h(dp)7WkmAh*7hyV%ZqrHC8nQqO)xDRy8qDV@twnwfH zdBi_($z_M??y*x29?9pP?hMe39oQa0Et^ zVtxG5YXl_jjP4PiYSnKsKRF`F&P8t3ZILu;`J5HuL13RHdFXMPSTJYf4X$G=K<9*d z%s{R0yFLH){(ocbMXAg_q-r$lGF!=-5CXw~#?zf~NLzFmU=iFnOo?W;4t@k0;tCdXk+w?*e&V*lw(!ISomQx>*Jhh71h16VfKK7PBLU!bQ@# zu@Q(JhA-rVbh}dNO04OdK$U);jm@^SVe~HQbg9ujsf&3szz7JPJ%fxSX>s>E4JpcF#F1Renu6QyEl8P9UsN+p2I zLODt^w%6Ie`-eSv1etr?z4|MYm7b;5Gef6(Q{WL%nr7jw#UVK@kJm3n*I?G9z}tNg z0HBbl&^Q36f!1aa6l`%3N=1vliY*cT0e+*Xinu=?XurC^OC>bM0R>8La_ExF^2pn7 zIk!n!_LV?{fBY+$s;}d_qcn~%iQq{LhWkJ_Ik+bK50(91)tw3mqZ&c7=7C3X55qM0 zKOJb-Pox$+6gdTN3MY*-<*{Jl#pe7?ezzI}|6&*DhUJG{`Y=NAlJWI>?DUpd+?tXa z5jur@6?434rzJjy>G@2ozD=1gH*@YyrK*a|1%bNqUwS{Q(FO1ytc+2s=n82cPdK6s zmkY`&jzOp>-+)OhryCFc1*aVMSV}O5MBA(DDzY zGP)}c0~2aBohfAP`xD0r8(0=IU88~|!M+mHbjHT&IPiVj^gx`z#L|y`v{p_uHex*N zmWfJ8_bS}HBtxl!GHB?n6pOG7@Ja%Nqy-WYW%^{^$ACkIPOYW4=pWq3b}`qE=Il_g zQxxVxlv2G1UeJ#jOxnmJ#$AaO5k#;-A9o4>BG9?9@;5710nfp%9=Xtp;rB=j6E(I>$|SXci` zdOoQn77@`HDL)Wf$_!eb^7jvMqjKFT_xtqQu%6mC@zeck?GzyH1&W~wvIB*KNFul- zqzsBzkhj(=6@;-6AG>h7HMCL`8kv{|dIna#dvtH*%C7qFD>?s^dq4hid}P@fk9)q5 zcJ(Z*M3T?UEvGG;kRI7=e`BzFTGk;(l7)Ysu(Wst2-9OylnushZW7?rVOUjvTC8L7 z#czK23varVi~j|Fx?kfLb@7Mek{y~15P;W}hJcenvU8JpULh}4c#&t~?q$q}vhveC zmjVc*eG-GEb$#(?fMh)A6sNi#oVtXZ@O3b6>#{7c1{v=f_>BdNP7CBX>f6bE9S?b z+zqoGs;v4WxL5tE8wy6sg_MyWpqcVdDF6}s1GU!rXcbg}z0!Cm51W*Zl7fl=M!{8p z%CTv5_E|}B%$M(Y=TF~DdZ0!?-mMm2Rkb*{BBHfiVw6;DP{2K4KRFKy@=~q|nnQXR zut#2Y9{tl+r`Mg@Tcy$vH5L$|eFMX#RG#HZlz4Kp1+Fo3el&o^1&jYDRs(ZykKsuENW56Xc3vD zdtI6=Du`MM$b#6MUYs#rU{TAZa8L>U+%hfntNACofn_4!Yg>ekcG2B&*dOoH!8&R@ z6t7#8{!KNB@Y*VO>b=da=?oX{IV;?04Dvz+^GSu$=t>Z-X}bNN`b7OF)||z)9N5vv z%DA)7PAE-EahPh**r;`eS0coQGxqpQ z5U0n+T0UoJB~@tD&i?inneVUt0YBXeWM?KZRRska#r`iaoCH#s3fF+u9fk9)w)@(+ zIZP%aM$p#62PeY;Fu@ops}2xinA11_TU6JC6lFODz9(? zH>+~6CS`TIzrVO%0uJ9V# zgPoC4C%jK8*{LP)^$F`kc$A z9oB6#_b^%&hd!yAK*>;tJv7YG*AEi~y(_f&xc+ zPWD$Dh_B1F9gEv|3Stw-+>9fMHQb!4IHu)te8LJks@N?_HMF2s;Jz*O{vMQVMllXuvi|bA8c$*4`XlW#Kq;5$o3?ojDjbq$~ z3XX3;+eJ55wFW#hONRT5I;kGxSlcg|&n5*hI-%poa8PijSFp;;sh!$^8Y z562&|ZNA>cmtJ_&CHU&vgG=_(?MYSE;wz8>L=V)^bVOCOLTy+ec2%R2vC?`kz`cFU zgvfZ4K!%o9iKj;N@1dX#L32_OnHWQvtwg3Dt2 z4+md)1ZBYk54+#}f2u4v9B|F>2=dw!2WG!1k5MdWx`F9Woo1zDp?2cl<~BGnP^LZfEoPU#!x;)hnjS}hS8DQ91v$AS5jl(~B2{cA zcle^oMVw|+dsc~1?ChRd6bk8N>?UOXQJ)3GO612N3I8wl6_~{f91$m2jeo?@7Fy@8 zJY&$Mx+#}q1_T*sgvEyR%}^`-NDYkGLS$$z(Kp;}7ysbn52Vn_roa9^Gd?IBhVfY| zGyGhQxY>{#!i9zo_p1DyVALC ze^NQpX{i9~^S2C)W-K;C4wYb|U$0b<FM5X?a`*Q07ni4M^!x-$(k59K=2&u8&;wMUd_iJh=>I4-Z9MtdqW8ROUU zQViM$b|)gS0Ge|GGl?r?REXeu2)mGMmjx-FVq87KE3TLyN3O=f-WLlr`{ZK470=7K&C4$k=-wQ;jcE~$;wWK-+Q>K3G+(p(9|8>ngk)BEXFW)3L9mt zQqRGs_+e7H>(S1E5v~VxMIc+ShGzT;MUY|8Di#uVq9BF^6XrD$5|)5(z}H*a6(5Q5 zB|?qTEtypk5kWxq}pm_%@bMHa26gol`{6u?|Bw5GkKJ*21ojHX$m|R=LvH zs8=e0j(^6@C{w`U3(=?^sg<YEI?> z#>AZ%jkO9A)9R!vrc)*7Kn9gsz$i!HYOrnb($U*)csSEjC*R4T+xmXrz||y!bd4RA$#J$Qbly_TH-#4gdm9Kfso;)lzHlPv zI+V>z+xysASHX|roBOarOHIfY$`r-0txE!XOjf5p0G2*&cuO~W)a1aTh$H+JKsh}x z3H3%~20gZ-ZxU)zb78nbCI^Y{@Qu6u)t6r;19VHK%Ry5o zKvPozNtIZ|^jQE7^!Qal8*j&_p^~AQB>~k-roE&{18M-Ju#zj9@_Yx2U_>iP53KT| z6ve9h4zyZG+!j-AbCS+#I?Y_T8r^W8CvNy99Z{wuGmfX_ z*NqN-UBQ74;RC&}KxsobOS~~oXs5C9aK-CcS9LJ^3O0NM0#d#{!72r^ZqCKds6Wli zlD41yhPz}4?QihST`}n1x~`I7p$AbQwhO5qH1E5QV?6?nqn&6>wVGoyd--SIcdE60 zszyKuq(B_0ct}V-#em%KOmcGOmWHD8+*qO@2ZiSHPyCh4u+40Co~QCcHB<57KYwHB z9r)g|2F<;8Y}Rb7m7N-j0SPtKn`gBp*~4>vz>9ivLMoN@z3O|{-92OnoHJr{m<>#c z(-2*ehkHMAbPee{e9>9R@`D2JU5?-c{)hu}@3-o!Zyeq_Y97T8-X z2f4AmNHtD4PzBjE94@)V|96W2>&yYmyw!|G)VVGXaFI0YjlQhxM|)WNdJ}1z})*x6%->V zB%=C}c0x`1#JO-IVST7GxWH>DOV?`^HW5wGG8Vn!p|d8o!o&!k>Ecr@MV#4SB5bNS z1t{c{5#73G@ms;=F!t0mE;6!0oAWo>W_0Z9Vix!!+qlcMo6p+$lfN4{4GSr&7})zP zl_BXM$dHq3*cQ2RV(;v5mwZ!PQs65fU6#_2q zIruL|RJL)vTfx}o6y>n8x*QeJSeirMpzqUN-&xf8 zEmlx=Ozht0X6iTA9BtK4jhv@DKT$tk%k!Z#=+88h^%i`yvPfh^$vouHL|(c4)_j$Y zw@X2*Fv@QC5iDd;JS&~C!4=0BWRq%#gsl$iW_58cncFUW<%e0;P*%0P*G}w`jS1{I zfa2+iL26e@6z8>JD7F}%VFj}Z=3V&W71oayjS$#OEIHEI8(OEs5I*I0jra-@G6V4Z zbB>CHrVvfI^UqB>94Dd(DOEwR&oV->WyJ`TQg#t-zUhb8^Yn^Z$y~*~b{Ln4Xm*t6 z{rKiyudfhd)ae-CPyuU1tFU+`(y3L2$!EC?3Whtp1F(e1o-~N(KJ&jU(jyrW>XO>< zk&(-#>8*^gK1H_~QT6;z6SMzO(cEdbM}s9J-DvepJOd6_Dp>e8;pPQ#CX@Rg0!)c| zpiy}5RvMq}6Z|rp8tBcu%u;x9oLCj8qZAePiE0wMr&vsjTFm%FDYV(_%l>B7BVLF{ ztDRH=5bQiA0`B)#}Y%ht9wA zMXx`b5-T}4VecZ^-;_?^ozTDgeE; zM^~(8wi-z?CoED`XXu_3XHRWOa3_u18# ziZ!|k&)XfPFUee4XN1RTFr5lkD-jY;!fiuPHoPkYBB%-@R+u4MW0LB{N1&cSRbJu) zjXn8NVL&KBylg>?5~2|&xUEWy_7{HlSD$w66KGz`Qh&>ILCopESWE;p%on{0G37Ws zGEVNESyh`o{yTARR{I!kB+(_hrJYz2;7D{xt_gipelVm_a8?{gwCDJd)LSBB;9q!H za9-n-!c#aJXhnRq3+3cLeCRPxr%*Vyr28$~fk4~^3vh}9)?W;;>bSuAS;oMPjm;5c z04rfVZolQ8>xYGu;8@a5T1>Ci04vm{!VSoD7RCnn+o*F*)oU5#6&}mic*@W2Ke`xS zRpb23?lrDTJAGEx$SAUxv_E#bg#2nImBD6Ejf1U>b@`UJ(Ys^Gk&@Sak>hE)c^~0uL9V2ACq+quG&rp!jGtW<_NWo4_K9P zqH3FwRmT4kQ0F_2_=cvxhjn*4r@iI*NbdF!kMgya<^%;K5f`zpuYKOrzBqXjzP#2` zq6Bts(4%o#*WTWYQ`W(+_DkD^qjQ=xUACGejp5wmKF$Y=mK24=e);Vh^H^> zsoVR~Y!|_Lj!30v)HmgFiVhU0vrZv1OVU5(v zc#V0XtH9iew-VDSN{u8U%5a6yIO`sVDmBSWvA!f{WOkhJmNz|?hV#B9`gEp>;~}{G zlJ*#2LbJXSuF&;}35;p|eS>&xCc?1Mp|8TNr`sXbe57pk;sV94m;jW=mH<^58*S^M z8=e@L;z3JbOAQV{O?*&YR=b#peDF3fx*|_ki1oi*{H*_H_U5cvRERf220)w!vO&&y z3zo#MtXSZV$R@Lc9x%>YK!mD* znAci~N}N550(m(EvH)wyL0|Ti$#Uwp*044e)8~*Of@8zvQhdf&Pv5L^QMHnrv}wrK zzvEd?n$L}1%G5S={fx>MsD9KESm$ICk;V)N=}DibuhxU3WazkzOzSQq^hdybW6CJS}T?|?vM$8 zr#jSf(6Z8w1O^e-Ol0IM+_`?)(_f1(D(jWmJFF`tmg;R{TzYBBp9+sMC@?L^)gWzA zDVO;g+`JH>Knio1fr3MwhWccAlkb*8NObKkxd}T)J()NXS5jT^uz^_F}yGnZ)n^8>$o?0 z0)Nur4_a8axN!*wa%JU!@Km)xBpK0}Q+etdQcU4(M5&rm{{mu%3)1}60hM{g{0dv+ zRUz0HdOMzy%!tL@H$HRDGbH9NV{y(=L6UhlL9*F=Fq`g2j?_fSc5_~;Ak2^A?iF5R zpK4xsl39d}umkK2R+dl$7pRDCo@T5SIbxrGD?5;xp#eS1%sF%+O_9kFXs_9#j4jK) zP@@=)2Q&ZX65H^iBMv_v4_-DUdas?=MW55#nq;3=ebop~-Hm)Hw;%{>UTI(uCazSF z*G}A=Z5Itk=o`GiO;$lbhRKnlhPltoP9!h#WJ%WOW6uPk+7?Kir9IiVtHq8tK^i-q z#&!NHK6lj%@U*4-(@x`>HML@W=0ZYjcq8|<*^6XdWs$CmoOy2`Rh2`CQafv{J6rcQ zEVdF~Zs#=<203`LM|T~fE~p$mqh@pQ?Fm0R($m6yd0PMycz>>KcRZ5mZ$T8^w24a2P&ey)EY??p!|ecEmwo z6`z~bU=~)q5#PAV+B|eO6_Vp&9&+WaBQ{_ND-wz@fny?JVe$ zYq}ESXsKQaoUq0$2`row5KN3-+B`x;4Oo;?bCUUXvPA8yRfr`C88);z8!567Qd`MD zns67*hSe8;gF^^wPc9M7g({juaCs3jES<u{Wbl-QwP(g*1}Unb z64{ZH8W8Zb=|NxM-EVL1_%;_<(n!AdVpRejO1X%sNX}zmTULG5Gzan*K<=h32s3fY z`&b*_S5+(eELj<)&6#tt6$-u}v;zNtfIz}!1AFv5lK7CKF2dFo#VId&=0CF_S#Hy| z;Hi=kC3#`gA3srv3mGF~F01~VTmSS13at#Jy%L>Cnt@T1v-?Q(2)$)5r5FIpy&mE zBqF1M)~pw9MPaIqdr+hcXBEY#8efR?6eYWTaZS4HTOT{)jd+~W+7dfW=K;73p%jy! zIJR`O!6L7UxxJ6$!&b0>fl!R>YDUQWI&3njd;%aetVRXDmn0K?`5h!gtLoVO-!=r)R$qJ z1u6g>&N2oc)=TJ5kV_Rj6UQ;F!|uTz$~T!92@+D|3hLO8?7l!Cj$BYg+NuIzCe;qX z1oc2vGW@}jleZarF@a@Sp@WKrqIJ9}?4Oe6+++;j@JMdfg)s8}z}uqSsoiEXAd6N9+;nEP}ZpcP6zI37uqs2OyGJ8=cXK)v5kw*ij=y zYIW+g5~;{H(E}j%AOyq?#lIxZ$iI%*JKygvzf-Py|7WB>xh%AJm&%X*`Abk7m#bWJ zoSB>k=6{iOPeF(tpmG`IWBEtWE5$%O_)wg$9KXuOpj^K ztUWy=5ZBsymTG9Rr83QqH|T)|UM(y(tHP!J-I)slnap7cjLhY>QY*tfZ=1Bh*+!R@ z(~$HB!KY1z2XV7b-NnWWy>giz{)F)*=TfHkE0L)k{6s*#w0RE7z!pCRht$Ue1d?G> z?eWI8vF0Sk$PHK0q8+$-U1SrDu1lKa*ao}{@t)P|D(a;&309zG6EBz6RYz7vI(x%q zcwWjy89>rSuzt>GhF^l!*GdlR-ur%4D^|iSZIX;A91V69e!Ypmp83gOrbo%YS!3<|MB`9J5;;uP&8b8toLp)N>6p0v?jKZxID(N_?6OPqYCC3w*#Bxy_`ldHO z?No~5@DgpXBb*MpC|H9G50wTdX{)`HM)l?X=G+^J8P4`xxM#5`q45eQ#ruhI#ZF9T z#tK@Jzo0WR?+C9ccq&5g>+byCl0}q9S%Iw`&!oF!E6CuYZb)PWQXNAuCUJ`Uj2i4r zIT%@)FQwDwgR_4s;z-{d0+Q5?XL^$y3{;8<8U8pR@>?}m<7K7p--Qx%G3TwxVkz=cpv4h1IMz??G|z=>+$AxCx5=*I;4isW z0S29l+ZXz5GmumenY?qV$~ZG~UNxLzFkhyuIf}Y1B)Iahm%WN!v+NAvy>@UAG2PPE zMx0WHmb7+%t1}e^!^Cu(^b%`+c&Wl-*#5VSJt1s;NyT|;BR!sWkAP$gGnX*`O*Q(~ zYa?8)co`o7fSDPm<=157q_RFf%08Ke?#hfxVde#TIJ-M zaOVnP6+#VkEkg7v_O(2R>KQcvKvW(b1$Bp|-Q{DrlTF}ZBWvK41xq15_bq!1&s`7UksSv2X^cjKbG7gr*XKZ!YI94}=>}cD0O9uJ@Rnx%G)yu2OM|FkoV%71QPB$f6j$OxP)1f>cCkk^z>xzbF@rI8T>BwpOW@D&Qf)Cbr*1 zi>d1R8blFFdua5k2MU||2v8P?9I+#EoO%eTYs)3i{KR$FKv=aWmPpHvi#QCImvW-^ z;^tTkB0mzpVL5sHmHM#=BTaPng0$ihoB%}T;@SC%w=TO1Ph7hTKi!u3TbXS_BnLXK zyM$iAq+I&H)Xxuxs4{2bQGoxyEGgx&C67s)tDaBXx|k7Z=_G}irV$}0X5&nJx$7^v z>CXS+a!U@F+iPb%h$EVf<+6CBM`~xB2q?H)Oty&fDmT826@(y%RSDE=TLy0xj!J4p zGRx|pp=a2zwOo`bwgtE+LGK8ZVwQ`jo#>W8Dv!q^J6jM(_n%-Y_(}mHr)y_`W)5YHzx7>3Y+WYxD}Lx8C+qK16?zWikS^?IL?nsRt1ht zJBGD*hpvpd98J}U$w_|B(F;^e4}A>LyBh8M&>_DgOHw)^&d$MjC@!A{{&J$p4n=Gp zUp{L@M&&{S`3RobG;`xZk+0E_s0C`1u|PDmG9D6(EB^v}Z6)-A=vo{*mfEb6dyQ#d zhJx!oR*S;4j(idi!+rRkt!uoOOZ?{pl12i6nC7jj* zcT=|m&mzDl^*PEb4Lk3wN_>AFZeC$(Z*C)37ZpW;Wbq7+cAisH*j<5t!1QD&0l?b1 zGV<{#94%Jl$}e32J74^^p9sX6Um}28R51>!)3(AKFQl`22d|^Rb}B9zE?40Q!Yaig zqD#_NzzP7j@1!U0%;A`7YrjsG*;xi01y?rwaL0r9E#o|t zbucZVZ5R~CO{qz+nM$(}T4=eqB_Ps#8L`?{@n=v_BVg=j+mpVlTpp`NzWW-ws@lmV z8uc@k2Oa-uEu8&$V19<=hSVIi#xSC?N=E8axU<(Bt#Z*xWy@+!!)xP&lLVFp&FdA2s*v51k8rtNw)S^>S$a@9 zP1jDOnH9NRjPJ~%Y(}Q?s(ruFdxt|2Lrxzh;X6q}vo0}VrRck)Hb*iP;+SkV(S!rz zW-d`6gYji9ksIE3?Rt`nwcp^U+c^JRHHmdRry*{r_jcMtg(5G_$c(qg+m$j>4}Jy-Q_C0JMxJ_pEMCBA0+6jt;O1fOw`4rtaC53R?FH+)UDe#!wlk3=+E7 zASzbfQu{i7y3NcVW>o|| z_{Jr4$ciXW2t}YVDJjX9q8XRds%IZ}2oF%NJ)=ZUdsR*k#^vQ0Tv}f{-9bT-Z`$MW zYdA|}q??n&=$tqKV{$QlcWSuOn8Pdi;lZM4yOmn{FoOXrMNjoy0+=Bz*U}w%c~2NS z7ptURtoj-9W<8%=60oM!sAIY)y@AaPwF*wfMRwzo`+Y-dr2eKvWPetXF$VT}*d9>u z1xvTNg=(S3)+XrfW~GA89r)BM5qt^JqoZs)wC;jKhc*+&=USfJ~_g z{VTBit$tLUF~n6}xqZjFO<&z#p9o<9&5GJoJvMjEIPNe)p6uU*KBzSRro80(uKI__A! z`_ftO_a3MK%eLU$3g0zcI#0?R8^rPS=s2ntn_Q2(7kbJx?e1)WX^Yp?Mm>d`_iS#mNBpb&^e5P}R{7rd|z{sRa<{fe3 zld+((V|@2z2j)PDrZIPWp_vlY{X2^22zQwN^a^sxD!phDB*x%VMOMJ z!t+7O2ViA*(SpMLUE^1oup-KZ>hTx~i(`D=mXK0Lh{(Eex2utUjQ*vYayM}u(T#I#6&BB)*k(&=&`aALiH3-6Y*Ubk?P!Yk?f+4l%l zB{Ja4M<(THoT#5a2ESz8gP@_-IHrwkY0d2LCM)oK3qGJnVty?c3gE0{SPU*>D}@6) z2pUSWI_u#PoQ#cVHcorr0zD+PVIF|Ia6Z8TYGs7CnMD`M`qj4|b_yP^Rx+k)-(yrL z?7&>!!PE4B_?c+JSx%&Z*mYbS$HfNw3UIpb1TR+5tZle|A?P2aSOl$jM}CAA0(X4j zcnnGSitHdIW(e??V7vJ2s%wR?oB!cAwcifJE=-Nnc}iEcCQRq?2F{LjrhScKmbydw#_1a`8` zDpm}rAj(2_H7`En0?Mr0+doVlAglVG{FwJOI znXI4D>IYL)D3zYDYmIGst-}5yE?OYfs<0ncGmPiW->l>biJ6G(JeY+3z>-F)wOA`l z424Q7`9xW+82(HKaz4FbYL&X)A%Bdok2Hht!pnAk2dS^Mz+dEl$k9Sj_#6c_w;OeV`DKUqK-fBN2hmtV6@SG3WPn;u9TsthX$xa7#NRb>+&*i znm(yt!JZ!h&8Y=W`0F_F1`a6hNqMn=Z(aSdgtz=W9CN4Sw3OYcagv^g#KqyMEY>v% zopQfxHca4&Yy0ujEg?HWNEF~8O6cYIssqP!<;IWP6O(-EZz2TEmy|Nn1yzCM)z~-% zV$eVE^vHxO$F9xISMUg~vcm6uc5V>u#H!{LMyZU}Pn#GS8jc8?c4D($X^hI13U=aU zxEXc=H7eQ+98r+F8K=4>bsF0OTGQ+G9*7yhA>><0{+6#^BXfxnB6&dS4yJ(QkFWp6 zfB9a04j!azz|6jrlAWA|^|S43o!UF}BN|pJ*i20(h3>QKi2J-?BU1dA-Y%O7B0G|( ztpemPe39rBJ{zVUyU2FMCC_~6T}!DNN0itNJ1I$3W6Ky0)`E)~L7k724XPTr0uo)X zR8Wn#;#(8jps$UyxM1eIAw=zpFyzUMuqndvt0yI~+q13j+?Mmh2I!rw69H(RT55@O zrj6D{nOJt7^vc^=Ls(Xeu2x5|!5_`$flELomVrFA|a8pJUdv?aI~pj|Dk zA_^%3QG1!8Ju4IMYAepZ!;*5c4aK<1r+Hwm=r(QGh_fPvechSgTg!8t%Es30%T7U3 zbaK!`qO0)D%UH4vl?V2)5pGPz3l56{C-UazZrK6|s1HNxh8P+ohe2kR*N*h0n$ihp zkc1#soncn(Yrk~e3sT6a5Z}SRA8%Oq!RtOup_RcDJN<_lJ*!=6L2D(uMhxZBNc(y(}BvnE13IHrd>$c$Z*TBfFAXTVIDOVg$m-&arm(O-UtZ>jNg zwr(fxcG#@e7)Eq%Ub7P2bwNlRZ65Kmq$5v=PvJ0NWR5(G! zLz(EFrrt}y>vq#^jYW;hyVx!w0&+}43qH0P#+iW)#Hc|~#KO)|`5WJG+q*w^44$qu zCVsJsWY*p|shzcQ7Gu0G0qbTlg(y-DMkt)mDD(4u;b{vqzkrqHSHd%_cJ7KYE>`Qn zToA;G+0yi1$YbN@7Re#XPbpCmJJo5{`JdYj0C*#<~ehZex*R1;(u*~;9bBlO|H+P=(H*EYUSOJ4gue!7?0 ztIK=vB$HNp>djZcMr3J5v8rKjTx;;&0rV$Xx*4o$ z{m?gjTn?8g8GpFX4r@BN!jPH-EF9{|No)CVCZj5pIPQa8ckV+RVp=@ZfaPD>O_@dS zL})pVP#9`yQ9V*op*b|lvOmhmiCxLOu%3J3J7oCm&Jkb5D=f`5uTX_yT#IVY2G)rcDlP}ER1o4{8Pek)Lw4Ma(B zkty`c1}24V!KdIaP~rqRvVkqCkorW>qUg-6Wx_Tb=kgl<#h)JhXFPh@Q5O4F&!W6u zgYTr}$Ou8xr{G-G)Mh19ekF4)dOIAe5U&#qxUNwt z%o-}W2$BdALDwTiWkD$>a7j;G1fu~}_?jiSCJn7XhWiOxrru2J5!c!rG^L&y3Pm}D zNzxT#-fM6F`CU|u=ahJ=wJH)OFR+nD;WrD1a+5ef3ugnye^d_Fs^YL1RFa_gy<&|H zq2`*_bGQyk@!(Zw3^J3ICB7^gBR(rj$7k794%A1~Wn8ZC){>X(g11_*PM`0a&&4+9 z?lUf3M*DLoe!3CO87j6}Vq7-j8+#?5w?oQVv&=n30iiJ_^@*Tj(aEZ`c9#DPv^FE% zgdxv~m4r18hi~}UHqH9i{rCSIR@PjTMn33^Nd; z`)hygr=0k!(bwX+O4$%QCyS|19Xf^37q)#ElS3Whai9(gEk_%WMy2BwKY<$;ka*-| zC!Gz!CZePLXICfwjvUmQ&kjB0LB?<+jVKfn)?H;&a$C-{-mo{k=eEQ!SCu z8yeO)<->;S93gHv@=LG#C7!zWHT-mIogM1*U|d?$oPe`Ez^_f>SV)AImX)s%doI9d zF2pK)-jqz+K~6@PTCmJNAw1)}g&w zg9BZ;ce?Ejlju|UWqt&Gg|+O)?JGC)i3$GkKG6H*{dE@HsETu%ohE)od(|%ezlz>9 zh*Z?ajfC?TG+~N+t;)jHUofpH(OjQc>(ooUc?VOWkh-}@-TCf0|Dx-^C>fHnYD_!U zY8C}au(L)>mc+M6C7ii6nTgm2=Rbce<`lb4MX4%l^`M1@e7QtU%(0mkO`&ZeH|f2X zGwH=2LbogmUE`-Wr59zjFY*VLV!%V;E48auHnCLXx$tiJ`T6hq2dtp%RG57o)j|fR zYhb3`a1$F&;?BTK2VNIogFw5SgZG+P5`Yqu;q5Q}h<-hm;D)x&~lQSevlzKs9!EQaZU1q3-5 z%fs@ubqU(ayw?6DX3cgqB~2d&zmr@>p&n2mYxG4ZA2Y zj@2=(I8;q3)>c z09dm6XZK$&v(4i_p1Y7nrz{y@=Q9zptZh!SZE-R7l3QE$;!Me}8^ic@g>2z4?p%V- z4=ZX2C}#?!xo3AU(Zz0fSP!mq>P}Lw)E*DoStFQ=$$Xh}{{3U$elfnaw1nri3Dc|{ z#zZ=lu+-PU2X@-qe65Tsb$TIkh?_e&Af<|NWmkcYX5lNx|E!NLh4>K$=XDo}EXM$M zMJsrHS_+oii7bwk+l!~_ZurMl$Gw+Je?*COc%3f&fw;`2pV1uI=u0NkyRkWq3cqG& zvRNr`WR)n)Kk=E61BnPQO0ET>iP`mZAu6#m1M0Z|zTU7D*Jrjk5UME4Ib$ zVgQLb+RaaXQ{NySu~u?Q=DrJ5BIHrl4!6gF1LkiT7{%cwE*F9f%(%prM!#OEp!sBS z`gW#h1H6b* zUQg(v@J=rNH42Q1ZM*}?%kr)zq&}^;$blJ%n9QuY>Ky*V z$wS1&lod-}G^?uf9tfk4xD*^`k$S1@u)S{VRwhXZ=O{Naa;uA^=Sf7G$N?wj+C?c`hzB3s8>W~?$ZV|$R>Y$XiMUZKk zMR{Up=EXg>pP{f9Op%N0a zPEdmZxGdAz3gEu0`)=2X$G(UsvDC_XgY49;M^bDU!2tTXz6dRLQ?~=@g%MuK^x49A3IK#)k8B_1JPxl9t>&YAj!qJbo3HNDts-h;i)T{v@W z*lmSYEPY4VgifIcY3c&oGyhX3-k)mq{1Sm(G3x?jUI9jmuB>04O~x@hLl6)b>p(fg z!e+6%S1e4HLkbn~*gD}G5{KfuvZ%|BLel0>HB@+6DFfjx6B)P=-E+~+dEdP+mGNvP zCo1myfQpXH#5$Zu-rcYAJd^VP$~ zfuBxk#AJFh3$3+Enzr)XMABV0ZYze+pe*pAyauBp+=(V=X4cPzc4+fki;tteafn|x zCa`maW^seEIbC3+6L<<}^2TxjhrrZQeyJ2sczCzz&>|N6Du13qbVKCkVVO)Im6aOO zEz6Lh$;dVYN#Z5~Fhe2(raGiP+eLWGoRe>U6V_3h1pKh-op3y@P77dGLl<`fmTq+<6Zq@~DEgXvHHd>0U{c!&>X(;V6tU8wC&S}9D4+Xb{BrS_3r9f6xtZRPr^L%!18>e zBnaOWL`qH-8&}@7;s8nhMSfF<7ARH+p&|bwyHZux)dhhukeV;|ln>l<>`~liWgzR5 zx?Ez;m!OT9H9af070uGL{=U)1?<;7?r}2@!#Lqr)NQR}V$Jf{5=`?0^JjzHW-1ikk zg%=+pfcvvqv{n)*;hL{pVe1mfK0rCpO_-)gt9FXYXoC+Q4q6F;=U^+u)_cXxOR8P#IJ0CSX+f>@W-7%~Ow1|D9A7FA z1jr_F`>M#0Sp%ye|MAHc0Cd6Llz1}bE?Yrvpy z5~ogCC8IVj={3O~svm&_b1NdYz{k&!c8t&zvMr27(-6bH-GQTN#JszAfAsZu;My(t z>DCB4|AhdiX9E6p0>knUy>G@jkS-@i7>LYxO*}BK&BVe^sjODw_9%YUOm;G#+F5Vx zl?a8Pnf6Y?C7@gJqbjtnR)E7FbnjdF#%pvN-Rt_czILLD)y;8Gz+GiB-0~yaz=wBO zZ8Vd2f9peZJ(uIo<(e##fiC$A%N(Rw@W={*mO|21X262ufsyopA%#-8bq^LuKM))T zl2220tH~0-0A({6!dnFm$KNy|2LKb)?qM7#JcegA3%99^ToSeC9r}SMP)Cj|(Gfc_ z;$gUa+Q>LM(8s3hi<(ntmAG#UduXgiwtUpCG=_L(26}(%BUDe`hMNU*XXYUr(NC!D zc8wGayM4p0so}>8t*t23Aov&ew;Dk!W2&YmqMV4GvT)wza>tE#|EM1iSlVu32PP10 z9i#~yw;rW3xdrOFD3=D3L6NVJ0dI~^K!6FZ$6seJhsKOW_mQm$(LLcMC!R#n zmGx2oG}&NO>WsE<#309Q#P(ujha?*MF(&oGOm^4fRFha;vyi9rr7RqTGcqs&<`$$K z@S|2=X*HcJDWNW(PA3eybuj0V->QNkB3+Qe3Fd4?QN*PZO5*$sjp}R{x!q3Y!hI44dVBr27W){v z33XtvAOoUIs1fr3(_>ayWGpv);Di(F6b9>qy8ZO8lQ7V6g14}y)!f$ZBy3Lf0n6Jgtxr~Qyb-srw(~3iDWDkEK9ZIEL{ApH7WSC4XucjGH`yXCMnNPF z*nQv79;qY^`!g-7^J(Qi0r93C=Rfu4{Zb%ATB%zgc1i+)%R%b~zV(?Zj4SY=>k|9Q zKE6UwsnbPJUC91%9@uNliBh=cb<-|`V4w#sCjN`hsT=eTI$TdS9ncPRfJ;mwp{OOW zv`;$I=k>&_Grf1kMee1a@Ayy&@ z+s2x9Mx|jjeXDEef|o1~ChUwDRRlQR!lr>sjt!af6gDL+y-TjxdZDaCd~lYekoQF| z5R` z07ny)n9UJih%~rYPgxl>(*`2w0y<7Nx-9c*6IZb8<-rI>0?dVVxNei6x4*B3>{-!2NAKV%ZCv zCtiA#wodZvnNiCWR@o=PPE>oxdJ z2QRiYu;|n!xp>jq<^w3nlGE7s zX9MV6k_SznK85dGB3vx^ci$yWS7bWnYj*5tx(Cy1@u*NmZpl*w3IxUec-^l?6~?>) z?kZGrB|E2FF-(ECm4hMH1ScNF#-A4Y5Z2%Pg14Mbxs@FKy#Ic)xDP*y@9fRGpZq!F zg=+~VX)6w9g}6u@*=b$6%aCBl0V_!u#fa4PC=WogTAt(+1g*2K)@%KN1w06Vw;*%x zTDE!1g*yatKDT7Q+HC(>AWGeK?Sjl!XYqb!WHQ23AtW7}0BA{|XG7C8W#aUK@gm8X zlTkwHg4=odh=PaEIqpe(X7O0YKo?Y`Qe1Gu7q32a3DxW-{B#?-LsiY#@Y=JvGctxQ z;<0dy1nN!xmSdZ$fT^{(vDeL8GQF_OB##}z)OE+0%g@A+%Ql0Yv7nEC=Nfw6vTm0B z56l+SnMNuJ{bHl;=^3uV2uz|AZX5P9Y}kwrdTY4lA`e!9%?46@C%&>Txz6CI!r8>Ghe~Cx-h&OGOZQ$H^eQAWDdy3dSna%Z z3?E^>UTUJO(NO`0AaUPUm;7nl)iQ*nq%(fM9S|ah;$ZJ94*Xi3c0wU1jX1QBk~UQV zTVW|~5IHI0l*lb=1XBf=0jZ2C!j9EszH>!tja?S=wv7GF@zj&w;iubZ9-eKigDs0u zeBY^>K~X#48wGly`MG2$T(@Dg^+>MVSrk38JJoU*ad-c#fBSK+mIdhDtF^;DW@A^d zm)YMVr+~!%CnWGRwA)dOl(W5^nMNiTuyNeyIKOUthUr}`y_J|q1sjz@*~h3uMeru= z>`Li)QLP`w>(eH%(Ljkv;>*I&8~*i+L(icYdrHLkNL3n^d-O~WkG0SZgkdA@nHYoO zs670-0ky0WhyOF~OiiGZQ*9Uuss2@}N=i7o_K-p3yv;v^0mvdI9qMK~0t73PLS7&x zE$#GqYV9?CE9CeX;fIbw@~ksRk-N|!{ta}Abe_KJ4n1!FZm~cMO9c366(BJl8pAOp zs##yuo;VjF`?)Sf`gdI5wZ@QLt3YXd0k;Qi@qGs>48~Vpw$=qiOz9*A@)E%;8kkYB zNMfTPo5Uo==`zK4GuQi#EOLX%F8)FE=RtM|KMXg^&`;CCOWyyX-BJ=+7FO7~D&!d< zL>}~u8UD!pj7Jj^>)}!Bt>Y6NSGFV!e2{3eB--RQ5B7hUCcKlOhf(!xX6PAgHl zqgCZdhRi=`IWpspZor2E5pcEIw$17LN=#$H{B?SA&tCW+;D$X?(;OyYWNcayJ-(AQp~zbd9~NmaP8 zHe7b*Z@xrfmE_&_AE&}1sWKn)AqzsYo!-;FT_6+ES#vm_L(4G(DLs#Xgk;piD3Mlh_ z^n6%~yEVyvSUek4kR?SVW)XT)`)VP_s6Z7}QH_N9^^+S1qV>Z&X(WXSR&$`taw0#J(GEMXw>#t)w(fJ`^9U zd|mh(M}p=g?>J`oV%DG6N~#j~&rP;!0qTmd(~2}g9rtmH6YC-x8=E5?^zc?m8(fC_ zS9&8;QX5t<7)3&ph1c#dRx4!yfW<*-?Sx|}LmWmMN0vA2kmrdtAFMG?LUW2D4oJW4 ze9I$mmw~TODe;PSE(L)Y#50U{Ji*#!ZcE>f1Y!ez4F$}+Rzc6$RBn2v6{>Dyf;e$g z0?#OuqLWhDp0Sj*g-Bi0n2*Bidm|q-Cqg5-JCbHkobzpon zpV>I#gUKiY7v|0er{R+a;Q^}bxYy!S9U+J{N^%k_Y|)I;(H`muTZ@FgXBMz__I*ik z<=cz)U1RTTy@kSQ%3kL)hXvpM`<>rC7Ee^W13%qrbFvzrSyr1f@y*M$ki_sIGaX`K zdMuBrSV$Q)ueR`VHz<+J0P$w{)Yn8vV0}%hw^~)aLO2v)Avp*H zYLTjR(iT!1s$+`uPYXrh_(b^(s8AR&HS6(UqKWvU_)M4MjiXE6@m$K0iT-YVc|r2{ zvm(dq@V!yDXf@6<&>`m`8R^1q*g3O_fXj`L!sCG2YFxXF2C|VUb1w1_N6(MX33jo> zDX#$8`k7rKc@w0I?~g+NwH=@GOVrD!8NRz66oXlZ%_}?0E{7l6Tep#nByB65ku9r@;RTnzK!x|IEjQA^sC$;@SY z$|(jGB!jRE6wM|>)`)>xF@?ofIQA4Ypt4FIFUCQghrUS{+0OgT`6eE|w9$0`;#m|K zfqtL9V5ikARO#BiM`zzlH7h%XeE$*^8reM4GY*Cy%-Vy<=9#8(G(0a=(6u+unNIG)spsR9EZAuLKH!DFHTQf5|#Z4zG7HYiF4 zp$wvD;tOaG)k?#ydC{&G-m%<8JOm*i5=pF zMn^AH&<)ZinX}QFK6}8-u#(*Md`c`InqhmuElHG@iRagfWxTz7*0$Tb%w2{edTDLef!HTiK1c-xF1SMsZ1;*r5W}>p9iIh~1-4)dY ziIqtZg2nJUgu(H=IY@as5$$gH;Wf{%Q-UR@*zZ4k_9Vz&tu-7Q8XHF6eSaQj5&1+d zg)T;_x>D9Wu6lQt1U`Z|7eLfx;V1|LC6Pc{eH{8A3vSWfn<>tndDlx& zzh&JfE|c@G{nwjch3Bg=4b?4^mdb>Hdl52FXne1)?C+p6$Tu4SHwK&VN~0}TDp;kR zxOri*VnCEw`*_3Srct3{a>M!*ng6-<(_su4uz`m>XN&YcyEwxQ=3z(=C_8C;)5L>n zjxh!lZ@=0k#Y%w@G{3v$qGrf9>q zREdyD9j&H<7=xifa9WRzz}A=RA|kmjIbfgYq70(yj8I16_Jz>yF_gtWk$bWX6gd%{ zRt1X`K_T^0X*R!T*88$Ao%P-MlvWvK(pHr^Or+JCuAhN^6PFMH(5B`tviNPl!i%3`-yb|C6EHLOhgL`1J+bqCzob;kVBb0V_6hqI1A~H(Mmq?`4tEA~9T?V2XbO=_6-)|Y-*RRB zyhK<@Y3uGq90wa=G`!4wjO>?%3&cIzU!&na;375&<4w9K2qkp{vK-q(dM!6FNM#*P zE|Dwmyyi-&lqiFJQ!0@MP$KQYb_`_ZUXY1xv=t-d-l!9uYrU9{FlbBH(3LZ4K|V-6qRr5@da_+IH8QOw79B5$Kqz7hu%nBiEz z`^tBng(oj-_S|ptzNtD(nqaX_Sm+;rb{42j4s7$_yzx+2lpn7JAQk}mP7C` zwO`<;+cED@tsw!wvKh8 zjG5J3D#SB_RfxjevQYIj?h50T)l9n0Sp3ktp2oaz?Xe~J_4T?P!lz427Ma3+5ao@D@J>{ovtz2N@~G%K{a zV7;14S-!^5{$BIJB%Y@-onn2Mp1FYS1B)Y5=I}v4odVc=ojV`&)vKoQm9>&t%=>MO zw<^FvUg!JpotDr>6SF)Rj6UAFvLHeT1is3sw#;t8o2KXn1vqMz@Db?#5-1CA2`3T; z*!0M2p@>BltU7p=1IP!x8q_RG?YS>K;xtOAaz$glc z=-?hVh@vCvIHKZ+lI8b2XM5jUx$~L6KfC9TR?@d?x#yncInP;MHV7l$@m-^yP z^K^Jzhh!}7ZMJKTje4yDCSyGpPNA5t1y_rkCAdl+M7G??P8*(|>YQ2;+?pFrQCYFs z`ZPRdM^K=KV;PgH%YtWp#H>%Z2{6)5rd07ja?7D{GHRz1DCJ8Ub+g0*6!irVo zsQuYxt}OPl3EF@!prNp;X$h*4`l4iz3G4!DQ9u;tGcqbq9c<=K{r+$7|KLl{;O&=e zF1_oWstj!1S_Zc~Q(x5FfH|P1YXZ47^t54X>7ZVypavxN`+TRJ78J9uCzu?&*2Vc{ zjaUW6Mk!6(-CQjSaNGeX9E8@O)awZT2QC}Jwq+!-X;QLFA%(Te;~uLhW8!TGdVD!1IO1o5<8YR5v5nLBZ4^qH+JzHd)z%gL$<7TGk&^3`+L>8 zR6I}=v|**LNY3wxo}dA%S*7mN#0wXRSp;RT(N(@--t@y;F0~jr*fA1&i@zGE<$wL| z&VI}rr$3F4D-9&)>D@gHmzN=J=a##AKYBVqO-yf!-XONp=m{#wPR8SM1+zF4@4$zZ zJcAT5@%W`b5dje&jDO`PVtD%D&KHu<({a{WFO~ZaL?VKIGXFxTkiVN4LfV>I;9VH! zK5yhuVY$l2`F709qvkl@Qpp<~Z|XzJ7)*73oGZ~4vCP+r966t#VGu>Aq9J&NSOtbj z1fXfsBk03)+~k{1;-ic=K)_l$&EHolYW8bIY&e6+6Pvy_oJuTE+6!yz#(4q_w5Psy zA|1LzFgiLi#aSC{Et=&KoSx8Lix+D>Pi``=J>}67`lLS6Ft+h(PJ3!kSXRf;;~ue8 zRrsX*g66@dV9Lr`RjeQu*F@!|P&7i2hx=CS&y35{LOZ<1g}8IyN1yg=qWb;#>2@%- zczoVXa0@J)8SnJ!NyNV?r-fkk2xFUZM{q#fMF$tdvti!4;{*1aO%Q zT^5|Yh;?U6{{75*{{wI4$t4f_V!aum1EDpj-FLU^l3LmV6on?n(T=yGnWR z5*_GtiPdSU8BeYX;;qhcUxG=o!`Duh3G24|k8Iu^cMncPpf7;Nc`Yie0l%}i4YSyN z-SpdKZ||c^BxSp+nc*!*7T1~@t}hx!fdvZ$9i%eD8`Wz(08p+~c=)VuM%$s^vZ!@4 zzN(E&C1OzZS5q7WltKe$0=4jrCSEy-RE5s^F-4(<})c}i$SiSk^P%xpRP;sNT{4i1lx48=4o%}fdvSjq&lh?gp;4yTHj zMu`PsH&w)u?{IMqh!D^}W^HjN;ynCc#P^vA1`ehWtT37@Q4}Lgf}*Ly(Yo&PYozU! z^kxOZ&I|ae!j!+u^0ucR{jF)rvgAmWyS}KhWPUJ*>na`Tut{@u9&MY(nI-7z#)$R1 zsm0KQK(7LlH^YeGcr*vdJ6a=G&``ueMthsEbUE6Lw3i0R6;yH)(eVV&DKN)u4KatPk!EReDBh|7++OMG09XV zL$g?n`Y_4F5T&+|RT=U*4=vV6cQ7bf>!?V>JEl=;v)Uk*4lps$I7m z^(F1dTVc}=+u|rkSs~z`0=(?9IpvPWysL>XTehb9t{YS~q_@0BW5x8=G}lU3hSLjB zGi-on-cpg8AVH)6R^2Sk$@?+TrJJ0E%ybImm(5&~u)23=rIy1Cxy^(jriNG27n;Fp zlXN0VMMn*#W^!45>Jxu?4!&UN2 zWYZ>y8q53(9*3%e55OI?8mQW1X0D3YA&JuGBxb>IlxNb^*{e#BkYopDOp+w%UvycG zw^4>{Ak^g0QHzpA!*n{)(1UFcgCj$7&bJe!YMF{uA?HG|<&*`jYbE{s4ep>@YTuq` zsj)b{-o|+(W~)X?ebRnShtw6U#RTbiV1tp*!}{31B%&00!wOQVxu>@0{L5a%aP%J~ zcWV2%8Oe38`x=hBb%r99B4;t)+Qd^4>`Dbp#73qynKLEh?+ljVpsuuuUCZ78nDuSx z3a<#(;(>B2bEmoeqOZN-2l&t$Z@BxZ?$)PDdb=NXFi~HJCbvL;EQzo~g{0xs?2i6$ zz;ZQSDt%09_u&u^zZFl9jR~F$69&siWD5+$HmqOCw zjsmdHWpLX+ym04Me3{yA{Bf2a%y-cV43Q5@LHF)qKa+{)3wTV}9?IMl{Mt!`N8 zG|uQMjms#b72=V$idm{49i)DL2fgQ>7jQ*O?WZO8_n&%y59R%Jz_9lqZUTgKPCw}cv}0wB|AHnEu6(}Q zGDj7S7qvY9&`P}(j12li(~CNz+Kcbsh8kyf!NwEuw%~q?r-i!b1B<0`&ZSdg1}B{ZD1wP^SOe+w(7MC#zJ`2 z!)0Fzx&qfl6XRo2ih@ZA+^_@Ed4u8)E#Q>eSb;p;It5bj;F)N$jL{vB{C^m!9+%+~sek!7FFPM! zu(l6BUAfSn`)5A4H8sMqHJ+j!VIR8R zLTa(P>?>kO-jdi|sDvYt?lIM&LOQ77-|v3+-EMsci#oN(9GFb(d9dC+d9~HUxWADt z@csC|i6BnMt8LLsTx8Bm74$;(<^j@a>Z`_|Qh5eRUGFA3Ew`d_0AnBP-Ygj4kF{m2 zWotlqAcJ@lJa!5E+QUf0is0+9JL6y!Qk(18^4ljqlPxZ#!m&-o^D3NPUxcXN6siwA zFU$Y(tk=+p8aV{T>g=V z?3MnYl1bD(4^_?KK+M3*hUrdBpo+oZ7AAQ3EcRtrpKV{}o=!>MGS27S*l3P%TW5t+bH0N2>W>Wx))s|f<%DQcmM*w1<(JG6Q{hk3 zBJ)DXd7^CO(BFbI`I}TL^LZi>Ax#Z{MXxI!g8$5nwZ5Pz5wdH_c0J4KO-MUFc+Eu*C%!3Z zY}}J=*`0GCU4+l<5v-a;T%t4Gr4VCS9)#hDRV;ALY)8{{tk{o3!!1z4i68PR30Q&y zc3~w4E&+lQ3R22e@pX+9oc;cfJdj1}+94$&?=dOlxxh*qC|s|qH&C#;rlHw`PhdVp z(7N?R8Hl2`>A}GO#wiNq4j%2~eX^xf@Pi{BwPPnQyuHF}3~p#UU-9ni9*=KUHrlu6 zuz42A+wi$7rHTrtp4}1d)QUl?$Ix(yf0{oNhpt%zUJ?04rYdp2&?n({R18sYv+POU zC_`GVo@QCY4}MDLMoMK5e!7w26I3ds#n!ZOgz^-iAs{^u)pkG5@;w$Vk2ab^LzR}8 z&ftZTH)P>gQ(vVE#H}i4*ymFx%8Y4>A?Z>0Zq+5fO^sdZmf)SCeHrnEnFPD{v;J`C zQ=W>iQFchfo+r-Zy^rEEJtIOnGlPR3pG7DLA@;PuvdDaVib58em?Gsn0knwV+-ZTY zI{UbjM^EM5{vJQwPx=VGTk>jk9_)!X@hvm=+8t2!Ibr z!|8b5EqF~-?7irig0=cT2^_@G{&4FLe%rs2#VFg_x5xHDlPOr!Oy?OAl#ET|$YPuT zP_b#}LwM;r8Aum^=^()=Zo~x*gkITli$<7`6AHE1tKe1DoWvUmT}uj+tJ|B~2nq$&c7gKMPi1liEG+}N=>mCY!F?QIp3 zAU+6~V=KdG?z~;Yc~7uZflmmYD{19g_>3D+TEv(;Em7HXw2Fc?!ZmF`)%wEr7(l%X<8k;sw>TqN*24}^ZLYQ* zR&7+%K9sQx?QR*B&Ls93ng*2A=x&GzM-+kXls;wLlqI6i5K@NnE(um)PEC3 zfkvE6B=x*D`fB-SlKv<&AP-pS17^S3Du4*0!i1}vQZ#;mO8Jd%S^L~3wYQWsc&=&! zYtL(kM>;L^=N_O6Ok76sQ8Nw9&vcrzJM}v|iC`6bvD9KxvZtxAsyD)FknZS{5Xh{3 z1B@a?(3urzfjS1Y_eky?N+FGNx$_mj%ukOL)N*YX&dw*lcIC?{ocopd*XOBl=2R;P zE(g3VLYZ~@O0F4}ky#5xZun3R2uA^=vPU)(MBJFl+B6{x!t}S40ey93xWy(Hmqh)A zuXyB5l*H3ZBw-7j=S@v66saJnD2mR=4pnO(oPi_d5vGNV%+OVyt>hfFRYcIPg#Z&6 zCM9Tv&SSh6<~v=jFsA_lbJbCv;Y8EQG0$(WyoeGjIi+&X@hKp!YtCR41AXu9si5(R zUZ&*tXnM!*E5v6mY3@m_84@tnx+0wjb!Q63z?;55>dj7^*2cZMThUk0hRohnDdE&1 zBM6LRK7{XxLHHY|0Rbaz;L5$6-~X;%k6QXme4$zys9U7>{~%n({iD2aLZ>yexgAvx z3ZXf+5q+c0ssumFKkS&%wHP{u6fHmS(j5Dgp(Kz#mXSKU=E#M;U97>IAS7JnDxq)f z1P5#T%z1>Av8b+Z9HRKynR{eL>xCs=r*B?VVJD=pNasD|nOO@I;if)UzjwAjqZtbe zOs25X3rDWfNEGvVW|J2(gl3Jy=M>MIn3z$J1kathPV)rtfnSHsDP}=~mgQ0!;5~If zgi|igl7sEjKYY;Va5rTWv3nM)@E(lI(4$TZb?hbWF)W{OYa+M-J-{ny9pse?PG~1T zRT>*}mO~fJ_)UNvVa-FZ95hNi3ELpi>=Oz?$lvs|Nt^FHhq|9&L&eidBk;xHyu`00 zZ$+NZi*$-LJ)KkSQ&vldu?s+X_nUrq)qRKyOSY@+u{FagMD8A_FPt76&1#S;MBPfD zS1JhcBluJ}CF>%~s*R8kJ&78YY(3+CC{e(uB6*Nf*DvZ7flJI1WJ(qX5ea~$Je_dQ zhBwWvH`h;fdH@e@s$0&x$Ie6XjmtKD?pdB|+nft(2R_v~x31{#cLa(FswA}{<0=Ic ztxt{JfqycIN%I*}sJfv9mmm{X8#GZvR<6cVi-@nx!=&coLOT9;A9x70rFMLYKUj?{ z7KHcGDA`wB+w0*}W1=&n9!C;*4c3DW&Q)f?TYKAVl_)!TW{)lVo+k%>4L)_Xb2`!# zUofFK4@ewy1TPM#7z2_XMqB#UjDKh8kA$nCcHhi@|$v8k9D_5XBLmO;7B*+XyP=vg5wJ1N(JZjPQ2{^yfAQ* zV;wtrDkIY~i?YPS8f&eVLTV{XhKg~5+3`3^7DD)XubS^%1N@IBmMk2)V0M0c%h!HJ z!TcOQ-OSM|)JR!&QNh5P*6R9U7Y(U26%AG+aDoFE=8Fu(+g2)*7jm6*bl@Y2w5Raclr=7*(2hEQ@<9HXZlNr-3)$!-2G1uJn{eseo+ z+P{%)K{c{}-H)$1?~iXMK6w!WvU&#kTR7b`WD^O1C6oQeROOrlkQ|O`(YplV_1u8u z4jiGi&_hhA)~rB0LzI^EHjldBD(UXyTW*l=LO|)Ujm}vr`j!W3ebWWG`{n=em&a3( zB@@GtEhPqns9)kt6Va-W6XuZR*N)rQN$2#e%wz6c@oUR*G4&I>#4 z9ldbx&xSb#=32D*h;Wj-oRVvhG}coyJca1_@;`A&4d3-|&*0k3Qc2myW=g7Oe5Q^P z9(dO{)|yR?&GDHAcvk*;Hh$tKDkO4f>tPefepJVz$vF+4r8J%@>4CPG#lnGU*Q$aw zKw+64jSw%w0-DQgw9xsOyp*rNf`83aQ4=@wJWI|T`Nrw^;&BVEH#W*3aH3*$~t%A({1)nU6r90gf>qBi)eIl+n&Y!ubYR-WhJ2Bf-los+Dc?igkn@qV+Y#PTsBKN*xn8ix zUuF?FZ)Ae!3I5VkcQM)MV+#+s+E1%Ce$5NGPNaJ=!G(5KWBvHi`2J;k=k~lYIj)|` z;jvb$z657dyMBo|%CEUUY*sX_35;b_;%g0Q0!%V#I5yTnC}-2eH9HvgBvTgcV_5~P zNCH2F0v9ER4rp46-((TRoEd3f{ZHM3?7~>^f+wu|Hif|+t?qDW`)=7oiZT!vws6{V z4vvgBp}Y-m3@p>M$y)zEoe}5ZKQJaWDcq{?vJ%#Myndu@ZSLWsuiz*?GrUw6Clrxi zrd3jd7MUmv13tnG)_$Lottyl zHt#GkB1B~S1%i?qiu(*u55Px3H$>AYK7qNts#8QZ594Mx(KLHZ`&Cal0$;LrBYwI~ zCR^V+hrq`~vjiX5t4sY9i$$+t9vs9kU|v(H`JBXaMl_v~aQWyRm(mJrPbqoI?^Z=; zmN%CtirdW)#f9qzY2y2;L;lhkl7|r3G=c^nYmf>l@m1Qz|D1ohl!*-}&7cXoO2?VM zkX8-_#hwj1p&AV*C!cuhFHfMT{(_(G$A0d-imHQ81dC+PJY@?O7^RYlqWIv+A2LHMt(|q8&vUJaCtv{VMltb{Qt1jm#civs-Ru>%c*Pf?vfx z5BS_E9;X)Pg(dY$!V0&5qzS^}DK7LXo(L2>M02}z&wB1xZ#!H(YuQZ8d8$a_S$X_Z z8_V>u3MA@%;#u_qAqW~bXK`S-iSoS=rG#5LNVk+$ff$B;O%W;x)CvG*JT32*SNydI zGMapH9vAZxIOe?NLd+B}&nH02IH^u`#se8_Z9%Ct4vrpv*XO?YT71tM7Z7$^neD+P zyRwkyhT-t}_D0eVQ!(+xjC2#u5J$Yj+4NXHNYpaRO(G_y^Y9h}e6Set8y4obG<2k!K2}x6{ThRieii|1@Q(TN=BhHUTb-6=Eq%;b{+iH zqmRdzEghD#6}a;(tJmYxfdKq$V&gbre{2)TC_3m#I-x?vn#AI9nhBMS?t0c}eL;eR zwG$>8q7`lk^;{yum;LLpETfgqvs{o&Yf*Cwjc#53s*cyOE0Bn#u@Pq^p|DrQQ(cDF zFM(y*Q>IUdA%jr*%r1iKf&b=Qu_OgB5M|eu&B!pCh9|A~T5OMZP)7v7n_xZy;2Jcm zV1r$8+n`WHN=REVEc$MTn^%1DySRx`%J<_cJ?ayrhe9#Ti#x}$oX;ITbIL)#*1+a* zT&v)o&c@5(o&=%kc$We)MkMxR6l@YC(nKds_p*T*7p z*6l4k#|=XZ7}iV~75%z8bGZ)f((4uU>lD024|c?ZbC;T^d|lBR4``ZiWD#5-D40=U z{`ik{j;0rHQVRmk+;JM~C+9wIDL$>Xx+I8w=6~&mzld+Jf*rL~0{}i6P*NNvN>QHV zT9>TOA*qviiDKX;dPH97*^}gA-ri-XQ*(7dZv8icVkU02uVl6s2jToPcHbbbF|sbt zgQos+7a6D0?&W_~c@i-#!hyyk(!HEDdlNC?PH=&<0qpahJz^qjvsCu~2M=ziio`Oo zwMaCx*qk?U!zi@SBI=Xw9Dq?)=j9eFkd=)=7???WqTPZ|V zqF|q$M}Y_$_vPZ;f*|n>`W3##Mgn<*DFU&+AauDh7)ca)QwyLW!yqs>%nZ8b#lE1h zyYe@&UsG*!Jq&+5eq*TsEd~Tjce1c+3hbg>u=SC@rC+Muil1)hWE-6i!KL0Nwi=aI zyV&%D5+^WEV{i=lPpb-OcnMy-SPumeADTN-+zmq&Zwl5+xkOt*T39Lk4I86XzzQzS zw#^;ge#I*ucnm(LlvTe>wS`GO=2KzdYg^5&?F>;fs*@jX3{Jy{CUCIV>{`AJO>-)m zZC!!%b@`r+SF-tJOsD7M{-9Apcqs<*G_RW;=RGS`3USFarF0>(lz=y|7Lxi3Tk)BW z*mRANj|z=duZ5h*RbuBKzj)|f_}XRXh41--%IjcUMqvrtgNN&~2R)@|B>%uc^AZLH zkfc;f(!PLKugNBzt)AsID%>zO1@W}-WL-Xgt1u~nPWK+7BALzMJ=k<|Kcpu$5L32Sg`|kjf-Mtnj*RcSO22tS--)Jl#+)#lYi<(oq*#eC{Ls% zkaXBXa-p$7E>v*XBoDKE#4>v4y#gyK)E1y)*YbKYZZ8O?tl(2{^Gu<=&H*E(zFMM| zN6kdex@2}d?a(1Mx7HSycO_oFl}$6)zfS- zkN#d~fa~dztpdTvnK~ucL(Sn2_6fjW0|08amTo%b`eAI@XPe5P;0$#W)DfzdM@I1n zmJhlV&pqVOkFXX~w!mx8wV6k2O>&B*z8dGx4Ho8j@KLli2a5zduX*RS{gfNQLwB&dF0)JErDlB%mVF}`_ViBdk{22sy--1Fuf}H% z@EgkfmZE?>H**UOMpJMrN>&+%U?9_i0m%Z{(k}^*AO{B*f_JUl?GkedocrtV{qY5q zz%xrEU>m*fgUh`zk7lq+4Dp@zwkDi81_no4l|npu0WlAOaClHSdPV2l+}2<}tF!(A z(G#^LhgaU~1!xl$Wat1Yg`7umM{nDzAZD+D`W2X|;&1Ee3+bT&5rYacJ{BtMhVC-k z`QbB;zX3N<`#OHQwdNbiXY~!i^g&pzLjY-|;TG!61{~)w2u5JbZ09TuJuJp+*Lx|9 z`HOgNF9=)1Mn2*tW)LN!$aefzPC4$x@2sQyeNxHe|K_~j%K7-zl|m?5JB>ItG34w_ zh48lQZfC~n50^S};0du*6}e@`Be5;bYIVm2&vooEUJ1xfewk@RNQa$vq8=`$;~%j3 zP0U?Oo4dcKVq(WiA7JlHy$^UHN`G|AM8h);xQ^NNEZejG7+xuM!dx}`n$jrhy{N!< z=IPpqjOcF8Eg~aG5;c~k^D$;j_16IrxeQfm#-@)k8w6xqe{X)_!ZKJrRRt8B31hbk>5At#`c4(Cx{wSf%3 z#~wOh^ceC=qb*k|1RpZOYv4O9fPmY;o=v2h@f*om1;eN@AzjrxD$_#m!+^y}tr+#J z)Ju@z6&x*~&Yi86{(3lON7r!w`Mx9k({fZ7)bPIgz*cA_B>XIsQ%qxnvd->P@lCD=aWQmZ z^_`D>I^9RDI_r(^7CUy1QmqH9 zi)u4jWIPai$P$C;U}ATL{S{O449SKql55>IGR~Tsx)*P_R)Cf!xsvO3IAaLy`19ZQ zg-25~FDMC6yE8MvV@3nyqA?x|5XknaBBPB{!`EEWX>7jc^JCY1YI?GVYb|!Fe z%j|Y_naD1{d-X*ZniZ{-;pOd{$}4`bBvk=elnt#`p=epJInGN>{PEZN2ja|>e1~$| z`YK1-=BI!P2dB74&j7Pq&TZ#C=!egu?8;os&*np|K7|iMjTuEk(FPW_Vh73;Fqb=x zF6K%Zhxq=GrHu_)b6W!9ncrw$MUj1V`J8p6+rg3in z?XSKjM0HuO!*7$OEoq}oE*G1e0f(~<8WSkQR`OdrAhtDW!*Q-=T0t&0sRALVfo&ac za!Dz@rJ*n3N!`b?PUc6bk)DKk_c&L1EXog%3sIp8BZ}%~c=oa%KI}R8wzcP!XqO#x z!7w<7!l6#}97`d_ltPyuKkeW^$$tW6BFw^e4{>uWl8M9V0^oyFEyQ2H#oDEp z9nP9gDaibT-r_;Hyrexve$br{F*MnV;pW!SYW*KO@Jilb_FN)MLl-U+26dC%R|?iq z$Q$%$U=CKh9_Z^Cw3Ns9zeR9MP!lA8TN!*wp{qt$Ao;7r?WsW0x(^r4k}C#(&)8IU zL~@j``=##sfieyj5`$*@cd(ttO0r@)ygC#fwh z^;}f8ux1&$l&W({(B5R?S(PPET_ixMh%&G-)nuj3LjEc5c+VDWR<5RH@YRQvO0gO=1q-?4^ z-q;MR~AYw?)hmmH9VZcQ;F$4Vg=67j*C)D>nWAG{qX z5GE>qw{@M7fKo^|Q4*Y^ZPBU3mG64^=yz|yH>@2|5}o&{SQuuOHOYA{;m#LyQpDsI zm0>e4q5IV?RWOwE@M_DO46J2M5)z52_NwVw6D;s6E@nMYVjNC~W(-HrY1-Q&SG>s{ zyof#rF%)8Fmoi+Dd+jinyRQBtQ`OShHaikTmFF~6S`Iv_YcmR5tN3?~Re7-` z4T4Qz8j9|6@9SB(5TB_4ij1BJ1d_5_)_{{V!h>>@zzi{IPhPf87|#f2v^H+U;v=?&VV7-? z&0=JFi5+3QRKdu&ET`X#-41EJf!URxc+Eyl@|c={o_F(PdW{Gn>&9tFSc*gl}a-~u$gnQ!TiZS;2-%9aIqzqm?-FhO^ zveJ8SLGd4Muc++1>)Zw?%@|3f6yOVAP<1&*Uv^z~wul<4dBFAOBoaqJvs~(J#{_)Zf3j2Fe!L;-do_Qh6gBakV^4RMwCkPNl5O7mptw!O0Hxh z!(Kb#hHdA|Kt_&W$iBX~(>xuZ!85kQaBZ_)Yi!hO6{5gSynH3k(u0#tUfl@8>=&A+ zm{m$PN2T)+>HS$*6cFtI6=cV7pe>ehK|Tizo@eC(^4YVvM0iRs6D6CrpebpO%Te5| zJVCgtF!gOSvwJv>ogh+~4_BdU=#&V}tyav2}+{a-V*kF8B6q?yW*z4L51^KIoGNVCdsV!lKMjOXaYybl`n8~ z%HN2$wS{tMJB;DqV=wv3V>nM=`w4!!GQhous3qSImv}5^9j7n^b-;CKB1DY-R%t0} z;&p4|bkgVmNPyJ}9$aXNX=j=Bz89N>lYbfx@%|l=m8ZhPI`mNvg^jjbPBz%0?WZB+F z=&j!umzN=%TRYL->ZZXIcXVWm({|{7t=PZvDZF^8*4)YeknixD@Z`iRk?bN=FQh)C zCA1J?l;$;lZ!~>8dzsQR(ow7mjsr1V@r6c4_I+7%oyBwSJMw>ujX_v=oKPWrL6_CV zPx;5M%3g_*y>)vJohMm+39|AWMV$p~RoI)nIg?kCbJWbuL!XP%v6E$l%wvM4mk1@! zG$uGeCn_fASsX{*Z?Uj(@Dc1*W8_cd0$&H=r{#D2HZZ@4u7)}9yy3q4*vMN7nC#FS zbs^}tSc1*1u59W;(A_zVUsmwK(q+wWoGilVY2|~(=O%||m3v88wHoJs7vNLQ=jH#1 zs1zV7rdk@kXP&;q0J;!XqKK}jY(|UiMOs+VhiNjZ|Nfez|3Vp+><`*o&)w`C$>`Jg ztd(q75bx+;6Y8H53%Lso^a3=MOv-qZoL6VYAr3gx4{)_&hm-_o)&hKsbzxHkw-zZr za@t9i6iOtTP0wauEfx-J|Kl5X{yQaAQbgNphn*aZ%gf+szyO_uV8DGYu2YgE%cZpH zW%eU5atNNBh9s4kfOL{-8LQ|ia99*X!zLNADi7q~tKCjr_APj_L=o`O7%Ugf%K>Cq zHuv&MWN=q?{k`fpa9ew+8rj(>^Clc-C~Lu4BQ~Xbf_p;1_H)CviBE$WY!TkWpk)Xv zLp1LBovqc3#e87iA}S6n2RDk`ll5nfvo5J~U;M;t1=k!3adpT31!{0){g*S)HG$|m z&?Z+RR{uxk0@rQx*tglM(7W(jI8|>_L&;2Xw%i>dxnPzN^RjLN$$+3zN_T3?#@xoj zAMHj3r?FAW+Zjn`jjwX>VhX?METKCeb;jquh_6_-4`}a`RW8ijmZQes;m~kiRq2v*{i zhMl@ug^qh41(Is{IF2dgI*qP<6u}SciYsVoBw;@p$`F&-+`!o2&)!q(; zu&M((4k6w5$ivl>xZGiC)hNQXfda`gk?(d%%QFURX~>+je*zmBaRhX+G^3iT1XrRj zU1Hm>dg6@iQYzU|w)g3(QB3b;iV8Zl2u*%N*cs$fV|p)RRM09M*(28~nAs=s@|6U3 z{Ni~?5f>^^Oz=PiapoI^>Z~XLTcky5`2WP{#*+{|Gg!@Hd~6V*pVD?O7a^=SHtnU+ zw62NQv%YxrN9l{pmd)(7<7t?uEeB4l_jcNwVhEo~rgf+B_ISHeJ#HIby2u(AvjAp= zWux+`6j=Mo#l__E!%Mls+2YFeUdiIFwDwQcVyEYb@KV9{8vagN;OY=0iS&I4h~)TszFK$0{{44L!YhfWHU_ zBg{qeAwk+$qoNgCtqS0>71thxSYy6eC}*2_W~~2>T`hgVWn}(JW%I%m)mLC&6V`@I zqO^j|@$P{c)$!~w_vKeA_}_Ez;sN1SoqiKvsV%(jQ9VA%;QF)84cEH=>=B#*@c`^#{I$G%Z0kIXVMl%Nyb+9E63KA=L8g0Px z#GiiLg|Yo<5Bl)6_;#hKW>1$e){cyw7DzaRG0ERn5XKICT953B;KR<6A;}&Sp72Hv zK0tLIxF2o7OPK_a^cYTOQLQm&;}SbCy_f==!MmXVDf_=@PUgX*cq!M7u{eJBr8|T? zEjcZFuN_nrnld-S`4WVqHFyOPsvZ8&#VG{3wGl3uP(~AHH!V_vHTbLXpUOR0TZ5bz z*xhhP{8Di8@|j7bmcV#<4mucXknQtawJtb#^t%$j_T!$qGYdQBh-uae49;Vx_)Mp3 zuw~=O#6)8=`sFGus^upRFc(r-tZ+r4s`ON?(1uo*iEKWzfgFT&#H8Tm#SHE5xQ=^J z51V85ndf2of9LHVXP^J;4j1{F-@fp6imogt zU8166bn8b$P?zEyfnNh1qr<2BqSgO$OU~5^G%;9{zdaaxT%%=rkV1wtH zH93L2-qRr;sM8XSZ#t&T98%+L$YBJ3NC4AiXd;jB`#?qRg{3OwAuMHE?t-uX{(~Oy zFnr%q7-;9qFzbY%W)NGaWEY;JK%4)WX@Js@3l(BK(}&gBZUP=Om35)XH|BhEIV39nuir=!@jGGf6Zvj?xJPX(f* z|1Ngq!RS)kfpr=by9yR;zvjeod}wJ3wLxu%q;WroRoOBD_%Ku;jmLSVfg6=86+Fv! zyzNRmA;EiaOmX>ubrGSi)Xd6wh)13};zEjl7PWu1OVf8>@3L=bed#YqyyNO@)p z{LJC%8^!940WI~pLS^|{SI|-^aaufY>B*`0kl<5~dNpVEYj@(O+ioURf`Vrd%du?) z+mK@fgMNn$APJI+Yk$dpb}_%9Kav57sO0YHG?1hVhLu<>*ArSEkQ`p9UtqsnhMAio zicucN?|b{==il^9e2cQ}wR^L3V*2OwzOTjy_DDg_;b-=MkFQQzmWeH~utY5x> z(mSfe?q)Krp_4(T-`kAU0_2Uk`4_*&TCFN8wb@g!)KkF-m;&|EE#MzpF(nOQ#6(w6_dlI~~g(hm~2U?};+M)OT@~NMtv`RKX z?X{D3BuJaI`rBBDRDgmeuW??e;INsHOEK6VvT>Qv6g+s@Sd;mjKzGS!Nd5^$<8Bem z^k6Rqw*-(Pv;*Lx`zZ~s_-D~#T>=L^|CEpRQv!D@(U&t+U)ZD5kN4+f&xqgs;rJ!; z1yo)TpIhVO&57yOSe5wvD!c(_xkMinJ~{YL!9|%01S;>$VGb#Wi>Bn#nv|1lEMZJ3 zv=@$ZC*%Uyz315F-@{j_J*-3kuSo(}iF~%O*q>D2WJ|qlrP1tj@j|43dKbZa`@ILz zpJ;^W2gq|obq)q(5yCtj^b|7*%GO5Koyvs8 z%9YUm_83Abn?Nz-<+^bgu3`L7u7RwQYZZ)xWVt8OLXLRTf-Ia1V2b~+@`*+6uDIov zko}$XAfhb93EAu@)>Yj3A~^!3n0x4e&BAZEe0IP4IiKKxkY$J5@7=EQAw{|>TijB| zzc*l$M0;?w(S8y>W1?Lt!zPE-=PjTig9uhqEl4KdT14Dqgf~L8M;5%CjY$kk88fQC z#b4`uk|G?h!KE}>NC)~U_+jfr4JC%>!u!I5BPS5M){q$K14cdY%DmLS2q)ovdphjpIDe*$?(p`|@zEt_sHLfPZ?Z5i$ zxu;Nuzr{~C=>2DvA#*78JT1^OJXp#74oh_Ecd(#Pu2k?k8}Z`RW4eWxih>{+J&Npz zRelKy6G@_mSaT=Hmb|OR*-5?k5Roxs?nLf9@4hdR9jGkzci-yU(ygw-PL;8-`iq;L ztuuphtPF1z8^92LHeyZj^hBjyj6@%clnhcUFTg0`su2uY4+s{C;Nxyn+NFYavu0|x zi!edt{u(hc`KwSClEL&gEa`DGl*{1yul?=aOxH@MLEoV=ApTn2oI+L%g*&0$j$V8^ zhAnoXu?ZI{JnVPiwJ4i`{Sw9Wdy7Zwow~ZlN~knB-(-y)CgE<;DwHr818|uO0e^s2 zL1Bj?1ZRwuWUKz-t080)y?U#CfWtSkf0AFw}CCZ(wMX> z6~rPyo;0lYK+%ySvP!^Wc(SFecW*=WO1n zveA35$w~1*80XL^JIS7%kFnlF$kN$2y=Qb#un|&v|GZ7u{XHGL%j1;A3r{?P^7tEm zx}A$1(Aon6FPMjK)3xKVMRCLt-9C}LKR6~Kp3h)U>pzGLAt$9|75QFa*UUOTC4E+GbS zS&zUTeiP!NVp1Bv^~c17ZJq2*Y8L-evwn9)GPeSR0(oU&Q=EpqlhJfmjbqaY#_`YQu(0870?~;T=A5qdBtlC{&S?hp<5|3b zM!Ig_aAHaxRDz;X^p5LwGL>APHLMt;BYz>^46n6eNZ|xB|3AF>*}qte+bC^K|D;Ne z{vZ8)1-^W28t1g)XdGnxRah)aY?XQ>cT^-Wn>47Rn%MJ~P+<+|X195htP!K;4>>%B zUNu;76nqQToXUFQ+`Lr)>@&;fu3M~Z0)1dShtr}a{d7*#F@Jd2_HR>SWs~RGxk9>i z1YA!C(7<(#Hmf^FK=klJ1;>9aUfb*WWZnTH83dK43khb5D7_T`63F6*bSns4Vjd|` zwh6;mG#kOtQX3D*h_KeKD$$z~C)~jJv~LcR{8&c-wG`mBVC}7QuebW6dq3V!qkTdN z2>qO@9-EuiwA(!HqhPa-!|$DZA0KRu4Wn{X&3509cQES4AG~C8oTZEWBZCq}Bp__M z1B(oH8mhP5BN8SubrnfUa3#p)3}~Wm34DZ=yO>2L`Pd6~NgN9fQ zUV}ZMV?%fh+g#Jgw|3;Wz!=*qsM%?Fq0@1{5R&2w-9T1@7_S8p(Je@;I zs3PdsW+2j?&9gRt0N1 z$GgILQ$+N4KF2NwmFgdM9E8RfHo_+s&Sz{~ircPy@)n+8Tw3hdsZzWrF0W|^wr4H5 zH93yh2(oFgT}Acik$PJjMtC@fa%IUom`uct3#Llm+83_E^$<^RXvqUxArguL2V)~> z!LhI95LO-W5_M|&hKrBoyl4Mm;B(LY?_~1jdD1NQQfB#@IvDYo!lm#D8wUe?k4z=a z+I!SO$tTK!riv_z=Dy8_bOxO5cYqQyb4f?t!1ZMK+RNT`B4u(o{-@hZ+X*=YQEO2w zcK=L9auR*SW9Zfy#a)b4QI(J3#Rd3IJ;qbQ&iyn!UmylDyuilXX+RG-&(fD^Xm@{P zboy(*;Xnpyio!sF)Ol=tUBs$$7<@F;Hy60EE7ffb~UCHi3ljB`mkG5&oy} zI{u%8<4bk=%LqkD&?^RopQprz+5cykGNHc zj9o+U?Lr&N8(N&xz6LAcdPO$L5aN{Z;ObihwJxazSA2Zm7JT8d(>?cocb+BnPx#z5 zS(3r;YdIG{5kLv+Uu!joATE!9ZEjpWIM-uY&x)5oGOVcJJTzo0<=il1&D^b-{bQ{Z)|Ilx=4ldU|t+F&FS7aF>*r-FGAFKVZcc@(d5rugll zTU7|UBCaaDiU)LtD+o^qEixyKKLp$&Psbw+oqKRiIO}`Y^}PT#$LY@d2sQ zWZzZO9gQ`Kh~7R*d-NH-7oKKiMfW(ub5d)$G)d zb=W1#N4}&zHr@)L!uZ4E2l&jk68vfL7XE`7r=1Ch4S8nODpMRM`i&pe80dD;5zy>^%f>!I@? zl6T{66_3jLpIntK6d=gs+XHc=L+zd30<+H>^RNI5F)qnj+$0T8%@ATyb@eVXyaJyX ztOp&E*F?-e)c<;~yD@Z>(iXo||DdAbx~}@d>A_LtPwpU8TXd0^Ua6ohU%{vLDuI~M zS{^F!RdwzVs?W|9Xp-bdYE-OuB{U~tBzqzLT4Ij~LzXY`FN!J?d4|;9T#yoDin!N~ zL!`rY{8H8db?ie9TYEAE`P34#vvW|y-wd}qL}eT6{WDQ=XI9Q~V`H>AQ>h01NxYCc z;w>Z6s33JPNjlw^0)B7}sAh~oV^}2DsUjC&*J(VN56gMVRF6EWeqw@`*hWmj}+I&WvvO2CrR=>%Dl0+l)H+JCWUFV2pYINAs+q85+g484g>Ez5pQLj`G;HUB8^_)hh zZSlMnn8Lyk|_LXwEN5MHcp?)Hc93&Qu~bOKD)CN6#M)qGOS<_T_D?j|yiC zjZ+kFQrvO(O9t5*P^+uU%onqPK>`1fUU{7 zwhw?2Bj4empbqvRX08*UQn(@5N`aj_c+xa@c`V*>^Y9Ekcg< zIC&bzMy3|WG0vnN5hTmN!y#Km6V1#}6$a!zc&T6t_z7JLL6XXPDYICXKXpcG4>V4hU8dE1vGbeS~tDw;`QWw%K9tz zJwzqeX6x>s>ZefCt(r2LH?7D6@`Kps1vdr&kOu23hmA6HzwPiu{t3C zmji~bS`v*bco15t^j5Q}LO2!g@CaY%V!HgzU;6cWimBwFxqS~$V(M+8v967p0;Hbc z6+JskXd|E?hr!ojBw;oNc=KabP&9nSLK6m?q>!79VT2P!S<06vtCpbENz}x}DrGi^ zSE+oW|3reF1~l*ZTq|`Pu+K1ivNJpq2q)H!a^p}=cWXJshARKQe#sp&2P)!f`>>VPk<~E z1!L0-?%nL42}Ov|O)R@V^NLG9i0@an8erdJRIixf^s@~P!~&KdCtiV`Yg{kb;*I}# z=i|+fSDktlUhCr))@q}^JqzxNHVGzRGfS-%I~ABS{Y$>eST?rhFo)5Coc*65dFAEY zu5SDEH^=V4S1IdE-*=ea|G~ICr>g;OUa2x5Vp`druz1ZB2E>O=q&sLLe(9Rtpgb6) zQa_+}i6krpjgZ>mU~3DQ6n0zqN;Z06!)VE{oU_CyDRyUG>0bcV6ucnu7-`bRWq5th zgVK(5L~j!(THbpoy-2z7yYaVOdz z6ecD%u+ZftE*{1v4O(~_$h@hC2GSB+Ku7JXDa@py#U`m^f3WKhoJ_27DMeQiVBd3+ z=kCRmV^2+ICL4pM=N^&^Sk})Av!DxZzEdUifAQK?1mFy}kP3Ud6)gE!nUsx;p7MU% zVrd7kJfmayPK9VLq_9s21i+-r3#95|xZsw~8()iWRK}a^J66R&4n3DS$WJ_D5*NI3tV7N zAUm=C=b(SfAu2Uya@L5YE!|1iz5bknSV~|}SjF9YyT6J$y%Mzuv$H$_wD1MJQh7xE zz$iblIK^7x#a*9{UvkwH@4aj}$-WmQeKH;n<2S8X&QESGaW^dm!^S*%oW}R_Hut015MJg9D=yx zFW0}1f+#r_YoDz>q@a2xK-^Bu;H3GHGw*RG?xwaIKiw{Rq3Y88aOv+KpuT01%5Dhn){npxAg|@kGXB+2 zqI7rQt*_cZ)de!KeyMPufg})={Ql1V*;gNTBtEh1JfVHIvW`?4HujCk@(?VmnH(O8 zLxmWsF?2c7pqAUU*(l0dz1ger@?P-FsEkFem~gGIc_QzRN{^cEguVWLi;xK(zRjqN z>7*mGF-z6uNy`(Czsj&taxLWF)TSi+P_N4YF}{|K6O!TiS8_2fIPzz&eF5&JtfgpQ zpQ;J*bI+Czwvl7NBpQoYVrufYoGqD+jooZ0=OcKbvyAFbGgO=1TKA-hFp@?TVyshY z^ubkx($Qd<%d0CwWcMTEHB5OcqYH)XhhTDl8bpaXyLQae_wH@s8`mCM0(BOvfaav< z%EiMm`yev>aV0PvwxD?z-G=4{=#7=;BkO)4Ys<)<${>jEIx14^qV=8-%_LGCE-fgs zq%BmY_2NBT8dbK-WZ!a?2%YmnjMWb{(RA5;R0HSjhnllLs^OM(YI7IjP3b|r2w8Xk zC)6`W+nG8-Am(>XRniu$h*Alk1Tn!rGeMJlFHr!I9*3?;Vd@AiIiV~&8 z30YpPHDl3UK&X?$WxRv>G3S30qDqd+s(TjyGnanx!+(1no5M=!*ppRMq{-&+c!yg) zq{1Q{tNep#4Pv^ZTi%i*ZJ!YIk{KWUlmkF`6f~wmS+e4W5{(&afgzePVDD&)6pR!- zDAstS>6YR7^v7<0JO25{_h?c~oO$bx>@Q1Vn!{oITfUfdYN5^;hug4;t&IK8fT05! z%7wHlOfyDH_1>9oWxhABA|x}lOh-DgQ<|Gp%1NYTiY}~Ej;r4y-1UA4tXo*GP+`r9 z`@ZE`6%jMkMQ{p+1ciV0ppygxIgn&l5o8LZrsle*oOB9_u(X^F)7Qzm2b;PQiiu34 z-~I(}I`fqu`tNjQv)(?#yX+7D`?f;gVwH`HRRF9nXa>Mx{;s_v^*0-MdZ3^oF zC5F{b!kVjBofNh4QqUg zAZKkx+%Bp$GCr7;>eBza;?$4+uV3t>ELgYbwwsR1fc`!%5VM0kHeG@e}Ud+rZONni6Nf{@5EH1e1FZ;^5 zY{@EHH@VLixv@#+1iXFJq}fk|qjV-P88klK>0ssECZsOyjX2;6gN3L7-Dez=ysgH_ zQ0=7W9rB(({=Y+RxbU014^oL;ix(FXcs@rwdYi_vhY!i2snKX)WrHG_BH|mj-Rw0**g_~oYT|we zmc-r0id#T^4P{+5cnYLyNe6ntk)8|b8R;K+I=*sH>rfIm!->1iG8cB;I`$1~kKh<~ z?T8Y|*iIrE<($pOx_k&xIX5TRSY$%JEM+Ch-3EJ{p&GYPRgf&*%KlT{6eA5JQ=~L+ z93u@9AMDUem}<%SGKxuFo0$65-}}yAAC50vD{0=|XX}h8rCzYA&H5T1t&$G>q#qyR zg+@m&%tnj)Rg2EXYk^jxB}CW0&kSdhG8^IO{}!Ddd=V7dk>mb$;zI6A5e!w-f-?VPww8J;&}_+Rosd~J>&%z zngb+eX+ZR2)2*0VWqdWfb}A)+A2IernI9u|R|MCBp?fMUu-8gAx6AGzomlt;;_ zU;93+@?cSL(J+s0LPhX^BTf&;)j_{n<&@LiXR2UWXijO9Tfdr2hMVCnIL^QUw8Thg z4-qBm#R&Xa+j|ob1+8AzCzt|mI{7j2Z`3z0_=vD_7kv9)e!YU5g-Suoy*zn~r@oICKNyocN8K;#`{rq-`#3NT-V@#jjo@0LmML?WwzHPRODOiU#)L1G zA0^>pJm_AFUn#v(B}dWhvsq}8K=dGy!^Ju-uuYE> zRgI0!kq)MEW+lESs`x&I*RPb*3be@rQi$O!rA2Xkj)5up!9rVyOaj-5TIzB zlAuU+ieFl}m3>MEDPuW(q!n62^jc+%8UdFz`%y0 zz}PryX99rA9zsXMY{d2RGgMq3!mF1w$sXrqY{CALSJFrgURDKcP(XcEriG~SK*o_2 zf@6Z>Kp`mxFIlP}Gii7dlGD3dLU0jX@b8cQgCub!r^@cLiBCGVIqGuw`FB)8pTS$M z5+{;uQPWE?P-IyUo_=dRo6TD3eNU0Q9u{(}!J6i47GJP-$0ySo$^B3IW*CSrmlGK?xJB-I4+p zTot_ZukYfZT>-mS5B&I_t{F`h>?GM!K0-dlF!}aB-|L@bT>nKSPAVI3^LB{B!OnR* z#3WCAo<$Pp68r)r*hiw88B~x>`kdj3a5WzA~8O(?a8-Jwk^ zsd3Fa6n8HzqfM-+sUS5bGUh#UHA6rm|B?L)&) z+eRg(aNk^>MnSj2E%!Nl-J_vDr6lI>Qly)MO24bmmH4#v-ijZc=TqXp1v{!A)g>T8 z5a6*|CygT}nA(~cJ4(*U1*N(eDN3;c!vkh$9Mxr{0F1>I1}92q&+J@v&GhH`y+>bo z9qy!de2MklkzmyvE&cns`Eh!$r4vlY;JDy)qnXkBv@C+sva zkQzeKFcK$yK=ZSPzm!M8Dy3V+63L>vI$6##c{IGcv|aIrzxl(r|A_J{*$l<%1)6M~F0@C~eGqi*gsq;TSQjwqLczUZbvCwMezF0sNB@#vzwUo2>3Woh&w zWSoOU3r*c6UqD~8so9c;uKNRXp3<)Ezp0uXjLYDo$TWaxSlb#K57wM;6zl^MA8e_^ zX{575?{29CTYUz+2hPURzRPo_kepr1KVnCmaMjhSn1ZFs-u5as2F0 zSaiYd#5_xUNSgtVvNTQrszhzY=Wdx5HfC?x;K0#VeeuZD z={UI*%K$xEvY`$r6YDy0gsEMt5H#O_m#=3#dVD|aE|FIER5Zxf0U^1Gu2lpMMAI}x zL52$f6ERmv4n$q#T3G>0l4`p9JRUPsa&c_=(uMc`Pl}^#uw;LxR`Vl{H{+9g#Hq%j zE!<+WFn-+T*+SA_iaT2)tw@2<@~kpa8&3kM6W%<|6kvdIFcg(j5L#u%p#$ck4m$0O zm)@5$Dai!)-!nx*RS~!+90Cy&-o&A*A1pE8LIvgcG+ygzzh%E@2~ac8dXYY50To^u zfWcU;AO%4I*aU~bq!Q`@tNI?n9FC}0RCAUGkqfwJuz2Ti>I?4wrW=WZ z$_`fEe}9!2>4k+jC$2~@9D(1WvfdnQ3}X)%zHxJ?v9&X@X?Rv^Cfz;JucMqGUBb!j zX8#3-Kz%HUEoN?Reu5CZ5hV+SgzHy&y_r2rq~X+uzlLv*ruBNJP16!!q^)P1P9`9R9cncU|#< zyJSh{6HD~*L7DS|DWhmw2lFr#=uDiSUT6SEqHg#NaWqF0JOf99ORX=; zDrWB7X=ezFvTMQ-SyxAmIyO9vq6ude&aA#MB7Ie&c-zHe<0e!6O_ z`yZx4x;HMtSSO-Wfx_90(2s4V8^KG@j_opz=QVgOX->@{!@+3HPg+;J;O?moSsP}7 zT8rj@6=^PFSe^V=hi!q=(YzeGW7OkU}CoZ<}y>79l`IC`QC z24M`i&=}%{3JOBT&*}_;oo!|$fMLe?>JyiT2#_d4;Nq&Rlw1gg`ZmbzOxGmL8ekCW z!rJYOMRqkf{(C<@=am!%E6Lqz@Q7q9b6SaTdpQH28$}v?b$x2q7LR}X78VQbun##B zD_jM#5hFD5$Exc}`LXw0Dm|GqrY@1+3U_^6V11JXYm0Z)q-ZT*VBvWTkxKJ-bV#@!d3aea!%w#vI(vjKVg_rDu&-CO>O7@Z5hND#r&5O&! z?|b#fWHh;?jd}kOnL){L-DxgDvEjk9RCaCNJ)l9-SxhyCIiAAm*F}gh^T!kd7?a<;T=Ok5ugew z2H>J>hx0JS0w2AWw00=M;VDFx9@;NlmJ3e!%d>Gjx<4xD$z?#-n z9Lm8!wE@+bLB#7VvpfsIm5C_O(>M{Og6YJW0sT67p58KoY7;8e@Ig${3WIey^8|$x z&epJZ0V?xD5dVEGK?Z8_h-V*}xkC~*iW1!Mx%6tghR^vvrB^~`?zi0v)Wp7_t$=wn z#7-tWYGO;SaDJIrDrh2cU=NoX**sQSzYgot>8*lNTB|tu>?}WUCyzwJvpZNTPvz)3 zSp!POQfFvjE^|>Sm}nMERBv5OxBu<@@BSmcZ`mTV{m)V*V+FKtY~=Lj2CTzF*VLv> z+1XWfT!c5!i)fmXixq@L{$!2uyVgAk<&tDcG6wPAR2}&p>6196OZt4BIe?jRr=0ds zgLB9vnOd*Xfuq8RyL8=~SQ!o)#U{bQF|@c;DjKtIbv^FV^G|9+{^jlN zV*o>ASmw=v0!S0Z320fl$;&0sBPmAXPvsniurW7IAzvI0xJ}jX|AEo7@a;+wk@STuIItbXZ}KgzFKwkUW13so-6Isg7412?CO@owvc z-xp*E|KQ9jWCDH3EX2iz-xjg5ij}Dppi-Ickvd8$I5@gJBK(UvlnE%j)`9-T1j3`1WNdyY9CQ69S~>a+RBl?XCFStRN=|xU>rjqb2=rPE_hV zo8YQkNmM2LercMXc(N>qf2uX=pQ&T<2cUc=@wtM0e5MO!!LO#@{ZgXKdzW~e<5huJ zVd{fVnW^`&OU2W6Hm6`2?$}HNu5(t0*tjs>h*uI+cp7EHLyW)(}9hbPsNqt zCT4W5xunzBe9h;_uKCpTWMjkTYcB0fOwP80$vBkAvph9@j48v5d-d_bel2 zNby^SA0l_?>6@5Rgr`(lcV@_%ga!GzRBju7{x9W#qZgFu#tEt$l-d$Z#bV1nx<@eg z)`_ARi;GC$c?mrva;XA{`5XmdladIp!j374s}Rra1lD z!)2tX!FOQvl=Gk~YfJ?trLZvT=;H{|U71R$@=tv@1nd!Ni2B@Q!?v zs4}o~LI@-%3JYdRN+=8ZLRLqRxQ9ZxKlH zYv7%-CQp~t?q?tL8{yXO#P{!ph$~aXpF>HJ%^VQkSj+o8h1wrZ3GUMM`K1Jp;<3r@MyH3vF)V z64+|HR3XfLkRpN>Fwu@)g?O+4bsTJh_AtD7I7-Qd*O1|+wC;+(Oi5@K{H@+Upl?KZ zsS3*?AqkQWuB=30Um;DLKIxK|J_eRonrNJ&LLyFFMoAP0d}x9ypsFpnbkXbVBrvZy z5%uCk9m>Sru#9JGPGTamI48~Rj(}7Jt%ze?NMbR{0JzNguF@D`5faZP?O+vEg#st? zTLHC(S68S*U;fGq$U4-XR^qCfDk}~R%+WNITN^X8wQ|c^#jvBn zNu{HWL)z()`CxTA>>*O_6@Y>Rg(zh=#(tkir& ziNH4G0y`B4vMqViCX{pB{786AwZ|J<$C{H^v_0Ic(k0JxC0N-?%7pK%EvGi4EZ&RR zTAD}^ra9s@>9gpe&1lqEMHLq%u$w3d-T}1e(Q3$UUbSg@eRw?yzL*% z#WE*Tb*@L(;uE7I!GWWERh=S$u&j+=a`LDcX|XX&whVjb43gI2lpS=7gK+&n)%eyY zCLkGF9u*S%XtM@M=Q5_&#dzCS`_8!^UDsaxbR(wLyor&e*u{!$kiSIvD;R7#VOAOo zdqPl z(V#M%%lGHK<>nU*-NjozsKlGt-XB(N+11bruQvS8aNheygd<>E@4iQb59cdjnC?cU3VWHd}6P56w$q9w(7KUA*8Aq ztTFyQsOJdx*6yRZdvZN+8tS2ShT8+l=kGs2m96~(Ki#H2t+y;Fg&RW_j!X`>V<)Dd z6#N>83iH<$9(W6%wNmKE)J8$BEjdPI=7c!T?UZ?sby>gyP@xe*T)>&-$kI`WK7`z& zcU-^WNVYbXBC*r-9`A?Cx)lX0-d(Rb(xXdJ@XHGK#}AV-coyC8ot%jjM5WVB29F5i z@uUdz^FkXkKh2|~I-6puB$mv8WMWueXbSD?n!1}Rf&s=S84wg4D=f6Tg0ueV6<1B+ z>z5`$uTojD1$9{)29H4A3i9d*{MHUeLks25Nb5)(%(RJlP!)W!1Mkw;q#3A`#CNmN zy1oRhq@E6`YZoO+v_Zj0!LeBxd9IG16&`L=Nc$3%f{8`PxalWF=Z(NgR27 z?o1|!rP+}+oIE|NCGYM%3BJU`vkV{T9Lf--p)L|m^qrH=nkuKwRz|NU zE-OL=?In+)8kGs)eVdGBgcwLAnIYPf@^ztNm34;J8PBLL&hw*me%0=yfATVN38ftu zZ=5F~l1Y@ALAWWP&upMXr3E$ee&qxua4Vh+d7yHlDxQOcSOaB4sP(MAPD?-6t`^u`|P7<~Mu!LvKFg3B)U9 zxb3Z~D(oR$j=tuJCKRuGx9+H1nEh^DztPv@O_A85p`Xw?xyi({M3)YcYM~n^i;0>% z2XHamj+-W35utHFh*arIk#dCB#ZyVH{>FEm@dA9MTD`>Yyi?`ChrXPna0pv#2ZzT; zhQjv{{|GA%))N^qFI8~C@4>5k1-(U>fKoxtqqjcyMRt!4PCd6N6zEb4r=99t?hWQ4 z-p{f`(H+qjciYD0h;OFPaXmTt{DXhVjb3HLy!+2l`4Hc)Xii`r@IY#lU0ki{P3WL# z;JeLo!GM+LF2QS8cbc#YJ%~FfJ4sud6u`^`sxRn1FX=nUFi$=^X{I9+Z|ZN6*f_zN zPY7s6sog6ssQ^@hk8_AA)nFIgDQg~kGdpri(a?M6S8yM}#}1G<2wjoq%844i7bViP zmEFtyrikKo6&#zgkU;h(0aKIUlvwOl3I~1$Fg$Ro49KxE?61`8?xm@FE~#A?edZ1s z_9`o~*dj3E#^uA!v3hT(y{YYyUlS*?!Q<`mb|o@u25-26d5#XwMn5PXs&(jYQ;NkB z1@1%bk(*Lo6rGD8j|9ni@=#JyGMixXAf=tEmOowp-v8>q2fjw>kee<164Sz$oWp|! z+!22qpFDs^Yg~t&j)D6p`wdP2TR7K(8^V$$Hy8fW{@lkHdZMtPj!Q#+OOCz9at`w8 zTE^niGyXHhG4Cm*R{DRdM%s5!0xZYPXa8yYKJrSnAK<4uLfaZJa=ps|i#yyq)ShhS zx-zQ2Z%pF%72Gse9VL=Mr6FV40&Q}Vx5uOi0mz?;ixqA`=|>4nz9KAoWe)oB(~dkI zpHVBrz8_UrG3N%L*w+W3qmqorm?mQtQ7}Le*?F}mXBprWk!gx+j1Z16D zs9;Fv;kAo>NHk{dHEX5}vNb^379jh#;D@A5RPrQ^To#!EJ$gM2KAPnPtLA4b8G<5A z)+#l*P_SZA>CPM4|H3`EwcGL2EujllLZr6(fj8^xW;*D}a`_yAUn54L4W~IdjJEY7 zH+4qP7CtpRS%u3W&7~D1d9ElZS)Xtq8g!e-QPRZtN=p0waWP{K7F+Gj>awh@sEf9! zZ=vYehaU8;W%$U_5!g@tFWm2!@!6|mhRn0;99&5(!Hr7&NFOloMuLPiHwG&^X&{G} z)v`!IMAx+?)5TeASD<|4D0+r9_4G=%RxtBf5)f^qi`=|!x^&=^(-h{f@zbq5pGoG0 zRpz9)>MN$VCi7xKfuT-R{~IXTZ>dOu4dK68gO0S znrNa`9(Wxafi2-sfI$3K*Zj(Fbis%I@g3`FB|j;-(SOZvv@?V5lquQy=XOFrg5|bY zplBB=_>mXmwX1#VByyVr`%&Gxkpr3eWciVIk9!_v3rfu*RyV)!V_JA=S^2YiZwx1M zwW8l+%BS(3Ju*hC4l%Ng)Om=z(NkihaY}~;6T6adDFUln3<$b_YILM}%wCe8Xb_F%~ zJY|)fe8vtW@I}awzBv#q96b-fww%!ynwqKy4Q_}<;0+SOG5C3Dno6rCC2!P+0p3w8Fmg&26t6^9o}}aL|qN45??hcu zH;ui0QA1=JIL_^?4PYbuzJdx}jhC*JN>EY~RtoXeFgg(dDfA);Cz-aX4+Po+AqWCN z=TXdY`iAV{SO=q0qAoI#Wc)*XZX}a@6~)E>$;;0!zLVcG^Y5R+z0}yX*Db!QRD6VV zb9TbDD-k2k>WnbgfXhH39rjKX;CowFl|i~SUV~JatVy+@{4@gW?HqoaOU`-Ft#Ghg-ri3N={j7JbyR$h3pXQCKd3Qp@ zp&V97zXBErNGS;Zms6Hb2PoZ}+nz^pd-TUY>%u?xn zgASSmwkUsnln!nnUfGed9jL=%IV6RBspj*H{C*r48G z&&C8VR*=-I@cInqDp+&GX$#|V)4ugrQa`J|%ieFnbxoP)HW`tqOGDTZl&DD2!73u+ zd$}C8J?qLZ{Rh5E?VI@NHiaAi7v!)ApR05mDP!%?k9-b~St@7bnZx^exliLop*(Zv zzpZ@P2=9h{*4=mWZ+bTz{_UT^eg{t39&kF#VYoVhON}X{%N_KtwJOcLz5_3Z{yRk~ z&nGu^_(9ff9YorB8}d|uPrLdO^l>{{gc@?dBjqZh;kIEX7;0&UrMF1gia+Wdo0j}X zFXU3%NAO)04!fTI{v(~;;gSE5CIU4{-=QOj$_dqA`@*Y-aP$GEST1uU5;1aknZpkC z0J@%wk0IcwyAig8XrG0;p`g+PhGz{3)HsPLF1^}sUvuVbaX+<^^P={DU!^zq(ez{Z zz=1;8HyX^SbRn!1yM}2O0MnX+`;`QUPR5Qt!XC$MTXa~~u{}d5KGEoI?KTr6hW;3> zc}SmLczEOLEbyHCZ?}A6lv3iVvu*?2^}pawIEB(P4NzsrB00Q@?< z#fe(iNT`%y3E5rrGeqMCj?76JliWH6hS&?{#UgW70hS~zgVRnPKI8r@8x=OxU#OTN z_zc&WvwGk3g_lrxx8kQ;V{Xnom4UzBW^8+)zVH+mV8X@_PEMTtmcb#sQbdR68@9%Z zvkbJrY4cPm+<7V~P}1P#k}w4<;)HdCYRqw_{+{id58L$}d}6KSNQnKn z>Mh<2mse%yLe}wb9v$AsxftyyAt+C@D>b5CgV*;38KgiZ1F;w@uzQ21c(@U!5jKsg z`}#DIkw~dbZ?cJ5ue_#dHm4J`LTYWU1J(lu-(u6TM1%Upygx%S{ z^GJt2|Ixp{H@Ls$PpI1bwB_vPET?&`KYvwb2_@#b1J4s~DrSN%tWH7LBtrNZ#1UEEcM`2C05PdabUi-!g+*{qzUF=dF}R z$;ny!|CBrsrGeHCgn*IL(!NtFAqCPzJyow%kjV$}V!?3ojKv3lI`f2Jb;f&Vw=P6m z!EZ=R*CviE#Y4)f-OO%m5OQX|VwVAcREraxS}eZZ`RG?1DZKb$B?@y#E}|)%O)y$t zKEeIot}`kkxzZSwD-}faUJ((XsIUh}*rL~swt^TRNrar*Ck6xnE5|_P$j{Cr_V@*` z1f`JOMKDi|>Ox`Q6Wolg%P5=XV%`S~?QM^4PZwX_82l-|XW8k{`~RGaXU;X~Dtziv z9&3R|o0%5wBG;HO6GcI&7GQw^mt>fy%JsrKL0rQyg9g3{nJj>h6CU0G)aBIFlI=ZB zdWOo?WoiWnLxtVSMUAqk$s;ztNw{XBa`60D)(3o^GgP z_Z!BoiYjIy%`YK$CR8W5vPMEB(b-U7c}((c1~KF>TwL3~zvYHg@V#pfEm5m|DlVe) zHOr>+x$-DAQ_$7=8tU9gRV*A^5V8?yk{AJ2 z=UJArP;Q@wy;tbze&+X))uDYa%w53L|Hs?Az}Zz+XX7UqG)7Pq6|7oEY!y^e#0ymU zG?UDPBqU*SA%K^joXnieoMdLsI5W8nq6Vu%rE0vTctP=krYbgQYw-eNQKV`sUaDY0 zsX&XZ+DKcaUhsRKb$j2vv%lXzyZ@Pfzi(_f`|NYhyY{*~>sjkvuRwK|NaG(r|K~CW zitfCelG$k>RGK&^NINf|EG@Z*=@UWGTsFyyp|EE2i^&y}pg z2snCqbL^yMWoHMMM#U)ZxQ@;i*l5xF3(q9luz7q!^NY58FAeD0fJBLtX>p-qi;}RFB zo=4rdI6|Nix3D;Zp=aWh>rbZORve~6`x}c?aBN+gwUb6|y9T+Z4R8sxpN?hXB&saS zqB7_nMpI3)p?Y$!!Z`sV zStM{nocPQ)ul^3D$TNbAhPc16Sf$ABeBHx;czJ+bO|=eh_cZSHxDnxBXl8Swp2K;i z#(8gKq&BoI0c6?{Ax!DAMIdhKw20~(2i4R_uT?fMcKno4!q$qa|nI+#~01j0VL54T| z$=`h1t{1Ju_cji1GTGnA&fl;nzq&gKV|6SoE?8zaG`Guz8ZP)l_|5@uYm~_1x(q9# zRT)>DMPdj*`S;jm+oFvn{RT>5`3fp;EoxF4@oZg3TWA$EGE~C{aP+QSS*V1s>bjuz zeQfAMoC4Nht*C4wkH|bU!Oo7J<#>SY=#y4K;S35iyJD0~En?^k6ja9jFetX5LI5RL6; zoXntGh0NSSWKd-n!Tkq6ay>T@S8RXT-#8(OU}I}+Hz~$Vt;x~gJD!C5WX^(}!F0-Q z@WXX5Armz3@3bJ4q7H08-6f|@=cOPp7{ZDqpJe_9dVjH_rK%^vNQdk>Q2B0 zy??Ss*1_J@en35>L-E5cv&`I-WK-zd$oG>eOpHWLf)nj(8XtzG)0wkgVy(BLZ0ZDC zhXYUv74{(`@h<9hGI8p`hLi7GNO+YlM%VD>B@Ws7O_zAz2J zbOZFSV;e@jqlCKrP$_XBFc$_7DiV~va=y6(u^tOU*=w5NYfplESreO4E*vUA`or*{ zL<0G@ulS6QAKx!K+y^R@2OesiqAe1D3Us6%?G23q(_+znSO zIFVVGxQPP2crH>kYjKl?DRSB7fU!pgTe6vpO0t&ubD$~d6(q$G-dakUsJa>MYHQy_ zKiMjfya~m-wVER>(NAnzb-r@Va}%>|*Xs7g23>P*IN^7%4l5K#V7RVzKqu9uYp`$!X$=RW6?|U(st;Rk0D|?|oRDm## zK_HWDeBH|KC}xehSQz~|H5^x(BXXsN588s8H%g~M2NgFS0|Ya&q%}-N?8xfQ=nUGE z=r5`m;~S1|lEv{9FnQt-aw%Bfd&_e^dm{AUlDPS zt1!KSrUl8|Glx)2N%EV3ge|Y*u#R=KI+LK%wZai*SSl-bxJis0eDo_g&9hQCFI3?i zgUg#nx?{*9F<8GH2`kOQW^WDi^%_tA-4u+C&Ci0gl-&y{g@W7&_tazB02tIXQ32f? znEZ}O69NEThITY_G%1X$ek9ji+V@HiCg2hC8jMHWbJPzee~MpPF=kOnLsJTtUTglY4b$*5^l zn9$9|ydsllDPghJ2f3$5kh1IG;kI_@C*u!{QDTRmoVUNROx4LGHVJumxAmY))+I*X zOA63C;A`tRS<`aI zGe*!-Q-#LrRAL=jC5`zOK_s2fNC#U&z55dyt4A_G0G_XbEz;pQkiWHi3i0B5Gi>On z2Q}FsotHe_IuAbTfy*TMuflIq)U8~P+M10-O-jABCXM=`nGx%iyRr|{Dohj&2iZ=9`iV`_`8 z*A86Cn(`^A%*7_!*lyn(>R_xzYq*y0`ZL_Uo`w)^f#u=o#PY}|{n9p^LSVMn>C48$jxkG;wcCI4L`D?qkn&6V6MeO*DeUkf36QF zRadQ!NqP_Rj&fg`X8C@!qP{t})l|($e28n0+^ANlt<&&uGTg|#l3e$10g0>Kf!Tv| z>D_Sh5AHgT(tCD=QQC1BbEjNvgEVIgsMsnZNlWlG@MGQNhX0ouP|oZrV9)!W2uB>U7fSn=zwIR(UQC%)RZ%vn#xX0|4D=6n zZN(@~w@O=3nU(C4D>$iJuG9ctAH>b)(7VVF!-I7qw!}w>TVt<6kU>^h6U7LJZb2X) zASW*s`;R$01Jk}DKr+#heA+vFwW~&dlJF^5_cX+MG;N1qEJ|d?e0E zaKJ@>ucE>+gqWMlYc+($uAa?i5O|jO)rt@lhlh1I=rj{TCT|V0DKkNE#0OBGp%B^v z7+cM(4C`oKL?-?$4DHrSwi3=%oIJR{VdtpO(B?=MZ^B1!vLi5vB!jO29&K@Dc+Dju zI^v3zmx&PQz$hYkYRaoX(}^)}Jq8y}0yw|Vk|EB_OZsR!a{mLbx&2#|%i}6^e>*={moERCc@?5X0&ude^aBo#om=$P zdJ6!9V%7wwcdF+>Q+&c3c?ny$E@;D+gb2%yU1e5Y_8$k1r)U`7%IwEWRWvM8UVu4F z)6*sTeyWYb(xyi1RUfnQ_HB?Q0gbQfT(_XjY0sQ33IBnsT=rUV5)BQP*m~PyPzq0+*sSea#O4f={${oC|%3S8HAHV3c=iu`jKdV^R_-q=>U2AnUocXoE z+bvvK8BuNDq`u_pPbYzyVK&RjY#`J+b+sB?!)8?3bP}k9@ks!yKgfahqStW~T;uT0 z!TpVCT`()a7wp1m;O(9b-RT%6&rJg}@-ogHnI1U;^l(>K*L)f76bBIi)MzbRkaB@L zM<x^2ps|Tj1@e7kxSyheOJEqwfJF; z&EY@tyy}0Wx z6(O5Y`;p_IKSGl+Km;Slqc|tS{@^Nw5{Q_T0R++!RJf9VK*UO_<5q~|K>esDi2P#N z)#R!)aK~qFxtMae9e-u-m`&8*)S6*G+DdqD$K^DtX?YnW%;@Nm7}bBM6kduui6PTS zE&I7VrPfBod%Hy4GvE#+2e z)d+|uYKho-skW6KIJ2+N56!+DuV;ih`oiQ~KGz8NWmhfk!1b;<4a-4Z9fr_vS$o!1 ztLS|XKi6=7B6RQm9U*ZLvorw!aBF0lxjPJ+2fG=oCu1fd<8MetWy(Dl+UWN({rt*J*gEE{YwS{*)1lSH?s`yc!2 zzdDUVs&dS4Qz5Z4xp!g`{PS{D-(A-Tds}=JMdDELdH zNlO{Lmt+aDD4xzM#srsx3MnEIdPN8amMmVySLoJkP#$YFo4v%s(LLJIgEs?Q;x8p2 zvHYR`zT;f{hRO`dX3i5N&iY{EyA3e@IX-+HZ6fU`R%)Ach^J3^NDe|A>ZUz`T%J?B zHfKGndj&uixDBhcK1~`uDrB6sKyYC6mNejLRA5P(1dse2J{OnS`Bz-~%V$w$|BSz~ z%6vMx_F3x(zx$)AEQ9#I4K`ULRb14CJsq=$3+p)AOY$JdKVD08K{`4j1J`12&4qe+7451E<@0ttIO3QQX&It}L;^jevDmOj zfnL%4M+0$TCz{*#zRnrn_&L6#aR>g&E3@%;v)DOvj}ad)k!2~#2kmF%hiN(lWpowl zBa%Moc@!298}WACV+VRDYX`CfFeXv#{p?3Juwqr&WBHZz*k-NA@}6V$sl5T;NhhDd zBgSrN{*wBW%&!g=HhbriV3*Pcs9Xu(%XA>?YBheW1dfm;a4fDKNGFak!UjyZ=1@wi^W%yM2i0;|4fg-T=+H*fSa9aJkB z#iOxXUdrM%Ps=kINL?vR9Oj-Pr?bpP6DquwT1D>J4;|e32I9Ahfu{Q#-%vF;7MBN@ zrgkQXyU|k{^(Co{>m`D3UaGP1QG9T}I~#RR0v>^B*zV@&1^S)93IR_zJ$HjvnnM7G z-_OA#YmzaY!W`DkkM4UqcVJic;@BuGKIyaDIGCZw79K0+litBAO>BywNRDX125_#y z&71rfbs}b2ZboCr$_R7&Jw*!0jQ)mbL=c~L$#v2K#zx{PcqllM!xU$I@` zi32u=;r6lRw)0+mB7T13tN1HBLmLN0XV^P7bC}H7M%WsgsU@*JY8$I@tHAx_5X6KJ z+eX6OF-W|07=-L324XXQ*s}stfcvk%dgq1s+{V55D=+1rROhJxy?DG}RC>@EiOu95 zze(M6cjHL6>2?d*<`KlJdu%P+aOXPdV3Zy^S%(Iz9Mjs$TAg?`#mOl-GH;u9JA4k8DG0tTUO$l5&xJVw3vvk=V2?lC2O$mMOWU;2(0|AE~o2 zD+q16EmiXrnZB+PaYa1v#bPgdH&kZ}a{rBC?zb56xit(Y#kzwu+0 z&0<{c9Uq!(w|druQlEeqK{4S))I4iE?T_L<;psracXKu|o~kKk3TMQm-iN3=ZgrOl z_sOH;RdC<%^*Ln2tr;kNvFVIJQSopgFhDXHdA{t<0 zcKB_wph)LI{cF>p}4#(0h_^93%mZ7&C>9gS#0gaTsbHUrB5)o3zXw(wGSCQ*}tz$@~xY#?C)9 z3262%s+hJNN%7ElrPTPn@1j5b%Aevp8jr5VwQMZrS&lV|c_y#i;lF^A@U57#P7*4`F^-&$7vGcSivk z*+$zYPU^;$8m7TU5|%ZL<1(+|N)GAxKLy%|-QY!2a>>!XNX79;k-^Fvd+=#IZ~}-5 z+e3BJn|*l{GywXrwqoN5QF2p z%j2ok%CrPWiDkju#WnHb@4xeB6jw!~^1P!}ksc)C!u-tKvu+1pGS)_0-^`KinsqT< zhY!=(z!s@Q-s87rJw>SFL=duGjqcojwQkPa};@NZm(;hB|?^O`^^NyJVxiJiSLgKtw`hD;nu25oj z&cXZ44J8ceu6p?rqP4oO=&98B?w?`Z+0ae-D!kp09l91LIuJ8A(hs&LAT`W)<4l(H zpBgdIXXlJ|*204NlsT|7=Kb(BQ&>{tnTLDzc{ZJ6R`u>v_%3hj690{diVcmZ)kv17 zb(`3jd@lMg3-~6v_P|S7^^u?BCo&lI0U^_ivr#!mh}!dDg^^5UZG$g2;nC>r>3~sk zfvtSl4`%+30=o}?rT9MY;i_=-YqQ2=y1{nwq2i8|uXUY^$Lk|l^a2#oQ~iw17w1mJ zMAAU?i0UX}f-N%n02n8#w!Y%VH~#BfA@vSF-*W%FW9M+i@1+>iHd!5J6u>ob8FW6P zKOeQVv*c<4r>0|DOcPkm3Bl#}5FKsK+jlK|sE-P+fjW!m=@Po-Cl8z)XW1XFy9lR9X#_xo5&gCqaSruC>yjA+SdcMjilLec~U6KuR~ zw}$HBOJ-%dp@syhODDW?m=ab5*A3qwhSP$;So#LptSN|#+P!pe?ZjK`giwxJEjX99 z6xLYBRV5D_7WOfPMisxS-TlXX0Efrm|Gl6>UN-FJ(YU;Pgn%3)Nx;mYss_d}l@p$f z>x1b!`cCwE4Ip|oK4QI9hNLWwy=`gYB!w2GLqMH^qszPFeDPA1Ci7mLiQbV6!&yS@- zKqOQVNk^k|2(FjpwiKb-+(p2X)mIVvKwMa7t|q+OTfAVlECaFuKtyH8tf(8%xY%7G z9a1iiYv1?!>o_2xs!wFzNh%H|zkO}ws3_>3jWZ$IsUwNWFJ#V3%^iBFhCn`zyL&TS zozwNu6RlGae_LTkNw4C{pb3r`)hJ8|6q%$a5(zAHQt?b*!t=!g&^}DMa=9g{By6-$ zjn&40LM!>AyU+OMQ?QK2x(Z|agIs>7KeS~G=TPRQRDQf9gE)DqhWt1vN4l{z-w>WS z)+GkvJ&sznrH%;IY+>FDfut71*&stfqT{(=QP5FXj9E+GN20;lD#GkU~Mu6$F*_foBO`Y4Zc-P=JQU?r8x)MxE|lz=kBMVaUwH9WwHjz?bEe6T2;bL z5sH$*6sWK3{?iv9;3+>9hu-d=_sq=cw5LG5w|fRU*zOuUBkN4Cc3x>BIl`41I`RqJ z?7&YlH~cRAZg`lYrl>9e7-(-0&zV_g)1p1#se$-ANY6wgk^?D{4NL+De1Eron@h(tbviS+jk~Q0w!J3v4I8NMgb116s91cCo|eUkWM)J3{(4S#NXXr$a9goCOI2X zt*svZgA7x6i%y)!tfaOQIh`=dgX=!L_1#!ggE?RsCp}k1$%MBL#8j(?M^Piy${8xO z;R2IS>V+C6Nm@d1fY@UKLgY*~#8<|iWn>foRrTbnmDYYh=tlMvg$1K4l%Ls>^R z9);P|4W~co;y$ITw1$DZEmt^%o>yvk3G&#RtU)Bj4>~dRwUQ{9?wbR!8i-uya~Hg# z-I9qu^$zw&2^yDrz}OUylJB(oP|ycZ7HgY0OE;EZVPg2`+lXrWY@y zzo|03l`6qwaJe5E4bDM!t>;$PL0*hWlDk@yW34(?_ZEESW@m_56ZMVg<(eRr1SynG zvtza;eL|%zBAQb%EdV@DS*RFe$E-0+IjwNyC_9wdWiqnk1;_n0eqW=axqO}tZ+S2- z_o3L(irshArpfLeOeDc#g!*pe_%laF?(Kh*ZI=7S5@4x`42Rpv%soN zMx~xB-`+*04X=u3ggV}Y#hr7dq0C@CgGj*F*h6C6i_pQK3^JAqk+~R=)1i=D96XRY zle~8ic-o88fp#(l^ISt+R_4H!Frv-6!d&@->z=`YQq|}<&vv|%^}@)%;lpPbKLb}r zTHB^aZv5nAbNh{-8NKo9om0)N+i(2TK_ULallVzkg@*O4MMN2Bfr?l^+k+X9qSPM*4IErn7|*Ou zK@xe{t*p8sm`+2|R^Cl!FW^m^7qwU*G`Y)g&zA=t`##FBij5vp89oS?A;V(*Uk=4! zyA6-0tD#^Yz=ug^Rpd-w&EWC{5{YBVJgu|F$(1|WmY}W)yzqgrQ>%Expbhw7oJId0 zt2mZ$gG3tZ$3R&Z@Th|)0CjWejO_gWzip#*svOz2Igkz=S$}buTEN9ZQWm`;)F_Q~ z5&bN(!E1pQ=J_A49Hr%JjLjmXg9#rXh^z(M@}WR*rU)b5@R5k5&NHc$U0^q_{r5lP zXpTn3Y?FC5hJxy}vWr>ljw8vk%BVZ`X^po!leIh+$3zYIaT^XBVamEH=cpZZyow3|O0Dc#Ige;0pYQTSZMY*py8QmBU z$=x*F^Uw(M+#H*;3^+y`h>KoZ*v&S3K?iKj5^+;Dux!tVc zkyD>u$qu}PX8}8DIp;ML1{>zUlcMwl%_@hIt`cghqs2Qgv`hjYLxO~T*MohJe9i?d z{#KmCw}0MF)dR9ytI^ioX4VBy+j50qXX|!e;Gi&Gr~wkM!o83WXb1~ASx17*r?9== zJLx&NMG!IL&=2+WH5Jav+G<=cfRoGg)hKQ zu4Dms&7quVHodIeIiE~I9i=9fhr;Lqaf)PhC`*m8EH-;gw)8*Wp)X5St5PLl{RN+i zmRVL{&1@EZcolr_Z+U8TSs+cbM7WR++w9gG=jAPysfbYS!~A@D8g5< zCe%l@`UU5RMP@}OU*?{Vo!vtQt7?$IybE=i-1e}#1z6a#5v_*7_(^51OJZfPIfx!k zY~!i{LTV+dmKe1TIJIg4)aC; zENCW|l8^Y?^drKKvP=xpclzE%xaB*~-A-`Qm{;LoU!fvovc9_YvNpz5JQX`PBkq#1 znC^}>caOHFaCXy3t+4V++%#JS|k)QVvs4Wpjf;+2{=* z3c9S(MiHhj)_HL;hJZ_CDMg2*L4;dsR4EW+$a`jqv@-NrPDjeBOfn;V~F_Sj!Q@@arzSv$<>WrX)xn`_<{Pp)rL(Q-7-DP+2 zdR?)G9G00j(ku94xzlcY3oqAp78l{p4LMIK)gXxpQdZ`_0Ii`C($wBfZnLx!tBWMA zPB(=BAEMDzU_@>ngeqCL=nWtG%`g8OzogMy5i0&vmoAVK$R1m%TG$9NS%jRtfM_ch zYCPua@tysiKN$z74;UtGg?Bz9Bw(xff0QtDCc|T?)IOYPm9;MESvHETaL90hvkh+Q z#w^rW&A!6y_yvMNLU=xjP98zwTja?Y*2@HV>W!VR+)e>}AS}`guwdayEaHDUh#x%Ws}AkEu+f;wdKf|Pd{dkAXb{mP}kB)g<664F?!BhtlE>~ zmU6K8DW@I4m{=a2Dl!3mMac4V670`N_QQtL-MsU$e>_1ca_3)Je{5*jqi}gO&Q#;J zR~}Udi|%4vi;MF_T;6V%d0d@cu3?S`@d>Mh4#>1z19eWZXs)9YX~$d#;(tA2EIdob z>?4x^%?O#hBLmvY6|InaMg`PCLjEZI;X$~G%)NR0=KE=R4YvA~#rMv+SHgGWtJfjA zWpZ;86^f11gOWc&Amla~x;b|)*8VEUfnmUB{3oR=1q4J1GhlOjG|wzs<0NSGY&m`G zrn<8AFUJe@zye-bN>`|q1SQPM04cA3vxy_sfCSP?NJ|uMw6#j3y6%}!>|o^_`pL1Fj64t>2jh1Y9@wEehs z71M*XJgFZ^->>u=u_Y1_v)s5u^;wNZ8iO1qZ za{7Y~B3cBweV9#<2?Tf)f|O-&tt75Yb#$ADNemF*DK~hdX#2@ALKZNv-Oznnl;8Fa zJ@cgb6lK*`zt5^Dj}=kw!XSw?<>RGD0kB9p+#bdGEOi)XdcKWPickJ0xgDo~*;krs z*yKq)Kq()j2n)D1MSZUdEB)pW3LkXnZYVzd$NFMh;!Xd#zP@|E4SI_yqMz2Lox|xV> z9=da%BGM?@mLwBehj5wf{o2fL7STMaH0Vp2XP$lY-~`^avD1T(G0<@8mC8I!j*Z1A zpaTd@urLTK_n=9`La&CjW@x0^EO z%WcEp0X7bfjCF3`0k*sAnNm(px zCwnPCW6va{Q&9N?k6`K9h_lvqFhvo0)_Uo#m!JM%s@TISgl3~nC1TBm&@RFEo+C&0 zwMd0UIJKsrtg)CaXd2_!lb=+MDGNY8zDJ!4Zq)V>g+PXnplTBG-1FFG0M`6mh3P-%p=-6hk@LjgjsrNjT(od>yhUC1vUo1E{;9HHAi%sdTg$V>S3LY?$&ZHH_;z+`L)4`LotXiE-ZD7YHxK>+n-P(nk(w z6L&-Bl#_EHskQY2-Ul&|4vCclSPseU@H&xT(EDc{ghIIx9!wGyh_Kbc<9iTVU4lIe zANMNueN>%EKkwVBU1Yaaf)HOEqCs|BrN>umNRIuh;yLMBG(*#VyFB0pWE5;bEFi1b zat36<#I6wV1w~6o+j?Rq4eip=ZeE_l{(8GsL!ZWR`zo!XdP}v}i?unKn$u(KPXzVQE7KI6Ett7) z`ehA>+Uj-~H@)Sk+aET7@2+I{zo*M4y8}(>u!@Ysc{@=XqF0tRql7FMYApCh+-nrO zQ=*RNT)D&b1iyg-8aKT7HV^s)FBs~grI8vcja{4Gk|GU_a<$zXVx?=is&{`kA0aTtLD1A_6%RMTy|=$ ztng2F{4dChfzPxLfl2g0Vm#;@;a}-hfs9-gKp^#N%dm+6R|O!56Cs~i>~ZiopRi)? z1ie)6tvA}qYNDkmy1adT@JQL#2%WNl_78PpI;E3!q!cO^gOl325Ick*M}lsMiR9crTPG*Poi`B(VX-XNzV9VrBM8NbleFWZ$F z(}IRIE|IihpiLNS#7J-^c)KPUQN$475NcueYK_X0JO^WnG#%}?10el`7C!=>wXfQzA~iCw?^p;Sly6H6!q&Hu{G4qq}g)#|yRyEC0KPOTf$3(Xl` zr~w~dhI`Hb0AV^}aMYPWo?@$itlFCa99lS|LgkB12=wwHn8-Gk-t?qC?)Pb&Sz$20 z&@~fWuWj>e#!Wjh**+TYSnU|&>rLb|c)iAoKZ{#eXlIASaPyXuf5^X?2q0yJty_VM zYoWpDu#}9|hyK`hE6wJ8jS>Q-6Kl!hUfH@GjceZg9{>{5ps_ng_HHUb%`C5Ao`u9@ z(M!K|%4@NZMpc#Crd#A`puSjqNgtgV7T&Pl*48si+zKV%UHm#y>sCsJiZOFGch}k*4)t_4z-`F3y zb#M<-Fc7tq@Cn@1+8PwPtydIPxj%7$*6<(jH}9Gg5*mq8YS3AE*R?O-hc9oOe7HlL z|B%Cj0Q#I#ttk%z$~bIm?Pw1pa~WNN9Io-;F-$3HH#&o{gsVJR`{pKsbG%6<#R?yBYgJYzj>lScW_6u`&2~#@oufY0rJD^Wb;RKG1I3g z4Njaj1TY|T|7A`PH%-ORzO*O~&Pj+tBd6eXykCQpT!knd!m&=wnvRENOPflnvgeu~ zK3@iXFy$%5+4+ypBr-J;jXHGHn&`D~FcbE!)?kJ&#=S`M0FSt-kX$hWKPj*izPr|COsj!k~eE&SzV)X0^W%%9MU;1aT^u8!!%d-(cX^B6~ z0FKm>Q)QokDiupP0hBbrkT$WCX2%Mn!p*pgm01XjQGAaH$WT7OIX(EviwKBwMi5$r zWZ$YIHrdMO-1tp@_$sMT{Z568oehpWb<>D}vk2>Y&WXe&w~M#uy&Ux}t=)#7*nHar2q z+C8ggrYp5 zgQO6E1RjgXB$f+%0)_?5fV9nr!3Nlqfb5Yy8oRaFgg~FQ7Pt2JZ;NEybl+sBOjxAF4MURsg>)glq-2yf92ZEkM6Un_NP7ab_ZLl_1j#M^C zTV2o2QB1kRzK9Mw09`8TdT<52u3o7j81CXK@%p5?EtF%gpu{cXT?)rHX0jUv3yW3Hs(u-1DA|=OSp>^ zF~B~`{0aBK$gQJoI^(0vN#6RC7rx;4DNdf+Syr9rsp>GnLGw_cGSaD|J9o4>LKO)| z9W>8F|o!;_@Gk&`f5^MYo{>ox|{;Z2_6~0CM2NGq# zGuJ5F3f|Ag`us8bK@`$0gq%0`sqPC;`j=0i%=le3uyX$Yne`Qr^4O^J>RiMCnDSuL zaiAh}FUTN#MXCyLKz|oJkh3M?B;XI(0VMN(@wfcVk2~+>@+(fX zng4?1GqI@~)WeXR6A@kRj0H$nctK8ysMF-mVoc8DsCs%aDa<_SJp7~;AiVCN#e!ta zr7lGEFY1ZRKd|*V|57Ps*yutYL?u8=P%PP)R%AZn=hVH4-*N5P`|e|o+eGO-yuxkR z@NV+dklv0i+IsWDM~SR3zNZP7w?hsHs^dWZ6gOv>JQ$J`Knlh43`~HSmbO-~2u@dn zXf+mFW2y>7EPhEoXn^$$0rvDTTH!49VZQj^Z(oXE)~I3z`jauuCQZaT;&Po?>rFF? zA>jNFkPBrOk1nnR99Sl{gGbFZNkne2c3vXP=r`h-h{>me*Vf2sT2vI~i*Y;b4V2Cc!4HX?w!DYHJE(0Uh(B!t@>ap_4zyA8g_(hGsqbOLFdePgS zI&|4Xe|r6=_RqHo(M&!zbcZH8J1~p|t=fgdEhaIB1_xYV9%Q`|_G)~n)NYId41+`~ z?9RaseL>_Rvb_=Epgn~G4FWEWT({4tqx8jG{)1C`|A^1@2^G)u9DSy$>uimJHSO^S z%C>2&gbh=J-90s)=9Rc{g*GwpSEcx9wR1XYS3Nv({s*HTEZsI)W_L&dFYFoaGF!5d zHBLALS^>l|u2s>d021dzr3b);v*p(x*~7DSD~X4Vb0QqpP_?F(=UsWWm1uo-^jO_U z@)O}8qO6;xaN0KIji6Gh(xwj<-2$6wJ|Z7#nqNQ)SDv`{k8i`TtJ>f@e^ch>yWDcO ztUHRcJX}{!#BJV)AcuLQeWTt6jyK^Gur1P`90HPU4hs%JDh28he?Gtz6$2IQ8U)dXMRYTf+2`xqNn~U_Hcv)=n-ZeQ8&4pGHF? zOho!>{rH629%tMR8mE2xJCY>bUa`jWb&W^k5=NaO**gp)PT?3yl<%$EsYc1@MflAA z0@a}V*|dZKM-JRh(94IV3hl-oa1t&-dv!E+5XflTldtX0GX~zq4#cX#Ec2WB+IU9a zn)dEaJV)}aQ!Sp)H_Df5xWF55=Xyd=e=-ruOsm!9*{;t*Mo1#HuuUzP2T27o-{=m{ zC8Unu*RPI4VKpO%vl4cEmNq-VHn{I5z9RV)7vIV!{`#fMv6`yEWbz=yA{}f+G01)_ASc1K2^X+`RcL#CL>@kgHfOG)3eBCP$|lFsi8Y zH!cSW1lDT*6Ut)+40JY0w%`Ym#lvz5)1eSff!v|KiB>Xd1z;AB6Aih#+0H=Kf%_WY zeF$SrMH~G5LDfIfU>iqTyT>^d2>rFl#oV(JaiT!Gdz=%2^imBy`~vP?&n9^$8jqpNF0s5I>j9T^80#J!?MInVVET3Az6i?u21+d120;_2lZ$}($Nae zP(&^B4jJ^0_|uE~k;Y-ql%pJbrqW*RcH8s#dtUZA{PxCUDsbO+RXc*%O_(AEpT21X zli$Me5zC{A1{az-->Zhe-imvbPGx+u4eOro3Y=4cd8P{l7;|&Q5HVgerpLK>$fk+b zDZfG~je!MZA{;U?DTyg2Kc*4VrE=+2#~t@G{J^RWVDm@kP%6{-PV`&qd|?g2oRZ+E zR5cxa{FpJJU228K35|UqIYA5f7G)7-w$8j-Ycfd*@6H>4L5Nnl?8$7|blg2SPGV+z zH>!>_p4R9#1b7ToXxB=3cj8vn1$by_Crr&emZSD_Z?5`uQxZN@(1_}FQoo-h2*?ou zh!S$9B#|A{ZRr8C3X#oa-1_~kxZ-r zL-;9cG9S5)bx4k#uhd0(%_>37<6O|X8MbEOGgFCY7w91QDnp^cs z4S7ku2F)7~t-zJ?ifw17b5@L3MLy&E;8P2cH#1?{^K8ti4U56P zQADi;Z_+*8LOfW=hWK=PNxoNJ9r~zb^&9Pdk4>FO?fmFLG(l$hz1!5_As}GYo#FDaQ8ZC>XX97y8-q(lO|R5Y2Qt*9ggi?GLMDY7!M*wcCCjzmk&=dDM?uEu7BUA!nPS{Q za*ILY0NXP|b%?72_}so|0@DoH3&f?gNztsdmZh~KAfZWG2N;N30qY~fHpHnY_op{{ z;vi8gcUF|P26pR#RaB(^o7C8KY3cr*_lVD}I9+Z2KGmhUk{0{v`%;E2SYFE)+HVM) z8y*t7SjNb#Se9%Ve4cv~?|7UFj}4e;9q9f^{BKBAat!DcoNnsI=->miq+k(!>4#>f zUy5H@*{Sqql@8&{1>k$i83O~-aC>a5)!aSO2H{gjkGA99_2dk+mTjbuMg?w#6?MRq z&U=!OEx;_dN>3Uy0WzgoQ;sHGW;Zh1u(Z}ouUWrVyh;^Rv%%?evDO_}YrhP4v1V`r z7p+p^=}835C#k?hqCY4yJS%XCYjy_3%SVz)`34+U`^M=%|3wR5TuJEJplXSw==;N* zufzDf-@~m#?bi4yY^p#nSQGzuf>Yyb@V+ucro^Qv=WF#XM9aMDr)PHIk^9&b$NmQM zldkhdumgU+2`-SifeYXv?}jQ0tN|%O_Wvd-Hr!BFDI{WZ0Ur3?mQ!Tt*FQlLWiaxt z42;a705{^R*TL!&4JzX+v0P@u*tQ2pDz$N&4=lhXT!Y$BkSzYXFL2*ge{|>?d_mQ$ zs`>B9Ouq};9%}WRv%45UX7u%D7q8dA9$&yWE@xtF#eDgd09v}s%85(K_37m&3!VLW z94LS*#g)vMDX)wvNVF4hI=L8gHBbj=gY>vn7#!TJWkD>=INmYu8-e)Hx4-ti&rpKL zRUkMUJk50If?YV*yp1z~iU*m@$jdknsMe`R>=8RxdUNs9)QiAR;`eI9u7+d{GKC~X zdzja;L86r4g_Q-|)#jQQ-`&d`CZ##zTUFI!OpPnm$Z@9~!xp^8z4$9z&HGiUgpbs8 zcos68x6Gez@0o72@qJkz5=?|39j!wMsqhvE6`OrHnhy{1fCk>F2}6VSbL2AU?zS9rS6 ziB|Vp&wS)Yf{V&F>4PdL#^a6c(HYj=tLkfL+G{npb*3*IMk##s$Z-3;DzBUH(S5#k zP5p&KNyivoiFdNvIQ>iuq&60mOYU8?k2isDO&cW;D;%}BTQV+ItRX;xVLT>r&r0nf z`35$oZhHj<4~9DJ_SbXGV~^$$KvlEO=6^!P$>g~gaRpfr3m<5W_T-sl6vGxaKek4X zh$Q&u2df;vNIA-WRd)D#MI$IF&jQUVWrl=r0kx_uaoumj?MH~ z|9%vYq+T#K(?m}IWIS;stho#E&G^RkaL^i%1Ke0ajs5tpsaa?a2QIN$;k08t-7+lT z00L!Q(+h2$PDvsJWQl@h>};S+BFi+1obadTT=^3Gyvi=@Y#w#*_|PP@cTK3&3AhC? z2`{3H;0WN5%i^`TPevNZ(=nUV#5TA!KUtYu71YV(wr6lxYvKSunI^b)nM=zQHbY2- z@@vlxAD#LLmtS!}%Y2(Ky%?8gZT+mE^s*vi#H+F&*5k*0_*us=5}(*u&A}I1bMiYW z9lg6qv@qKO9Ehpf_;2f8*TQc01*CP1crCvpgh&E*vQjNe#kX*{t6^Umq z2>wdkKlz+IhmZjof!ESdYO__B(aP&T^L6ssRfjIm|Ej7O0cP*yOsQ3iojAZBQ>f(b zrfY7E9np>;m(dh%?nB}lg+z&YsPo;PK@j#O=%R)1A*PXuZG|>M|QLH`$Ic_-#>zESjVO zlYklYK7gR;2Xf;WK#kLpOVBGrKY({OAO}-CDrKXxJkhy{o9Ro43{Kphz>Zi;0cv7&mKeQm+RKGBTt!r4@I=9LPXh2?kbW$a;2jxF8Sx=lplPn}R&MLXb8en86DW9!83EZWN_aw@?NzwNUIO z;Ds8opS=@n5&%-P?4#W^{3N83X^OTfstu-=E2F_o7hPSZdW=Gh&3g%U!}=s-=8T9v zN4M7udS?Gr{mz1=i}JvyzkK5-u&T!D3Q>Mv&6Y{rvdPvEI#7C+O?JCGLYAz6Zq+MI zoJ)x-HH7&k+*~lA7U^PfS=tPdN}8cEo+ulmP;ifMW1wLmpJ?rY*Q1PqU_(QpSoVbQ zF5|T21Pmoe*w zK}}A@HhO^zHe3*9FoeAzN5b)Y&|pGbE+zYB71*(iYGaNcDV-Qz#_^X}DDmr2O;s1D z<-%yhaG17ML?SxLMqsT8=BPx$o8-s9wAiK#aF1P603Y#L?DN1UxE#-T`ak~kGRpC{ z_$x^fr9vF&wEzW+)td1xPl!Me1U2QNCHd#8= z3Wkf0pkOu6pS%{rLy85_( zq)@7oy`QLUJqVZKoyH5o*p6Yy*d4NMbY{G^Nv-o?Xo9uRw+MUBYpGd}`tD@B$X}5;ziD(aQHFj29iIT$^l8}GOo^)sBl$|XmvS~A> zvhZ5nQ)DmFMH7pLv+zK^_>oUsyqo^E5>fqJHDrz!e-pm7KWz!qjU#f5S3qk4@d(D& zWsz+FU}Ge9W^V0p5T3kEw(cOxlbl*-hmoQRWo>it(^-zA0bOHRqAQgEOxVF-TH+iE zsDsf4UPzl!oWTwXrHqpGlNt>-+W2;7T530DXGY9bJhJd3;n zAJFd&xXMi@1jP>CqB-h2q+Asocep#q7hzjq1aOoGEKxs5o_HUgy<~x|q{JDCW|+ns zB{gtKHEtVxmYhOawK@F1|5qeMpdpKZ`?Lb2k)Uc|QW;O0XS^F&z0?OEo;VoZloM)6 z0rvw2U>ga1yQ-W31x=H*w@m_v%jM>u&wO$aKdf>Rt4;NuV-5OaeET^}oz+^>u9YH73AE5r4dUhRLciN-P5wIOc*g)gpnzjBF!XH8-QsGuSvZerV0IE8g4u-Rd z_AzkljvCC@Xih7>*fJTjH%!vVHY|kn6@vqEIXrUFEZV+rsdUIx)Cv|fl4zC#7j@d@ z0mw|>@O`*aWBjoT=6$&NT%OTO;4i=0x=Fl$B$gyDxu^}B>4oTbVu=ygNnr<{jSrWh z$mCsw%anSR)>$y8NZJ;qojwB+`l=K(Ej2r7|D(SC1^nD9B6q?3B&9h~pf0|5vu#U( zmx+YJd5QOh$*eVQe|&uP);8*^Ph4UkS}ESgecZUQl2M9NIS0b2f%Jw})aU7D;UE z3go3GP9Ni?8mZI>?p|v|W6T|M%a+=x`A&awBz29LAj(^lHiQ`XHAWm%uIyOEn~euH z4IlaDQ-9RQ<@Vrz%FBIdrs3_W4z{`U40N#VCdy%a&WQZH(wvYhH5U6W+`J6wpw}3( zyf}QioVe?dLhwRN{RAT5-2j} zhnc_3eRol-_S|ydz$@|dtESW}umSrtqB)S-tNF1kSx7Q#57~l2^a2ujt@Ke zR%8Mgt%-Vt&Hz9PWE*(dZ;(7NxiQVPkQpf}Q3z9JTsOS(fe(I?Vjx&88`p8FJP*d@ zK2Y7QAoXZelifYoAk)T%@*VA3&XX+(>)B!&-BDWBpz>tT3rUKQre5t3<46RvbHXAV ziy%w~8B*E3ip5HQXKG|ktenW&z3Iveet5$&{GQS%+^6x&HLiU}F@04W2A-XEEnse*$j zzS)}19c1hVR2e}cD!q9ECU`Y>i;KSXgV%qT%l!@h%Fos2ZF9N(00A@T2}dKByF~VH z5gW`jK@1(y#140e^e7u)n|Oxc1dBwNHNFuWa7<{h7EDFhIB9j!tgQk*KmtnI)1o00 zZGX~-oYHpX7ZGmEtZ%((^cyGQw^SV|z2L;8)EN9U+cEP`@U6?eH8vs~`|E^AW=yb+ zq_Vlor_tC%69G|phjaYUa|}#iS8+5TC5lT{om_%A4@jO3T7{(Z)GJ>(%^vEi;^cxS zt2DSrr+>6_VQXu9dIYq^@Gxc-xUAIsrrY^vIK3EO>@Gyi1hM{eaj*Sc>vI^p826D1jD^GWsl}F2v0uzBSW` zOINEKPS~^l^;k<)NBRPrI?gWCezs4nYwdzZjPsMpA+oKaIj*nQ5FhFLO)`N^T%zrk z&VYj;MxgG^AbMbUf;mJvQYvdJi6CG|6!rz=!rdLJdE8qsh%O#da3Cx*Wh3Ow(i(4j z?w_22-&cuFpRT&a0D2Zm8k2#+DU9u19D|5X2XxZZ;he9+t>6^HS&D@Os4^BO!hxuP zDiZ$*=Yr==8EHRY2F4MDePky4Pogg?1s>>^RCF}Il#UGL*5Mlan};>NXB0+V{6)Kut52d~zDnmtX}_v=-aNCc7-|yR)KYnO;hS zBkygEIAY7Wh6M+gk#l^$F1Mw3e&CsMw$Z<06=k{EaP(P+IXm!On}x(l9l)4oloh*> z6$8%e@em03k<$UPFmK|SaL9gSN3?C@69*<}KY1O=jeMoIKIzOKUWqTR>T_Ihnrg^m zT;?Q}p7SvE$-@~LfbFfp?$#zc0>EU}E6INVcMrrY2O3p|wjJCFXk*7ibkt@oBosxk z9Znl28c8e@>JSX8HRd&h?65ErHNCSM-J_Jz;tSWjT&7vJ@N}`~S35TsQYhdtjQJvrTY)j_0F0Bw%HsgF1 zS|W4#w8nT^QxkJasT6fQ^%o%@sWw=qmY5QE4D8H9e9nD_f@1B)khQ>hq!dAzH#*%? z9Z24RcZwNiZB8jPCRpY=Odc=!F;A(SrVbqD^1FA*_#MB(imIsm1us-pVA?Yz*O(hD`z>~ehQCf#?g=#HLu?(JS7_%srkMi8xpzxl78%J8( zrbll4wJ4z&HoPfdL{|4Fswjcmf_9_3 z;8Ya@@&xDtn$&KIq+I}BvR6JueQi#3rkvylJ}&vK|M;8B&xf!Y0~Hcm_P;5y&*4Y( zidV``A|!xJ4jV>g5{ZN(gH1~c+l`pYi3?Yw#hscB3PB)Lv6V2NwzPNl*CFp|@it4Km4PRIps-`50V23+D(Aq4NlB9Eb)3GlOgm zac@Uhx_u{}BhG{w?E*p9ady|@X4O3HH?z1W>7Quo0#6rNaHXWz9NUr9yGPvuE%PNEm zP@m%20*8_4w$0-yi*X!r>+fInmY-3I6(^M}7)WNex&>?R*@&jLsO3jO-{b0K=@>a6_bULQ_`J^k>l0;*56B0)c=fcEjC5Kh} z6_6MS6hj%k!`n$KWx6DLG(PIi-@p6P6)2!I#WXw^s;c z^5rETlzJZl88i=|7O97!3rAy-EF7qAivdFx%)$F_~6a)-g z41xkzkCf93Y~WER1G|7t$+52+GP}z3C^jz(^cN88f;;uYPyIc1Y*x)%Sa9AP3hqPr z&gIa1=P%WY)R^#cqU{uULm4=hf(JPa#Idd*E#U2{5HTOu?fR z400djW(gdh6jfPg7u5ZWw|@EWD5xr4;eyObe$7{IRV@j$8<<%A4Z=<*=X`mz{urgGY2M1g2K@3Z3R^eRLjh$| zM9%*C6APg^LF1x2^+{j7fTsaBeu=*_KzfOaiZm5ZuNv#_v;6)J>ss?p-G1C`o zxj>CcTL-u{Qfz2b5TL{;iAb)RWKNs9;(R~0A!^BiyR#x$QT(Wljr#8-Ruwi=Y4gSV zK7HG}{u@80Y6Q}Pm(G!r+=%aERJL}^tf`6~6p z^1if-WhsR#UV-X0s$UX%hWp@;QwU)5OW__8b;6yiqlQN#p022&U;JFGwZ{3~4(FwyM`*!fcyv(x|>~amKegL0 zm}*d#&V`4~xml@_2iTDtCAuP4V%)n&K6U6*?dAwxtRbRz;k!KU@su5GDw8;FE?fhi zW$wtVv~eb7w8;e;r-b_ezLgABA!N?S0GZ$h@k`qOC+>ia7a9Q(J6rlITq!D<9dCclS`U}7U4sxmvkEw$SgJo61IxSw-?cdr!LD#@mB;|8 zWyC2NQkM)R$-JJ_aHXG(Dk;fu?8a1#3FMZAKIa^aXfeoj!s7J@c}_!vhvk&Prkzni zj&gN(YGh}NtTeb$H$f!_@~3?1W0268~d0U!)3S;WX>JT9K5~Sh%P1G zO?C8P7-F@OwCHwsjh(<74l7(lZdXe`dCh$??EK^kLF`mj5H1e73#%^g(-JODF8xn7 zX}uo;K|mJV$gK>pgy3rnk-LrNF2q%F!i1!{*-fn`6;D!ID?AlsRRT>akwSDF>asz31DyRYyMmzNN<`iD95!2Wv zXZt{@?+THm`2nIzH4SS4W_84i9$9-4qo}6jBNWbZcYq!T1tc;w;Zu3vlHULXsRp~ zFH?Xkgmz7UGJ=X&i*0cMyK_<{e-Og1U^tEWnUPDnj}er8KYn@H&)88FqBZT&DFpjM zH?3%myk5JVb~nCltwa$gkuqLK?SN59DaL}Oxg=p_cG!hPJK4En>l7YDk~WR;`Tf4` zGmiV}b64Rx>Kp_I62k|uL&re8 zB4wtF9J92-yd#~e#S{L7C?*B7qOJo?Z= z!8~BFY8^a~bkbT`7PqsZ5{>Cbg}K1CyyE9?{S|(G<1YM_wd>N%pLWKuJ~W}9g&74= z4HJKASDM4TQbWuB2;bQ2XMCw(GA(gD>Zy|C#BhRX-e{tJ=uTLpffy9uNa@R$xbNjB z-T5TyM8$~e1$M~D?CZo^@rBE?AXz9NL7BDrLgoTmsL(7AYXOo@-PGie{qd$vdgy`; zR#fv$7-{UN5ChD0P(eM;!!)0=Z)W%`?hmXwC2hfFb7dwB49wv{??E3^Lw71k@j31h z2O1HAMRIAF4w?%<6}Fo~W+1K7=3Qd~p%}jGn}7DN$FaMo!LhkzWq+eCn|SkVP6oh` zppAngW1XP@-^80c^b!tNluI?#{UY3LV9N4V^>H-WtYJQjl}bp$Dex>#_OEfsLU;xU zD#rmCXXU(#r_}rc7s1M7KJZaWplTG!0y{W`(d2Bletb*AYQlKD$|qFTVDGX-2DP z=~lP?n=3RVlIh7wZ+~9*JpAUWlf)O;DH#vLWpBahMe-11Z|D>C1g2drkZ`S9b8p^( zn>PSQJ3FEv$ASY$GfU<*M%rF%Zm%M0pa-;ClG=O1m-64>Kwx-T;ZNdv3PH)s*yaU* za{YesRiQ!O?s*j}sf`C!7|}b`h^Rqp+aU7cu-k=3Rm3Co4I7MS=UP>s z(ZskKXpm}&u^|d9q4eGbxE`)iltmMEnw{(gjU5$GN;|Ghc*c!Em@}m@oa(2Rng>1M zT?^kqs<3Ko^n&;0QXrn>P-MrLPr^-u=t3QAH+P{)Yov?m1hsVJ4HN{?nZU&&^vWPo zauk8NC=n+IJz2>;F+f&ys|nB!A+o|jf7v#v-C3fni0}t^0s;WtA3$98MTZ>0I zg;eE&?#^`h86`HR7n(D?P(xx2MSWhkDS2XD3Df7Q7&CgLFkz zBD{;2$#ut6O%CF^CdGr_nu47!JYYg4&m|ba3^GXc?T#cL8 zWL+9WV8F&oYpMi*pAaMwZfdtwFQwr?D=*^x`Zeg6R zx0&lBxOEl#4}%`dST9AH_}Pg#jkiUD$MCeI$A%O{w+K-xOTFT@;iCi#gFy0w^-5W# zqZ&^PpjXf}AZZQwa8Pt#=AN&8!J?)Aho*IQMUeVJh{tNfL{Jk_ij{1}zX|nCw-Gs6Nl0wF)>JLJ8u> z^sb;+(77ai1{thy>5&#v4ML-aSzTl4vxnJM+c>Gh>OQTi!t&zUNyxqzjKp}WXWh>6 z)M(s;i(|Oh#h&ngo?nC?bU6(SUcCPi_^Flc4|c)^q0%{+X9y7;PE!qubSAOKyAFb; zBZqW!6dxme!v1JDn8uu1))skz6g+7?168QKsNrR>D$6$&P-EF(Fz9x?!UJaHpd+8K3(a9% zsG&-1d05Yc%b%hopK2p5JBt?qkU;m^l!~6 zos9o5QLTL16%U+CQB@2+TyRsuQ!1(*J!g-1hDQP*NZKm0+R@x0S851L_IvM1X_T>; zQg}|O89_j=AK7Q)$FQWVzDm}|Qs0cd%$J>YvLy)^#|qW!-_v7euSBd(Y=Fn(5MWoT zTfcb2tLdUD=aGFSm()(U){Stm9i(aw4^&dP(wwp@H6-;ieCsAj8DtYgwg%}k3zVdZ zNKrbe4$m%#4YKFPn`-Fyg+~*24jD*Iu`ont&*;tH?xlV_yTUvFovxbfmz{D1^ni7z z`4VKm?4TpGp39{g>n7q}r7Z|v4Hkn+#c}{(r^UU*s7*4a5PYz*C@st*4hh$rxnTuV zS*%K|5~U(tN5DM(IUdQ_WfKz?qzazeh)(^FlRNA1(<`~-TU2KB)B|1NGkOMEGigsC zB{qa8g29LIjMFs-AHETHZ$=J=Mk1Gs;WXVymK6vCv!UAunvsf>z=jF6)3GayzDhfe z-Lt8A7>UWMBOYTp=+m^}I?lOOv|={v64LG%xEDzi^Rc~|+_7z+$ew44IbD@^&R%&Aq@Z%9}{nO6bR(QbYpS^;{xg+NS+R~o(5NNEV>&F{=yM3;bUss zM*%}L42G8JQK>#$kdCX7RF0{mt~3YFeCIzA#a3?p_@OGzQMkOJH5I^y%*W_X90-Kj zXEp1(1fHvKVh^hFg>h~8Nn|dV!wimerg0h%+K9aND9=!SxyB<8Gaw8-gHL3DFi!cH zAK0VBMK60&b+la;Unspwcn5hSSC#l)Y0q*&-Mr-Ge}y04Xt1_h){lQyK{3{EAkBe^ zaTS#=z-eCkA5^+nS?m>lSg@a#b`gNN)z!v8QFwh)z%_ndGXpC;C>RF&#(Pq-omh{A z%3W1b#&GC4S3jnOU(om#{>n@LkuII7IF`Nxa@>d$MR&Mm5ZYl&ViP>d4nUuJ#xcMT zP4#K_iSnSFKsMA1Vdw-=h+$1CW@wV7{#Z6Zn6;m9+lAX+flqII9e?E|{ZyCqAY2-l z!4LPfNWHE*)!x=@jiP(5j+rxy=#@qWMbTQB7Bp}57FYle|BQ|#KF>{3;S02J}@jyZl!|ah9dh!mC&;`8h4$M zxZQcen?FiMw{c8`JnowldF;ctWhN@xfl#OFt;~lEL83*-=|}8Ba3*9O9E@}Wy0@n1 zhH)ew1#S@Q1_8nyO(9>69H6ufe@aJW=$mZ+rv4u0a@8Rt`HeVj(VV=tjQ| zeL{N*2eNDhfizfa^YF#EwO@dy)tJ42=pGnb%DiwNqxn?zy?0-cduO6EHHg--n10IJ zAeDrI%3Dd;9h&=(y^sIBC-BVi%5GRYw_x@b&cS|}0w_}^3p02kxY<#6NCRYqV#DM% zqP9Wk2s42ob*Bish5IBLVo#0N<-8`HzABLg?nx*9`Pft6i{Dq-sPHSbhuM<^S)TQ* zHW;g7(V85&G4ptoaE0tl$@_b9tx591P28f#b3)dGr*X1}ixvM6L1MiF- z`FUpS!ddjVkv&@|9L^yx+sCg}IINao%Fz^9o-z)Y>VoZPH!-sX)7k4pPmXX|>u3HC-#evgb@U82({Hk7hJIzAXViwnb8NSbZnk8)d zib#06#d{$Xp#*q>OwKAMQfepOa z5YA7_>tJc{dJUswpGtBsn$1MIh2Sak zrE`ofw75qoT^2{6+XUQ@FU*Sby;3iJfh6;agKAZHbi5}otpn{#!p-u-XkthF%hQts zDoVNXonJfuiyLUC70ulXk5NG~uA3lNf@X35Mncr&ID(gJi19VJ({Knm_|z*RnAe;e z{T>i9NgwIHWN%jvkPC5Isb4D&zPD?6D((~PMI6%BIQKX3zbRwM_As;nY}Waf;;3mR zhn`z69`kjs?vj{`u;Ut}1 zi#?Icy+NQaEqph2~HPP0y|2TJl_q zPu3*;$PVGSw5orKI>ZAV0*Ky^CU;eNU;nS+NoiBW9q$G^ztPSGZ zV|&%WSNg7bDW&wt3e~bv?nHC5EG6bDTaldT{L@=yS*N3L2b$6RWg3m zTiC6yRQwsBtjDErQ)sC#KtDNZ4V7InRm-q0f7+o}J|DW&SW}@;r_ZhUZo=2Dcb&1y zWe!i&Ic5D4G)7p6%qq5{pDh!WF$f;L!gzxkhy95!0|J7eXwHcCEP}x5HQak;*fwe< zV95+vi*E@xzzTvH&PLrGyX?NVZ^N3Z*z$#E%&ja*5v?a?E3uXCVx0N1%u7Y9kubJo zY2TM5og{mi9>FqAT)9O0LjyhGD*6QvHgpH>-XN8rbU z#uiKM3e7f(zH(33mETA4~AdR-ra32Kpfb^^FTr1?(S^aSpTmHP> z7VAZ49O}F>YEltV!HAH-Ni#cQp35^@%2F~TBQIm*`1D8(^z=cBTnAG?62O*{4EYKrCNT^3pbahQPlTgvD1l4Ih7!!k z%M}a%4*wc}311-o$RWlG0$ep+cq#6+wYqMe70dH+5$#+4i4Wjyq30ag0*Ts0wEb(dpdxC#uH(3&chWB+h*E<<&;jbE#BVQNPdTOM zgqkWaXWDS$&90h4iSFScWE7%g2(E4`@A$)K-Gj9>IQX}m*PoSq)@q)n0c#%|>5fJx z1w)=3v(dyHdtNvat2CcQEC9R%=Oi7tlD)aM(H&d)F345&wHOl=Q=}6g?_CDM1{NGt z=pmxzTGyT%D9_V|#Q4uHmpLkxY+KPH#20 zb*3*I#`;E&47QtmF2?N%!ia5n>C8*V9R7u~c% z@O{WI#kHmaMA6SM^eINR5J==Bdp~ufm)egKDDn=g??^CDw&USXO9A9u>|tQfwUJTlO-WRczFt0g$Z_8j_y>|9g$rsRq3h9~<;){^-qbi;Tn> zFiA?Bd~yw?WJOP{!+`ps+^M>0X|t~r`&Rq#q}L{W2efzb^!#Mux;ybZt2WLqY^iw2 z#r3sNU8v*-XkhuRJWM?z&yDcrx11Y#VKd`61j0gGWnG7EuNFvT*p7V92%`V*oz*Ul6K-XA0{ zV3WZH7uzkrzUddIQEWtwW!tiG#l<^XoSxxQ2z{$WZgbvU-msSZQRKId|xY z+cwAee*%CnPX}*9(nfoTmjaZ5FaQn&IdJ2)?tpV#9i~QYl*xJQgTl{ArD+F91&ZnX zuV3=LD=5XMR!H$>$wT!a)&iHpATaHy5aVo<8zL0190?NogvyaAqeH|DUuVss;&f$V z!IBst!M?BT&={P)%iNfG&9 zP&?55AAFG&6OvSexdV~U;1Kfx2urPuSHulnOfZ}mMf^5wP^mn|)XL|HOLZ|0+;v;O z@WJ;f5#zLqktOY?u$bom=Qv9f-plZDh(^IFCXWXLV+m!U8P$RN4oYWCD-|jA3_7UR z%2knC2>!q@DcJ&+c6)Q6E#9|w5aPG2`{pB-;fZRGE)hUBm34m=eEe9q8h7|I?YNPk z3s0LF_Ix?oBf5^pnp~UL7luJ+T%sqF0qFtt*o;t3)Eh)ttpy~aHaTT1dWXa{rliV@ zH@pU9!FX(t(ImTXeanfnluo@wIy+T87}pAsv}6oZq?!{`qpdi&hM@<{Lu-(Hs9l?j zLHeCaiJ{qYEL>wybShwP6iUNHgMga3DFhQz%{`fnU4egER)BfR$rd(IRwffPr05%1 zZ!ym;7JIs>SN!Smae#i8&xNo5@&xnHrD?dgCi$$w(@M!`%4e%x3Qqxi0#7$=t3nimm|g5#NXR)Ld!K zkr>S)X0Iz&x%E9?J%<^%8fO4?1B0tnNf0JkI| zjerBO`p^Vn38EX$eS(AjOq?dJemsVTfpwilpId7NLCHTf7t;8jxx|YQ$ta@E1oKsKHXd@}b4hgH@eS3QSL0rCBtv#^F+wH@Bit-z zb7?%$s64EuH;kB1aldH;VhvLN1!Nu-717PX2u*Qh%IBIlpX`14`(BG@tNjW;-5cpM zDhVe4_xnJoJN{Dz!*nlcLS3g)fto4I@Eg5v_?gtk$Z`fVv4VpF$ysY?>Wf6JzAgCB zS3dj5zu-G-i%TqrjVt0_=pUcm=Wqg2@{RG?Dn}FCagQ$Zqx?uaze5)Zu1e;B$tgm{ z#qdR0<=9%m^L~exgcsRk79YtOZ0o|NWbQsUOClrD0MhwP#aXw$}f4(OW(5_ z4^wua#ep~L%E@8$Pw@Dzu2UM!X7IwCXUDnD(9^83Dh;m%gAvPoNdA%uSPhxrt>)mx zMMO(!H8o3(3Ly|uE-AmkX;QtBl|>xGm+eOpp8Su8qqe(7pLq9y&!wy$P_nyh^bCUo zm(@lT@lK+P-<5^n7baH3h5wan6?Eo&+`igRWJKH&D2qw}PAo%K7*G>ok{DA4N+6Us zNdh(xytL?NNY8?y4_C^^QD8VGU`WJc>>hT_*>&!-j$vtUjdjl5#`RmOIm{^2)?f}u ztCQyJvEZGirlY^EAcHe-rzSr=sqUULMF5TuFqE4ep45UA6+3+)RRr8>;ZJ>C7e4lV zXD{Qrctmpdy1uLHB16#MnFT|Tw{7zM;`66a!#;y;2rhn3$2jZS))*OC5P z9^5>pSvRr-oPf{|24J(t%NfoRQ>?vr;7*|hQsOD5xNZf~(iCWRT5XDpWAvT%AF?K= z?3~~OZ=FYR@SI>6|2*%Qn)oG@u;MP?$VyK#C)Mb4%tF z{Fv^%9G|M5#@{lWjwMbMePE{yTltLE2IRKcp`C9Ylon_zI3w^J_K~Gw!IU)hDrbxx z$d@@WoJuKgdB91dAEGGAqMqAT6ioRp=`@DNc*E}sC^I{o>&t#E-Khq#5??Sh7=1Q$n3dpq(+{Ja_rRR*w3ASaR_ctmoaZ?>o?-OXS z+ro~5R7?3-ta=0%2)?j2(L`G|UH{zX;k#=;86UA)3aYZvWax~r6G8;|lZdf=Zn z1JCb)()hYo{OLpI(I%8ldOGlTx~^VahOL;0c!sZkD{2)m&}Ylo>_jE2$tfipn7${z z(h%PL!2s)bSU#-*tH)~vtbxTzQH&(?wd2>lg1RUAC69O9mN*d9jTdPIv8Dp6(+O2K zeDuUW9FIq=m5hfx@a}n#2azIhc`D*D&#A7};APq+*x>N&lN>qCQ<;MK;?}l}lKxoo zJMgf^&1T*Q<~WgyaKmbZ=*XqQEiy>%fY?7k2b98*KzTWs+k4)9ulhcvSJqT+GhVn$ zmf~Dc;5qD*^-!Wtob^PHJml9@kRYAcQKOS2l)b4MP9{GW*2zY*0?PGJ7_@Q2Hx zHn(F*-La?*i23d;%GvCcLDDvE`v0b3+l{czuEgAc-pcE0w}(eHV5ZtB10%z`Q?TlEm)O2B2FC3EQwo4#OICPdUK9xF~l% z?Ajlmhqctcf}gH^)pOwAM3m2^D5J{7q{PBMkZcw%afy-PcH)XhX5{m*kGt{xKjvqZ z)dlq&tV^M1Ukb|p?Cg#FSlUrf$`HLq%2+o8be-5V zP>7KLRC%#^eq_ud6xX+N3N!GGfi^Alkoa2-b>_w*6_!z;z6lXHD7=93g}P)`$}DaD z_HXU|EY?$Y7*>zXL79g_P~TWO*%)-BD{DMHu_|UB`w;IMR>mSt@uXC^T{*Cx}#Lnsk(J;jm=_G z*@}c9>csrWt5g(fIW*+p7%|v#cYp4NB{%bJKW^Wsr{}@>a?i#)+0bmvV1RysFd(}- zIJ6x*X99;Tj#mj6SqincKj;7;8OlMdadXM+$=PPPlU2s=f&`t0XAIpkP zUAqbb|B-D$=IA_u;=4FxbjhA~uZDPPC1)A;9Ii5AWVj632XsYf8bSn|`qzGR;exEyA7KTrL)Hcqo|rnB1_0 zIwlJiM2%Z07udkp4ta481y)kX+H=G_3hX`j&QnqPXZcirX1r>3i&-Sl#Y@5^3TY9w z3Cg#@$^h;m#gs(GY_zah7FMR6rvN9)4g*N5^Y({HcyIE~M|^^NzV>tcbeo!oXM3+X zg`82dK7bOjp-8yWVS#w%l|huZ;YtO~8o|x#jU=A=0!hx3roY-?vChwrAQwd`* zXrPr0xp7(-ZV;4j$i%Fb*_j>V&l`LOzO-!cUC$#km4FLw)Oi*>$UOJWvWIvCg|=}|C3-J$j1NNG>D<+O_VWfmi%Vg%Zf_3DaL z(v~sq34Un|(=j1sH*5Sm$dENNFcz9}@a=TfZP)xoSiPTNE!}$Z7?mB%Se79KX@qU2 zestP9Fa)QG)XBEyoZ2zm6^-NO4cG$mSO^EAen5SwXu87@vl74}4=Vb@69J%(;5^rRak_h3J56^H|J`+Z0(secAikotUM-1>v1wCOE zQdydcQB~n)00^{rSiNv$fwZm?V2$aoscEL3rD!lu z#Akbi!J(`A-B+x;_du?-r1QAPCIZdJTHlYa430+>G#o9TTFSW)z0<@|VLcem@>Xg( zgh&aefgF=(U~^Y0?5v)1Yz()cKI31)PXMlafj0oozT>dYyy*Maah6MsIr?t1@B}pr z^C2q+JHiXO0T6kSyU~HV;IZ_CbVKm!Cxuzojyz8$)02{2$l;p_q^mhl6%6(wtA=#+ z0kf+$?h23~e6zty&FKKY7)|9>9p;u6H&=Xr9oAFE_VzqEx!{x3p48WFCY_xd9L&g} zr5S9?l?n#umH5_yXe4&$se4D%C=`$Q-WI2a5*SyR3Bxi=N=t=50yC@-7k-5Vv+yf& z74)STG}vFsB>Mh4?jf5d38Ko_-kwD&53=7U;f+M{gLW6kt50AY_4xKqr!l7{cDFLr zCeNq35TF?FIHFDV{1iwT&*7;vMZr#MXTh&)iMknjXvcHd$@<}Ggfpv|y*OMyF(>rI zFUL!v^7=-1>7BXvp##6cdTI+xcH~p%Lwaw+mz|>AquGrqK9%eM#6AWx5b(hkuYejM zy%zRGL57X&@tjFkTBuB?|G8Lc13^qTd$U^xsqx_|HTMKAm#f}<{N(c}m)-d3wp2EH z>Tp~-i5WC(XFNU{CI)6v@G(}vyVB@CF*q{T2G3t5(%gtoUycw@-#9BH1NKTzIxH=z z%shf3^wF)Nq- z1s$LY7*z<8ggsMjzNStb}LrMIA*pt+C{z3kk_zOBd1{VB>GUtGADR&v~A?9`HcJ%loQu^Iz6f`3Omh$g%}W>qPlJ+u zAYC~Bi6O12%&cGn(gL5M_0o@Due(?9vwdk2VwXnecvi_NR) z!=)ANX$H~0b{1c5ZcZR!KeMgc{@Z~&`5MH*HXqYh-i9Szg7TsVBbr@gIsfwic< z4HXW#(?v3cr^kA9UWlq3JGg)aF*wQj_7~jzFL?a2vx|FHCOfmL(Hd{=JEG@k+&R(O z)*fqYMOhSm(^Fl;uj66^(c=Wv_k+0ft+DrKqxoLAs( z(G{^a*jTPtG?wCr{1;i#E_Nt`uV6D=+>%yHT{X&oMTeS8Fqm}~>cty^A+TMyclIUI zY^^Ru!|Ucz7KCD(A_@f!JJuS4`BiSkEsO2}dy`r`gXN=M(RziA-K8^UXsZ#Z%+%6= z2?uC%kAZS?79@-IC5lxmDDQ(+ZNn~?8=iB~s1#_HG*9%Ls&Zl6zN&E+3N%+7gRDxp zYld3W?eW2xvBnfmyd14$!5MKbGxd+`Fad7pbNZ+319~1E5-;<kw;6NnK~ z0|j@@)&?%2ZqY7Ph{4~DyH^@=#=Fm*vL~N{&KJ%ziwEJ1SdT~f!9JvXC9G6v6*FxC zq=B>p%yCPFu%SSP3LtO*Z^1V~J-VPSJblq0XjMwn+o$DDY#s!)3*U=U4MQdQaRM1o zNoJW@l#Wil@;Jjf`OU{?)P+O|#(jCqO@!&h0*bH=Wzj@MVYn9!SdUI|h_BuzObW&7 zVqEdkTSpk4mmR*|GnntbvyoJ(Zy0Z-bSE1Fw>J3u%1vI^<5ukm+#RE18 zrI*dnbbBjWru)Z&swD7wjPX|&sO9Am)tPvebcY@atBXwxEJfoML>@cl=oCyJU1lfz z+w(5P^Ow%+?b)I-V*+#)yzy*(X#?H+ora@M#<{4C#Mo#UVP2@PKRGz7$gyJA1Xu3i zf$Yq1d0D-%sFqViRHXu9q-FMQ7DcX^8*okcnoH6>@;kgBkRMsy@aUgcwO)+ptlf>D zZX~`KIHJjMGRY3V!_}~aMj0DswPM=MnuE;GsyqQvI zw0hy|Y;v(RM!9?iPNCpJ%n{d*f}6~6pYWZpf8!na`clI^o^7Nih6JrfBT74A9o=%^4Ea!2cCNQ))l0tM3MQwvx3B@>Y% zhwCvKRSAvUV-%DNpXR&gxE1G5vyQWD+I3Gh9BW>7PuO9_be5aVib5osux*gbG9u2j z-^>JS=MxMuBJ^S&6_zCe8H?;x{Y*16tm(qp_1s53>L3b-v(>wI&!lS6!MMz7tvbd! zM)1B6zht2nCpuQieDA`2nMuh4B>ku4cZ_b&->w}2Ghmdei-+ofQ&gEMrA?@>)ObMJ z7cxNTJqN)dtpScgs7FJNbaUnoJ-7~lCe|%1IjbxUUtjy{k3ZolSWWGS64C8Y(NVOk z;C41lv}fEP6GLumO|wq{B|DgNP{rVMS!Bs8K-b|%+~C*(ynUYsKq^WORHXIyzBvVH zX2BJZHpuFJ*2*bHmq;0#E9$s1X=yC1(g_!T%bz~?mE{!7J^1O?sq<7Y5`?vz;%(*LF?_BHt4H4+p! zGD|N%;xT`AxS|AFoFfccRRN5wT-8Mpvj!e!h;oDLy}X(y0|pnv<5D^EISYUADN3b` zEjxdnrE(>{S9vS7nM7PJ1kXW{3X^oN_Ny%S8hl|MR2Gg%@Rt_KN9B;fl2>~1$wF9vIr(3g5FsB~qCyv_u!#0fru}FjUDJUk`354G*(MhTk=($A z3TTgLB9id7J+k~A@SFdaLz5JO2mc`GM^cBXH|FtRO#rwhB#}HKGfQk0l&%{^5?SiY zCFUCvmDfDA#|-bS^`|bBW3L}oBA}Pgqkw39*D=<_YI2;zy z4th>RpmAd0?KNo6t(B1Z>cyjhK@gKxq^m9`_vymfbN%pJna-(|i~{X>jS7eC#>wbv z>CD12wWlIfAS~RbzaN~!?c;E9Mg;lOx}C!Wf+3ex;IZr|iFkv=M%1)Kjjwx=_a zEJ|jD6U&$m%SmSlD5{6Fm(2x+#z5(h2!j|J%ciwRC_owG13aKpxrGs=L&fmnFk_>` z2hRKw>nJTkedD}~kj8AOcGHLss$K-E6COa|kEgcOim73OlLHLO*ji0MC&8)Tx535| z>cTbHXfos3d?bkZ4)z)}EN$hQcGC$b+Fim$Hw{q3RO2RDt_W7ZvnX)UN3x_Q?ht@!Cf~(!!)eDa zI)!HJ*ZAqikZ)75+z*#d9&L=(mv!1B(XywpEg8x2_ISGzK|6&HOggXFHmxNSj}jYl z0oXECWrY@IvD%z&o~-N0Q*ylSdV7_|pIq9rGw{27ne z{rcZAPp|)6eAjZoVl5B_+mbKMA&Gili+G}LL*TD%dWjUY)+-zz;U(A+78>+}$x$*O z6>`IwM+3~_`}i&@^KOQ-8Or7?l}oPD#UM1alhBbX9Dh#Ww*=#ujTC;=ta z5mja{ukcc_9yU$_d`eOect|jiBqLOjWVPDg;2T|DzxsdoA%+g+Yaj&nTEoEF-w;)a z73L%9r>gYDU^sv4`)BW~AN|dBv>1ej-753$`IXyw_}YFgi?Co@o8x%Ev4O)ycvF7l zwd@frSIYHMS%w2d7fyzxa!u^2n4!JR(ec82Hvaq{@H}M)<@H>la$pU&%#~i>n8JyF zQ^k@>9^a0MSaziXY+*^yT9SHNy{!fmw$kcRfxdt)@bZ9Q0(`5|zM07|PDU0kScGx<3LDoKo%VwFy7r#3JJ>EdNDQlM!04^3*Zz#6D2vpu&oltIVG6DgJaRLJBhkx`>jm^n<3a@!!wDbj07$Zj z6_4uNg@-th#BwIvpd#4|kE%f15+*f086mm)lxtTgBp)J)&f-9eMcE)KBhWk@8l=0V z{FEe0&t?j>@XMd<$W*{*m$?0p>?_4H+S?~aa<wgi{Uq>gGl+2yk@19q<)ZdF@bp;6a&Ajm4PkrJf?{usQV9!Oi$HewZw|YjCZ_htk{$U;6%^Ayt8t9g zM13QA4kG=-*qw#YbTk!*QIXb=_l%Gm$#PT$sll)fCfiO~GI~8(26(|N+7+v#J=$6A z)Q+L%B%%@=oobzQuw%`55B4zy0TE}a_$__Lxkj!;yS~2d&l2R9oa)iDEA2Ts)dMG1 zOl-q+uH0J5ksdg%LM~KLp|?Xk%dGaSm^7Ax6NQL|&8@&LHAk6~qO2;bcRAZ zgP9}zpR1h2M+&wHlIR0GG2%lNY*PtaSd?zz!(C=qz4PN^%*K~i-+x(U#sZlAKU>~9 zIoLw7+M{+y-2TeBU+_EiVlc&ef}n7xWErFO)tr8@AZS`iM3!vMdCy=_Xke(l(T7-%yTpPr>cGc`L3ppc2DCxwAwVFGy z0uA4w4`v9uHyk`1Dxa3=Aw(ed-M5F!%QV34j{i-;=;JHG?CyQoJ!^QhV(mxx=?*Av zQ8gfuyau6KVe}+J)v2ah-AZ9r6E_Y>LAa$Tcu11kSh`TW?5MXC3SKt@m=Qd-2HTzr zB+)D%gf{^{gg;TTUF6^|{g%GB{rT_km1PG<_k2?q$d|4M)WRrrO&H=!*E4DxQ~!$@ zLrngiCoaqj-6XnbSXdgG)Jf+9 z-4?##t{=Xf%P%?SxaWJiwMf;hMbaK62Svxra+hJCHgJZmk&!CJOs~M5k-}AusX?z- z4E5Yp7Ba;-6$Qr}!IJP*5|oRX(e@?-ES`E}Xy9t*CfAM3uDw6|ZwbnOk7w()qCZqg z^iUF0qmedeERGrxyt~FAz(A#x)490UYucRA4tS|Hkwk)%bip#geUS7GSlZ=c1dEWj ziqA|$js~Av4CQvC-FOERLA4*_r+d}Ab=9;RYcVBrY^;7pqcbx*w9UOK?FPE<;X$@w zIMw!vN|R3h88>T|m2fBvPbBDf^dLK!NR=5B?Yxy=VHZeiL%dqmBKi=G`TV_}esKLC zzKO4@eIGyFE6hew4>YDx(73IB@&sou=PR7lD}&qQN(JbB8dr#*gcWr;j~^9#?g5x0 z&@RPPBNUd4t{&2mqeYljfL8e04qepz+LyVuCze>RJ!$t2G^b}fsDCDH6k}?ryp0wP zE*%`9$*%+e=xUbJ*ut#f$ylQ-iWj<;WqjiKvsWCxP$H#NZ@|~L89E<5;`m_Su#83U zT^_cYiBE+Njow&Q7N|0qcM9K3)FxquwiLGNQ^2LFUS8CFkpi_JV|DISQ!HMFGO6;ld zd68mVapspl^MCL(r90E|6Sb&>EPOrT!URIQ*7H6fPowOS3|RFeyz zc?OyC(xG#|o;Mj?i*M{VR3p!*RDyEIZu0E8vo)rFvcBFq3$4I2-vOapz^%czmltK5 zb(8-t%NU`C3onS3`EI5RN=#YVhzsn}MOPg7UJ8r}vu+Ff+e~0Q-~hv;mZ6cSKxfCH z8N5(oUoq<_&48@a>~J^WMROK4R-6?;!B?`U9kGSBmN7hmIo6vDYDp?E-;QiraZ>|C zN|-9tup?;~jVXWc*1GVr_YeByHq3 zD?w0>zYX+3A(*2tM&0Kis2e3SJs1pAe}%F68)nMS)$!QZeRlE$ ztfzKZi4gBqbz}k2`u66{MG?}bi@7>m-d-Qa#dp-^_aLZ`qs=*{ov& zN2ov|69}jZmK}iJ`=dP?5}T*iB#FY}-=G;ir3qsW6Ne;iD%{r3k7K9LeCHvbdLbUE z>|CGT1LjcLlT6$%3h-f!2-*nxqlJp$wNdrp8DQrUP;M3b6*@5&M^9x8LDf1P8@!%z33%N zj(_3u7d@3ts-+5dn954fQ@hP!(S_LNDBLz~2XM)8cSu84gHWHsC#(@TBL>ClTp_kp z>?v3tSP0N9VO6L30V#$1jL9Z)T4ujMc4%;bP4R86O`=+6(gLC;$6*x&R>q_(f_MPM zzVS+cQGC~)e%H5equnX%f9QRL3XwF}2Aoyq+m+CB3h#Xkt$W)TKUaZGH}S(1Hanhf zB;&6BO*KJHo&c&uB|z&CyMPZ1og@J8@_Uz)RIJKDz`Dm05sKIValLX$ZVDJbs1XIb zkhMR;!3h0g7s81;SUYsdSN3TF3?*aZY1iAlyE zpqazYPnVJ#V<~K7>#T@6OO(TJW{PH7aOUCP+{&@_Wd{)T9y!laU_6(XI3#3Qq6`FF zToa;HzH_Lw=HR-R<=7or!Hi^EEOQ$$7M4sRWW?N#wlby0W7t`*o98zc;K7B2nou4%6g3gMxkzW@Mc)O;7H*Nq{LNOg-o=|cN8iWM7WV> zGimNz*Z2r)nrkIhbGWng- zu^Mgm&BP$6jWXdd#I7*JGa{P}CJ^@X=;4(%06-yZ#F@;LY=&Am$pD-ebAphyj^;KG z7p>G)_PP`WxgL)G_^0oG8YTBv{B+S=z1h^~jg48<>eM$3wbOufmN!ky?+2&&`wEEm z#kf`Ql4umrd;m{3Q8}$_c8F7;82W4ioq$^eTL@Mv^m2%TAUIHBlyzXn;7A#a!wOTJ zg-?6H^WKSPDFp^k)NM#~wV#(Smdr;NMp)|`(PNGbWQ8TB4MLpKO|+ZKQ(aP~PW!es zI>>4%;ryjEf!azhPb!pwxi(!$EQC1J_kX@c;~8|2f@{$3FTMKa|Dp&>YQTD*t|DZz zdE;mkGlNG)>l>h*oism!{1i%lQMv*WezJopy;VHprMMeD54PDKPtYUbQeotl&h1uT z2Xw_oKlKN!STZKHHQ556mqkZ0Uc=f{c~_xe#XS)FzR936CY2)TES+`jBTsw87CdFy z48PuIseDLNK|XktlQ7d~Ydc~_Zn4JL78s{S)oj*9xYex(LSHxh4Q$kumcrka%!z33D=dqU%YK#63NggNWAw zIZ21hRBrjC3H?PONn?T<-6E6j1Xr=`u`tn^n-^oHw2OgF#cQ7QH|K<3vf$Ozn&w#YxGs!ZmPc^ zq7KX>PKRAR8|87V2ovIETVuA8arqE#6lAB7B_a^K>nQOPtKs3i5pvGSctNp2D-)jx z&(9OcGARKZ9$)HheC&~O3OUko`3(-pBOfjB@B9Ph_RUE z_V{>NxbisMI*c;9r!c*RXJ+636Ld|qm33xnp*s2&#-!W2yyH+4I4TEHh zGHro-f;mT;9BSp0T@s)qa**_bG-qe~GMO?H$)PLXaOMjrl0_v-bdoC3VYs{z)5Xv( zRX+(eAk$NufvnvG5p>IV>o%qb4UV?X-dbsBFEhq#{0I~BCT4-?S27nJHM-CjtwDpW zqE0ZFNf)u(u*Gt#lw>GQF!85uj&gUd_`vlyVGZAMdnVp{;(8*(l4il)6@LS1ard1< zJBp!LLT7Y^ZldypE=3U_$p$HTC?ek2!xsKA!3}EK14Y`+LLfjrl_SVhQTLv+=Srz4 z_LfM-EQ9B$U3e#a^{l@L;l#85y6u&Xh@MwfVP=*$)n0^a8s$CR+Hr3#Sz1U_u#guH(v7&BACskP$Qp&{@BPQ>}PQpb>n z38?!=Zc}h3cdmyyd5n#JC(GCbGo`@X>+gdb)%S)^03y=27t-?2b*bI(j@lVAN~okD zsMqF2OE@DiieNLfN=r1S@M?s=uYj&Dfb3QXf>4fI>!)*zCiI<}evMIN^Lhn~M#Q3| zV$&RLz!P-sc|{SVe*JIInG{^Ki{ZkXe)YW%;F)SHj_Tfh8&!E&7qxMA1{BdL!mwaK zwp)2p0`B#Y8Lk$P4B_VGY%?^(hXqN@rXiaKu)1E(SmFRBL7^EMa2k`*namiCNp)6# z0A9d6+6ni(VhL+pOKr5xex9#|ev}KPL&BbLa)bCN+Xh^j;YAO|gyYefMe5dt^;uLu zRgQgT3N#>d{6phe3X(WIRk?W5ioqUag?NKU>czhCT^bK(JIjTKK;*9vqVP)2D($t= zy@chPa0(}kOnqacgVUL2i#rCE4U8^Q4YR{ltj#+pJRGXb76TWJR(NKLjl2=%>tq+{ zOt&K`v|>v;3n*1cikOTIFmf(;`o;H?#eJfLDc|5S+WCXOyNFy(S!YV`knSWJ6qL|5 zx?@+yYa`9^@y6f`%51A4$JgOrnT~4AuDKNHArcjmc6Px-{GZ}9p0EeOcOx*Tf|#gm z8>y>b?yftpB2Z(S;|j>vWwLnY&_^%F^OX&v?`_VXOy1-&foFr+FxTsqCr%nMs6wJ( zio;SkrxspDF-mx4<#1DVF6CgRh(gkOmee9i&jeKkLH;+my;^I%J}w~>m<_yN@uku2UwI;&vu_>B+xDn(Ip>_u-&MZw@p`XV`B z3B%Qk_o-BBFL`L$?{RhL-gyMUUDe;5kPh zcw16%{UQ!EWB6iCxU@jIywzZnF%0fI75~A{S*j&IKK|hhoNN)I_NcnD;2EPX`Wscy(G+5yde8zm)z)k?!N5#SU`;gN_PM< zlay@r{_gwU^IVl4i^$if@=+SG{GEq9ZNq>K5pq0!ueQ%w4<|QiYT)?2U@8x09a=d* zN8W|(Rm_|Tzv3y&{0;bo2B1(p2aDa^+POsQ*Szw693WhpsLQ64?+=$?GW-I*t>3G6 zV0$#Vt5k;K?11B_Kg^I8^%0x7pKOzXdcCVy$4veX1PvozN{WcC&}^?N=38HE82-%a zLoH|&c1*BvL`ykwEO^aDIQo)_7qg|Rc5I1KzC@Lh_)I{_{utJ<=PXsm_u@lWhEd~s zy`WBgV2-niH7E5v1-+O@FJY=s=^Aj1QnXP6d0C6^RbdtAWl6*6ys#Y@Tq0_QDK;pp z_9t^W9s7m{ZxrsXWROg+&10q$?MF=*>{ET?Xd86{ZuRIS+A}E1m~J-4=9F#NbAgKK zUva0RHd6Vis=!FK#KKA9LFn*Js6E%p01G11s1FSfu<5m)*bHKSHUL)lc$VY|uj#ye zmqMEK%!9eOb~Jx=Bg-yIIf#o?tq!KRCWdjIeEpP=6syTFN*KQ!grK%Gwlzl(QH(7D zKCCSmZ{u8?!Pao?v}Yf7*{@%J*q1+Wv&)Ie^EG1Bfwhtsuq~;U7zK)6<|$h*>&(}! zs8S1fz_u-fOJQ{|DJqRQl}oNqD6WXay+O1T5I}n|3RUVmSoUZp!ybu1C89I~Y7NgcIU9s~+^k7E51>WW?YcAsrx`o19Dh59dCc}_p(^=C3STzhDV^4LgkI>i0He6m{>Y#QAVK$08NcBiWc7;blb z;^3rWM-nsw0@ywbyBf5onjej*`o#!!ljxbQrW{8I<;2k=$mo@_I5xmr;-jfioG-=M zf}s%-AIYzI7)%v?xESB3>Ym3n#-JBd0LB1ot))kVc;x_F_}T zALu5=1&q5@XjWC{qS*QDzx075uGNU9ySK-sx;^&0C|2ORR!gaG_zyLev5na$7E^gN zuv2r}1t5JH$DQ@CA)5VCHsvk443bex8lBBT*rU8}Iyuf^>` zWL8OL8j6PCCxCp2MK&5)|S2u z44^B6ia9JLieq6zWaE{ChW zzG3g5@HnL{C^o%(-sJFUeD5-g+Y{@kY7)d*=u^a|DL%*{hKek_2X?*n^mx)$f(Z${ z3U>=;A!Zx&ezgyv}AvEAr zyiwQ#0{19OmPe+V6tu`Oe{#Ms#+aPwE=*{5&qE|1g^oH47D9fS6O?xpAxvp(pJ||r zYR8Mu{?0F`V`b6ARjOlb67QevpgRcDKq3|+3~KPV90XD&82cP<9LNh9Y#}n|6yno3 zi_0mERv`5QwxVR?KK34_M);0z{hjZV)gU1Q#n z`*Qk_Us`s<9hJ`|pkIV~y%ySZx(W9EcEu+TQl+;#p8bUCH5rJqe z(d}=6eMTt9GKrpk`|IzNTzpvs`{88q=1UK^L!!aiIf#g)GS-(eRaxN*z^qgY(O1`7U1?V-6S=>rM>@)kB{I4q1%S zF9kqOc>742uw#;5&YUG-Egn17@9g^g7r!D$3YPKvHqd*XHRRotb9BcTIm&53p4MI) z>5beYMWQl@YGf~lTEk3{3bncpd(H&o0NztA?h>O`FUz!u$Rh58;?OL)-t4^fNmm?0 zz2Q8WZv6dOwJ{XeQee1dYu{>0W{?qDHsJ3Y!_~Cr8r-@}Vn4y)bTS&kcJTv(Sx}5@ ztRpSDP)O~R7k+^E62Modt><2m?=hE=xHi*SyQjVcqy?GqRC~hu% zE5d`@`cgWGVcUdc&73xnYH&AR)}I47U711 zg4Nd_H}!hgKlI+$EWp>+jw?}zFX~!(M4GAt zdXbS-#Lz04cjil`TT+FP>w}nGrSs6{o;Q0ZK4PPtl4LtZTObSX&2gWKM2K|T5?Kx{ zBqedGkVRA=JE%qi)dE?5V$2EYtgtH~1OlVmk2$#B$ITMJgZ&1oA0U z?Y0SE0$D)9KL%rZP0X*6yhSjTj21H^DlWIndr$nye|(ctDr<@RdNMN08hGcW^~;o0 z6O*wq=XYof&c0H%`v2nQmCU^)rcG4_B)ZgOY54-4nWbGP>I``YzCiUb=3oS{bhsPe zR|qQXpWv0GE)deTf~WW!HbDgID^}R^I|=;IQ)HIR^lJClSN>r&C025hNAEW>o1=OK zS~r^$DmF*e3QRc1=*)fRabVms<0T^KgbznGO>#z|HLxZ;R~1@9%bJDns#r8e5c$YO{78|2=IVpI!z;)w! zc!?+7Pc(<;GT+K~9W(l(OQiQbP&Zw1f2={ariZfMMFpT&aYU{RCc9XHlvU^m))w1^ zntI)m!5jk!klb4;%>=5%+i;1M!L(pd3) zuTWMXK5RmllrLoarFP^;e#`ArD><~i*9NQWeu0WKWjgGBsEsuCi{NgVq!{EK+gU~q z?rf5SDX`ZOd8n1`f`rNn&`tQ#RN826Fwv1rvj)XsS5;VUOeSCTt<6$6S{7mbDBlC~ zAe^fpoaJ6{0{@X0)GD0OY?9RKhz*ecNuCB^8(mA1d+V~7mj5Y?WRY#6_92y_c>u2^ z;Zb3xyrE_WAVn9~;v?VpXc>@OR+yI!b4P(KQ1*sqV+M2S3(Pa4gTbNgfI|~FTyjpM zrQG%k;*nF>WhDY_vn+;YXf+8^*e?Np<&KPx2}kYc|7Z$8%?bA9KnJB=*!*cof|_=L zq?#U5dN!WN<#g){XRoF!tvv%fuiLcVscLn9*&006VZ%5MOLBw5(gX~vL=-y3Uso_U zOrM>Sj=I&4T2 z(1h_)ih-2jPk)bAJb*B?aV5vT>-K}r8OIt*9s4iSUR*v5a{!aM5rg2HX~qvN^=4Ev z4t3h&lXDy%=&HpTQ>n@atFx$s7&$$&falcDmbiEd(?C+59ujx0AqQeijZKrndfAj> zQDSm|5keNrIBKvnyn{MAQVT+%WuRdfZo^&P*u`2ZrMvdYYRblEi4 z%MpOiVhA{DseRQn){IMM2f^FUY0QtW`7^ka?ODd7DqxqI2dScrEDNL&UBO(k#~NAZ zq?mCfxeDp&VvdH(HdSIDm$$1(SnFLAIm;N3)y++8NIWb1n>~uSt9`;9SWIanmyLVh z@6vk@zRwcG^zQT|sEiYAkmF3A3AZt3*s%>JSRNxW;6_9!Xz7xpV@1T8ozEn!o{BJh z9nEwGA)Je)qi|FkakGnP^p@xRnuU~Qg^COAqY6fr=p@ zg)Ld<%tRhM?f~qOm^SP|OpZrr)mU_}gd<^KtZJB+O$av2iiTe3jIQjnGGFe{H1T6z zmg&Omd;jZSHA7+Eg`X~uwZKNh&yz5j64;dTgRu=XkV;ge4g``_3DCyo+F`Xu8mkn% zn1VzBj$(H~4>+iM!Y^7M<5C|{qBjfFh>*HJ2}rvWY!_qOt?lL@5<-(x)pEm^<5pjw zMNY!<89SKUSq(MPK3JMH){@|i>c_%v>gwA-M4+xF1#j}TkgROf6v>c#WBB2sIiXqq z&L8o#wQu03TMHJdXnJu8Lu4ijnHe-+ZyRJeY{eY$Y4|W_Nfo|(R3wZ;@*H$OasrDR zLRb(#Ttpi#46c|h@fFn{a@RGx@g-$-tP38cDSjtX-G1l`UhsjH5 zSdvQ>d{g}$+N1`X8-eRDsYidel!AAXl{y#@Dbgy22* zvOj=@3a$#k855nEfYfv-Dvx!hCBkr;eBGT|X(9Row4|-U06w0LRtn6M@0zcHD7%P?q!Y#2*~f}tog8+B1T;66hu@TH{@lFjy> zm-l}mzEcMZgek0hl2!@jz`dE>pc#gF5c^FlPwC{bvru0CfsmQQDAYhhlTd$}&2I1> zU4PrBzxLGokdCZ<7eC!^`#62ujHg#Mz@pVRp#Cj#Reb5gZRXyGaKL&8*0;(_--x^8 zL9uNWw|Jmfd}b%c;h}`C(7J27>lTC&U2M<^U)J4M-qrd5zM(9mz2JCV7P+NWjk8d& zzTy}p2MSZ}rrYC#Gh>Y@oZ&QDNtZ9fhprEoY9v7xrHalPg0MX=kq^-gcP=q6-GG(EgTReEVCcQZ`FVoUY9!C)!)pAnm<^ zW3o_%7+r6C?OS;Xb!&F1f(85}?slplnU26-jM#z$@;$vq+GA{i!6D^Q5VRY+1JbbS zS>OC7Vf6-LFtRL)Gbga7#$$>7%O~i$J}MmL!zpj$)a3)N_?Vm`S2Egt!83ASI}akH ziow@~tBY{Q_cj6`tHq;KU{E?Qq{GoTMc+zy;`FB#_!ulUk>Ue|5LXPD%oWXb z_>jd*&O3muHf6QO3v9HzS{2G?pM;dESJi|RovYwsY@y65@WE&Y8O-BfUH&gKo0O@e zK1m)FBSwYK9vnDXAW=Z}Z4tAWe7Yj7-Dmyao&zbElG(uvmZ;*0=Ycnv#o2P0{MIQV z4_<(|l?xU2-N*5rQrIBQLZJiIny?c;@EQZ&v~Q&(l12{{0#K&a>%zq?WyEdS^~|`@ z7mRau^BC)J1+$=jAkH8Z+>AnXp-(fJY4w4K9=kb8cBB@C*+Vz#iy!mfZ+Z>ZQF~5_ z;aaM~I~bRFR6zYS%&N}e$=1eDd-EVISqC~-#Zz&jftsugfQwdfp{g;_tpP!vq6L!H z90a~oAR7Kh+&E7=M46Vi*A`hkGuCthZh_DcmN|Z{??N^OK^)>)J?(?`jiaw3Ldy~r zF1s7zS-}R5f=gLe|o-Ndkb8Kk$yse+H z#%h_qox5okJm%2MLzl3rthEAvGX|waX*IHKu4@)Da{t;txrL#U&y^7)?A_@>~7ywdVjj$FT zb^AyZTpWeVda4T$)OcL3V9M$L*RVZ`A$0H!uJzqcD{!J%AtBMiPIUP~0Z-5&wxs6s zkZfNmwQM1kowP%}Qy3vA&E<5%qrUf-2U2C0mFzZ~GkuWCslH(%9eKm#)3(+$r(~dD zr(#tF8w-}fV&K(L^)2?#Y_{ejokGOc;Z)=zE4T?)^ONec05TE6QqkfKXHfX86h#0l zxe16d?)CBx1yZ0c(?c>%Y5)bbtvY_yFy`b%Z~oIISW?+ppbJjTpn{a0;zXG7c8bl8 zzu(1RkZ!EQNFwk_oZDxrj zJ7meALu$OF8+s)Tqv#wA7B;Ff8v?WdLSkd`4%fF`>+gTcos<=4ymwpo)82nnG`2jN5y;bub+BDwRO_@pxY+IMm_E0mmRUo$67*ka-o7v8pij*!x8;uz%Iifbx?V_ z{(+2*h#)mhV^(fU5r9%y3RZ=9wXJdNgHJm5P@0z$OJ4Vxx=aZ#+Eb(38!X8V(t>pR zR{1r{v8#;Y`6BLI59Y4l@uKRNG$AAZ#?7F< zWH)$}VctFeDrP;oTY!uDg$%Lqtk42y&^x$$*G(#AjO(tq4*$sCV^KApTiLBFo99W2 zAHw&AOHz!ITi}=>=M@sNT;D6^rg?1=B?~YUex=KkIrcURHI=apO`}4L$OzJlxCAOo zLd~l$KWTi1j*kxT!ZzO`54d)LuY zx}#Tbrj}F~4#RH*G+z9#e}mdBBLvhWOA)vn9HZaa6SE12~`jXbvXgel(>qZ=%7{qCf_;m$a!^(>O!dy{q2lW_ICYvfH zJ%|$itM0o>4T|9d?l%H$Vu75HOFm19*?r1vb{zGVr?cL?G-+xhr5}XL(h!28$E7&N zZy2*{JScq(u1QA-&SU{+F4rnZL5MUTg?DlxqZ1MNjPnpn=O zm2(RMvn?lb8pIUG(4Qx`0Bbz`7gDuYO}27;e*ski{UCu8ET6@6F3P@JuYDO$x2bU& zaQ9y9%&REhhHpI;O`k2AS2(LIZSDn?OKc*DF_O?ebCfyEWO_|fkI|Wl%FyVX(wE!l~~XtT1R01M9T65WQ@*xAAEhUljF+X|v%BSt?b{Y#o6qXgi> zV9~JANEb?|Ap8lqAGW8eTjOq0%*m}HF%`y(B7&Xf@p4*|1Cz*xujCP<+>ZM)*aU57 ziO{YekiTdPv;--3s%zV!PrvJP_r)4&cjKpfU)uQX(6;>}vKQi;R%^MbGhiK^o9ix%V$M@lA%NK5 zXQ5cH+^6u-1^;L00NfXJf{_f{0bD#8FR$iBG9*|pHjeTg68k9Nbhs&qpu4!illl02 zRwnX19(+c``Q8r>W0;YpZuU%T=~2z9pD=XUyG45zmRR+FnRh8NAEDH)$9hEqPWP6T z(I*|iuiL=dh~W6Ie5JA>1#@{`4}T_^D~GQL?tFZn?^$cFkg(9?a>F6_{njBgL}b0Y zch$>OF3dFTzoGV~SFgs0u46KgOIH^y-G#D|ENA3lTY#TL^kB7{l{uj~^RPsILyaj+ zs8_@$BlAQ;g}v&k<%+WVuSTQ}g63dLz<6^6!0 z#`Bh)A+zA}Tn88)@o*2{7)Ro!A>_M;nlK(Hs%nGPtz8@+M~W8$&=VE3 zgv<)bn37OF!YiiI>kk1##%4{lWCMJXBpaEx5Xp&p2uR7D4LTr2Ob+3Uy)I<6cE9OU zS4a?kFP^%4uUwJY5QNH8h{IRmD4O7V#D?evj4;B53d(d2r33*5@xmTyAwh{`CBTGs zX~rR`f?*5U`tD7{??f~ynb;Ig76Gs-Ocb!}{n{5#J`>MTdkQvF_u{jO&8sm`uz}3j zvPN{)kS_Hxy2CiZZ|*a8uECwBuq1^qPY{C`LyzX*e0`)|mV$EP)Le+(=Kz#^v3!QH z6iW;JH$;8O(qlW6(s-}q1Y2)z1eUJ;Jjwjwmfz(!>J zI@{r6f|>TbUgmu3=H8XGQ93fuh3)!nlLi3FT_UCr&YPHa;Ttzf)GO~Tz3>zmXB14x zF<527zL>f!=$1Ox$>M79VLJB0!Y2pM%16Mz+hm(S1PWsu!Dz`)B5}N7%z`Jk+?W3H zBQqCJfMuO-*Qo$m8ML~C2kuA7)kFi|Jdp}w>$o_Mi-Rnn!yt_bUaYV|ndDy%t0SMd;0fF4qS@WI;smLaFWZ7P zmU&)9!+33@m4+wBqYlMNzq&GinJpoc4>_gOa$ao3asq@{Qaenq;N?KHZ5mdp%`^7K zZ9iU9Qfn8}wST|&hgMNc02zLrB zp3yVAKliyOFU13v?k*dyOWCY}%R?X6RQJ$A$_5Pva_xUHw(xbheYuj!3WjKS^Eg4s zED#IQTyB8H?F?C8?k-|YA7J3c=ST*vDKu#%21`{CK+MQ0vH6BI_;Ic_S3Ppzc}Ku# z*N!f++@DajIhdkB;-D~dm`w3h6Ic<zw5U2RRz(bm{EshORV5%!49ftz z6!(^e=7x79^W!?Bqu|x>N?W@iY#fqJuGwRijL~qs=!P555|C-P(VR;)v8g6|QB6&rW z<#eU$#&v4+fomTx6SIDU2k!<=pH8M|p2W2k-?~OHCfttXjDgm{t0Nfi&+?yE%qx3N z1cc=}4~qba(Q zd9n+#3D)zZEpNv+OYC5*aEAB_8ZTKZIu)sKq|}1PCoZMMk9gjp52KVGQ(~w8T@{R+=~_gOz=j)VI|wA*w=-@V z7FdX*JVvUpJMX}qOEhb)+Jp7Mg2KJCx;1QuQdtsS+9X4w*R(|B&F_^ z2x5~Q8wO4=3SP5?7KNYu_pEvQG2k|VkvL=nHtYk~LE`>s2 zJme3E_2B(vGMDRDL8ej8kpaatjMyEQeHlxsTtjYs{57-h!t<2wqc5oldT@E|)M%u8 z$z=dy;!_(q5qF|elOc!4=q1HlGh@}it!H+3m=XYlXDrKyARoac!w$8^zV z`%|SX0dioO9gB|m@c+RBm1dy+Lj}ML)LJy&jE&XLXmn;~hvK9O<`^)K39xSqrd%S% ztYS=d;%471hztCI@z2Bx`;t~iyE&kIxH6H60FVs*1M;vDLH#+kiN-c;3=@?>rMVXD z9Y68w5-dHsL<_!^%*8-+dbWc$B+`A+Ji$%VXrXj@aD-7(CGh)J+`Cdwjx`cADjGb6 ztuq5Pzpby?O{z~%bW5y>Z#SlvTypkCas)s>;bP#&w;)9$M{PoS;hK}fbLp(u_|}DM zA(+}<@Y8KfzdeuAVMW9`s(6O&ZBt9_5QL&5KCrbV5?2%9nf|a6R(BP*g1?YJTD!Qg ziEN;7AS1eDU;PP}b-pC7gafy`SO1-PT>Zac^#b#mb2g~Ym|2uwE6=3tN6TrHFkWLV zRk1_dK|nLXCvTAQwG8-Y0gu8HL{lz4PeQ>ROMXe!RC3zCcrXVX#hTo8;zt2s7^ zubLjO7A5b(-D{-mP>i^iXh^4>>VvFBQ2-FdCT9e6Yzg{Pu#l{H%KQtdCf3tr+ds^M zQ}JLocnVVuO4|}0VEIVpqoM=m!yOBFbwi<|%lH#AzrG4|^&HH)n2Z#L z5lO5TPr+s)Q0b@4w2G)e74sAteLeI(ZDzZRVY{1~TQ2+AL+BOC4vJXt1Kl>9akg%D zGg6l>AMrtW!xNZwh0R(Cj<8g3o$$3Vi;{{@I9qqOQL&n{*Rcdv7U}GY;9K|An}EG! zALZaiZ&usoscN1X?$|zRMkNR>f@JOAa#IGgF5Ooyv0X2J&R&i@s2x?ZD{Z*@{*@RB zm^DzL*bvzUE9@mswYU9{!Qmo=l?VY2ELS_@ADm^D6sNqIjK3ywh&2$EigPv{|>uph>P;3>I56KsOzBURT+9FU6e$%s<#pvSd{z2~mgK zbom}Z;iIFQ;x@^lVP4RPSD}7T0_&7LG|PR$?D^;2gU6|rB{^@`UBzGs71q&}MVm9W z9jEx>1QDinN5ECIw@i=X9HT`@|1KCuZ%%WtHC#LG*@s>B>(?LleC^%?PzC%FG7AnasO`xO6%}q_`J`1>y1`1H0=|2~=qeE1=L56E2o19X?tSEKY z1~U{Ej8?5o;Ks!>n7@wm>D9Rsa z?hOdcg)_PRzjo5tl;#fZP~pg4GU4DDfHW(aX4*wF%nKC+b1Cj!fsPl$FnEhYcxmEV zu(8b1(|8iEp(T~&)aJgzn#Svv!V5S*?T%F2oa>^765W2l0}X!!#~Y6L+UGxe4@I-2 z#1QY9XT2e$SkI&oW4{df3u?`m=DOfJ3Uzov9q7O#K?@jz;5!OPfwVD%X%;MujWRld z9Dyk%-yn`pi76GA>{#RT++kqOxsqsI61?Q-$v<%+rNcyit`cN<0e0RtxRyc!hM_nH zUJc^0x9MSH6%5wLaI-C2_MHaLX@99cWD5$_AWN=;eX@NAccv?YGA@&8kb*NINc{*@ z`?11LP(u!!tYiUB%#wQY7s`U_BW2JExh%4SzA-PE{m`Dvv5eZE@zWh|{90wlq#n*{ zYj&phoh8BqmJCB}4C6SY3bNaQ8wb2(+}|)_R$GE5Ymse|vn0SAj4{&(nBkzJt6m~6j1Awhp4+}pVeNErzq_KwZjfXZQ6j)UGDuTE}OOramn~lb8NIR zU2(+0Mfil}#C{01vMCtgX;cTeai9m9g0Xfi3r_l$6 z9fn4A*zN`+vOLa6XIST97Sau=0pFK>$zz7^vk+fid%(UHxX(t5a}R95nX%M_?s+;) zY~vu=#^9FL^f@DVHDkk7cEb6%y+4&UU{&s~Grh2wQ|X4VsaUvBv&`eOC`>J=lUK>` zWT)urpGZ_tL{ct|omU?6N9i_TbkL;)eFr6fv;kvoCpZ-a<0@cS9rzN*fE%BYi70xh zg1f#9cbj`v?k@SH1Zp55(GN8S5C+Q{U^lXnz-B%@JkXXOQJP3cW#EuROgd{{{XH-oc^rpna?>2n-`iIY9y_!`yt-${J7 zqht{S1f@2E3b4cbNwNn|J@)v^@Xrwt=ESc@i?Adt$kvV?U-{jmTc6&-x7Q9Y(Tv09 zf8`f*<*CM1i>#EqgxLhM;G2YdU(fIe%psnWY+r6{MSKuh9&8x+C8HCKV;*fQ;)CLV zM-2~p?T_y~?!PFN@8G9f9}ZWkaDv6g#w@xa>MQWZeXlS`oR(h?lC!I@Pfo*~<{At~ zVEKu$^9NQ6BG{>Xk06$^7zw;X0wMmcPk-?-d%lY=DVvYq_b^=*0sBU13|LLHQjE+7 z??k}f#_(`9!=oCjQusTHd!vFN;Q}u#fnsVUPYS}YX$hwyj|I(TcoIVacvfCaqB9lY zM)##&{^*Zg`fPk_*&x5ZBj)J^ej4Am#z$MJUWKkk94;6@Rt&q3-EAejaAN+q2=}G> z4fWAG%;r$Lj z-P-@~Oiz$Bfu3v}ZI3sCt)`x!(*_p?b+%ZA9nitOE5*r+t#TStaWTM=?DYuY$XRaG z6rNR1i-07`5JV&t9^jVpMGnGHjY($P$pP1x8=f}xwgG&9jUz<57i~lK2^cnxHnHDF zM(Z13bvtP`7JZ}+4g*0n*_j=xlmNU2clWbDfRHC4-GpnbsR69{I1w`l3n4X@d$o~q zYkJ*^k!2S8N>+6-2P|x&M)e9TY%}TZ$uiOAH5GOuP*Jsm>lo9iM*Mb{+V084;qdogasN&?TzWkI*Y?lI4X=A5v737F80Z>=%Ry9(Ie+fA<_^RAF;}y zfQBBDFA`WX@)0>1eHq%tVWPU>l0zPQBSp2kM01{$i;6b6zGVB*Hk@YS`lF)amBGz= zrGlt#!na1LX-*>r0g_r(d|?9_fTuGh{SPj~#9We&B2N`$#cg-NnN9b6rAYty_DZbkKP zgCqQX1wmd&LHdNOtR_X)lyHKZU5$ufXW*j&QXvm7P=Mk<6v^o+FC_o1GFDmQj*KhN z0FvqQbf&=G<3F};Jq1zHT-#^k*aaAhr$?d?XA2Y^zFZg_mkSj{aXG$orA)g(+nbM> zP4Gnd0m8ru49ZZY^43^WCrvXd`zR}C85s;6O&azmf(GS5)w&brtFd$7kbG?fQSRrI z8MckL^S*ERtT;M$l6ISH8!2ug>OimCTk5M5b|#@V+1NfdxDCd;iq(D(ZtPEk&}bMC z?!}gHpOahX%>P*6mnFfGs8gQX*$6e%68(rRC$_|YWe`NM1bzp@m*OVwf zD&|`+33z6sS9BkccA(n1?T1TDDgvADI7#(RU?yx3QJW~MY0IVWdg|+BoO8+4i@wDw ziT$rF%!>?Q3&wC&OQb4O5`Z^qA^>+h`o(53OaxjfH`-}4IvV%k&T4q_I7}^8;KfWU zT|+Ke^UqtQQ@Ny>tM7T4hRmWyVFKYg*%m|-?!XALwUHl_F}IC1Mk?(lcH*q_qK6Dx zhi!HGB)ECQfCb{fv7`AXtrHL`LTb_ggse(aqLpB|1z35QmXQ-Knp>W7^N;8mYMh+e zZD5wDXjlxg2~GM1+Y2${;Nwwc8!C|X1fWaZt005_+h@Bo@-m z0BCK)JH^zkX+t({SBA-Ae;HgfOb|SW%j43?@!OwDd6b;P+IOPLgU)#qa!sIM1{%}N z;9%&S&z9dK2ZY~O@JOG+t!e_3ePa?$r`&po9tRwW7p<@Lf^OeLSw1#d4>QLay~%$N z`vnq+eU)-e=FmL+$nX`EkL79R7zI#?vv=uT)i)ztW?6S`-%0Z(J%!WAaKWB*>4B;Y zoCxA@D=#v(3Nmol4{*r*q9=^7gCczv#m|I|+)NDq^;8-q&*Cm^h!&C=8 zgjp`89a|26Dv!mkJ+oxftx_?O_ubS&CDH6uePaX7%$?aH48)ee+zfCEvz1Z=*Wq)Q z*)SCeB-ABo02Ru>FrzENkOkBwu2<*m&YV#`sZ$6)v%LAg#6G*b9}rpID<0kMkOBc z0=^0_=#z>MHCK*; z9M(SYgZJW@YW$yWo4scK>k$qFEQGHSsrm9{_wYOdt@x0S6W9Yez&}O31I_{Fv_X^| z$&M1Vq_9~kZ&0+uYAn-c*7(_;Q&?i2IIQ;FhmQ4fKvr2{Xx|wsJ)-OW2}I}`bw~%__0^ zI~e1KDm|70t{fNF6WI%G<1i>KF*>6$AGDuEzRFGJGm!&XyT#&hEjA?FN8KcUmaK## zSk+C<5GTNufK|e2c5kt=IL|&*0iij->0` zs%t+Km*?Xg*gF@hFr){hP!$>}9D^?~|Fqm*-)~t#r}441G8Qa&=!EDw@Z?0xm=T1k zzn5|vQx=c>baO*=q~DZ5$v+Ri`){#>|dwJ3%+eB*s4b@^3VzWJ4Y--yC_A$FA>_ielhtS3K3 zlELwsJjJiBQ9N!|Qse}KI|G;J=pSG8dzM<%jw_L;jf_4Jm)Ez0TOd$tPK~4J8%>Qv z?YRK8JJ+h@ZosXZq^d7LfI>);{o0!IG;V>v1ZPWCG6NU*(-n_{lt~GpSVK*m?>vGq z4Losoh?N~Z*rS@hvvVe(l7d1q>Rm}3(tBp@kA3d+>+ZlR%BB|dos%ry$xRG}+n1-} zPG>9VNOKGa+Eo>uD2cctXcVFqL0Q6IDxpoiA|(}_JR%Uq2q}L+Ez|s*s$kK{t|LH$ zK||im|1Tpvvd#$$AL*8HsNh-Kl}rq}MigDX+C{hb-9LFMw`Q%3Dc_ka-6}lRemO(& z&Mm5S@4|N$xJ$_e2TICAVwDT5yu^F3Y^EUizes%25lR=exmPVd5;sX#n$62dNhi^3 z8wH{JHbWGIZ>C-Y2VAj%rIEE2CEL+Pby9}=c_h)Dx2dEU32fkGO2LuRQ)7i7rdHTq zF?YcBs+HA?mG>e}+#V3t|I7`47IK>p(9$IJCtBepFGwT`JI7B>n^+4K9QjLFZwf2{ zoXK(V@}It4>Ke;3c<)kOV;t2#K3hjiPpgy0f^myB#%FO}fc$z69`$DrQR!WTI|HM- zC_>FROl81vsE0riAcQ@0m<7bb{FgzBK%I$lbUUE1HOprTf$9o%+@9XoJq*uPD>($P z&*nBVh2D?eAW&I#q%_gVcvUmmV%*X?zvA7#Hw3sggqUA)Tybe4iK_ zmq2~XVLy5qCGa!+bc3g>lLhwpxNyL49v{#3h+o%+5q#e|8FItCt7~o~QI>^(Y%446 zsBaIG;7|?+js~KT-fZW#+;`LIyJq-GFYo`u(rK==Wc*a04WXnR^_4>H$0u<*sw+OL zyqydHB_P)-SOU`Bp6$u1_%hxxN z%Yem+@@^54mrOfBA~2t9H%}AO9&LtK*iC_2k{?GJNhN8WNy3&G?%4b37ruun?6Sk0 z`fQ}6;Et(L9LLPL%h3}mxI=!;V^rtDKKeS@w;Z^`tfQ~c3@W2e^D~0)JTa0*1^&`= zOXNlN8U`tFg_DLlNKIt61+hnIZG=BirPR`!h{7D;e*MbRMH$K}9Br;786(typp*z* z6{tHI8;>Lr^ZbmTqz$VzG0~h;t)mNyY4m}tw^f;KH;L+W%#G55Ch`FW8KhYj+X$`i zv9y?5#V&R?IJPW-3w&?Ek{ytd@c!jbe&Gdw#8Z_P7iUB8mW(yFHR~rv%Tey9;9$^! zowXzVzh_LlK>iiqEY25e9n!>xDzy;t!XYGYrFHjOa7CZ%n@6RH{2J}YILfN{KZ<8H zvtrSt#;8cec|6IAtfkouYU&rmTKz*a>fQ_p4wFTcCzA)lbsO1fzKviW!OB(;yZ z)EEurbuQjkL_!{nkM?}3TXJ2=jkgHdA+RJm$Vr670W}o07W81w_++K1R)V@oQ=eHS z>68|?1vd6?ahrTq`==jx6(v|Q&8g3ZztK)DA^JzdM`tQ#If+rWZb;aQVf6aXg~xD} zdka1_Av!(DERU{rAL+|?MZwa8KNEfQG@GiV1mkLXJgo^vGRi`QITEX8xfW|I&akr= z9GH>1>F9rY%WafS$^7I#n+r!cw4{U6OfkO@MSUm$m<|y=7S~1~I6P}>qKRrXnzFg2 zG;=XIZ)IS}wo%ZqWRVMW19=2%5y|TtG@oYvOpRRRcV+WSXkwL;UOB?7T%4ki@fgfE zxf1oAR(rT4dI=r79lH&NW4dh#M`*EasDqf!Ef>QHPKX3Nj?s z1Fr@dMzJ(~o{%mr0zQm`j+qapfo{YILxmmGE+TKmrU*2}NSKgj+Gm&bb!uyz8VdNUg;Wu%d1)wCQ}*!u>A6f5L|X2f^Vbe%W*A zaa<-;MS-LfIUv;*)lX$#Nn+AOoLrnZS7w%caX0;C;Mr^$t}Q6pV&BNs1J!J^08401 zj_%w#?qha{Lzf1(G+HQ~tpt~L;{N4~C^Jekb3UH+$^zURENCp@o6=Jy8d5|}pphGD z^vzIZw#&tE+)D=^_zpZxX*re+n4>{nidd=H+Lv}`$^z1D430J%!_|bq{*#nzRr86* z4by|!7@161tw7~(B@boJS;x{SgywdVW7Y&RQQPhJ5!V$An`9CT#oEI8=ewzxfpW2} zSo64#or~u$O;+5h+H)8#FI5Kxu-$$3^^v%0?hB|pg0Q)p>TB=;YuR%cutpN67NtN` z*bV(z`MA`Qnh^qDE-4xQmF*(eIrw+~qX^8*Kf>~A+QBN;<@=H;b4DMwY^*heREf2k zsOm;3$+av0X*bJ)%MLj1`<{yKp}4G~YoourQ^(j0nJVHgjxa!lC)Wo%cD;g?{y4uP zgUGhQXi=33&G#lDa&9-((M8w}u%vc23uFYb2KOugyi1ipHeeJ-xJtKmIRmSv&B}Vb z&=7RDp{X4^cHYb~%G&cvY?zG%{2Pdpnkex}gmvnvMWg~C=%zB`ljRDP>(Ch2h^P!b zq8l4Z$GaU!#On#5m4}^~Yg7DdRxmVKA}SZ(-v4<2v%imLFSUI(?T!pS)CBWIy3b*F z6s`ch;7Wy47#xJs_N}8*X&I^}1uf>-DD)d5ewo>#ETe}!%5$0xgN<9C&i8Y}W(V#- zjWS+Nwlwy72qH3U%iKB2lR(0VjH;Y*9VY-D;1lKyc1ZUVguih4Rj+o zHK}cu3l+93tC>`2!jaHdXe+i#B`~QtedlGJQ30mSceK`!rJCz#X= zfi;74l3KzJNB%ChJ&k~i?aYr~zf4-+ZpAXX(Ui@>nde9 z442F3o8NOI^YNwg5dJ%t%h_PSHZ&VE7|a@hF1Y~GvV%k0VPYn5g64P?E`Vb-mxmuV z-$pouO@d&SFW;-Q)KHp>m#vcp5P^+sfG9C5f-h?)C;$vqEale4-KlAh-9!=?h4sSk zdA}bnnn3jwiwPIr3BUd7wyDEf10y6~7b^K?BW!LdF#r5(L6giO@2|N}oo3axqDR zMuKuwGZ)n9iyuDrc|3ECsg!Q3@=FyISzi+r2LcXf**LPkCMu2ue>h>2p; zEmWd~2jY1jS|6EJzQdSup`HW~H6tB7O z$W5#$1^gp33R1u4yOe5`0cPC#$ z=F1HIC12cdF$>m8Bj(@FqtuvK@0ajJabnaCiM_SjA1!Q&f(8luK%0|461(i^Io!PN zY30!^bm8AmO>@I~aILOD&A*A^%%QVha0c!A%90&-kBWf}O#dHmZvrP*S)~sbE=W3! zpn#&HmdgN+g1ARzBuzRY3F)M>5WuadbXU47>F#Q)J0y*wamT?0cNA1mQO0qJJ1$@} zqcZ9!?ug6aHsX$=^F>GWd!Dns@2%YVzP|r|+TU+7YTd5oo_m((JZE{APqZ&+Zo!x! zQopgWY`J(H7m>5+MPz<*v4Rp^hxa4#<4FS2t*DKTa(}&5Y#N-8-AHCjPa|Rlv5x4R|$|LgnM1r?J7u) z8!pEN19%0D?M;n(0!Sll!|z~Q-1*J! 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

Pb*PX0%^*ol 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̳Un5WXO}f*#_tXdLf;g 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 J5B474vqnO2R_V=*^It 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

OPf8L5f%AedR^lhDXX* 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

    e!1EqQ7~*~XBSRa+%IBM1nvB{(H~05aIN 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

    E0-x$dszJ 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

    ykzt9f-WBQr&ZM-`yA-muAm?&_ju_3p4p8Q}Loj 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

    hlxg2ViRk&k~$Xm&idRMQFh4) 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 oSo7rmTlPR9VpoH-rV3)K-`m% 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

    LVRz893sDbQGndcM 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

      >JYJWM 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


      $ol%Le%mZ2kz(P8$5?>sC^P`;~~$CONWU za#3@z@ARP;?xL|L29; zh+b&J|L-ta2u`xCLJ`Qz(%eG0tj?$?vM|jFF6$t57R$mjzV~V(SXtgsILj?lSrw+H zY}8NEB4!~k%wqAtMCQ^o=64aEuvxIR;TXOU~q0FJ6f2 zsicVHMewD%sP?=6uUEZ`qADx)|5p_i%lxq2Mj8|S)p^L-^kU4gZ#|aGV9)UyPcM~g zZRp%rak~QtRPq&k6_#IU?I10rj*0nUC7%Gld3;mk7GPAknW-|&4astiMp25%NXhh$ z$YR5~o9i?Ns(?AX0l@|bWDm1n3t`UvAn{xZ9WWZ!0f@3=LmCF{*_s<;PsGe)2TP2kr4^dy5BHF<-w`EsI%-$ma1;i0cTQ3#GTdaK(#@I(}N>8mr4^_f_#Ty z8?cwvxALVYz2~lPQE(+kb#Hl}3XUa&rw$CSX^ag`R!>1?e0UBr--C9g*2gPtY~wHB zX5*W@ggeWf60M7Dhhe#-#Ve_bQ~j2Y6e=bYVPPZM9`&E$W3j)PsZGI9bs4>b3eB9A zOjF62ipGs%whPr`Zy<^-VjSsS8s1 zkyW$?O$=EmTqEg;lRG%dUkUNZw3x$LX>*yA+>&b&ssaOdjk@W7?%7*^Lz$GN_Aj3m znS26IBY_fZ18_au3yS|^9cHE7v*CQEjP^5wu34qHrG@)U4#R0b=n^8!*t;CsfII?l zAvG7OCdEF?!jJSqu*!+ZZ@8!yj5Qv56-8AtvS7;ymvD zN0>@S1nSz>%CMkh9cXD z48nlzTzvZvzeEX^WwSo25~Kms4OkzChL5MiGiktdhPhv9!+^11e5H^%4Q&NyvZ-{x=&pk{#!G7lMn-Dua8l%WJN(7laHqz^a76e- zhMRDV%GM>TB|U{H=aO_U^6F$bI!qA+r4-nbWXjhRPMu{ z*690_Dhq;G$YMYS{{gX%_YaJ^JP2a3%Li%97BD) z9~GlV;UHpUtta~1(gX$#OBu1KInZw&Ol_FvY;j;dNv=D&pa@+HFtV4cx&+c#L}Az+ zn+Ht>wozIFa<7=Qb_3yU%zJJA{pqj19^bQ4mgW4s3W-!Yjv1Xq6XS&R1G-W$l*Tcm zn0am&+RzC4b$Hp}-IRy%)HU3PX}*jif%=075&P*a6P(nm!d1COES;for5n{S_^yK zEUF2+Zs%pwlpJf&2>{h<27nEsw2%_N8S+s=E@OU~F;|PM_(T-Tb1k;lfq@<19WSEv1+|J=LfAk_Qug<|QC1O@CH9={IPwNjftt!Eh5~?}xj`?YfyV zNfj3YsXcdG@$Jv!YgOo=TBWg5b!nEQF@z^BwG$;2*Wf*a?a@LkNlX)#!}@tr7W=4@*Z-~Drs9wW^ezC;WehCi9yGJdmD&Wav;kDk z#mz?C*dk>gxL0NIrbj#}W`XetFqUZx7b>{TXNc%-lGLTSU#-gta0rGQqXEsc9COEu zKm2xloyvpw)B4)Kqf!t=+Ze+%hgB$$kNgjbKUTxjEw(vn=C!zWH3}H$38|g@FGqr` zB(3CC+FGeeAVN~v6gOmKoYg90DKw4~x04tPBT|Dm)X(sx?^*uS7ZMqjO@G|-{cP!U zr}(m+^=PADD96rU{20BM?Tjb77eJf%!OgSq1FAlR0t>xTCqe-Z9CsBmI+H?Ct(to>3OsG^}+@jlD+{g2PraA z##(tWqlB*kx6rigv%-j==E}vk>$3maO<++e8@KkuSyH1f<9W-o1Im2UtHr~1(Ql7a zpWs3|8Q625jiC>>G^S#+pQN%alqL_Q*Z6ALPzD=nS zzg0KWtSZr!c=l?q zE}eWQRb;x$yf~_^fSr|_Oo#9Vi#?_*%&O32a6lnSOtBNo+stC;y5lR}Ir{V~ZpC*f zrC)aGiVwtPEp>s3<1ypN@;XsR_ExK1>f>OvtVw5ndT@ zcbCeF^oz=>0a6ngt0>lBsGyR<JXWf7=S(#fRl>5>angy+y!c!Mp*Bm^sM3YFV8dlND2?4@> zQRJ7Mp6zUuCVI6dFSVL_wttvr2m-Wxi5hMdtq=a>skuOt6DW9bxt#EX(dGX{xs;7* z*`sn{{Jp%seh5=F1~4(vw-STUQT!MqHTdH;jLJ6LxlHCx=Ds9(MQ$NrVmsqg3cquW z&t9~d?PQi@3@if;-JX(?W_uMmi;fx3GJ-a1}Wqq5Ef$+ zt_1Qk0w0uyWo%QHPAeQNSf$5Pm5Lq4?n#R?tU|!K8<2ynYu)Q*qzvT=ci(>w6Zw^W zO7@uzfER%^d%<50R+rZ&)8S{#GC^FNX9g!Z(dIm}*WvCw%amB&(0WGfwk5Dr)~N0D z=sWj5v0%#~=qAhS*PQYV<#Cl+{=*xq564$2o8CQDQI(-HUop96{aC;m(G~2>5%g=L zzM(DSyAz+*B@?a`h~`OkfC{4i#7U{YvSKMML9Q-~L7q;}vglnb719Bltbr9jk zqbI|ietjX+DAu2t_lEd9Dp6Fk+k(6_$Wzk8Wq8g%4S$ogXxZ_bQ#L~WQMkN(5?bx{ zh(kDplu zWGt~NfkXweutBWS69rVFjQ>=(#3AomP@+D~QVzs=uty*Yg`teCl^~U;i8Ur<} z?ZH=4UH%<^S|H(+4SSzSb$J;cvrJ}+Nx{%w?nB=m)F(30OfT|4G&R#w7U=;aSoKuB z>nmDN`TQS#hNn~>xwjde+J82T2vb5!p~R}U;V{j?dZk!mmP`{t1?ii&+zs2@@?q9N@-)$ zWQAp#Y?NF*`H^UO&=|*3kpLiKAn<1(y3Y(j$t+vVIp4UbGXMc z(TY>UefbEB9A!zc7bTjx=m_*#?OeWW6TIwE*|%aZP!%BDY|i*V7?{s%TzfS(p*Pr%Ewk+m7Ha$7gl~n23^MW6!AYik1YU zvK|4@Jg*bgo~TGwD+q^5usTE7fv7{k(i z50wyn2MZR(FIwYD#S~9~OKyJ7x#(*r$}TMF>zw*~l@V!f=u%^Bf^$nbwJXuw8&hF^j7*lTjh)7KrK71(6E=gA)0qCV@y%$6E;c zGzWzvE|9fmHa9ChRG}s;=O4WH#ie)C!3!Q@cw1RmvPln_ zMd^JF&vYzpt%BGw83s<_vMUcuM8rjAN>>oCqXyHNptO=^!YE3^1rUW}(OerPQ<3W@ zo(PZO=?U7Wfm#a%&Fj!S$6nrHa`%%=a z>bt)4!R1h@G7f&~a222+wIdDO^(1fmAO!Rmq*f8eB_M;ZAJ-EiyO{cZH<!fuHcEvphA8;tXWQ7N|w<7o> zW?MY($AedTIdD31CK+C}Z7CM=R09@_>NX`4n6N@%;wq4f)~%GO1Uq0-t+^X@(IktN z5J78cN+OqRBkp(bW8UyA3aVtf_tcTIEvOIS!Ap582yHC%T+IX=7Yt11+wg)jsIR|U zEFKIi?5<2%SPzDofN&ks!YQBk*Faa2cVVlcCk6!7s^C|mFITFaU%2a|FQlx>F#a=U zTUOif;7;I5&}>%AP@B3Kwz(qoLy|4(pLw znHa#!aF3eJUAIOgjTj`}a5*iw<&Cdq=~CsXC7bV`R8Eh;<(187_aG177{@7wYmjE| zX=`}f2XX5P**B8T5E4YgpDYB?9G=Zl6)F{uPa|YzeTUHdW@a|kY9YE=S?I4bB^8*P zu$%xiOH;d;ATi0kg(-8f&!Z)lbbQz9u_JkV3{nK??mE&TktIeE=O2>Lq-msL~TX1#OZFuASrE_r58}i zldlQ6+&uqBn_rBtS$5vQ)QeOutegW;gJX)u_YM_V5e4Ho+K+QVdcg|S+beE)2X5~| z!G(^&)M{mcfnfInpwm>z_;ajA+SMW<1N3OT0Rw8(Jz|=`9A4bxv`Ww{+I5WE14dXf1+~`P&+zdLO5ndx9KRSlt`t8Jm zlt)Yi8FEujP8G0*Z1+2%4)Qy=BWf&^tGzLISd6o zd411dR;fZd)2I09l{PHydANBsR2udl5rmjYEjEsrN)_3So;e-3B*_q_{3jE}VlGnc zj*%WP9Ap4Iz*0AyMf>$I5|w*yUiEE!p~|yM+;OMMfm{eS0jwR*P*~TDf*qo z+y4cc1SZmHHjW>~M_Q4;e594#iG$9_KUbS0zrXtnU&dE2<-iwaHUkh5lOOkD-wwmA zy{N7|iVdwO%;2!A(KgFcuEb|7iE}5@4pD3>%pq8DnH35}0=W0=QsDat)^nH>Ly?nh z_PvTNDnlA1(r410Ar{HWoC!&w$Kwh>f;8Ijws#-3lbT;zfnlfL5Erh(;9ihi)l-1= zCdSvm=eY5qI~wF6;7yb&*7^rFtXtoX!Mz%{ci9w7NAT{H6F|1($&{!SvQ2~_kOrE= zgB-18NB9A#NUB~DiNK=iZiY$1L@}#Z%$PTgwM;W3G@sjV2bf1kE36AaLpP zWz$S=kSjOwY9*;#5dWod z2+@v)ZQg*Kn>j@ZdYyC16??n5=AOImiIWu9Q%bD)Y84lW9~0N|I?l9qVbPeIutxdw zHbh0Fr`0!%Ik6V_9!FbV$DEgLNfr-=H}m)7GW|LjFBOF&7+tjHU(~QM)?hKF(5$+q0U2c1MrX>jieEI z7PfjknVpD2ziBkAUxka)jb{@b>dX(AVR!kQbYa)MJhG=k(y-OMyds$wRU7a{-8{x& zECO^|W>p^YCGr>yL_+JeC(#%Jj5`ht9=2WVqSHm4llI=lSGf9>(29+#;2q|EJE88{4E^srysqGx=~u9v_{2466lN#ICQd6UD-^> zK9B^Olpoi|@Z&aiASrubBX{O%YW!b{z+pr(azpd`9ZZ|i5;N0fc1HvT0@YYE@D=p^ z4j53k6T}+W)yRL)V>of0+jN)8oOj>-pcLKQgKyeuq3kpa?l_EK>O&Yj*)pq&_y>VH z-XM+|2Ed$NIrOf>_nByHny9S9-Pi+B6a)T(`VzQWaG{$fES=q|EOnFAJ+#Fl6xW{u zW>n(_=;zG|hWNI>Y1=zF_@!)?$JCgr0T(=@=XLGs(gk0D57rtfsRg2eOksw&cZ`i< zW5VdEPLp7kKJ5Dk>5`>`wyF!HXNfNF0|HBMP=C z0p{41X$b4i!&F$*;1zHXS$$Fdc4eCYdni-thQY0(MH3)YwV;}1Mp8(`{Uj$3j88~X zAH+}KYLsP3MGc8Gq~@KA_E#j8#HO=}S{J_sjA$0!1$XIpfADA-+4U4C8{tbpFPK0H|)(;rVqFU-HN-DV+X_{$#1 zc8%{SryPP4OU5{vo+wVp5_57^5j4s@5BUrRlTtqE2v}fp9y&pyAmF;9kst2PP!2X! zlrChbFHNv=UAcMrfggW0R#n-*#9qHy#dshtFJVa%2y~83%sY%3Pz+=4Ll3V_zsJ~h z=3Ly~DSV>96RjwBJ;NTHvOTD0TB@ne0j&uEF{w`K)LBOc z`i}hd1K-(*?^ZT|cIur;9JD^mkt-d7;d9RB%CLWreCK1O_$twndy*RyW1CXX3~!&MP_i)bjp#58ol-ni~G6c z7nNwhyJpzn`hu^=^X6p(GYN2ov_>G4Y-_eom_v|Fx>(f(<}Aqu6XgQ(2YD{JSRhk99t)QR8Yo>T?k+XvYkV=!gtS(tA4QR5X!FPsGF(FRCe^p9US#n zN5O#W3JsFX|EnXKZbMPtj{BAhWEW?us7~df(Qcv4**tWy7DqA?1ZQHIGZ3AbTIdKw zlf|Pg08o-M_zaiBoXRi0cp$CFF(o==Cl<`896p0*Ezz{LM)MgLV#N?@UVRUcQL?Cz zW)@J)y^#mTMrE4jP(bRZ7)2}<(m|Yd#wl< za#f6}kiX)ES`RO@vCEhx6QO7lN@)hHj%iQ98cqynuUN~DtU&>e4A{j(=^XD^h9PQC zj;@{-v+3yoWmAgNa$VW=t><5`jJon${AtB6SE{ZM$syCZM%c{e$ZP6D2^AB`;R3JK z`s`X8vS{G;6{hH-GeSs2rBOrJ%{;8O?WNVb5+6kz!@QIpIWPTXOppg@WAA+K&#!*s znRsMn5B{{S_T#g@+9sabk$QJCR=VJHEr>~KoV>I+4Mdo0G8#&;i7!=q%)Q#!)_u*p zkN?hDT=(rI>)xKNd#FCxsLmglcn#*hqx{?*io9iBt6>1VU2EelzXDHPZAu9`D4+al z-o+6a6qGgna*m0it%Ns~Ux0@p*AR`xuE|Hf|7j0BnwngeSp`^ObSefQcn@$sqqZBYX-&TdBu^xJwuL8 zJ+;K^-k>@|`#2AV3(X4E&h?nJ>Iy^q*rOL}y}ZzdwlG|t=P`y@EXlqY7aiZ8s$!&p zS~SF%Fpy-_dO$rUObTe^6=b-FD4%qLFl<6BWV=ffk%gdX1qpC>x;dSrrEW~?OX5kD zGYc6q0JGmYS6=)Is^+cu(`t5h%%Uh?iRWPff+G?VNf20Dx0Ee$KSY@z=p!HwrLzPr zV#0j$x~6Qq;lb_C#gi(m(rjJcmu7K!@53__G!MQ$^P6Eq=~HcRx$PQ9XmOiP7?4*D zB}tzvkk-A7;#xs%0+e&_>r|fdyh6s9{XOUQpWQb?36+c>o3gp*v`yqnkWYYhTG`~T z^6f?k+bLmPOao70m& zpd)>bSE!Il-R8x(I9-K~d~x-qu1;$wAGMfWC?+cSk9rYlc*6h%1uJA`FLB zE|cs?#$7bVIzP2wSEJG8}mO3?&o+B^7enFD_Hjv4m z6EXLtbKg1o2?}#Xi7>xD>%ye{?nuqY0@B3L$^yI|&^Sv*kI|DQCcTLL5damGRyHG| zau|BN4_aSD2l{VGDrB}>BaFywR?nBM2iZJt4_B$&iS` zWssj#WLo#7c6uRIJm-ex7kyJM|H+?DeKww3IjBUBzN^b-Dy6fI*tdx=7GEH>EYN1L z(Tu~n`Vo6fvkKC&)Z1{o&~eZJU6}Ic2xGiqC}$VEm5w@=;FCh*7J7kbLVv9*@|*JR z1wVlbkB}Qtx>uc;A>VZE&+j3ZS*etWRBAC{=@YAaF#V z_OvP;TqqohlhfO;Lefd56YJnMNHVy@`U?S7M%!*tOEs< zaSW~!m)8Gq{x7)vl5<_AY~(uA)}0Lyq-bK1^I&_UpqP1jcu8L35zHeEw5YE|SkZ@6 z$k5RU0xJ6sH#Z=OKhRq_{RIbo@ZPC|zWK46eD&|a-K$-@;fN96Iq~f-EUYT+3e#mO z5_RDQxGlU=5x8-I!_P}SY2kIRNGX7Syp%7Sop97mUWQP>MYP|;pYqQq;+vK>)!BG; z-8CBkvAP@ejhI{)Q3!VpEk~_qJ!(8h`ugj`(AHiW70%TgTz{G5`H%qt|ry7T0Vwp>VAom{e=Y?3-- zj833+cCwC5f^>0E#25nuGjO4{MlQ6WN;lx%h3c%e2v}kUOM_`HRq{(D>O^?#m0npW zkrBbDWx{?bdM(i{D-Tc(Bj=43O}qXGS88V}fqmD24FJ>yD!Pj&z{(@w34yyo`o_lZ z-G{|go?9Zpo7EuAiUdE2XLi92XGTJUgP=IM{ao9UK4mFyQI%)CFxNH`1?u&WUn6;24mH0Wm2C!f9WYn0hN_|xjnf2uN5BPLqcS>G_w zn+=jyBPM#+YnR&4JUViJwP{-k<*mvD_av(3dAovCwV(zn0s9oaAl*`8tf12^m3Tfk zNpqk2tD~j7{COox^0Q1yFvhoDUCHw@(<2+4x8?5|mu zxc-_45EKQ}s7PwW)`1hyCTZQI*m14X$DlBpth9T`!`n|NMeM8aAcg0D#1T)y0uCr_M3gK7(HjzT~MR18y)-|zITPknYHex z|5WvwaY0>%=P6GZ%kUimRtVg$xp|sTTc3M$^@e-py>oI$jV)0YJ3BO6%zr_$-lwK` z$-_B5#*h3VhH}|#fA@)>eGbG@TG@8H%4T0&?nHxbJx~Bc;j!i>w0WQvuV=8)7D!|{ zY}6>`e#h5M51o_K1G6&GEK-J?bf}SHZqt|i@eVBu zrfI(){`OWGK~UDI_^Vlw4?7ioi{YKZOX-`1moPZwB_db^xL71A1tWw7NzP0+m8~`O z5b7pyLfi7xQ@IH7G}~dWA$zVl{(i!dvLjlj?obKP8+G*}h1wiJ=NBqzCJHEM4H|fR zzzU5{bCQP}n{D{m`BdB@dQqAfw5fk-Eg>>f0~3H6feb7sw#aPIHXB7dVH>DnyeQ8ln_Z z5tB81r)dq9aKk}Dd3jbQRJ0$k9732%h%WSB_T@FRAcR{M3M36EdJLqx!>oomVk{;( zocwnIkfd?kbY;Oax?gt^zGZ1n;-R!%PEmVMU4}D0iX;ta8`_XsQ?9gOFo;ZiTgaPL zrN&E-Y@P%vtYolq*3cFBAPvmbl+yilNL6*}?S*ooyWZ+`?A#8$x81=$E}?gSJt_f?lS zH$v&%I&dfS;m0^dfIn{IWz!yYdT$KA7g)Ajtu6iP1-7!=TQcAtj}T~DaGUFO;(8_6 zbzSmB_aFX=O^mY2DjK#vMc?8hae3j`*nqE=0c?GkZ7Vg5IHaj;#~PlEyE{^|Sdq+t z{xM7szQ@|FVbgrdm3p@p6u`irm2~)Z8DNVVc-lNktXi0+qKjd*{dbSA@5VPN>oVK= zkGgKDEUlk~KK%tpfJlpOX~Kbt=5TG}P#yD(2m0GuK1s;aq>|g%qAZFvveEiEneA}| zMG(LxVLL-TIL6Y|n-Q!#5TWKhgw3|Ft=(%%wKC0blCs=TA~Szy-f{3l;uTmo*SZ&; zmWu~$>sYlAyvh~_v4L*#cB9wL5RNwR!aHhzi*3^2p0%)&9Zz~FX4$x>_q8oeYuIq z?3w^?4^{~#gU&W^B_F{(=D(!C%0hf~y5d@uM9H4$VQaLGz%prnNzr#RC1CN4DVR&} zWrMwE5ebzw)@-$5ag0+IHP)`h7!hQ!*>V&aFdCh8dIO8(;tn?(ZyO`ZT@{OI-#}=)-tpp> zNORlWSVZeyJStPY87hLes_#KOZK>gFQv}$coUTpCD!dAg>4Zg`z*tHQQGuy;$K`fR z@Qhm?Wk7&s(!rJ|ymaSfoMBN0yS5&!YdsK`7a{pGfH5D{`D69hz|y#DV)|p9U8}9t zYi+2>J8}EU0!#0D@8zK(iInC zLYuRsctlwUzoU0Z835=tc(km0Q};$7PNmsm5IwMKitxhWBe6E51NIcyN<83vlkHQz8hU)+x9>AF-PFbSJ(mBx_@kJ-mFNBgMhlChR?!T5BnNQ3MDtrt?>_-g${@JK;c=miDaE;YW?S0%Gqc6|XVvT!8t9oyF2pm> zJNgUcmdnnE*?PRH9f!p&Lf}E`4F-kvMrm%Ws9qhX{q+qs8q*x`@8Kc|gihwuu$Ck+ z$jWvjv7T%^1p;bOs$ClQW(TjKMT4CKpsYyT=X|X;;^2oCSy7O1aJHLW2-n>5@Eh*^ z?}YHY{|`dwM%pHjFaeEzZ>15ro#3gw*G65tflTizfdQBLdKDaEX^~OEI;Rbd{R`OX zhR%i1fA8gc4yF+1mu#o!&$19mbgoX6k?pDQwBSmm52;8nT1m6JZbLgkkX2o^>;hYu za;GjT!Hp?_w50_QZh%EtmFCeWgP$U2(V<8IOCr~$xarA*@1OuH58+R%Q95y!rML;t z?Dl59Y!77>jM! zD4X`R^(DIe{c)LR@K$kPNTD@}hws*KqD(tY6ST!rRHiYOEZUiLt%d=c;1e8T>Rh;W zHL%*xDY@3n11eU|V{Xj{AdE0%7f6p6(vH$I@vsTK3Pm^&Mtk#?;d(N zh4&97JMg6{yaPmdfI^@Q8&QXUIDYDL3CCav8b@IoPah|NwG+V;#dr7{%^Kn&X4Cb% zRiP>gH8U?KZyfLlB`kqgGCaamqzZjC#ul=`Dr;WJ9jQ0jxo}QA_(JZfN=b+IRvX;N z(UptfOS?zXv`z-~g98&a@);w2Z6-pb_47Z zW|{@;61l$6wZV&ZACd4|)Ew_$UuP{^WX(wU;pj*F zn008=InT z1%mR`FF4@D>pp-lQyPyi)zuRgpUMqU2j4P=>EU@GF(?-}>XnCIPQMKAvy{Llt*(`Y zo1p-DM`;Dlom>+j4~B$f{R#;rBwQermF3V}lif)QU?n{Pd?nVz?}FrBV&gE82J!TJ z7M7%b1_Eq#g6ikw>p8k`!CmvEJEfDftgd70G8G)D!&3o($B=UBZjMI)Ms93Se_k8M z&)X2&6}Yw2$!-5mc_hXHCZq(4@vC7P8X;(rwfQ^rk&)bHOHv^xtc=$V71|iAq+hAk z%>TtJ@%QM0nzQ5bZt~le7nb;`l`1Hv98Yba#$~UDbuq}i^8eDZP92jJkLOLbs=zHN zd@gsL(Cx4ro^KNOY}qsAXoCl|6oa$SSyIHUY{tWhrn1Lw2{~MuGozT#5n{OTw8G(q^w9 z6afn9HL&N@eRxDJF$wQa+5gmtec|)>tk{M}l&;FAb;{0}`BiCIYQhZSATk?3n}XiZ zy?Qtd9orm1@sw_-UCo!jXw9B$xGEk^*7~kao3(d!9iF&?5t;>hIk+OxLX9;_fxDj^ zW{;jpEo{L>Oxbm8rq`q9u6 z=!44?J)1~+>TIY4&JNKWqDTD>p&YsbY;xf=tKw;_HdSK?S(uM<(Ascc)j7Yt;p$tc z5+w)KZMA`-q%ozu9ky>CM#T3H6=_VVZ-@0mhE1-u;VRyZkDjk2hX?-NFqIr&LRGpP zt;}wzV|SEp+?#69%1$ z;M4}@YwbOa>W84mZnUg@sa z70xMvpDB+6c3<;JBjb1e8ILbD6)&H~HDAj$vxLN)Uh->dxM3caA_ayb9H_fw1l6kO z_Q>fF01Q8zD20IR1CfFpEI2FgbL~l3-drMa7CsaNK0<16lWtO5$H$0=cH!Ojjt7pF zV*jH`?5qt26@_8rH3Hv~V`ybOIEvk-e+;d|_RAr_rNtAcR5qHAhT9XYDE}9;8mn5z zN0pH|FG&torY{gR0}j?;jZZ7aY##gSDbK((Io+wzwiRx>u&O_Q(n5BdRep&-t-EWj zY8oxjVw{)*vyT4&v}6;(N!K>k_n`}^26#NZ1HN2Vufn}uGUG?ECF>P@>IpKd*=x`L zo~S!bLmJN}t&;Lt1pK0!zQj5ApY#DXG*uRr=tG|_k??Zy07#dW^>NG>!dN1YU8QerL;Wj0wnE^1sT~46X$QnTf8VcKy@HF`#R{Sa8!f#-- zopsyEuV?1PeXW>dI`{tbdpAJNglcVvvXg7B~>0%BFX+)mE;9@>Iy6H z9%lPQg%wFIqr|QW=^%206@&18P-%kGvw<19^P@{P5S{oaRVWJvK zZ$R-a!jjp1W(DaGTLS|7G|5L6srer+6lxSJHEn=?pz_$Un>KOy4%qd<>#w9mC@Z4g zIa8-Ib$Ah;F(=Jui{!t=}H?f%N;uN667>DWK}JbD&m6#BA`;n zmA*%459H&$ElS2nx#9!}%w!|$%!znp9-BP>PJ*aW6cl673_h8Ys06$dH{%u2@aZcR zHI-Qj)?tvcCN8*Zety97nEfi79kTTes(Q>8Eos1c7P3YEh@V2W(M}D6j-#%72HOd< z-iNz8kc=iBuWrnTe>hd3JOl?12QwM5B(kksDdQ3;ctGNs3-`C+uFe0O#p2k|NPR$1 z9?WO>8lR%Ci;s2zo%7(npO@0UlJ3T>=ggjfSkpD%s6TN{f^aP!vjBn2q*@@c;+l0{ z%qkqKdGs1HfdaD2Sh&X0aHV4uMM@-_AgVh^DOFpb;|#c|gZ;{UiN>@^XC7XhE5RMj*Y)7o* zLh+n@T9_kdaTvmNL=0+1hf#*eIx7$HHE%xXy&HayhnG6QH_o1>d>)VN@;Z!!Yh*`= zsn)pyc}o$PtBCPol055?MW6~YQW1%Kh6dc#)m~x&JC~iw2{s#MJk@TC0}xI$6)l+; zm3mr0cNg96C$B$)p=f16Nr-X2ijLH;s>`bNV;Fzo*pf*TRTdQK;^%Fs%GYr#seTZA zAmP2DAqAwmJqiH_Y^$EJ8J@|gQa4|@1TuMMQNNWcDZ8Jx4$Pb%Wtt;eup~Uc2fNnj z+B|mihq@d$@7j4bA$oKsqGPzsNOcwBl}KrGmyu8<58US5!q-zY&<6oQc;)7+Iw zBa+4QxZa2v_t?c0zCwPfVwD^!S031q3Ds_*MXei`50YPX8wmiznc1uCNDH&824GC0 zil$v^fdRLDVrBK26j?`!$o_Q}MaGb(Tjp;R19s?;6x|t!1q_BL;%m!Ri&EVQSe$HT zpw=_uXRy`a5hcpkbZ4F-OuQMZ)1;S1EQyjz@wTK9-IM4vXooExlaF&5iYwS6ejp4fFQ^U(*{lRcH>^1Jl; z=XRb3(N#EyycOnrK;?H3E-#rJL;7NKv7t zz&G~tD*`Gf7_qsc_=ZB#t?adNke>w)*nv=+;<7VRs9I!zG0ri@A-b*fqm)#xcy1`M zIa8Z0K+lF2W>}?2!0Wg73gruohm>AEsJ&8He$Kty}}P zn!^ynt7Uo?BG~x3%cZr06Ng&2!L`|oZA?s#!Q?WM3NKDs)CX`pT&)k#rM=Md6S%iS zi7OA)fs#3e$+LD2C{-e@+40pLB_`tw@R{5@fw|l5!qybP7nserfSH79Pq;hd z21UU@Rw6mUF?#e-c3s>~L~y~0^?zgMh;TUzON92tSr!^o0v(nncUC=TV~ShMz^{~Y zXd2Cfu4t!gNy%B^u?j!9M$)rn3Ve&T+@w{yzzqPV$bgX((`s*T8HP7oWMGnj$)zi!D?~LFo5Yqn`4Hr#NGKMn|RCKKhD<5q;CAu zn7}oGt*J^us!%Xw?5Ju7^EqzsY+fovqP!9Ak{Sn3Kc#S2`4i>i5P`N}8pF_l&S?_q#@W|A_BWit}#N z9k(woub5l|rr8%Ro()YFBRpFg#~8P>@~iP_U2xdesVT1&VStv(#>-dINTO>s$)H6t z;4d*+Vt#}xCatPyfhAJz^O^Rs1Y#&1I~UcNws45dlnIq9X%sj=bnExzLD;2R1Un!!F=_^jv+6RppwGV-% z4!&1l{TT~lhgsITIQ26=rC`SG!)UIs?Nat0{E76L`Ib5J=DP+@#y6`xyF?h@O4w+I zg+breMH`}|SLUe&1tK;QnkXRv*MuDEIlzpJkVKz`ip|+4J}8t)TC759297jrhX^Ba zR&cs5u4~3Wb?9d)u7gX&_3c>`7YBDarpsZoy`5T4p0uLNMmd{;~K{&kGBC7uf@HoaTVcKxQtBu z)0)84yS&JwY9d~wRCnNnUtx46Q7HAmENny`*q>Uc;nrAuJ-3q6*ojyY84+2-V-K+E zvrumA!rQg;;?w#lycd*gtRJZGh_qLl@JgznU3~3VL4OJ#Od?vai-J0FU50wd)TBM4 zL||%l>VfkllO-bXoN5jV@>FwHrRjV5XrFc$K`$aaIrUH@w7fYq7q?4p_kJBm{f3fz zX^G@)u>NCJa)T%z>7Kyp3hvEVuYf+s8sN|%;+FOt+I6@&cjq$aQl*zrA1aK9(gLbU z2@7Fg4$2*LTVR4zho5Hdy{(1`@?8r>8t)n4p^|>4gH=mlJEO!@-es_Ej;<5ra`9by z|LwKIu#&Ptkz0SHibtwZ=Qiz4$dXtmin<{$@3vlAT4JkzgH#!Lo7>AxQmb zEs-ditXT6(p;o^Bs6DknO(PUZpipYM-+Yg;LwB_iFp!}b1mCj}=tZ6roDsSTdczr1 zuYUZsf5lQt+kkACzJN@|Zi5(T1TYlTtIBVrhFR&DMA+Uq$+PfG5A0#X3u9vRWv9(K zPkZ|{xYGQ+2*dp5Vish9XA>OlE+eyGj-gy!pxL=H~hC*Sxc2Y(!U}Q*drlT(!&!4c(T+ ze?9Kdk3%35XC4cY7Z^&FC-fo97MW9pIxX?)2>ss;)@)VeQt~B-N|QpRo3!sU%5(2%*M9xS037erOb3RNjtis2ld$ zptIw8*N>eKo9Yq1>wpsd_{}VdgFMD^A$lSlz*|?qR(xv-hG2#D0^&!eLN-Yqh?a6^!GdyG`2Lp1^nFlN@0jF)Di5!KN2p|o&p{!Q$QqoH36F(xYu7FPgZTwKI zG&a2^fOLbpFs}H+wma#7OJV%|nYv6!r}5tE!WasLkE8u)&+di&2TW@R)ULzrq2w7T z;%mi5$nxG=bmLX0o>($IFr&&qnkTm{C=ZTDe6Fu~$7OGPDLZB>tT}D90>9Ta)5)%? zPa?}xU4T`2;72DrAwRD5gM z8u1qE_O1BK@U~7L_aV3_C=gw6+Q(4X=nJmwc_F@D<%kk_{4v`QD0jz(Sk>Pgt`~Sc zbiUz2O()c~A(Ic`nM@c(Ss;9I7QczfvJ(t^no3sBcGJ(^J9H{#Q^uw|INP$}6d!Rr867OkWtPb) zvN&TPRaI3zIKh9}%ArxK{e$R3a+^ihTL88SR{@?slIBw!%<_EGLHc$|gj)Ag;8r2?;7e z|HgLFC|DPiQ?pUU29k}vfmu-&WX;Cy_>I8%uB^!9rUO2LwNkxg8dUQR3h%(#Skf$h zQJO3~O3PEnDu0Q&T$0B;cH%oc6SK5!@~Vlagz#V{K_)%|%sp32f2U9s{Dn!NGjXT%o-DdYKNWOTG2PNMk~D^U{# zb;|!`Q9er%0Ztt`sB?5(3Q6pFQrGGKNlCDYv;{m}@<^2gvoVSisyK8f&2HfyvoW?f zb*Iq|YtEs1i*1TM9UWLSP`^ywX{C}f3(V=cAh4G#bs#UCze*KBu9v0x><`Gmr4~OM zAK}2691k~j++f?5ALYMO=(Cj423MKNOPdcYry(ktC3eYUR8R*|P>9B{4XUT06nSEN zO-6GPTFd04CUW+`n;X`xZ^taLFnYB{nux5zLTG6YwV+D(sIXI-PJ*B_gMsNn!jEgQ zq6l0F9>#Gxe1*={dJ~LKhAm>c0%FcI3xAjNGwUIgBsE)f&Sj6if?2(?@d}qbPGuyJ zY7!Zcl3`+mR61dycK{PS>V0iNDyEf{)c_|Y%vDw$QOLxl-6IAI)&|mm=~;>|Mef1N zbbYr7SsD&MfdI1W$;=cUk-5__TDq}Q=`U{Z>J8VjZAb5X!97?<*?CBpJbtz%_^){I z5@YXD2`{!sN<)(FX2|ZMaTkyn0;r6Y5X(!jI7kYdqNjlDB%NcS3qZX`hSPYD?qL_t z@^4>%%8Mx;R*$t>tAl1+JZIsdSR2^h%;*ke{rX<+D;^M9rHII20o99VMnEbs|D;EV zgJ7kxr!k8v_%7l|yAz?3?W}9Ae)wNlR8u*$#7sX)7d{7VO%Xv`0>~8 zVwF;<_da-5*G!bWOwP>lY^7I$SjnvrJdR}*h-Dr+vyX_k%oDraRi7p?Dv=U4$x^}> z4P|JcWB+N8yp$~pbmRCa#XD-Tlc4sy=b9UDp`c1et6lQ<$#AH0fc$5s5=Ai{PSAI& zdZ5LG4gI**hJu`j+gDgRO0(AvSRLNT*VjwM099O>Fsvzh5Zq&wB0U#9KTA$QPh@sP zVt#J57Jg{k!|xfDh@qs(_7XdDkCgK20TkIzjx+6zLo_FgxDT%glrp^RWN$mRIq^e$qm}2E7~?}#nTVOsK>Ch|d2(Gd$_7X{_cexx>$Q#jjiGv5 zgfp8-JyqwWl(dKpv;)CmtzZQi>#z#U(SHiOEEq3rF-B-<)`OQ4WLs1qy4v! zDHpRb8K>mDV}Sp(VkjE0pjze3vxRD*)CQ;;9!Z?JSSmf|(ieO4tJfXz5Eol5(UIel zWj=La7>DTLNZ(V?TN>tu-e}OS)cSa38ph@~Q~OLbHceFCjhj1yCrfEJIwOujhrJ-= zcOuR6oWh|3j!1*7tVmNDUVfQ_K1@XPGRzfBl?vd&&dh`hGYuvv(41iGtoXFD>nE4q zNBNW?x#LwnB<*M9yyM?&Q^~vrA84AcjIkuB%#f-DC_;K+0L?2G;Jv-^{Abt?APA*Z zn|FW^p9p6KI z%DI>tC`ahIEL^QiECcplww$wma3N+=q&nMw-;5@4O(c_C2q&F&%g4#VmqyeJR9nb8 z%y$BK8FtnasjrrEJLsgSSJ0mzC2+|^B0|{J&%L1vr@d9TZ$~AFijA4&#Nah z`j7;NGLG_#`fMVe3>~|Yx&*7YJ>`@Ou!zcjC2G{I5~Q>47@pkg>^38z zeP8D_OGe%-sjGWS*138XcZ{!>T>%S8KNa;dVGE_U#s0;@JsOPW58VREPG@MR!wustCE?RnFGgM zVsFO-S7ueJwmFbE!?*;#&}tWI9kl<_$4x3(WLaIwv}Io4ELQ4fqT)iU9@GKUI71o3 z1yvGG)fwwndH?G^Nf25oDQmtY8_2E`HU_Jwj-XB;+QkUsb;QPCZBVXE1AyGytvd8C zxS1Je15{bCn@AMUNmd1J5Y}o*>urR&VjBlE0VbG&@o*W^@UnWT8`|I ziZVctk5qw8MjfTtW*fxm6;F&m+%BJR(3?(?1V9;S_gYmqvfC$XH%j&7v1W6yz$aLr zN^Ol?`M;SW6V`ne0$hiW?T(qmOk5-nqcoCuGkBQzrPwXV&ZDr-iYSCd(kwR7-2dV2 z%>(2rtF-YF1Ojf1prW`Gi+~Hrh>mfEPSPP;XD0-guTn`@(w%g7wbdPxj;N^UAS&WQ zr=y@SE}(!!+)z=2YsMKzqNs7y5l8(dE-0=FM?W53`3 zC9I@UGG6*}8gfLUJwwkYe+J zR$}F`Z9i*hNBj>3NHXL|#fJbgBrdv-1TnVA-#yk#k>WBCOIC~Ej!uF&; z@QF1pwfzTu=JXzVxsvVnmtU-EN4Q``6$HXYG*>cvvXTnIVB@cLSDMQG{!W$Ghj43N zTD3Zg_6B$uPs~;ZF}EkQvEfWU>r{Wd&v({G&vH77!IpA5H*WB-!7X z1m(rJxGsG1XZp#rl$LKVO~KK31^@52RGYy5V4U9-_)Tc843~=4WpG+MriG8dGBmt< zrVP(k=afOiL~5}a;0Qd=zl(w&RLMs%ak!;!`OqGOctPUYz-zd8PT7CR(M(cGb5I+L zOKn=-#C(%#`yh+s@wrcil~e`easS5t--3+R;2YHGN7&3(8NpBLao(K<*VKlL1co~j z75W>&5KvRC)YsYfkQtv@gM;GDR^`t<-=@$$YNM-;=D#j~rRF89flbc(NPZmORi~gC!6Dts~Zb`S(*l%`RE6L{ptHE02T|*3biD7(<(I@

      q&wzVO&L_}cWxSMf=dZJWgh$X}Z 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∋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

      ~soQl< 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

      >} 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

      ~-wn6I}ZuGR1cY%qwSE#~vlTH>3(J#c%3VFY1# zcG?1|k#I5MCp{zeP62GA?8lbJVD+M;#{#1A9qwGjjpC&kg)8wG?<8doF0RGrKkXNc z2$hlKcU4@ZG?sQjE@O-5X;U#IQe@F4sk}XYbg}RPn0GI0sKqkvtTa z=aE@9@t^otj-bD% z0wDLfbdnH}x#ZTMv5SkMMI4jzg;Qj?PQYS z<^3CCjEo#oRipjm9cGCO>WemgRp0+|?{Z1$ufPVT#3*uF53s*wxR5L_5|4^=3y zzrO(wRK*G$JVoVk6fUC>IUXz%q4rMj9T+0F0~M4xkxah&&*NTiO5iH-c)~Hc&v5#J zy;IAJve9+%uS-#p%n>O@f^0+O1}R{dgfUt#vbK5zku2#mH9|9hZ2U|}4}1$7l59U{ zN^b?(x%jSr_V&lp)i$-`rz0rbV~_*8qRf}lgxd9DInf=T z_~&1Kk3y{&6?D+%X3|FIx!m9a{jdmBj&V13RyjL{X1He~t%Zj%EfWW&DU;R~>>~2P zJhBN}m&HNNj+H(PMZ*t><*tQ_qqldgMm&@HxJ>gXh zbd7J~Ul|eok;>)axTF?}S%T=N#c*YeZ%>IQ+f=kDBiB*E((5%ctc~~z0XmWhc;7?r zhy)F3!}95csZ$;z#qel4-f!$n+;i8n54;cG-}r+HC-f9uBB6h88w`CH^N1jzw5i$? zqG8PH9Rhm6;evG_FZT-ei0g5KW-op+bO0DZ#JSVS|67BWyBgMw=pOXEy=d2t9!5?Y z+}>rP4ry@fmx$AyPBARFc+R-$Q-kNwGQN#}Wes?CE*=au8*PFILP4d_bAuhFlnxvt zuhe+!ZT#X^8Jl8Br`&=lM5K^G!+On`twX!Z)-YHQ&9 zC>}QMxbhsk^*%rUGzD{Nh4R>NK2;u&f1PG;`-0(t%s;B~@Des(>!ljXb2Wa~X%dSX z?$bp^{?zJUqy*a(rYXx5GiEm6aUNc^dS@z;RdE%4WYsri=+o481>XitZn<&yzjP?3 zhg67ZrRvW-)qos~T!vrUK$R9pCtMK$up12XP5>;t&uk6Oz`1qgE(Qt*ass95Eo`j< z>d+Qg=dcNGFkC4+l!(99u>+RqbE8gu_sM%-Ba~&uj?9Cr7DO0q#_JW5L6|~O0%ze} zB5)s(W8%jUpp`yByPpW}3^vCPg@AM;dnQ zkIuBQL(Nt z-Bv*5Mm=e{N{Z8X?Zr<#2T#|i=%PNjNiAvK#qm-6-r2T&9{ceeDDBaWQW&JA-*ORvhq)uO)9B{EBv zQx40BZi@u_Phlu( z?CYpW9fiv)x@eKeb!SBOR>A*_V^>2his$Y4y55+dC@tk?Fp+DKfj5`YHwt2x2`y&? zOo21OE?!6`QSMB?AmfY!ao>g3S(p(c8L)UXoCWjD*qYQu+h|=Z`vw>P1IrSXmERpI zmPI0#>1N+>xMg~o?U)5V)ZRTZw~ZbSCtr;_H+QG8ka)hd40npiqf8p2Ccp&X#HAlN zr$4Q9=-vhgz4(?hawD)-ZdQ{oaO9=wtgwhKfHRj|^qF7cnW{Rc5AIw50bGpV>hqT0 zgwd?KInOpUrxXSl5IKPV1P zgmq#gc^{s~Ze(WOm84Y}&9FqKQXTej59!8m8%x_P_5`pjx$JKm`gV%0%Nj?hI!6Dke25tNILRSPaduA7WQDU21eEG|gI;=bmBE5_7 z@RG|<;;{`4j(IExE*o9P?%!2l5P_cyy`Aj!+9{vUc_W(p>FaRoGMmq(c#O$C%nxdm zjnU_alD{XZktz$LRii*tB4)wc$qa_RB_j!`dzRb|U~M?t+<3w7s}CSe5Er7HLg0^OeHl0SxCGOm(DHk+4_1Zc09R4muwoGc>2zc9mLUkT56C; z0;Tm5Yk8f?={iN74?#vNkz<7<#3zO4$P|dF8ZPok$Y!)x(m1qMOc?AzpW@A|&S9W< zHvvQD&La!7zJ!tit43wE=n}i>$6xsD20VD9N@5pg4s4+$wk*qAy`4`ocuK)`1u39u zo~@k$RDe|MHbIGvCc1@w9|2TYdbEEqv(f)+AB*x}+#-jTx*+2|OMcju&4xlWONUhZg z888TH3O^S6vwfbyc9=W@l8S1YbTvtF;IN))hbRBOWkcpcIE;;XG5emh==zoP+!eEx z4!%+)L4I;ocWAu1ba-m0JK=$k_*xI=l#go!y;ZogS7u*Wf@x#g_==75NhbKueEd`h7c}Y1m%8V=%U75 zhw!wGjTN!yb-8dbgAJRHJJF>7Slop1L2{PCB-YwF4RbdKnP}9($NTUt7NT|chUQJ6 zNJDa2kafZ;vec~C#uz)eO6*)rW2!>O@@kMk$RZ!8Z@_Jgg%3t-G%etTIBQ`{3Vl{a z`x@8l620uY)6RY{)vc;<_6C*cgK&8jzGc&R+TTece`I)?eY_a%JjVm3-On z;1he9cUNsfJb3BC>mF(F&2j{J+fG)L?9o@~e%F|we2_Q$T7>$84|J;ENFwXk zhC&ICEyF7nM|l$vx@eNB8)3PD%!-$+yd>f;KpP~ihJW=l+b^A@2rGuk9K3AdMaVLw z)^_srBZ`Sk&z0SgtR0?A9a0>m(6qr1R2XQFWrcE!74-vG6F7U8s|=&govC>@)Xp&vV~($2HpPalWu!t`P@V zmdrYd9E-43LBO;s0hv;dV-T1iq_Y(YcG3}9UXqYo&N=g^NGRS_B9q5@QSfgYL_?NsYfc!BPjA$(XvSfole#SuLL z90(nC6M_S6O?)%LfYmg1jX15Mq+}KZ96_@0955kPFVglyf&A?VSam7fGQHu_6Y*eG z^HmOBu>exI3BR@0`7ZB#O6VBQ!n01cBvUqc)97-^_A2G3=r1?iQjY{SW}snA>hLVp z@REq|+A@9Ge~%U1#FXR_P;Jyjw&b&KJz*C`_OJL?rbgbXB2$1pHMFbE*1gCy6kzjX zw(ZU3U^Wkc=i#?{yc;i#HPM7!8A%EHh)C?iw0sl(o>I*EtrVUY%oBkt>Rrue-1t(q zm^O~7FbbPzI0Hz9RivJsVmerJV=>_6QdyMl$afvuH!9=hK# zLpe;+v=Q7w&rK^%x<+1eRiDRI`kL9QJa5BI{8e9%FAWQE{gwbygn%3q~NqQ1A3M;Ko9}UhUy%8q=X?rIr9_fBJf!%$~K;P+;7o0v1B5#aVq*c`GyiOgEB@bi;$jcU1@>BAn(aZ03UQMN^C;CyDBg zU(^(1o0#z3-WZ}W$tupwA4`cPwcFjx;y-`UR_-fqoK+#lcP*e8KZD;~ItnIS&rcS8 z;v4tSEwDMy%Lwc=zfGY?w$&p+@y-O>lM(KDy^N9u-?|ILtaK|f-v!3ue|sbpv~8KA zPy{Sk2KQFn6@Em?wQ=feMoz_2D!H@2SU~x)?_;BnP;jBaL}*~LTf$QgqDB{xwLJ2Z ztkx|0g3pu-0GiUlkE){u=WULTP9d7Al~dF2V?9@Vr>ZGXs6QFzM4I8A|K9g(xt0>E z8f)>MB(c@Z+}Z&CIB(Pxe>MegMgjiVW0%~VulC}Zkk zxk_%cRA;z7R_pq8%oTi}7_f*i4gEaygs-0>8xT&bu)p`KG{_{b2CSasK*H`++YvRH z#1Z|xHHFV>pu-R2R(O3F+%Wt&ke-}IN8(y#;dv@$l$^8zZAHt7`*QS%xfz-++`Ojv z>ugi2OHKNY@J-4lNKmjwe)X4#tBDS`&1#Z7T9)Rj(|FVH+vuwr-^IVO&%Z7cR%dhy z%>EH&q7nJLcA01=eocX1qMR*}Vo<^?HGxD{Vx()KtIuj|W>^X+s1?T8LLqF&7~-dr zB)-(Q zzHgswduRWex%YRclG(G*+27jhTkF66>+vB>#d)mrnC$5i<8TF#=IxAl*PO8iSMt>I z{9T?{b6AMC){f#FHr*dtPyk0ohm@1OVcu1lw4g{^#&mZjyY3>HI_HQRUr3RZ7313= zSXRWIIXZ!K7mBLS!0^+^hbfV!R~o~-Qo+o;86Vp#OtP94*%!>+cnC=fhb0Vd29} zyoP7M_ivw`j$xI&3sr*6Mu)$xAc)uEMgUweW46zYLiA0ddZIx|zRw^R4v+$dL%v5Q z2a5EgMeh7|r4iu^M>OQcGTBoQzZ54zHCraTsBsPLRV<*7g!;*rZN=GEZ0vNLe#R-xDfg zc2|pk6TJ4^Yow%o2ieMBD(Q zqM35KXh$BfqZ#Uh8fGD9xF}Y=a%^`pcqW zaQa#RjfJ!js}bO#Mq6ZXhLB+#tKyc3c-MN%L_l&)?J0j_n!)u=p$!78hxlP`K?aV7 z_x*ptjoB zPc23$MOc-LV#d;d5|kN-n0Bk6EkTho5fQeIxT=Sl%>@z&Y*h>5Nwv15fCM#w;&XklqCD?Gd%ecuq+I zTCl<}D8&i%_wv`7t?e(E9A74K2TCVtdfGV*^Hrx`ddhRo;d*~rvfh7L!1Z!$RS&z( z{W;}zSkP}dk*I`YemA2AEH-p5B@6P%8Y{~{RY>Hypc~aPf74fess9%{@epO_7~FaL z0)sFFmV2MH2%+wGFP&;%`K$x0N~x#VCqv}#488(C(aT*od5 z($CRswuzu*(Ukp$ubg<}dw-Wu?o^=&bZL<^*of|<$O_PMu+@mRdS-N9V~-uXU5ZJf_4y+?{DY&ZKApNB6Z+f9m9r*f_n=nBav9HtwzXPJhqxe&n@i zZ&c9^5a-CWA3{om7naejlBeGgoZ z+t)GF_x!2K#>rAOY6O_s&J`)8wy;#8Uxvqs`*nM~4f zAeg1Jk2C@(X7lgpzh|0f0hIO$Wy90gLVwWmFkNRcS2oi@L}=GQmdLdV>h%_Uv-UcX zFLtUi+tXU)z!(>JQ-Ou{C4|sT_)sV#^n<%j9gqn1pk0CC%~E;%q_0h@NUaKIMoA}Z2CGuqAWu3NX5d*dlQ8_istOxC@ z4NOt-BWa7=r3)%##)k|aqwO^SkHG`d`=AjgYvbAL8nQo*NtC?o4> zjQU|(JfDVz^N{1@fQ>Zas4obbwj8!hdqjMX=5)Be0m|7Wu;|Cn`P*OPQA%Uv`xjIK z*Wg>1>nsfEnoDQ}k74d z_S0)b^S{7P_hSEj!4}H`gXM`MvS=M97ArOH4$ELA;bKBIAxc7@tM_VpMPgKrYV|7> zL5qsqx=OlV#f5x_t-Ah`&Q2LK@UxOtKd@k{CdHSn+CiFFSpNrtFG)DLrZPCisEH{o zUahVCHBn4f;mKPFdMueL$xlo7`I7JZ;V*h#f$uLnCi2c->yp_bw{Cnq#?aRBZ;sk+ zr;F!~Kc`u7EUVYgZR$Tige!929Z!!r@k3`~=*cPUk&)0y)Rcaw@;oe?Y zJz_GF&d5JV2OJgO<{L%FL>A%0yNOv0PwAQil`!m)6Di>ZMxOuZb4V|jwcgIvbb0iH z>wrUbR#LB?=wUu4Jn48LA!0=w||f=|DW-dtmXhk%155S!zGUPuClsd&r@G!(!#M z7tc~5Fhm)A4r}I5%t9tIQN>aZZ8hHnh=Ys-v=%Q~8N;~EPVA;cXpV!zukxDr;MPsnmIpH?Atl|qwtGePRyL#9 zuQsNzf$Eib42C-bIygG@f6*)gfQVyT`~6F z{{9zn*Vq2wV7xtdv`UIDzaOWZHD~Kf+vCWzxWwr4M|WUnbQs)K5!heg&NW%{A|Y~~ zxW&tqmJey`wD1XjfSAWN&8kUk`I%_;6mG+e094;PNH$t6Jbx3S$+n?$0IF23lrEbq ze*WOI{{s(NHg#{#rqv&X%jiTx?blF!U~pt&bSOw3<_(Z7;HAd2UaEkgufW{{3^}47 zKXn6XV8SXrC3X~DM+kf}S>Fi|V7GYb#y%!bh88q*0pt-3*_G3CdBI|I)=Y za{oOWZ^YBq?!ZsCZFzF0LTw~Z#_G$!JhWnr4BZGuS2r;49lhw)s4&(TcwnMJPCupWefWEE^4l>$Th09>cP|9p*ph>jv_7SE-s~5Z+h{2`%U30(w zw?#1KZ4MdMLb_Wlv9kptYGKMXu*NK1TR}F-X{YimMZIdV#9p&}Z9F5N zbnB}FM_Yt*WIc~Oa}5Pm!t2c0{B`2l0aW&)_j%bkbCf|!Q{g)8&MfO*M1dl zJ&SWmoqHDJr!dm7qL~TLoR_mKiWRB ziFT%>@Of59>b1t^)@Fv!fX z*;167M)8Z*iFGCEQBuMZ6tpW!B}#mNq1{|Hb+0YPBYFjGA4rw_5>gnf zaxvcar#BsOE|yf*t~mEx72~6Ed0=D|4E^N6JU+em7`}J5fdMhH2S@zHRqh)fY81JBu5 z3J`3nAEd`Ln!HLE;o^^-Jj;P8wTG5i{L@v0+>0BfueiQ+``{Q(EO!7+W%Q0?y;1=o zayLSNQQu938v`x8cpl|k?4!w?gNFlM`_s3y3tmMb1S4D`p@KD#2q`NT&}Fds`oHKoC zms=h+l*}rxEsjuFY-yY9lnh!T9GD=1nU-ZG&2pLC^1fOR(^R$RmFPvU%7k&1$prH$ zvXTGXRwk4QxllnXK7o6?kdRVP?nNTNRH_9^W36LizxB1}tSS_O_9V$j(-r>jROM%l zAn|!#F-mb2R8ul3g|Nn@w)dW2K4&#|6DKfsGt8}AC@FpfU)Z0@1w@f#^O*uA z4pTBTS>jC47G#|MB2Sayf_Gmb{7HE?Q0BxF${Jt-2lB6yY!v%sR?Jk=^G^Ob^o6c+ zckJAL`q@;u@8G9f<<_dONF||69YhL&c@jtfNg8KrxDV1liLA2!J!Ih0I7m~7$dG?!dBm3 zZlFP4NKcP$lC?sNSvCkB2OuW0@mQA8T+CRzjt8WX4anN44P3s$!PJY2aX*T0~dP51qfU2ho-FD|I z;lK2~u(nNdaAI0C7Z)2y_(b0UmwoS~l`^pF(Iq?JoCV(jZ^Q!EjH0m&6?1SEK_P2m z#XyH6-Lwhd8DLkF0Z`yC4J?u{fpVn!baOWhCsak^wRX4z zFm6^eT3<1aLq$^YIGwK=Q5Z^2*Ep`gfzAPp;>b$G0g zZ!_(@loT6#E8;-R3P5mpmQ=KPO?ghqC~Sew;ItN*M6R9~J0xnDpi*HBEj1;7NlzPL zCIG$E8uLaIr+Jf8-?8`iUP5oeQ9j+~VIu9NjUyQ1g9D=L1F%$`G?k2iU1uO6aXHn& zF%a`YC3ih!rnPgX_IJ2D9$)jaP$NwqKn`jWT##OgBdq6ZmyE=qwayf}T!DLe@o zdL(taI~A5?QnxPwj|v5p@i>8Zsab*xofcHt*~S*A;Hq}niH)<~jWv`VLq2DNl4)EI z!Fc-Pf2tzmelrbItfg|&5-!FvK)h3<$V;KI)dFHg5J^ikBJi+C#c7C+I72s@sVyB9 zz%VGU#Nihq%Kq5Xg9>KIo57I z^L&oqtzx(kcdnJfjYRK4yU}>T791pHbg+hWb)+pKl29B$PFLWtyzVVJcud2C6JS&NMqw1w+^hwVnoTz60_HDxX)ErRxAg zzzwY4RHKli?BGc#3@!&POsU#UO1tb;XRLsy>LIr%bdX5L+u4<*7fB@!+`r1jvE-9~ zyo9`M*+~|2uTXIuLgMnND^(NTgKzYFY=%kQ0gETXcIFAoE4;Sf)|EM^Od3#cmPk4x zlUy-M$}pot2y6K)v7$)uxjhesGhCCfs!QkY7d`Chqj=P^0?D~ot8@;-<^JY$Y!A}8 zk7a{El=1|#l3EM_-|C3e#c|p99(Z1Z;`lfGbX)(o>lOE}d4_sf(7>3fcLB@BYpc-oYa0vUwbHHolJRU-VQQnpP8E?wk10LT`$0h6Qp> zpkG7%ZX{6^Oa389;w0a4#r>5WxFB#0qq>^kI{t~I0lzVrP>>1p$`7;zr$zca` z?^hiV1TcZ&^vwyRKjW+jK>!o84Wv8y>v_EQr{AFO{jc$T8?7SEAtKnkE{`u|&{9yK zjv(Zs8$_iOdw}GoO|8+v4fwa5=M%LISqPIsA^HQ*))#%FywDirg$nAn7x$hulPP~> z{-`sQjPft=nHCM_`QsomG#%yXKA6N*c}dXGMd{c_*cjNI=}j0YMTxqkEF_1aMQ!9E z@i;!lFbjEHg!g^z*!w7nvJ?L1u3bP8UWe~oCUku9-O3qQ96Lq{gdOt|ASXP$0+-$! z@vv%;5QA#S(v5kch*(M+qNjF0(0yuO^w*J(!|)`xc)<|eXQ#h(K1Fvwe!89AhYuFr z%I%$m=5p;D;e`s?*T(m4pdrzIEf0l_@=Ny1dDK*}uols5x^6-`h&xRFLL`b_G7Ije z&fHX&9P%HQ@B=oWjA+OATVX<3zT)W#%#x|F;*aA)myX9Y#aNgeKto<6$PJ^S5$hWa zMc5;ep=%6w71`&AawL_db_^D*==CKU&Y&>GaY{XZkSPwM5%$_#rF@*IV+idTA6YEt zCzU0`vQcL)G+6kFsjhBRw^OiIa;<{sJ_yli;Ahc@L7`S0;_SN&la|EzqL@>-s6w&k zCS?qSMN-@!jd4PPsAp3wDX|1gu9kua1hpMCz*Y+k)TpzIlx=`jVi%(6*nLM|a>-Zl z%(aq(D(3!9chw<{qunE3iSHZ;Q<_aKJZWTSFJ;QO7lBF;Orl<# z7b+;!D%^__c-Ut$Y8F(;k_*jaUfUzXHN2TzD(sv?!88qf=f}Ky$?YTf*xCX7bg#wc zEfEAQ?KFo_;#FVTX}8BBjCvBTY|$%?Epny8Y9v8nnT8_%_n?X-*mBqy1ccn|VK|s7 z$167o#F#?tfFuJ6jeT)<+;Q<+ShHT*>Tt8ZDB|Iz1afuE1D%eU^1=);Kx~cUG#v~` znqQr}YxMi^sZNJ_mR@VK-96$3s;xq^aBO?2vQZtj;v%bpR3^3GsaO`n8#IJ6q}EaY zaFQ%N5N)7r#v)n#paOI;9dpT=D?dsxmCQ|@`^U8Jp#zge{_F(YgrRlK!Nv$8062r@ zP-6!gWk+V_!#=yPF2<+ys422w*xqcsaL=XH#rF!dQeR@om2vYBWP(tvP{S%=Hr$Z- z9SADI2iXmXtLcwS-Y$(hK70GCrzwq+b3x|5ln8(VQWEUZfvr6KAp%CgANjOwMDB@Tr)|lY906FG z@5DyLb~Ci$Wfi)U@Bnra%SI{t7Pgx4DF4H~5w@^v(W3h6u75V3zN}4m&IS%0jmyhM z>?q;-*+$iSD1IES4*JzZPHZ(shiYe^cJwv(|M}5hy!NYZ zfco(Py~XHP3A)Idn@H6zVUMxj2ry20f6)Xy6HR*5>-zE*FJ19Naj-wZmvlQ=8y)o6 zSRP9F!8G9Dz|njv%2Q&2a-F9K%JmAyh2$?R6&^7tD7>c76=s$cA|ee6(<8egA~Y@U z_aIk2Z__e&CK7`ayC46TkNP&gs??QyTTKGt1jty(d!W_af$rmi(`6E-F}NM4Ij^g)3ksTCL*_zrxmgii5zk({|e0QiA$eVVrAx#Hn@55$?lDCL=ex=^DS`H z^Z#s<#I9vUc0W)tun@q+K%#yqi^7=NHbIc8=cNjwcs1@`53h6n^c4Pk@ccFjcm?N~0|fi0`} z-VMt7$JICe5YJHBP+{Y=NQNzkhBWJ(vkjE#D;K-U3o>dO7b+~AgS1vfi@wDVh7H6K zxCd}=DoLQ^IG{+3RtMuC%&yWvZIlHa2W? z>J6tI_79X-83p^FX~Xpn?cm%57_3ffCTa+{;aYNq7K>LZ$cyMc>78g=mWGrCES;Cls`Lu(L{lPJR!!3-Y6F$t zBw?k4pj~F?zo79(iHJ%S0* zA&)HWOu%Fu2~t79###DDbp=Y5wJFfV8I=IcqytQ`Y2DG8diiQczWC;IUx=@+m4wav z7A@FnS@PH)e3}qM5$&b-1?B*6T!TTraa*SpAgPJgjl-IT@L?7ig(0InAVq224XV%c zT8YHwpLo*Nsg?q-D?84`wsUIb6E33I9$vDsj#x0Uk#=#Oq43fr6_m#l5FLZ5py87d zaS|Z-ha>|aN93%jTT&PV2o~gmTD_Fyc0t_z@K?U`8VceWC4zWFGRtSE)vd3?*sIj3 zOS3$zR~l`(Qenq@5H~N&HD8_)p^%>$f-xp!3UvB*T4nHWtCWEZPc2200C|a838^ue zialn0u)}lf^AXg_+(-vI7h#I5*(t0geyjE0w)wFW;jnrNFHMB-aj)YpiF%O${a} z*$;R+_8xWw1 zW_$oQTaHpj8qbi4H(U%Cq~JnWdKo+B*vyf$mQPs*Op-ssR&z$wfR9&{6l|9Uj!wE{j(O&XFMlB(wyfW4-w7%imea1nBmfr+37zHy5n}_>u?QHe zXwG|Zcdsy+O6+;!$VY0(qBF>vR-f%5dYEypKdg!eNorlx7yC!1q>2g@+6jTsIZ5m* zHon_lT=CH*7yV9KYjb}Ntzh;-Ft(+f>9^QGHwY)|=Is_r&&&3bjh3*TERD`1IAPS6 zg|~*(vZMgy#z6{E;4AjJFqw(T$`s7=WA*G3!Qw7<)nPMFi%xv$mDgi6WsTkYp1u%D z#ilI}y#5nJ_3=-Fz8x*(*;3c^)$)XsKt~6OA3?O^oat9jUb6 zF2v0RQ>1HG3++(OFunGh`7gx{F@p~-Sh!KWQ@n4cY?;G0(S_v>EAxTo8UF*Ox5k56 zx)=W}T|5){tD6YP>H|nNM%*pzahooFurUa#u$r6tD|~2=_$K6BrFBbLWM&2=9@O~+ zc!@D5f30<%x~&DJh1HWJf@jeZ1th{!#GDpeKg$9P^Ya>D=+}B*xWH`tXjG4}zRHEP zb9!^<#dzM@F(pEJ&H`%4rT9)Ht`Y09Fpj76h&sSTW->6Xj$M%n0Anj~-a7{qAzmXb{#_?3OnUqHE#Eo455iO+;K zl{C$O2t2p9f@EQLR@H1)yl8hLuJYYRo;~dKS<=dw`?rWFMQ7AWnyu~y(!l^IJf&oD z5~E1PcPXBK%kCvpl;S=3>E41b$fbxhYvgF`W@mLG1xx2=;#N_85_H%TVi z2&_DXrPNGRi}c#A<8DRGUDi6MwiokkXpDS`4;*>*ra$2lZ!cNmAL$aAr&`_GinBdX zLNCoS!Bj~Lre0!(w$+)bLW!=&2XA2Hm$I%2xj@B1vEw3k4ay+(?MiSbMc~RZ1vvEe zo99^ngO5FjU8S}EC|TBv7I;}ynJfzuwRl=lVk{A&8?zn?bJY!CU!?SjI~dhc?S<^B zUN)oSZ*%HX=N)+*zP3Oz(e47v- zS|P0At7@(OMz}wO9m2GUYth$dNQhZR9B2e)pHdhVgy~D#bI+Ggdm`WDNhKD(N0-FB z$7*~BO75GO_1-CrHs8hzaD#H80?|PdRp1dG%M3JBQuC*gPg+{dr~p@xH{3e+xL4vCO5=K)G{y>EwnD*tA%*N~=9n>AbBDjJu;fqR#&teK zpumqJF!SDeiNI;Jv8NM*M|YF>K^2Aa<6fs4k^qm0Xv>qYu1SJ5OvQx!@_KxSTLlZ6 zXtAh%ec;PKpJP!%*&z!1&eRR1^4bPa-QQ{rxx7xmO)Lp-PP6cJXtZ@Qrrr#bCaDt3 zGVBPxLa`2zzb2q^=u_zJiAoj=Bogxs#1+I~m!?Vaf~Et7DN(x=e~oX|t_=9Y7T!yg z(4O9E{dfZMV-FTKa*G5`*3QmZ{zf(y@A?9C8Y$_qU!01Gkz`Kh1 zfdE~{iX|+!y!3r{zXXp`mTcd*LB;TJTwVQsu!m+&5tDe4yZNnM8uvde{$jxHSU;|}!T0|@X zZ4>q;vQnaDzR2@`_^_|@Fubzz`F%Fa>5wk+!}zW~V@K2xWR0Av)Ietc;HWuk}`7{ffgs2SZ9Jbco)+#Uw#P=5ybyHy#$rn zWT!(arkn9yt9;~+lx69$2%-<#3W3-F9Bm*9m5O7AWF3`tL+_OYeg%h}xoLGJic-}} z$L_NM)^%<4a?>NBxf^4K=%R=;NQDHU#V3pVc6{i$l;1D$)4i8ok{KB08t_d#IWU4Q zR`W;_qM@g{RSCIv;9lEP*%pBH%e79*dYM-M1)7mo!fhqetVqO(8rOmxYNVk) znI_7v$-S2A&F00w{pbS})&D86IOi>(sIJ3z!cnrY*iUt*BL!U7_6Vqj<#!cv0F|T? zYetTG0HFG@!~nYa<)3@Cwakl>G!GqA%G0oz!g#BV(qAAb4sj{In?;ks- zm3_?xm4z4}HiZZU2T&r7!udlM=sE$s+Jgy8lBb{Y?UA2&or*1p_fb5deLjS}9wdg= znQBbEdE2F%A&s(QUiNKOaWKPjW@~&J>|de7nuO7q{Jt{7`6}GXWF(m_I&0-kQF!+7{0!|(;hBV-)(E6K>-J2 zPqZtg*{;V2ZVITLbJZ}eQWs=9pCxrx6fWrw5FaSQ$Cj74-HvG^05J=pw9EROCQr4a zDKAU4Q^N}NQs*Xyih74=Ax(&vu@+E5;yMv_(x8<`|Lva({ZuBnsm!2^PJkXCpRJ#P z&cLE^wJVKbUa4SQ*^j*p0NvP0+DtKp3O2+IWMPsXjFp9pwqz+>SHz~~m%&4m7)Fqb z<*>}=ka3bY%FPx|`;!)vWP6yCiI637Kq#m5dT-OXMgMX2_oSnId5Ol^=ss%P8Z_HV zJ$q;z18m?7EoN_55Ev_&>B`A8y9;F*za9(_dqTk5Ceg0gFrq4|aj{EP?ufLbIzFVr zsWQ@P6sAh~QOn;XfRJi&;28W#QaS{#B9G$ytKEF<`sT-{{~n8~J&2#~Fd~}*C^8%v z9ls!$@sQy(e_KI@BxqJifDo{e7TmKMkP~{*<2(*^#E}4XN1l5y5Hl9zOZdfnC~Un> zY{-HS6SgbQS6+E5X@y$J7~Xw5lDRsB3nx3%kC*Db8ri$10OFr?@6N?K*O=^=4=&VH zt~ezFafrbfEyC~w|K+dSD`X>WPKRlgPOb_^9r4RY9!+4wk>=g1aG^?so_q}`tLc&h zpSO-qPGZy@3V5ryvG?K=d$O=Om_&KQ-pEh?ZS*!)rz4uI?17#Piz%@FG~(C|VrcCE zGINL)PQU^&yD4S(>IGr3$y6{=lByG6tzA01ZhFi0QcO{{QC_3c;ovk#XH;rl##)op zBcqWXITqI#(=-?++qDXth8aQWwUi{TJ}ita_K7u`WkANPQ8J;VF|lG8_t+rmwI zq7?;n^&#&1-tO<*if=Eq5PzZzXZlPQz5=C>W0+0l(4P^eta__msIX+Fg*N!hwaNz3 zS~?j?5aFsG14<%ZiqU-!k-ikrM@Q^C%chhV&W9y|8XLP)#<0}>^wv+4NH05BY~RHT zxbV;8JM%4J-dW8!mg;^`tAlK48H^r%68;6!B|D48XQSCG22;WRl4;j~g<6I!S)d#h zXFw4jnu6;*F!ymI;^n+h1C3~&)$)z=hU52t_75q>l5-IE*$_>p6#GyT*JV{sz^?%m zQ2>E4yGR3^Jlq+@oQ9c^N*3nh_>=*x7_~@*e$XUBKM<5)`=}kF^@4SZPGuEy&0<;H z=?JGmx19f>TT*@kr)k7E1QD(oFtgBt4I@L%dNtEO3p(M(rqB_Tu;Jp%FTF*k(w1~j z?R$OFK`%D$!A_6O$GBUMqq(5D9hGgBQVAc!&FZB!>E+2qip*UYndF0u4Fd6qq+xfE zgVa2XGDE&c0S{q=^>u_<7NL{HP!rcxrJi1uyg7#qmW6VSt9^LlAEk7otT*P33n?_F zbyrD#Kua=mt%SyHLT<@4|O(V8$VO zf7FSQs>4#C-HBXr3P z_VMJ=dcTejE`+ZWywZTouxW;>gs&gP$1azF3T)F1v#jncI8jG6t}z+Lqd})AS!(M9 zml~efMXs_+4f^@R9XNE53ji( ztyE?9W~C7E5UrecD;%W{7(YTN#z1uWzS4L_T6Hw8A!X!NPGL)^DqT(Xmp~b${bLxd zI7uQHSG@Ye&%5ySn7DDmj{TrwHMp0$o{S zI0-8=^qnXV)df0o{#mxP8c|oE#mB$sd`VoFDbVEyE6_RZ?dh1KT!ChJp@Ipc0^e{n$*mrR%hq*}{%wP(1-8t8ez7yYH zHY#)9dlqofFTr;zIIudd3?6Y2%JBEbkb|ywsQ|v~mna|7pvD%r>#sihk$bqf|5dU( z-m8mKM~+c3Anp*~VtA=zX2xd|93q1&jTv64@J`=`oBO=gPO98hBiVWw??Wu8Zw9?fXFX z&I$RDbLnfhlid(S*9*u8;X(zW+<@-{REze+fc*)e#lwr0M06SoAOV{8OOTHBRpC5# z>%}&IL<|BThcyt4g6v+(J4pIiC1Ff1F!a8H1_m$l-{@S(`|CE zTtMlahws~@6a)$A{!*A`a7Cu(nMK!X1YH{=g5+WFFX)s2Kir0W#5pC} zj26n6eUOW!w&?mdFoZ1a-Mm^w!sKcnkp)KXMOQGrEYJ>est7$>6R1Mp-kR6Zs$MQj znP^FfSv)ZyT3JBk3HXYtK_ORly(v#8SVSnT+}+Zrf=Y)ZnU2sh7q=!kUF2b@#`?NJ zW!SIFWYI@{@wTPVkg}1o`?7KMeTUkLdh*-Ne-rv%ozMwl)$KV>NHcr8_sU=W>V0_V+S5ul z)JIi&1lG4ZjKL48!N9@tjKHgQnXv@ST@bRknuC*YSMt784-HNdDeUM%v6d8kp$|IM z;sbX`&qA!403W^hn$Uqs)gE$es9cpaD&j`;&$R~t0v4m~g1YSYC+9efptK$M6ALD& zSKu3az1&y{PxS)CA>1R?-UEbzWj@BgF-F0E~bKz^n{xyIYnT zw*bJjB6NX1Xx>ch?mKF;WP(aD%grScJiE1peNFl1(OPTtKJCzJ6*dnm|GGDarFkN#?Jd~Gm z8=pR0FcA^wNC{P5Z3-?A>Pu(DyADQle7t^6v$JD%Fis9-#EWrZz#3aI!5T;9RY{VZkDDz#!TVL+hK|b< ziaz6)K`1)=itUVF2b@p{n@K|Pfl>Ot$UUtS1|N%WtNjW;-HWut4CFOWk3=~X!&b?2Yw%9u;+$er9pL|8~7`40dOJWj|VHO6Nki{U3a z%MjfO$0d}Iul<4DtB2TFQ8ur0--?sOecY%zg3#?Ce~Ui|bFpPG3s59{emr0=K8z`BpI!LSP6 zQ=~^^>OwpH!lAwQZqGkm#h>oVDu(2dHUD2{APA z&(;>E!cY20z}4##la7EL5XyiFSPlM~)SP?=y0rnNEJI1$S^J>Js7lK|)o@qs_A~ds zixNAbL}K4qAc>IxP&<+=jw~%tE)_!+mrIfqI|)IJTk%%5I~nk?_s67wLSL98Ox@2vNOoe|H-p&{5GXjau(4(J4A(Enf9lN!Z;KvASdG{ zh+df{sM(mdD;2EJ8*wvA7x>B*cV>E|U6m4x=UX*$Dr$USeFc1mleP*MnXe@d8SUSnd@(n7n&kXbxszShHM|l=ooGX4fQ)5x<}!bqliQx=%?7-Q!Cvh#e)f zVA{Ye4cCfIjVFt#ylFSvD-DKGg3+*#Kz6CeQl{R-CXp>;DiR(I7Kgb~b^E|C&4L;B z3Jw#@eGgl52e*Fh%o4$TKW!5$*{Kf|5ycf4lr;YzM5Bb)x)mfkpWleDAWHUEwYd74qGo0V5(hfx97GA|zwC5p<~H z=-;8})}{pm2GB zhudpLW;l(pfwT88J+|6B>aDnURdgujz|L#Hb+cIEVE&INN-@iXcoxHpiqJ{fHsEGo z=pDa&&m5JYR&w&uzF+D>NmT13xq~U&$Kx7mQO6q4g-WxdUyBZEPBTu#R|CEfR3OC3v;c~Y z^}?)V<*S)x_C=*CEgA(CpVa(uLuh>ur9+hmcO6-I8Np+F2Gp$Q;#@`#yzK8E&Jp&d z5!J6$R~Al2*WioIiy3COm9RIPXbiHEXecv@7B|}eKo&!F=8O?$Q&GEqSx-EpKI2X`BzU4DSIYjLw#~e9iJ69s@NfiStE&&hp zqcS6EY`AR0NWn*f=(0Cn{1;+tc+^^#QQiL#l?EfH0c71V@o?EVYn7wMjVKsXK#>gt zhM276c39np@Gx@&!rgH^tCQByc)2Q(63U_ z0S4V;xI)m079mYziGTnLcnip9Q~;0=F}IMp5dx}Cp0CBnn*>Mx`PG}HEWD%vbHAPG zLcfQzv1e)U%Tkp%EVkJ|i`0ckRyN0ns%*_m@zFiXD-hfyqSQ-ba}+2m%IG!UgEr8G zJUhKaHfbUDuO|Pp`dWB~EK`NsG?aCXHR9al6g>zIUu=H7OjnRc}EmIYz@~Kvci?xb`IZ4$rC4;&?I5fL=r`3~5P6Tcg zNLD{R>yCA8+tt`|^4*l@b4uj-`zlYy#RE8pVY1#g2-^uj5vd%4ZlphUU}%G1s<3Z4 zvuv5fy8e7LY+k2KuI-e3aJ*}v*Kn%}In#@c3iV605Y#dy!F*pj#~aCYw_&KtWa*kR zOwBZ+M@6j}L{q`b`rdXlnUJzcvil#YB0CJ1A+m50jIgIiw*ZEXwZ`z7qgA%#$8fWl zE0WZS+0iKilKy1zku=LC=m2q0VPO6f=PO2sG%U}{Qzg#4W%kjDnc!#mu7(pz_&+xd z-W6yuJ6@uz*WK@#?L7~VUp6LZ|6^2EkH+PJ5uT-fQWR>p+R3Do08}6$VpC0o5b>ia$0=(l@%N;IhgVp}!FT*vGp3?tcCF8XAqVJiz|PtNe)b zH#TR{Zw{`ioemKsN}G}2gQ&vqE7++kaqA|HcmxX+sYdW?^4l!h32u8?niuG57tE`} zf{Z;`M^whLV~;$gX4Kz-Cs6oxZDAkO54i_&DQ$l1>YkM_=Vg@M{wJxF=p#3dV7}() z@JM|CpU_EzS83ES!2uOeNYPJqaB@)~hNaXN>!ag2A(*ag zc~0ALkBgpIfvKVg-sXIucmxJkNm{S~NyZjkNb)AV8@N_WI^c1F5;P;KF)KE(>aID> zQ=h-(M^B<4Pb?ASGqRm4bD=58bk3aYT%8v^%->hoxgW$g_SwiM8g|1O%u^AVd%VNM z3;ks9>KU=&B{!bi^B3aU1g~hPU^y#c6Q$fG7@xsy?Z_p*CtRzEY46uRf5TclbM0RI zbO)j*Etr^w@olkNB)t}l0(1y+(`ZNQ6oV$sqE;@>xGvPoE9{5UbT_C22in@+T1RcB(+_0!q*!9CIa|pz-GUpzu%I~3UmpJh=o)@X zz;fhZdnM9y(gYiVCt5qQbYA?rFIpe&uA6 zdrn312!)t=HPfYv9Td=_SN!MViz&&HZl(Rt)t$#0;f)A@(DYkB1NCb&(_1nch&94v zP^FnRhIKVYMlaa5y^7ytfyRcQZL}6Is}~5Akditu{u#b7-3%k-kv8m;Y~f_oBLZ+2 z>u?|EG9gA`)U_W4BIG~qqYAJ|366Y^^o2&ANPgV zjX4Gi*vQ+MK}!0Wdr>#RFjnJJvc&-%2AUvMQ`KCc3U?UcIS4usIvS#dXxzdr8NU7H zHCnimnJxQIRf#aL-Z;Ah$+9)w6CoKe`kus5;ng76U*l%7@zR`*H|CEg#W|7EG?o8=D#Fj&C zn6IH1fWCXkcdBRwscKeT zxF|(_>Yr&RrQVHO4PH2rO)imLZ@ToiLzGC#0Mz|<{*Ju;HeT;gv%YReF+!Nt-#6O$ zeFgRBSZ+8-8h+&9$n;oHoe@XL_ZpzJV9e<69)Xmi9Z(g^8)U9K3p{uT({|YNnNhq2 z)(_~OQ0h20mLQk#C>B5C?SOz{O^-8eR6!Tqp4YwQoZnDzWwv8=wrvir;0Tu1(k!|| zQT9k9h0Ksrq%2_&LujKAU>cYgwb5(g7vPFhG^s%Z-%6HX@GU5`IK|>ZIO?98u3=k9 zjgsiL9cM0>5H7;EEz8E|WyV9&mD!@L@3RGmvD|#7xY7c%c1ry$={lm&LM%Y4DB;SI zDAJ;l&*xbGf-^U<1hee)z5VNT^>iOSV4eY=>l;Vfn1AE$gNZlp8gwi)$LD2Jp7GF! z%(QmS)Xu`4VpDWjrr3W)uBgsVoDHKxVGp42w1?jGn`udDbaVc*cW(X@d_}F~jEDW3 zbXiO$_DtYF!R7=g~w}U z^dbv$qR~tOKH)=*fq;Ewgh_w~cxrK`auV9lB!vTlNL|B6K0dWt8lg*$DBYi(@z67g zv$ZB?>npc+rlU-c?h#gp7aAkHP(dKf2(D!s$`-7gk#QbPZ^MevS+;hr_t0g+E1)Qc zd%Ae0>NgN)sCn}b()BwQQ7pzfzUW_2t%<_CS@E*I7bZ6KEh zSLr>fiWoRcDCV+(?`{%T08+)v7tfn=gr4q`#R}1oc~(`q;10yB}A}R&TN~h@pT7SwXPLQUxl8%-ATMiabp+PN2}3h*ygAW?Wg$Z1{@6VlH%1h4Nxf}T$6xR%G8tu6i2KL0 z<&HPUTJ;rCdgA_Amdk5-S<3%=_?d5^zrZ*5OLo!}!Qq5&cnwUG@kp!=(V4@}jh2@R z^;gycZ@If1)lHSTC^KLMlp;`ua&?tB{eKQ_|06tTX)Q%N8JMLaBh>F;bV7l}fJcCU zP_N4i6_jC*NXJ?Fc!6RBH83-y15{}-OA6977F6;J5r)UA&?Ik}#&(L&6v!&*o7l)X z0Nj^pP^9_t-zA60Xuw5w)U!Um?<$JyGx+J=MV(|=mJ*+W$Lmaw%(r$Kz zQKrRJF)ByTeaHEl} zf1ns4{Wcfh&PV@codwEeCk^bMRq?UZe<_B>7fbz5z;7{UusPTm!G;Et)EsK;=pd6l zuOd{}0Q#4nME0n~(9Ej190|J$D-RGx_ozH6sd77HBIS_bkA2-hzPY_!PT`0we4jZ@ z?_f*rkXik>4-Tx(*(?tRgNe=LDsNk{Ddi*&KXu2co|E)ZZ0MVg(^Y>QqX#6YqC{QU}PAB)}8XV_S!@ao#l1^--!t zVK{HQ^8TfyeakA|_rGd^CDsSef)FQ0Ou+n`A)!Bo8NvHk78w66+sIc2$f1RgJf1~8 zkAf0$!4eXa{}Ac`43VLHOXb8?QPUF6-u;wwkt9#3f%-7Mq3$@o|GnR)#7f3v?az+x zSlStFO-_=WX3_gh_?xHT)?s)dya>ccNR%?wH$Mv2Ezafmi1jg%S}?r}25;XJlacae zftk-xqvtM;MR0@z2n=NUJymv94tj4bEZoPSfnxsQ2hL_`e!uyJuQN7m3B=6z}ixykWqI*jMa^~-*u;r1D zA|W4Dw>1*W(x&nSuutuIUX0}$^U}80MrT^DJWPy~>VwF|0`JfUo&6&~w zAtW+Fn9yMHWj|${j)!Yb=D8GadBMYe%QRfAfb3b-YCysJs zcsc0T8r)T#`5frx8;YsdO(3PDaMgv zcGXa1HiH_kNy2c#vdgexjMmnwnq0Spy?iJC5UZvtpvEjs z@4`Fv#rMDCK|Fo!EBNWQJ$5Ppg}1zkDZZ#3plcsS5kX2J5=U;N;Q@Tp}prT1Tv%*t|vD(nL4 z%!1y}%?kRTaiOtAE>zF~Mnx<5wgo5zILK;YjDg8Rz#PRe!r{SNQW9qUYLOFidLat4 znA$3`Dgw8|A$O7e*WG{H#9oT!j1p`6S1OjHaM{GNym`Us5RMde!TfJrGQkYlr3#|i zi@W>tDm-CUHSOs>XSwtYXs*^XLIG5}R;p`DWe^Oj^w=JkryffxJ{Uzp@*PpklLh%{ z<7gXlibUZPP=XlsWBHO^F9!3cr~gmI*vI2zkX#UObQbI3FpJ`uu$0QF^Ia#F1? z{iNXn?owo-%m82UtsVU&b8ElFPqz)RiQ5Y#6#5?kI`I77N1+dH=~7dRsL@8sObD9* zGJ;SOie(^>;j=jB!SPF$muyBE!FA(XKeC+5FFEyS|A!V-Cm4n6uovx~VJQ(D=?Xue zh;d;7j#!OFp1c5RksbrA-5PU<*gJUJT6ZGoNPRV&F+xvl3@L1ahnGE@Y_LZADgW-E z1>UM{w3w;P;twCYnM6scm9~N13#2lfDI+SQnj%N2alWJf(@h8=ZB!?UDBy!6QG~5U zTOF(eI6t^-{C)Hi_u!0-NXLmg&n*imFnbSV7O8^1lWI3C`Ro-G3#Z|A@1$#0m6$tO zj(Dh997N4@5g49HOrgRVVj~p{%QWs3pJV<>2o|l|3X)Hw;X)#jr75tjG?Yff2tAk4 zzHWeEM%ArnWRb6U*A2sGiMu|w#Gw9d@=Lu#piK}3Y{ZssrQRf=uuy<82;@37&j}5V zUEhs$OODW^e|diK8BP)K+IrN(HqT#m6oeJr|KE z=j28~HUN|t`5+J|GBr1f*R(!UYjyHHqKg(Gi$Rc&#s9$sW?OCTGs}O>X-c&pl&tns z$&xO>YFqfmWmu4H%qY0XtO0ZwXJG1ZaVBz;U%&aOGuCoro83tt=~Ko zUs+muc7v{z?VY{jqZc-}pgA&XqB@OJ4q4>I3gBqpVXnimIU zt>bSq)FcK?)2F(6N(R;P*cl%3NkLQaaeC4!jfuDxf89Hm+`5QoOx8{<+54Ya(AWJ5 zE?<;8!m`XbMJF|bf8p?54R|ierii^@{vtk&&&hpj<{DuqWrj4AOp97bjoH*KMZ!j* zZSrthTi87UKm~-$t$x!fPg{xwls0pIA<69w-ShQzm>FD**AT(cPBhwbrGnc0CB9Vx zU2r~mYAe$YReB8Nk@Jnbs|UVC%YJ+DA8Euy>a7rKAn-qnkEAom>p!xnI=zm9OVSjr z8I$wB{M{p-O6}rgv2N4(#RZkpoA9jz(hLxe!S+AhC9@+&3<_0f#qZhjvi>mqJrJpp z*@Wwb3I8Tzf%Fy=Xv^a(aLDks<`+b_?OmE-=p|w6}r_X8@!AL ziD5MFb9$2p?gZE9pdD^Z$*(II%n#yD^PmYXhWVmNOf%6~-ESwsH32w#n|bmfBmX=s z;op1tpuC!>DuInnt{DG_c-MBCKLG#E_(!vv_nmO=lb=khSr&oVh-Cs!3hCg1PAB2Y zNOSAV$W5Qr74qzE`O;IggUF4rF={f)ZuL{po$wlTV}| zN613KP^Lt}>5Wo;V|Rx)UH_Q-=6;VWCWqXu7GKW{UT-ThDRTPXJ$uH{cN;% z`gS2(xUD(Z-qOHgP?1&b#lH)8uapxNg1pXxN^uXX*aXGBZL}y}x}fu5fmBpp9*o%} zO@glMV}d#py2}&cTA|Yh_ldMtF?gfr4xPE;Tq7!%^OwgI)ZS|KFW)NJeva zt_-`^KmPiYs0{4Q?A|8XnB$dg40_8IK{|WU^V^tgj&>?pfIq>PX`8n?9&0sZ`=4c% zGkk3>R2Rkyd5~Zns7jY0!|dh10H)G;jNC}z)5mpcc)@|e;228x_22#d)2E-u<^Kvl z-RrkG$b998aQ&~s$H57R9mveTdbXnFm#Es9JZ9dks#^k-DC0~%LE5IUJ4BQ|O(y#a zR~T~&yPmb?KUn)+O7I>?z~d0E{WbWu{zA$iLUJ8E60Ei|x&gFPbq(ABMHL(c@P>O! z+DgODR!fr&6$?M@uYUc_TOY$Db&YPK`_+4DbOU#es~oK$T0(`DTO4oh?dQZ zI^=Ez`xG3RjnNRZu60swfi-+lMMK6V1n`>8n@I-N7`=4cpKq%G4#TBYolYEVN(k1R zV39xr1FNZ@Rj~IM?j}*=2+_SNp|#4ucnn7kQq8MZ%rwz`iknemBH@fVDAPoNF4%3p z%*D+oJ%+?@X&=^i7GjxK;>&uhH=T8WP(voc))z+f6`W9k^fL3KrXcgWZd(zsNOTXm zApgY|s-!ptt4H8wvdXw(X%*0JK6TXQhDYwH_dbIHA}H_HgL_p#%;B$Y;xtrrs7xZ0 zlbxaWR9u=I9YZtoHXO{sD<|*3jML`4hOIagLQKZ&77LtFy=p@pgw)Zu4JZjUCP4yi z&%CNEm7d1>A5D@Hsz}v1dyky@1Ov2|-CJ5B!z`I=qW0*RK$g7lqRU@`2de!+i9mj! z0%5vrbrbYVeE`*hQRyKC4Q+B}gE*1117TFz9}H1aRWde3XFI%V=BxC<#M)05P&SuC zHoYjim9kG;l$(h{`$JY)3RS@p*oFtA05LgB2Dr|of{{R$PR0h!MhvK=>9mbhl(SD# z>Oql$JM@U)c7F9S4_=EWtuX=7y_bHb;^EMQ)u?ts-*=&<@rn5THu-(!Tp_zq%fFgZjM|)`Np{LjjhDlsYt`qfTrf7@Y+gM34OT-V*nC8XI?dyh>Zf zB6v-P(va$pj5rRB$yChoK3rLv2G+$No?=4;B*8^YB8J;*=}lG)wUXmkmyN$w>!)n4 zysofULQiv?NLIL<_GVwn(XYj89@%~i7SkezK{NfXGZ4hCK3uNJRa`%2bG z)xL|L?zR4Q0oFFk^{8|c$qM}zmC! z?F;#1_Oc$aJYpeyjio-IfhwL{zEh*XLrr{cB#ekDm6z zS5qJ*ooWY;Re=!Horz7;nVqZ;w5J1{5Y&z7?;F$jeT8>?6>ddJ628*Fd*=QW7GNc6 zOBf~E7|x7{Hj68<5V{5IOj(5%xk5O1!{`XIrX@3QV&c>n;TTeElNN@W`*uMcbMES2 zNzUu(CHBRpGcSOku7;pMt7x!<_ZK{6IFzIXzKfkRknnk}1{F{NT6QU_;%Uy-udkq!ceY9tNd#l%+4HXj@OrW z+QZRVqfr7tT4SO;(XK?l{24xQt?(tEY3zLB3-@qXT8*Q*-!_Czx%*lYVk|&psGU z=$Kznqz3N*+!HO>LV>Dk!L;fU_aU#V{0rQ6jWFIN1|w49!sA2*+*~10;aeI`qU7BM8Ni!YBGycMSuUDl){B z_&WCvJYomoK<#-Y@BLZ2PF4l1!Ega2q^E%mr;8P57@yX}OfkDs!MJ`5AG?Ze^iY5J z7N?JLR7I=@L1?t5j05RLYK#<=u~J$7Bg!C*p;Asx3Q__Y`+ma*+IJx;6lxG!7a%c< z6#NFUwt@^@YS&%;^T97sY9-Ag2W&DjZHGv0V08R~a7K^EZ$)C${A~qkU4|P6q7qju zT*A8AFrGheHiRMktFfBqQQQp6|3W4RaB&6azmtXWL^-41$Ov%Xfv1xFNFmyZe=d~G zzklPa9>i0YRpA_XfvOT+&zd&0rM_{t(^ZDEb#!vF0btvjt`ZXvCiQufkWwy=QbPA7 zEiN5cIlqLZWJtpX&#@OxdZ0ZW)Wz#L%AuZVq=-F-d+~Va(u6r!7Hy6$ONwjzmZvYY|t4* zK~8YySWhcfvbtKM8v0?SNfe4|5fY?E*jt|d_3>LNtdg1b2i7I6>4POjU_I0cF6B7f z1Qr}bN&^R*H%8h(vz1CUZl=Iw04H@pnp%v+P3bPhYf^OW+a}vtrxXvYvH}L6wZwZu zz2a0g7@IUK{jX20nRwN@WYpMoiMml`o-0XNi3ORT(Q zU20u3`);rzAq96RP|C2WdF;LWanE~j4TX6`i7*EiR4rf2cjRW@*_$XNF&CF&j)MJK z<{}i@C>OF8ptN>kYZI8LAd{O7mM8Sf)#{iJKkJ{~K}nRH9eQA+N`fqes1=aZYPz|c zg_z*Z1&~tzH-8r5Pw}A=`()~1p#=O}7<_Z`h$*tf9UVE$9?Uziv_w%GSa>H=2{rSj zf;*fB}qmb8)bq8^a3ZN@Ips zD%f{M?10cg968g%QkbmxUPFk;?PF&NV%A?Pc`9iV{m-H^%j}jVMzP6=w@{Atvh4`n z(PHVoP_r`1Dk`r`3op01>ePPw*xOISQ`a6*vWYgU>O2CMAuJFZ8!-_hQl0dJtiNMT zWW~8VZ^o?yKIB8w(oh9mznEStbnty2Rd-Di$!-{U9z+wghi0q<$4ftNvlbmZafcm8>7!=og*kcWdvp?Nso>FI&sAWaLajz z-z0XVWa`&}mn@I~*fQ1Q#S&ORGWO61#^i%~vUivQB;z6yaTKZ0+y8}>e`b&*1ebp^ zl)`57iqvFU{j(F5k;bcO-@1$0l-9S;QLnoEZNmS40juaHE?&Ao5<3Im)r(QOMULo_NCN?v6>T6?02k1>U0=vBwG%UZb zoV0!)KGG6aWu8Bpm0Eg(8Ez@EPHMLm$1AY6(_tUJv8%Z#sAR9Vhg7HXG zU$S$8?tc6&FZ#%nJ|TsgW&5I`Z+QXaLyDqL242|`61+_VrigomB0xc^Q2nq9Rtlq= z0?;i7yNSKSzOY0TEsHy$obBMC3S)RukFn4a` z5{+uA#2&@v(RG0xpG7+;hpf6*9gAxd)2ASzk82G~fvM()Uyj?o973T&?Eiv!pFB9g&CN5iaRBn-x6XEDKCy0j5;stl~GcqT!;t~E=hKmD^e;6ZAq zmB?Ul!DT@0S*Ba9F#SLKvWC;CG?ne(Jq#S*>;w!HMitJ!D<_%7;-a`AfeXFroU!^B|6DFlcEepQc{^h`KFSp!N{zLE6#in#7(MG)?RSQrf`sR@_ULUJ&c6y({m{; zfLQYE-V5nFYNwP)XqQUpa9mzL3zE#OHY0~^?djH5oW{)JmtjDtHhO$9l=BqOQxBT} zIBzvZhiYe^cJwv(|M}5hy!NZET^#P(FQ*T9)0UJ5hJQfr`lhuQ0XaHU4Pjwy^ zElOpN|F@Os(Hr`wig^#@O@*{3&t71dJZJ3wFBP;2s`hPp%olI^++wVttmW^3&GV&; zL&CE_wv2DbVFVbsQ!z)y()v|Q#>PfuJF3b7EsU%O7ki^X*)5vrjzUC>!N{6$Gr_An z_38OzhBI&A+DqC!54=t_g`pHGGRGkLff-DGbcG?bL7h|s zIy43|U#~WaLF)P>udNGD^M~L9W{C8og4zBS&RU=kp3-&A2wWO5 zBVj@V{N0Z{YwvsI(5QWQo^D%Wb5&`Q`)QKL5F25O#<&3D9PEw;=5e9`W_vIyIQUC$?qE@UX*gF8e%?$wO)*J;gLd}+07k9g|`@GZ5H<9rUhBbmv8<^*RT zaN=hgqj4PWld4+`jvqo3^T|6GfW8%RvZESZlQA*(>B^ISRiw) z;wZck7{PJI`)i1hPJ!Bd<0G~)+%GHrKX7@z_D*x8zNWQfGyoo1*J;$UkKpu8{JH|T z`+M9eH7ya3Fiy2tSZ5<>fZu10c)p*tKB#C%(ko^*o|7UxIq8l#Qa9vc6V3?h=x1ps zBg0(>5Ut^aQhVW5a9i}7tbFN{e#!a7rJVI&s`N;-;BcE+j-`dP3YGtqJZx+;KLx0Q z0&#wTgJd{eQF*utC6UZ;(#HVK>U(dh?Ev;*jg(RfzC+>HwD?d>PRax(IoY3r1COn< z^aIyP6JyDg%mX%nmdxI+AGsnDNF~YmA{o6+^?gU;qv@w-3^shW9Qpj|6c5 z7+Uq07z@IsDQ)P=kg`YqG zW={D0AD-XgT<=o8*9NN|Qkh+e?@E1bZe&zTa(3DmAAw+fmDB&3xmBQ&1wkP^7ENd_ zEzETMhmL9ynr{PHE6dV~ySM%7^0{Sj^)X+-BbS{YaNsK4RE#^JQ#&SEBaay+z$=bZ z7&(ER*dg`tdZ~hG+J(DUX$iWh6DR@%VsjxnrYT$oLj z5Csn@HMzo>=@U!AuKpfzintdxj%2_N+c5i=XbUTaIDi)0N4BG=1T;nnJT%pq(Y60U z7DXoDblXe>~Br05nKC56dR;Sm3k?aK6@E{)sXxZ>S+;Gt?|-6kJic>VbY ze6=|zxSG(B$eW2aaQ~;|2K{rUHIPpR3M~hyhD2GxXzVKV)Y`Um)9+T_+?|oD*((xa zOq7rX)Y=3crjQoP?Dp=roO&0LOWB!!2R^d!0)02Wx+hvMu#fCnRU*(Eq}BD17*Z|p z`B)4#k7b!m?*ef_uXMP2$j5kaw3zE5h=ont#0Je|Ci-h1$!~TUtvuryFWpNStt+7- zKDzKSx*1>1I7>rk#Vf%e03yNg03bP~Knx(gH=09325MZV2D!~qPC}?Zm2&7YvF4<* zH@c0nr%9B-&f*Kmg~K11LB}B{gVI=s7m}&BmS>q-OEecLaTn(u?_6@{xfJJ3`00*J z_NX`+uWrN_0^syDTf?)#@GxF&BUZ)POihe~uSD^jj(Y_piAGslQ!p3`9JAdwAU$uQ zf(qYL`QnnNxBi`lN@ZuI9{89pfx*?r<}7llD7q}p=bMpVH^?Jb@ZvnRp}$}~Byxzl z4rkE~F>9?SzCsTDOQsaBe-JlfW6TIl%&vH0L{3c@Qxjrxe#Up0ztvq6FRGJ(s4Xwq zBp+YEw|XPKa}%ewtLl+M6Hgp26<%B4Z4tNhX2%Jnxl{4}gUw3vfwNAti*!%W<7Fm= zSs1gtp6?3QM=4g2?g9@r3bR+{GJN3nuN^L>AHTqwx_5?+(3YKn893M(8>Ro$AtHAM z+D~zzp^d2(RBIadiiPwNLBKFZ z7I8HveeE!|ZD590&|N(;Zq~!0HR45gF1RSX5hn`uXoB5l53B4YlbzWDHFc@`oz4_i$Y)rA z&60_=&HV47Q9%;AtkIc~0A*07Vd1b=Oy#-HEdwj`@|3_UiDNgisjl$;~^yZ}upapLW z4q|d_yg6Ly)xQ;=4D_MN>Kv5hbbe+z6{VY{HQHvK3yPZwc>)xj!5XKE00!s%KzJz2 zN4`J-k)>v_Rm>RMh#mNN7tEeVJmh1Nmo7Q(`oNbKKo>p_S*-6axpvk>^2iB)bt6{> zG|&))h?xQ?Cme5FQV6h}GD)&vTBX2HQ5?lH0VA|Uv#$YG#Nq(4g;uJ8_tBgw>~Zm3 zwRqWEzKIo;ot1ImHWeRz&?eAMhzr(ZOhjbj=z}hh-y<7|-&gQK7vt6*xRyvz0kP;a zlK}vX17bs{o8bKl@HJBZz@FmV`6z%jRtL9|Bcqr#3bN7_{LX?>iFN8)9AyjmjiMy_8_HX#<4gqZbCL_ypF2JD}JRvicO*3^hE5F9!n3axI>fla3vq(>r z-uOx&jPX%Sz`{sCd-qsKQhVDjqFu6m5ZXvwsncwZbD^Dt!0%k9C%!~0~jV0;ih|C#9cfXosVv(~D|6+3`NK9pm`bCawQZW%6a+uPc@A=FFQb@SA zL?RC)ixCcn3CA^zV4}^nDiz|IQPR!j0yvmN6E@}vyDKM6wmE;<_*Vw z=!zdC^8K0=pE>KX=t}Vr{>GrFNmTyKHVCtt}>ljMi76!*vX) z3RftG&g`&iY_$vX(5B}-ROPS?_x5K55tFXc=o{ui^2^*Z;B6(u38ux#q#%Os__HrO zQEK5!7_++$Pd?+2C1RfUhq{UnVii3uTYodjFXTqSXIJ?D%FbrBDAaruhEUC>7!)5b z0GX)u)Lc9Kv6Ht2fadSCP)QbP)(NOkn2gc8C8GIM{MeJ587SX58(Q z(+aj%-wj5W#sXwzT4|zt8oDbzQyRxx97@*LnPVnl93coJY>St`j6r>-E`=d->;LVj zSMe0WGG^?q$Eq}F-&Z42M?pu*YaWANvh*HDK>XKPO%ucaIbX%_UfjoJ(2@y3Wg`Xi zSPBb+oMm4l9p&$l-4`2;KQH=23BIg=TnhyqEu%ldnyfSybJ94(Bd*XCrYM+4j9N7OOhtfRJYEl8S@kS-o~$DRFnD2XSZW8B*tPdaga~wp zkQo}9mY68L!?7?iWY^QrZ-@ylVGQqjhKl8AJpHl}$^`>LaKtd|E<#zyRL9}!pkKuq z!+Lcd!g=u{RXBU_0bC6y*V6ZkXY@QvZdu_=dGx0n4tu{ojh(yIwwxwFbAT^55}N2& zaE5n&L~7zilsd_`E?9mtjPif=?x4eEdkT190M5f!nZA|fg-ATDSH z7k+iL;;10n&2dD3{bgK61egE5pY46W)9=@u%jCZvIvfw+3loaX4^qO8kwKM}~(^%T7CtH_@tKi#Xis z2fjNs=Yb3=nHqWMukicI&jU&UR(N^%kKa1^&y-ooahp4jOO~|=c^u}a*xx!3jVa9X zFnGiZfJC@36KB+;mi2bZ%i8dv5i-*)>LdT>c3}WVv7n?p(jX{aSzco6TWBKT$<+G1 zI23C`1!lNUOW{o!*wg_YlKGbhzv(_orld@`^LUjE6C!k@NT<@0=IB^j55~GVCPt)H z2}=cVWhSzDiOS|Pc<~Z8L+TQ8k%;0K@3_ZIyshMe2538|W{LI^&zK@*HglR^1^FF7 zkSf6-3?&S9K%7LoRS1I^fW%#Mwi@9U3_al^|nV#m9>P#-ua?rj9m>htztsy zWE{=eNUB9+gg50SW*)pW69HOANvaMW*#>Il-T{hSL9#U)Cax@k#SOX&CSM~+(dzUu zou<9+nL+1yP8Qx=E@!=B{x|>j7O*N&KcvBd#o>ioKQGKc zCJPT#rQ(NrE+&tXT`A&C;Sh3sM=|wJ!JzckjAxR9iOa;DH-Z%q3SP{kkF(NRG3c{i zBK3JZ1B3S5l)XG}SGM##ZI?8)GCJI)ck`96=@tgO%qW+u^q8TnLi_CK008h7M^BH% zPca0FpJJ)OmNw+Zk^EjXAJK=l+?P^_IjxV0rs(j>64j0Zy0VZ->P}?_$A(=!SXTfD zzS^_BIyaW7)oU`7rM_Xp^L;vj@y4qU8YzL_qDJH5yYDCOy=EEir^2;Nt*l3{ijTly zS^Zyu%$FQBh{xpu6pz*%t8E^w1D6jE{q=Pr1{@Y1qsn(1-V~lkbE<47Xl5Wx$aF!x zF|&G>ORu%d7aP8G5hovsd%BDc&ZN0QJ*XLJ&;?9z=vBegdyk4bNUQweef8h`Ei5)S zV%cKm2_3H=AxT+zLWvYloeL8-I)%l{l!rOwvd)F9$q@EtiUsK)2HDLBVbYX!wGsZr zG;_>Zzzw*nZ4n7)sB%f_Kzt+JA`ns#t~c~F9!dJ3!al`T6|*&xgzB^B-%L2y<4rql z$2!suDFL`!hU4*8)@X*%3KfC`>?)Oik)U{uQeBm1hv2^85Hmolz|PkpfVMG7M_5#q zOMHRU%C|@iqH}eNy!V~|bmLL@=9QyL#AVA9b8#)%G?BI&n2ToCH0Y!F%(zKD zPnP^$L@b9|6M4bD(i9*g7MaKd1Qcl`N;o$+Oj`~kYn1t%;Heb+>&wtgsSm_TBT;mg zT4JFk_JoiBbQPJiQZ~W%5|XOxm>j~nZcKTConjY3U4G1jryYAEGqpySj#63FKZUpO z(vPJ1z9q&sLkqVp$^|zj@d$to0W6Q5nk&M2Wd)Gjt4BjiCR10Sv;Od=X9{y!a%|_$ zAq{6F>@WmRYKogI8>3^91QMxppY2$GV{{0o0sM`lksTPA8+sdFy;{ya&oFo>k@Zyt zCKo;gs%Fbkz|A!w2Hg~8FG2)wwI*^6@K%9_;w7R|nm38Es><@+T{b&jaM7c_kFQv^ zjBw|$%I1-{ya>>uA7c~a0~As!tW!ANcQJsO=D%@tT8nT#j#u}>u&lwz7WdO|41j0f znzz^u0~~LHFIQZix8Y}%7DYC2$G$fpgHA3)BgF}@@Lt}_uZU8MH2#dBldhWuzVnEy z&pDF^`C6CyPzEqL@juKDZH?esgZW1>6h2YgsoLSvg=E<;HaQ zNrq!nk_fS8YZitcbV3J#bJ-D-JDUkAE*h zgJy$m5UoiT3r}f2M0i|M*-ZO1yn9b*_)!H=P(1PT{BJ(QqP(5Ad}QKK70nUimQxS8 zgoox-mXyTue^r@~SOMk4l{VEy6V2vG2!+zLWj8#P5Leoe3e%9DC^^bk!+qqlTLNse z$PUbmRz1v1F=<1-Y;01YmrFpAWhAx%(QJ(PkUcF5nt5Da0X1+c1X>#AC80`#8d*OF zNQ907F9(L*H|;*^l52RhL@9LKq;g~~OzN)K4aN)_W2g20+7Pl$5J2^T+UAMj!J)st zI;h1vy&La>swSQ}zpH+2olndoljZSVUQ1ryXIdzIL_~Nlhl%=Mn&-x0jF3TW1Qzlb z6gzqCEzkx;9N^KXI9*IfT=BARbm6O(%}njwJojQEBQ3E<{if;(;G;`~$cZ7I9B-Vf z$QZ^us!DS^SBGIulAvs{USkmG>xIA5H&vxWv(IYb5E@3daLmNC7k?GEmRf)yeHYZV zJ1+a}Ln)}T3e_u;uj&MG1SSQ;(NHXB2k5K%^+Iic7uv8&(w)(cFY5~7g+!@nSuEdj zIgl_Ma_*Sfg2>05RS{!4>nYY1XOysSFFLoOQPv0Jm150N@ZMlzLK)}ht3NzA^2yX4 zq!}l$?Rm@BbHz<%L5Wk#mK}C-?15(;<{R3ocpcZ^)63V^*M~7}H9eCyi-iWFK8V*7 z3aJeWUUaTg>uK60QiYiWtRUZu)LUl-^3`~4bb0eGzqmD|ow zwxu75u+s(%ExN&_c!z)oOO!Q>{yMQDBvf;+h_$;Q7e4os*9d{|9o$kY-}35AkiZX(;eE%vIFf>);yOY>eV{$HI|VOg5i^K8 z(HUqGcugc~Py}(y^j=n@5DylWs^HMg==_$p?z(m_+x1F8_iM6S^5;Lhy74i5awi_Y zCI;}-@~tg8kwfGC5gEgqTAWv^R!)p9JZUi%r3CzDy_A=i2>?!gf;Q+W_&;ddQmIaP zNXvU(_4pt$$h5Oz>pf3eC5J$EuAxiA ztC`Q=K6)=cywX$RRWA7dcK>W@>Pjxtf{uk}B0z6pvr%!Ch478mv||UkNU_sFy0r1g zn?N};#Y^0s$P53cAIOx~&-+cDO7$jStj~~X$A>4{F3;OP^P4?Wl;_>})9PH_r1B)U z)Y-%)D_N75O(nrL({j*_#BGT_Vs;Rc zL_)2=hqm~wo%NNkH~xrEsr(v$T5m1eC_3x6M&s!6O^BAqi_@@Y9-&gg4t&5Gf1qg- zt%cyI&ibK<$mmkh$5Ef(@zBz*Ze?dg<;Nv=e33p(=3REjEh7TVyYMyfm~q_I-y9HV zNfpk-i&5ys!3L9BF$i0*XB-~R(gi{L9u1}R$TUHU4GFs@-okJ3+DF}UhIDrF|5_jF zC3AX)#E_`QSx z+9%{RotR^hs5GF!h-#=oDh1Yh=NJ@Gm<_a18!+@H;|=EiuYKKd|M?euY-wZf+vfOw z*`Kxq)SNphFyJkVcEoK-UL!`T`Jk#uBEgx{dAb%)*XiAE%j4XgbCnI&9C3vo8k#~h z+PR8Paz*GlZ|M~mQZUsLyRb#MY(DI&W33i8AaKd>AXXuy?IAS(28-0#N;Qf_(tmv! zK#MA{*9WQ~4LkN2jihD9Bc(NW*_zoR_vb2qPCH12mo?1f7sEm{ZhFdw1QCEqc6;Ha z342Jk2AnOD7s}Vg7c}qCW7aN~;fE7S1)(CW3_*ri zisobOWN*Zq?i}U2YDOv*CKx)iguKNd6<`ac+B}4~B6w9H5I2+rpU^ra4#r@q=X+Fc#8q8j1i5~AVj5jP4$z6KFu;imAV7Jc4P3?DjvZDV2<#1yV_`Q*#M71B zodt$MvyU^IlJd#_33;h;y#R4lo3%EeCsi2nVtX5;7YSk)86y;kmw?=(U(^GD5DpPI z&E=odD4&u+mUpuCZz|+TYOS{ZW$wW>Y~k|N$I|jD&n)q1w%=JTQ#7ore)jM{HW13X zmFd`kU1~$i-iudv_*n^v>cM~OH<$AQ#9!ITn{f9!c%W5&FB2>aUNlB+MjaX(7x!6lM6Lh~JmyS9(l-Lnj;RZRAy5NE2v+${)`%*MVF3oz{Ny1^3LGjB zHzSnboy_f%SWtCxU72^`#7C?6DrL**c3z_rU_Bh=&GCBi7(>>>(ftehsNKejYw${) z`WCykW@qItWu7F_O73_wB8l(;QOy>2M0|6ZP;NjDE&Bwr)F_e&*qJ5jP!hrn4J4wd zFuSz;d+qf{9r84M=TdBGOJr$K-2+HV;89n@II+IO^@L7)9Y$LEK~-*KF8tSaNwvTy zcHOU(1p*X|ph%IE(uA-ssh>;opB3I*=_P$8;EqEZL84=>IIoTtOP?@Dw)tq*l0j9g zlpAH>+OzeCS3hzR->`B_iT!*uX-_xM<1|hY1-tG-q4p3|PS+4N|N21$Eh1sJJvh45 zB8du;9rYxCQ)Eai?P9Q+xOZ$R>V$Qf9};rK!ynIw&w9eVQV=HzI6rHs-FkjF+1K)J z>Ym}vEm|!+=94Fra4qfCu{Dqf;POeFwTuo6zG6eOQG-fvoctSGgIeVDDZEszEXRkD zZNrRUCMGOz2asZ%fa$~^xi7MIKe4W?X`J!O7XWzvL+inxh-r!gNUp<_M$Ox5V^p#oNKS{P!*@Xi+M*rFc)Drx@xs#Vy$_Eta^HoOHAx_+20-p%DT13}I+p zH)&KL0ww>9N1?)y;?gs(Ih-eT(MXe1Nfpi@NtzXy5ZS*x^cO$F_b>HUw!LhBTwc;d zyN+uT(U8m}vd?K8^|`j(_eb$+WWPCMt*%uRLMrB@fjpQ|k}Uu_^F{bg0iC2h3TdGv zwrGJLcrBNTIKk6&);N zghji<6)?l6Dvl9H^+j)hzz_-e2-(_+E#4W8u^OYpyJoj850n1eZuscWUwte+TG{&h zo!`+L=B~OW%_)LgS9*F~A{Ly;G16XLkmYFi4_;`{3`o9OR_~M$K#MlsPcc|LTG%@f z`;?Uavr?Kz7!i!~XRt637fK(cv!kr;MEF~`nhE5utK+E|E~Bk~+3}};#n&z!gZr+^ zh`kX@(cR|)qF1PovDi|>v0@~2+W~caBA$thF?)!$TPWziV44UvMxp9RpubH0Xf9j* z2^lm`=8;yQ7o<+qlwo0a8j1VBV+x0P`O@QV9K(05JgX$e+@+FXg1xLhh6)f)+Cqb9 z;e^=@yih}y#tUr(;cM}x-Nj~fp&0z};gMQK(*pAa&V&vrCj%w21W{p#s}TAY*5F;? z{oE?G5Jo%oexxEePUEfeQ23Qxi7GE%bPfSmDHmZ&A(=-ltE1(x+J`ofNDrt>15L*N zejMICf!%-Y=n}bzSR!lvSQ?P+rk#AZrVenfD8(R1=-G5K>}8X1R2PJXXi4K&;@P2n zk~C<0SBtzAu6Qz%abPZ&txLAO{?Yh~WhV*jwDpHfotD*^I4x;Rj3cFQoRizx23|so zf?aAujoySe?nQ45$rroFETy49kQ+I(XGwysgwlIY4?LitH-=c3Y$24o!=nv>hs~z~ zP_=fE^gQUMXRT#uElZmIQ>{uw(pbM9%ivk0Z%j-@;zV`XpqE&m=cP78@_xL!Gg}Se z=?uGyZB9mj93dxD#b|x7CN0mh6SkB6Oa(d`cdl3&i8|j5U0f2U!O$9|0hXfpZ(nPo{O(sIkLn9{a$5t5H2sn*XcBp;^UnLZ>t8LsSEWP%j8381K%!zKLda6v! zAp~+#GlXU70op@6z@PA|C8PMhmFJfT$o7>ThRYBTI%e>(IC=~HCe2NQQNnmKE^n~Q z=;ZgyZ73D_oNlrAg0>~Q|ypG7k>gE0fL}(c<#D`ItT>#Z3 zKikgARatMxt_RJL0A7mE>tNftk9ullTUUizk1upxOU7A!pY@kUD(6&Qcn;tz_yp@Ip;j?zZDuufl6r8@yCKSJ258bLM#Y zDirNzaHXcQd*^*N_ck!ns%iWc22t1i#q>k3K3Cx0cjG?lO$ORrg z!sEFA%GS&l8f6t;>luLQGwxE_-0C*qgOKV)fY=6@A@}fsZt^K+p7EuhaoKbkTfOVR zWC62&Qw+uLt4*^`nFQyNXEU21L#g|N`myLu;UhGo+^yB?+jV!`#~1_o)X zJv`qFU&`%4Fc+`XaI~^qX~Q6H!`m9EuQ%uR9+PS&BDsovIzp+4FlabDR~h$c0Gz%M z=i+XJ#gm2>VbjMrxI9?X=Q2OR?o!O$M5nF;U@O0BCZP)}=v{-kLn@x;;E%q4<$s-l z8>)2f3(9sqLgh&RdUE4zjOQ$GJ$Ho|gKXnqV|1XsWNu=SkHwsr<(Z5>@BkJYjlN_QT#WMN?Kx|GgQWG&WaMai|2n14t=WDOZcrjiZ^pFfK zcwUkxgG#x8sPs`05bexPVro0J;?j(A#~d_$rXO&BM&c+zSmat|yZ+Mz2TPz~*re1EeUyBV@!$o`7h^!ZE&d>zvY39#Y(s zw-5ozNyjf1Gx-tD3WPK#hCqWu*#5{xKPG0WlbR0X&WNBif>1ZqSau3(2|7l$?FbE zaR9hYWf=i`=`KK9dxNjF|65;7YA8w-9A=HaDxFYavDU;S#8VUDbQLS7VM6bhbm?qt zj@>71vL)oxt|R7DaXtVkEe(9=$5eGNFb8K&2cO)Co|4 zh$00R2NCHfGOw$J=rzzKJLyJTo)nn~CR|oqzIoeAUWG4R`91!$W(SX(6HPh?pVUF0 zn(4oMWvUBqjunwySeE;*WQT~>m~n1N6RNRVO4tC@99dThg~WYy$&Vw$BLEx?16uH+ zC-lCDxBcQ01A0=+ZTAh2o*k5b7|ppEN2yocZg69bw&`sK)QQhz4 z$G-?)uEJf4tp@Z|6^F!bcupC%1*JAQG`!I>3Tdv!wHjNS>{=UI)x@WEWsXCF74A^S z$-}MU(HjmSNdVmtVIYTKBa~|xs^(M?MxE?OR01(iO-@`5HvW44OXT>3l5-b#9j*6G z4(jheKB0wHcn#h(&{;GQI+oKB8t#0=*OiGW?Yl{RaQYM_ZfRErLUO(z%ghDukjH9A zw%TeK?sMyBjy|1Ow({^2Kk|$@l)@YFnM-X%!~u$zW+Xs>N(+OAJ8*AfB^@9-@eY;{ z;jwG=-O+}W>~%SxH1LZ%#F&ul^6!71Fb#5zzGeDpcPC?pY( zC#}v_LJqN;n}cW#Er^61u%Ko=R)l9rlbX9MsE-^I1tNSvBI|u3F;5fY*oFm{3`<)~VQgLd7zefwKq%GCp9%RqKLZ%zfn zQrRk-<5P|IDL)UpIXR%i>k@X<2kQ-aO)<}~6YoVi#$>buIXEEuRLMXy8AUQ0g$5VX zc^7{3Bq>Fg?7G_Zd=(QZ1+ct>fC|$sW=IW!PQ#&~8?)_oPAt>A`DNh-tIeb|DnX=R zN$P*4J4CZ3Fb!}tE%o5`7XWGI72j{X`xc|;)Fj$pVP5wz` zL*{QqV-SoLc8jAFF;HOs#(1S>`>xuln-FUD!D+x3MB1Ax4Un%f#ZqE~$4LRZNEv9o zMWdHQ>&!+G&ZUb%TEcWcqo=4UY0dAoB$3%OoW09v%d-3T|31EK2JzM5r3ioImk~mnS!{IiEV=kuhq0bi;YkOrV6S6N z#Y5P$R8R8q1@+A1;6Kr{B2nD{o;wZC3spub)z(BEcM5{p4WiM0E>=4=I zu>IUqe*YB8q2y@GU5n;a4h&OEiSGze43daOaJEgdACNFe5QVYKV{9tB2z(KHlb4`= z$VOW~jSA1-SY?gt?y(T)l5~V_SCT_Kjti#x!*hRp6ux2E35L5)%6$wbX@JS#f3f(? z130S-So9)SYE!(jaOUMUsW~Q4qK*(?4bK)SGAjd=7>NaO1^~qQz`9`=>r+(e!7E9b zK-u4LxPmL$U}XRqz^Rpix%?TI-gE}_1`X)n|UOD2o1(LO^DQu zF^sNn!fDfO%-mQliWVeUQWi!8kx^mTG^iAA$b!mbJu7iBnjNgGLCIw1mdvend8LXR zyfRpez)(q!FxjAdxbZo7I_jHD#~-UBmRGSOGz zEm!5qBjbx;6fLO;u<_fWKoM=62ZxHmd;;@ne8$Up6cK7sO1`%MA@}UsA^~eoT=|0M z|NO{KO5lhRMe3U~3A`PjxR_1Mg!M}GLPIPNk*kAEje|X~?eE^8D1i&lJOHlHdQxkG zP#E&l!>3ah+AA`sEPVk!o;|}S#L`u@L3I3awZj3 z29<;=gs?I1MK1#@%OG$OLE=6kCn%~pJ406@O3hUmBSh@hZnW*|jV;r-kIHjOglH?z zxm{t!G(r~(h1jIa)m3RtEJ?0$T&hhCGsj2EXIuLfuEERkrQMl?M|Gf=rr$l&aD{{a zHD}?5r*+_r+DU;>DCwwhP$2WGr^4$hAFGHnBN`bVg^dhlb*;PePj5K?7x>N1Umh2j@%oKlN< z@q{c{Gb9h!mWF%qRtDLjjHwllcm+is7v&Kr{^h@!m6j6qYyUrp@&q@>PERs%?DCyYWzH3Mc=;SAKLTEZwR((rB!3>scE z03=M47#j#LxTJeue%DcQQbEZc+FiDKe@?aV7Km<@xN{Hxev|M~6c2rsfblF6dXOWL zYe)mg+ntruNanQEUpbz0|3Ke`w*i^ZD71k1r{n#corCJ7=pyz{1)~mWn1Die=kMg+GE9b_1)cvAE{~^(>Vx0iiKUWywDJql9Gf z)z6yRNuOP&s`AT1-!T^mza^-n$A<*`3BbQ;B#>e1n3xc7tm%RyKR4E)gYLfUG5GFf zjoQ0xRsZZt>eG~zh{-~x{U;|^G}BYC|Nl6o%#9iQhVrp-(}h^2>S+#rl!BZz7Mw+t z#CjtAN*sh#VuhX7^-mUE=Y8mFQ$%f*k^@C{*|vTbkY?*_^A-@x*xJobJ$zTmY6VyF zUlt9b$QYIZ)?~SLE3&u4K}*gq@qmccR-P4`)#w@ZI(;Syz(k!tB8M2GRa+P;T*q#H z>F=(1FTQixYMEXAYK>&^R9p>=V#C80GHh*oZq$Gg+RL!NjJNfqndvp$dEuUkyrNky zb7@kOl6&QCPXOXN1WddGnxls?=hDn{2Ov)DHObw|3!bLB6LY61kB?78>bBA%7YH&_ zPnYC@8{WR{DU{^XN>IvxN|F`4m55M)#rsxr2Lusgul8U&ndkfPmd5;hp5r`vUiG&Y zviy5vj){}AiHM+%2#heRXH22>IJt6kH1-)(@$YpLjqzsxNUeDkT+w*5t#LQz44wISu#Quk${A}>1ogu0 z2(y<|N(eC!gi@}y>@2fIi<+ppAj}T;Pt}79uuqWR<;sT%^sWH_8kj+LYHLY?6%bIQ zA=#B{$3;6g{tEX|;TZ|7aAMQXu=42xPU42HMsL^0|2J62(w*JEqqu*C_U18Enim=Lq<21i%j( z!JF7(D9N918AGTN`?Hm|65#yVSHE(=(i8DzDm(F~^~T4tXFp3fK7fxo1)&CmeAdPa zPpQu}{%OLN;o-9lBr}nWR%769aj=6d?Q_FaP>$fAf8OZfUICsQ1WN z*;AiF32eAtJ*n9oa9W=_ywNVy263Sc{)olrUWPP)6*MxjEX8jq%iHxd!IY;Hmc==z zYJSn$FHaZfM2SU&5>#bHLvo~?_>?uC@k;BeB7So}~ajnqcuN*iKg$m|m0nc4st*5B9&sKsg?`i(o-P#7Iu zB191npi+y|lBaKBK#FRzX3Gxl5F8h9Sj9)(^G)jbXioBIb;{f3EY*~nTBe^F-|phO z`K9-t@)G*TLrNlq9poW8)|i@}0LKPkGZ_P})Uo>T0Fuo?!rHdd%?t3_UPw(dNF;_C z=t`!LiW`ZKFNV)T_*2x8psr$BmCzb|bs{x{Tt2Oo)pGHo1&eF<^ql@he6h+4N~H1f z%;K5@u(%N%YdD?GktJgUS#Yy2u*+1Nn|(iyS9d@Rim&C#!F+(ET9hT`#ub+u2+)-@ zK%ib{5`?9QSDk0pdPJ*c6tZ#Az^ZxSGJcpR8(Q8Mb(LJ)#dhHDj<5cRVtZJL*j}q* zV<}`6WQG`4;45f>81kz@#Ybdiemk)K4S4ZV@l0C$pa8reZ;VAp)OZ|d6`W5t_@^E!O>YN{Z0!Xd|?|g<&yEh+Gy&uldu!!4N~`Kk%nD?7l%|!Da?5A6QqE1oa16 zh0hwm+~WW?MYbaf4nD57k&2l5?bnyK3tUmK*WHgeAiZdgcZ0%cF-*{ipd4(E<={p~sOo zwB#@rk;Tm#s3eDH?Yx>~y8<&}!Q9DxKfm|FV{r==F2`!s1zQeJ z=emmSWTe^&ZmbcT*63VuA`n`l#<2;fy`uDbytX5PL1y|=aB+4>y=7`q5F0`&XYkFa z7>+^Gt|WX*oa0VDO;lXz?|c81Te_(9C8r$ix-4@5%_cYRHb>EI=^^;Zco{dMBedvo zhbY0fH)KUESxMV;3un^mb#ul_sTpt&r3RZU3^Ek3w(R|p@^n2Xho3~S*0_WuL@KLp zS`FYes3EKeE<%dgq734v9B1kbxs{{3-P&8Vm@UH$FDW926Pxp_n=UhwW zf8$T9>0F^gA*{o0B=ij8KzDY@MPC^EIVPGD)7-j&A<%aG=n!7o_F71iS4w5$ZvJw*I)F@=i^f=-^HKSTeW@Pb8@Q;8BXhYKCR!= zXb2s#v!tC*2so1&fnXaZC=H zOn|1bI=`LA$EL@QDOwv1A3+Yq9@(~Jz{ob|HNSCRi z>(dF(Jm|r9Qe3~ppH?HW)!TESPb2uaK*F)KCUDr_b8fKG2fjsVAWX7~F|F>V<0foeMNhDVl9Z5%Y_^A`ZondT8&y+mrSG zu{x;vZPFi-0Ei?^vhh(sUJlYF7~>T#vLpUyXAF3{IY%VTLo<#G= zP;HbyZi4`jGCi$CTY{`}SWBHc!fZt=G>%H@X`7LK*xiqt@zrr19%vvq8L3m}8VpL7 z%9ERfA}08eVyY=)stU;$(x1Ax7XIvlV+p(}Wvq!U-e!wZ-w>CukM9fViB3n5RZQ2g z25h3evpJ}3-Nm&%bTc+&nmJPg*7E)FsH@aC)P=of3@u0LDs|4XpeT;qJbut|sei`b z!-AJ(&q4~Qd55-odC1erLizOa)0#i(qqdci%C??+&crvt=R!*a2DSa05s|XAK2@IT ze(Z264ZsAUTV3=ZB!7<%*BCmpj8pI`Y7{1!ut}und>7eqT5VN!d<%cVHHXZ$9L)SCPpp zZ8ZCMc1v?%3fJLtd+A=Y94%T4TQXJpM|TC1v4yr^;WAw3VOlWDNkYYh}*du;vhp?a)=b7`;IZJNLedWB#ERuyoNXDa1Mtr_u z0v0%2JV(6m`UB`4OI_=B6%RKnt{!SsPpc2F_W(}Otgla_MW8-0S#OIbxfL%3iPM6g zTq8i^b98}=G83_3S)LRcEzx(~vfwRU=4)VC6@mLl2lFm&&?0*tE@m$DOx+>Ui8w<@l0p_=|HQKKAqUjOs~7q9(8d3!>~r z5^5-NddvC+k^u6tD^Kss6s%xy;*HY0T(w&&VQyI=!`1a0n$bEy&8v^DN4`~Wm&LyjFO429Q#c-* z2Cys3#wZ>IF`i%sf8A+a`qnC2!~-Hs-Z=XYeJc#-Of+>smzZd-W~=JftO?D%`VZc9 z*FWLQmEyrKsX&-sK_C+iWS~o$qhpQ2+#Py}c?CmdywZlFqE8P3F@q9F$cQaN7I3a9Xr5*3=POE3A_Z$C1 zah2i0ujb-vjsbTr+SEUS*Ag!C;VW0qxHeIfFtvG_t|DTQi+C9@$dkhILgAl;7VVF80K%ieccFn0-=3!mk!4KveOn>p-k_QTQuPcwD;c1C)Tu; zg?@9#XI*mQp+Cnrs+2A6__jX$xst?r_}D(+UM0J7F{Hsor01afq_@H728u**06Y6^ zB%Wfl8k!Z<9Lpf%@Z4QoiNBd*Dc6Ug>z?xM$1!az8<@&Y$ykF^LL(LtOM+y^xmQCq zu77Mt3Eqv@f@~pmB2*1pv%Rs-b((R94Bb8nxd$6VDCo_#mk>fLu!)F-4wrpuad}E3 zuf+FAB!$|SX~&&EdEZkWhp$?BVTqmCVH*46@~p|_^LR5Vy+#_`hUL+4@Uo7Bu?3G* z#-38EzTUL5EZ5KLQhBjRzamP4FS{wPf>yGC^*Cw_otUBi=-Dm7(PCtGEaX z*Pt^Mnd{g9r6bdKt3XKStiidcr6(8@yx^&U1_T#3 zJJ%~6}X&s-~6Jt9ZEUz|5^k2kLFfREYPZ)GI)}n zYVZ?yytn}^E&9l^c@v88RL&IUa?!v|^@)NE+ZciaVPAV%Amfoe2=|-cf6cZ@e6`Ao z5|QkjTakPfAKRH$F{+o)+J0V+r9(xE&EyFY9IAmE^0_8623dCOny1+$;y3GC8;9}V zI>Nxg!jwWWK(H|9!u!CAmAV&~E`JTNwYcmk75ayW-@_;9dzl}<_TQfV1=>Str|0gu z6(%dDg~ZA|hsiC5iOlYle`9%{?fW^Ll5-D{g2mL9`kHX>k%SuiZbGzNDo_?M4xs`c zLjg^1A3yQLA5cigmT26MRY(Wo^66OPH8mB5F}kP;w4I>3Gl|6o?YO9q;iZ|L#j}h! zY#Tq6_Tu7DU}A`k9iH@Enq?|raLvoP=^#uP>!YZcwE#x>$XQ-EGYx_f=JIF>k-5iO zaQU~cqcAFe#-CP?^-~oV>!qikjq_9+I0`47yiO!GEkDLFI8#Gy1UdG;FHh@Qy_qb} z%3+OCD)om>rGjZ9`o&Nx95f+CSRg}YaAI82F0bJm86Bee9R3|ssPo=*>C2yvFH_pE z_A9-62Kti_x^Vy1mFp&kQ%26bYf!J$nsQ|(GN?azsRNN( z%4fY=;@rX#6T4UCMjoSMYCHmI6_Djb{WMO$*|f-Rjjz)hTPNOZ*S?FHO2B6RYKb6t+^v zEIv+c%cEsBcd2?tS!fYIU#bQ`h9l5qBXbeG>4FG$oH(AdWeP|XGcwtQc=YS1Z$1vU zRN-h*Yt*zuzbM2-qxBJ-%gB&5Q6OsI@<(t?fL@qM)VM|Ecn#k46mAJsw+xr!u}y%4 znUo{5tU~N#k=jveb#Gm^hc^jk(}WJwTZbK5lhzOb^NhJl17rFO@;t%#pJI7s!It@} zR#Q+V-D|t;oU21|c{TPqB7Rj*!qo26%J zs6p={G71ahzu?@wM~{k$KxihX;RA+e6=4e(NE2|+vF%6UhE6_7p-BaTxAA}pjiTFQ z5}LVK-B6(3LO3MD_X`$Wc*j-v#%1M|-F9-&0l55kA5q@%DizO{@McTBug)GVW1x$H zx)CJs&v@oi~ z-)rFyGw>^29R_#ZEbsf>doO)E#m8l=EoQmmDOAErX7+7Iy2*P z;@1;v@$W5KW=_t9Rj@&rq=U6!D3~V+SWDo=-!D<8$Q`}zAp&)&R7PKacn=h)%(?Hj zLzt*VUC?lFNL}@_hX-&#YOY0?$-yNQWAxHYwCE2i8D{sHCa@6{0f?3qV2w5fcVta% zLT+(p!H_>qCfzmsQCgoDoiFd#sK6i{Ix;f9Cbu=bbuzBtBl zUvoP|)rXZj9N&n#*-*7}2u=9ez6){fdaZ`~m0X*NsP0!$ZN^*oLG{5du!$!G;7H5* zE$Dg`p06qjgRjwe7rh2qqm%HZlyNG8xeB?W+G8`kpnpIdVOkJS6u-ho*whIjl$ z@BJhA)RlUuxieLX;|{e}haN|_B&QTDH<}|GAHn?D%RY>JvThddK_DR1u{M&Cc0nd? zwJ!DB(e)dy%9X2#2j*>Ca2LCfDka>^?#HOe{sEUeHcp^xp%Y~@H!DKVI)7U0$4_UV zCY}GNqPhVu?DX3bIH}o;vkvTyCAlD8M{%j6pYS)Dmsrs9{0}`R9g=;r^TN=B0RsNZ zjxo^ed>?WeMjiB*gfeXdM;#&cvS0M+BL~Ov?aR&>+HFV0%z8NMJY2=bRkkbLKML>U zg-hvdhjY-uQsu4`%9s!wCuF^f@GfcQPJBExO-ICCV}ir-MJae2oz}D3F_}I$y|pLa zarqq-&HNJ6dwg;|i^$iEBL!PuU5)9{m`HvKUOKoL#D8;i80U5M5AhVUnUQ{-_o;xc z!dqycmY4-@%AyqIBQ90EQkLUrIiVXz6e#-fJXingtUK;H91VxVvo}CAK>ng-5YbfR zM3lS{h(?!Mlli(7=dazl>?M0Ct+F`(gyg8Y2R37Yg{nzM!FC59ONvwQbIBA$umVIf%WQuu?4>a!(r^DapssV5=eq>W9m1-qI zVX(z&l7cJ^Y;QmEUmo}=rSe()X+?`qSE-|~46yyK+h@RVhnzjq&(+~q8o&NScWq$r`0##r&QrN^%LHV(#(suItXC>o1$k+3Gxvj1`+6GIz zA|$eM8*shWKZ?BvGon;aI#`9o(Tbi49JPZM>S5>=YGHyNUGW{nhM9Sc$s8<{!Z!}l zSK{Cy9brV=blvkGnWjnNiBHpiN>wED*HVIVhmYSBg5H&33|FzDN%B;2?z6dyx43yhI`x)(3_`9(NT z0l$}3PD20a$BbJ=iO9ur!dbVxT8>=e65&?xc82N^xd&z77Y|RJgWcZs(O7#$ktzv~ zgS_n8OvJNI#q$Zgdg}rf7<~9S?$%lJucLU2NlyNFCK9_zCB|XS4y!KfqlZ$!CfHRy28_mCjtR*NBLTU% zvV?2Tv<8qbYLC`anTd)r5G|#%GVEayK^}(j)}(p-*W}w|Z)z`dm0SC?8^7@cf~b<& zhuyXdm#q{_no|shxyaUGiV?)}NMlChTFVYpk&&EVA)Rk#ZtN9F3|*EOLMl;{$bMIO zVyZ|=zGeE+6jOSA4L>7x43B}$hkj-6faD{KkS#fj411AXqEZH^pusbBhcuzD6VXGs z{gSIzkhUsYmcF~LTE}#2<=?qyaM=@7dSAqQMbm_&;_8+iDo0%8W5<^UrzO2_Zg}3a zBSj+!IPs{kv^d>|cZtYA0yecc!S6faBrZYYa^~DZoejphqY&mk{hn*y&DWp%WS$;U zSybZeY&|CpR@wy?VewisPVl6`O2Yu?0Q`6c2D|K^RDQSNl^uyF^rC-oVp7A`;(dVz ztFxERT$I+iXo?2nykO(!zD@zVnz}{lJ8()KR>aTgy9yenz%z79W}z;v1rawSA#@4u z*#GW-SdJSin?>C{smjNkuY;$C)iL+)*2{(qFw^)U`od-+y>nH1tUIn^GHdKTI{=lG zaKMn=or6*G6(L_FxoW>A%dA39oAYy^M0)Bwt@9-NMcqZ@pD2;0sL6))PdNXO2MD?= zB`5Rko|*&kT!qhC$_^Q3L@)x{5Ib~{@j3jq7%DQ!V6GWkOQRGCO3Dd^kuW_~J{Txr z7xhC4qnvqF)kC!tMlL6B(!)AUVY0cW`Q+DZr)jdgO-u%N z#^ezdZC$ZlWr4xUF=DTDd1m_w0~=ZBU_dwlLt({^F)+cM~;#z8fJsS3oD2&eZH zOikv3e5a2{9$p*|K}KgH$wIp2%_$xR6U<+7)#{(qxXPxycfVT2BK4w)>3VTH6ahXQ z-z27$H-juh1$9QJ^)562O@N=FNk@=E&m@S5Lwm@B;+qoU?h)%u1s5w{NVCuQfeI4ZB33|Glx=}#OHO_qnk)^k4C6W zw_p&`6V7-vEI9!FrUwH+GU$n7=G-N_d?cMw!Za`|hz=q6v;`_1w085q4gZhmN?A&H zzTUN@HIqZ5;H$v@gqxPMMt%&KKGBYoz6E!@DsM^_5Tf50F-M#5@{l7u0o90E2s0e8 z2HL+NXxwr{Lk;f5oXQFV(-JQtS~okwCHd4uRQ(-&4L-oVyo@}L>f!E zCwEzjo{@>}{Mg;rdEX(W3$xaZC$5@V-J3#mVABv~C4ehZ0*YtF{Uf8@WPNa1k@eXHiYT{TCX2aaYLs8e;Oh6^Pq zp4l=`=h7csXaf>+1}>MKAPDtyNOX-ilVFQ1N%ev$R|r&7qr^J7&biZ-#-I!rBRabY z1|klJ6H~X|b0fw7P`FIwiWGB$bV(lg_UjiOi<_$OjOSKK+QwH(vJ*pjsMi%yVHFp+ zM3{}&we|I3>`a&$C13^5MY+N@VvFprzKX(+?4GMr9X#=u)GEhFqrGY(aupf zps(upYZ&h0wKi043NP>82hH7omvzg48D*u(2BpR zGIL?O`8$t2tXI17%Jk#CDVTMlCBHGe?=}qCzU8^FJ(rz6G%QjI}0w_*;F0Vd_*|5S6d7B$y)t7Yam0?G z`38WkB|R($U+${4nHcFFbC*XzXl9=VRY^aJrTKc0>O7^bV!d#xfmiCsZQ~`pVs(2CdzOv_|7}Mx^4sRx{MMMmM$cUS0x7lQH=s0hh^+$}hk09Lj`y zom;i#MwJNxq0MV70#!I3%n#XSo7Pw-7ut{r!+n<@0RY$Hx8;esssWsD7Kb1YXpF!< zVI1U+^Iu@i)TnsnoI|X}iK*90Dk6ju%eHxhqwdDE@d@`WeTQssIi^HFpPEAfaU?1& zjl(yx>Ve)gB$g5bSM=0;Qy?~VZ&Wm7MKg(F9N*n5mS)PQp$uK>fG&cokeC?fUKlpD ztk;$4+AqB2oOk1ESGcCHRhd4cvYIE)9cDaR!#^Ii=)ODB_DTrI(22SZ!8sm#I8m@v zw~IvSU5RxAo*6I{Sug_F%m(~*xE`r+NWkM>3U}t5ZAU*-po*4qThdWhEPWc1esw0DZz`Fq8H``&46uBgi(mcLjl}dqMLNLmd8-5-C0uZZ5oFxTdIc?8_ zPx{_JLz&99wCuLEhzH>E-#r)X5_%2ZtTW@zBD<2iN7IHOIq_DcQzs1Gh+qN;Y5~Yy z7OxQxa3QS}>rD`e$;a-ba5=C-yZd?Pyz|q{RLi!H?Y4D@vwHU*#%Fb>%C5Lo*m{15 zfSA7DCugB}N-rLoMPs-ULx=Hr#p=+A#{#@3`~XOhoMgZFy{u8({7~4Cx-m;n6entL zEoq^U)79^N;5Yc{r5#q^OBRK-vV;4cg>(#FI8BtmciSfmHZaP+Io2!{hh)hk0ra#N^YCGJ)$s{s=9w>7B^rV^qJ zKzXWE#rzqVwtRXIG=z|f`M&mt5`^5@`lMoZT9}I@ymfy>rM~~k^#=JE3 z{-LVD9NY_ixpM~cXf-fubm0oSCI z>yXx;e7vi)1gm>M&Jn8+T{Es7T6W1UeBZLYmb-0z-2S+H5}sdSX*Y(m$8qk>*rthz znVmS`apY}yx7F6)Yu=0QPrfG`M>HLh8Uov9Bm`!i0%Ex2L%T%*5+kAhFf>Sa5GU5F z$BNxrFLf>QIF#B;&id5CD|m!!I|Ffm(~9j^}HoV4I=Eh3&^o#}K5Z%NA26Cy+$qD`bG7CM`2$`K0lvmh@OvAqs>7 z>y$&~PJls{*Ui(?pdfC`$dDXKfU{aE$S-fLcHP_w=OlW|D&QJs9jcvORx5! z@)9{VedIussZ4*ZAN8x5oz&){+J;xdN7@%H0x3k>#5yV1P>Ab~97p!r(t8ql&x9COEIb%crPlE%b1 zV@CAWYbe1bR37Y78@Ug2?Pzz7l+3q&B+D__fN!6YIE|||a@QGWc%(+2>=(RS1-+Yg zs0olhi7_v4dAEfpn@)qd^?R@H3!LhKvivRdzU=>LH>|6GQje_# z!8)id<+EXRJr4UieEF-;(=ZcdC@HN=_=@ z{rg=1W*Hc~0pgRp(EW3Q03}_K4c83Xsv=2LjN5GWOT$xEbb*R!6KV)PTW@3Bw6s8} zjfOy-yl`1;`Seh!kS(}E5W+P#8f*~hgais z6+ns;_CyH7ABiXRi0mF|zO}0p?MQdBo1+!JXpcBDG$YJu=mio!$u3(ua`ekS@XQ?) zM2S-Dsbn_At(|}O7>;$EycwUjyuJx#8=3MAmCX{tEh&_Fur0!*C>BV83J}oNI1(fM@%Ay^4B9?GJmzPo3?Ig-T|d|n@yJ!FkSFmcq@2z5}4+?ubJ=4H&{%m~*5qNbD?l4HQ&#j?To|qokJkp# ztI-a*_6fXDT_PR}QWx$%>E8r74G^_?S0cD-X$x2AN!Ahg%9UGgUkiz_A6#IkVxB1F z@t3_;o=-`?p7r3M5JJYw!bs;)77l^RBxOGGWh{m@sX*WcMNrbr({OZty8sph< zo=xi;OPJC|8$-A(CgJd_%we;NZk0v3*}ur<3VK%6ddc z{_a2P0i>1?d){QLc^#l)qxLv-FKxk|1R7}tG}^rU@Rq_+`u^5J`2f7ec;w1BOIjXM8gZE)TB8iPb5^~ z7ugwW25{DwE`MN>w_8F8?0Kr*F6p?F8>5o|ngvFHIq!)4yzQKqO}$y^G&I#nwR}Ry zz_)l-BBxWBedJCcqmt012c!{et-WDd9i@?>g6}m;jI2<5WP}cstj2`1Wx@I{QB^C4 z>Dpjp z6jhscqA&B?@Rc?OtBVDK*$IrE5&Cu~k?TTrtgWyJRK35IcOPCtqLfnL;yqh-hdG?* zqi`*gu!Yy@JekN}s23C8z5n>iV+mR+y(P+I3*_cdnQq4?+Y{EQ6v@ZJ$;becu#1ef zdF31#2->N<;Ur_v0AsurmTD5+oAVD|DN8H`vN-yT~kC!TtE3@PyFboC^RCq#}cA;_-O26?3o=J&1m)Rq1H z^#)q@v0cuYqR>KVO;K z;Ec%lfV3>=vDD+X=skNkBe@d|nD;V7yP7LhU>VjFWGw-|jTLRm3U*tb{PEW^QL20k ze_EyY9F?AUIj%27D%ICNG&VdCh?&%j?9Rvf8PuqFsSUkaf>#H;cl4+7L2@)2a~gCt z?0%67i=)SY1LE#Y8ICyjgq_Rru4Qw{du;z6tOOsU`@S637(POV49v`o5XdKWh8c7RDfB8sIo0AEH7B&UFdgbK--4@c(My+4I6Vm%w`1Fhrmc(<~M8b-w zhsyxOYzm$(NckXSk_eY*ZfAL#{pxA(L0pDgPfzWppYt)7Z64jzovddCwu6E?t#$yx zg`XhS)br8Lu5Us^OIzII$0#Gfq;O?fPS1P~o;CO&FgEP`Wm|BRFPs+P?*X#M_PsvUH;WFA%!I_?GUB9q;_Y;cFTb4NUHbnTV6i?XfRdrqEX@r~kh zmCk0NA}W=l0w4*{PQjY7twLFH+_p9~8>1NZOK<`^m*16}HAbnQrEk%5b)f}+tDr!}_xvFr zxb=*w(|Pw#172%=$hK*hN!yCXAegq*n==Ju1Ivq_w_yWpq+5-}*=&%f z3MSR$6T;KV$R7jl@DTE=3@)MsI*J09Vf_)YATfe$W*HJa!1dzQ#`WW1?cT zD9B_|NC}Mx8RZ>}ip7hGexaDA+<DE107Ie zSi>q4_UW$}o}^c447*j)tH6MV1dBAruzz7wW3(Or$?2ZOHp6eb%JJ;ARWYf*`B9OK zwo_^AKm?>DfDEs=TjJJ0EeOC=g&GmvieM9}vF-TfzkVsj!1af%{$*6fKq`6#xb05d zHA5}W({yQ&9vPdQkIrITL$u|!Hq3|QK)3gcc_$G}0WL=#U?h9y4HAo>+Yf9v*;1Rc z*P=Rouc;jptHg&y-fVTG)WZ}5F3!LL)8gEOanwr8gyx<1=nD>|oXYAyn^jJ9F?xna zqeV(|G3dV@f@^4BMr=x3ZC(5JhdjWWBT~|2nj?%9pwdNAww6EwJ5nV#`f``RYaZW~J=9Z4ISPti+z5(b4MZ z^@+{X>AXwo1dc6-Z(ZM-=)d^+_20%# zR8B6jzpW}eX45?w_8cAFi2hXkCvBo2{@ibvA$LxI0f*Z_|u92E>-~?fJ?p8>ySmb1ju&- zCSn8x`)AON-;M}K%&saNU}-2%ZcI;N5^X4W5}#Eq)JX+;mzJc(Nc|q?T{?2ut@zZ+ zQ6&#K+yA$UDOp}o-Wqoq4@o*q4hPiKIQX($Pz_f0LVP}Knp^gq*Ox5bwUv&hQac3*`OKK*(!~nInif_zE(c2B5j(7yk=J z#VbXUYqx~E^kfpamQhg`(Dujfcjo`1fXZ4<-=zX#HVy%efGX>o!m(0rF^pIkzpKHG zjKJZxH>!LCUMx%#gOx=YO#q{;rs;ut;8vN4nIP{KnOI&fHCeu0%1t3BciRAwkfmgt z;(fz^=xnTnC@7nRbpub%St6Js8+MUh{)`jfxRmaNKBm>Z*uqG%RG3>>R}>hdl&jNN zeE@rc+Ho=$P-5WU@#N9|NlfgSHw&=%!?4s#B0Q>2IVMDuF%TFY8X5^k2X~k15nj!4 z^MeS?w3G$)hvUMi-oO4KQf2ujzFn&@u2lVDwxvTHJPMS1AXD|=vA70WbEF1ww6!_& zWV~>7a|)(G3YQYdY8@&VwVqzK__$xN!xA$iln!IRo7-P^*iXKUH!fS$x5pM;vdCt4 zgFbA`QMfsXSCxSj^c3(y8wg}O-n7R`TF$E*`jrx)T82A-ECF;oP+L)_sJ~1@Xj!|$ zBP)^ysXr=2Btn}cD+m?rgrBp>Pz}v8XI+5IR2CQE+Rv^0NE3Hc*@Hi=3URe6gj&Zq zj?V&)+v4)0DgbWar+{!<+7R9VUMO;a4`n*({xrm7R0QP$^1wq0YeX;?p5~$ZA{k%{ zX_Rv`Ql|AA-1zCPb3cbqET!gbnIm@Fj1wsSD8wJZXO4mPyE5431wkVbKHzQ3{Hs zCBdZqX>QfqmR$flKKke@o->fs1;t2oG$N zEvC^{1CZDvk$_7;#l~_EyCypHm84CSmMe@Kl8b0w|C9dfbc(1fgnmMGg!FA6!o?6y zPuiTYEBm%4`D4Iz{J0G_@fN&t6;uG^h-iaUNTVlK*=v%p%1!F6Ln5e7TilG_g<+^~ z(HT0&ZSc4nfaUGU2D6EjP#G0vpKI}_0`Ft_+F6UYpZ`64x5_v1r`2QHzCngioB%M5 z)}ehuC<#lzvU)8$d9aQ2ts5^VYEYbIPuv+ZTP3sxU=)+0UegW6J~JJ^o9)Lx{zySb zoEC1qo165}l0xbO1-aQg40`UxFo zU*9()2|{dwlCvrpVuBQh6 zbZncV+QK;Mvikt=$tHM@hS$T|c<%hnQ&Th)Yj8i|@et(~1B4MO%}%UEUDisI2ohhL z0`4#@LH#BiE<~b@Pl~i-e$aT6;sAFJS#_xmkS2zU zc=WTYQP+Uv(7ZA@9efADS`%QShAbGz1+@jl$=!ClEzp}}O*VCsk)A$KFcyCtfX??R zN+fEyD&f;Q(|ZX&?8j7Icx11^8urRqk(4RBIOd)I*ry&3Nt8B--J0U=tc!z&*CEwD zPY#m#KwC6_Reb8mOz%>3CXB^BBn&Gd4t?zU|KxdqG>O+-z$RREU9e^^cKGCo>oY`| zY6LE@d%HVd`4D{fN_UC=d^Hmo8X=%RtB0Cn^#X;0Rw!Jk>3nG$frz}#3g&PqZl;bb z;TYkibWLOq<|JKB^=h#wX|~`2n;-cr)i1Tu4I)z4O#()89O~ z#Mr){Iqg{$($)AtWd>nD(ya0P$vgOn|F_uf{hJjVvxD_PVTyNjNPZc=o8NccQXIKIA`@yORoI z`UKP3$g>1eNtkpA-Fx%oAJ$NZ%9d`}LQ9ERb0{J5ID&K7IX9ufw#aci^0v`|$hn-N zkTx{&?_NC2oHVsd{VxD#>JIncr0}G8e>o4AS5I$7 zKD->+8enj0qoI#>4FVV1UR?heUL5gFQw?|oLTgP41V;h~rpN_X;`0Qk7D>z|dsCqE zJP3gVro%=<5m$u@1Q#DCU@6p=w3%S^;LA)=!+m@GRsor1^Y^{-+Tjo4>sOcrx8}cl z)cjabS%dix^-@DXG{J^nfY=Cice3AVZAXrYfrVkcJBq^G?Ec!5?gwR?{ICk@J z7U5I9)}y>;Y;@Z`9&DR3t*9k)v*v}i4PJJOOh|T=c%cVWgv8gg*xa|`Ks~9RwGp&~ z5J2(?XOYF@bw>;`1I7sd%tRJM3jQa)ROuoR0rcQ%6{;haQg{fo7@tC2H1QKN$(uX; zcBGd1B|%^*|5ow4aczCXI}ZK@?xb{j?2kzYL1WGeE4O@1rN_{rNHZtGa>rZMtRZD| zx@<|~nHB&=;Q|2ZuG!Qzn)DB`&KVO!8I(y-;HHT!u!Pt_I?7yBHym*17yBrxl76GT zww-IP;MB^SRBYVxlC@fh*|{4M%d^ZhgrY+lTHsN$hcOw=<^#&mUZyG$|D9%HXFQ}3 zCC{GW5B%Z{6hLKPW7~UR(v?}CG+g;Tz57l0=oQ)tqfWv-Qs&3#q`|aGmz&bNz&;@k zb!ibJk04eX6H;z`Uy;HJyttlJ*>EQ%DT<>K3e6$Y+_b- zS@-s+T-c%L?Rk*|6!DdK45Qm|%OH7%Nn@~HD1HP{Tj$x?muU(m;cZlpLARH>=)^;S z_Yw^el2@7lT^c*?|NQxzDUE+9(T>NcG#H-IwFja1HR_wuP+d6s87e$h>)(W=YaBDT zV>1D_JugscycTa9NXH9(@#G|Sq`XSk#!6tN<2h*uJ(HJSrJ7frNmqLjcz+_!N;G6 zPpp)5hwrteazwRi0fk*;M78a0CwI-i1+P?}uLQT?Z8B4Om_`Olnd=5+&_!LBd&bj~ zGgq`Kk;N0IJ{8nu^m>QPx@gHp{e;JnqQy1PZjdn`@>N*#l26nx77_N&{<|)GF}>;H z5_@^F+6$@CRZYx(j$o{ZM}Xxjg1#b5S&!Fou)>Vk(cZnPBDe8Pt+7|XVUA}l>ZA^5 zEj8PhN3~LB=oo>d+T%y;W`P%e0;&f=fFqM7@_@i%VIl=cXoa289x(^`7OsK((;PFh z2fhGcHx$?W6*+F#z_TuR#nFf3hAIy&k)myUdx%Ie%3RD78$5n z=-!N%YTtlR!p0lh*EGt(85AekgXYv*B-I|yIR1vv?J1UIo}PBXDFMSzA$^l@rz264 zhLAaOA>4c2y4retwX$l>UR(4=GwjCX*EA*`P&;--q8T>$;~GbeXVQA&YIGxB+2^s* z%|ZAn$C^=2<~$^DD7YbPiHRK3+7d)Hlmc^_6SRrgOujfBDTzy&HFj? z5L~Lutmn;t`0OZdq3j@vy|y-L*2C4Rs_GFlq7JTilnN8UXXGr!B9vHB!m8q(m0k5D zP@R&;XoU83r)lwQ{sF=?7m_bgHlV`j1CjPqOEp|xm%pof9*a0-dnflEukLDgCo%i3 zR$;w^!eZ8J-^gn?@T>lGT^LsS^+1>90;%a!+cwmaLTu=Xg49hQ9(+KXToH$^g#1rXiM%r>f@?3iZ;nVGsOrgWsH!0j7|qb z|2*2`gJKM-=aUD2?Tr*<$zfD`Z2=O!b_atQw)&vfj-3j5up={En`+cYXM~wfeRXo! z%M(HDHY4kMs4O=976KIeKz^0FsFLdWFOj*h6A`I^aKMOvDD*@*6KMcE9rdx{iF7IzK~#Ngx;CLdo*s|wghlk-EfrH&Abe$24Q(0oT9(dR z2IjQRjXbl_@_Vwx6;6*NF-b5}-BIdQduI}j;PTk=gF}xy1z)YQs6=u4l5=-?6w=^a z9y2|M%9ZB}_{M^PsP zNm_3V;wG3hB_+v1CJ!koL8ffRDlwmN32vQw=#n!iL7p?%>Z(pv36gDh3Bs$7Z3J=R zew|%cu2fJhxz>hW(dxC-kSD@08`UjosY)Vp)XpWCcCLe99U~3=#`E1LuC5^8IuP)< zam=BG^Y5`7)OLmIf<^1<6F-(>iHq&%&;Q~eX%;SN_T0O64i%5hp50vesT$zDhZc@Z zYC^k8wlDOm2D7Z@2)CtE)Uo&uZYbZdXq_;NWhHT#cJliPczO-MQ|~0ILbnnj9j#hb z*1Xx#kNwl)?YN&(3d>eEaki^tV!EYMomz*mGYR0n8JsAd>Wo(Iy7hheVHnt$Zq2Vjx^k%vXjt+EXj#ls_hoM?b)|p{2U6fq_1u7nJPfR9Fs$%4Ky2LGTD8eU=H~)4@{cL z&T3b@_u}(b3gSw>N_#>wjHG+=Gsp{qPbd}vO`7=?3RD({sYJ{J@Vmeiy^8#lyJ{K3 zf@)d+sEj8w=fZgWIaICqblVGEaO0Q)qHrwV&KCO!g)C@rGFXb(%u8J9s49Ux{ zsTrH6SHZyZxSNdGt3rx=?S9|w<2_b>jX$k1@T@t!(I!4mIZagp_q1>teo#V#OMQ)h z(MPX|hv$^qK5a;#+bYibKqIaRaFtK+N4xEReP`+Kc*kXcdti=~pMV=|zO@F(xTp2< zX~ApdNub*>iVMbkXC$6N<+~ z=ny&O&`C`V0S8znbJujukhUzc)PSA8$k}zR^R_`;SLLxy2 zA@LXmEV0Do=2%deoOt1mtg-&a=nxJdXv}Esfd{0I8K%g|~k64fBjh$A0pQ%AG{TDM$$*DFUOV;Hd0)4@P&Z4;LC}fukm;puetG zTRJ}cRaw?wvVm^zMDkpV$jYHEI5Amh2pHo&p9V1^7RJtO6^jez)ewyPY0-$>9_-2T z!D}m?@s~a)Z7q3bE*Z8CN+I|r7;;p{jR1~GKbOLt)vuoZ3hGE%XrG)*DU4@Qz+xHI z0P?T7Gwzp7rNA)xvb}W~UFTt56v^pX7?IN_30eCcuf6uQm(1rKKf1&!ru2@P7%ajP z)8hE=)A3VGw$}S`z&rAI5VZrf%@f=yHY^m8SsqWQs>L9I zI;(A}J=J~E-&A?X#4bS|lt6y!MoP4hb=YUc6qm~OW8ZnrpYY8poQ!XEvYS*YWMm-~ z?$M|&nrJphqEgG@gLQhPwob0J5rum3;!f?$miXiFRk*`IrkVyZv1d<(HO(pDgXOEN zg2(o|n)i;qH}bnxmX|#1Epz{@W%5)esWnHnJ|`yzy)>vgpiv~Jd3>ToA}?$t|2@I1 zn#pAG$)l+Us1RS;=v90lco)OO(72#jorNaWbXnf_&-V?lqAZ_OB1_xYc?d4kZqWL{ zgm55&FsVc+2rn=t#Ok4$#}T5GRX*J0+K$APlu6(^Y5lOfH%?V3ffj&>m#3Lp>*Ge= zi@S76Uy)wQqM>(~97y0Ui@EYRTs%AOc;C`(_@Ro?z{tC(J4y zUYPmepYBi2!)L-hriGdW5D{(+OKQ$3R-M<- z?&_hdd!Z!sM5)Efe4Fs+5QH{OyH)D8WVva)(7VhFWIVZc@#p$bcw7+<#d6I#;{IP= z#YG2|$CSw8^{P1}BOr?*Jg0F^f>DQDd6+Kt`!$S%@md@D^A@~Z^aq+v?GEG7s4j_; zq=M2@%fF$@#oh!d1*(gWjyr`3R?(5kQ?6d@7L;JPTf(}oNfF@9A5Uam5iXW{kAKxo zf5CUFl=Z^CArlK?aASDi!Cbabp+H_o(oi30PeHzjmkJF)cWIUcx{1?Uk`^qt)!40D zg$CvyyvBJz$C~uO;yyj#Q_L2xiuD^ZW2mkQOo6r(8YE?s!=;=hpRSGYd2mMf1)hLK zx8+h?xZr6QodLb798{uQwj}vbT<#nqhXcN*dYaX(T)mFO)qcO4s#-J0kxX-Y=`KBZ zOVS0IfHqyK#dO&rAgvuC8}&2Jtl;rRNzenPw|8V|mOQT_^mIWS_=V@6%k;8r@%G*e zRGsEn5X5Lp**4~!o8L+J$SB1D_|X={8$(LcYi3wbbFXMicMWLx2Bzeak?jJm$D50b z!kZ#OvU@1hr6{ieobd_4g1IPf=zq}LWCK%K7txzll#BEz`9Sf6eh}FpXxVb=^=_g6F zfUpJMF6JmUsw}j@QA`Hu_<@E%m)C;#KkSLe;mejngSV)>B-jBN4a?#?40yPpn4$px z;X(~`GbcZ0Zh3?Ty`FyV*ca=nWM{fejZ@#5jSieHrgPX=%CImsf z72~Cn#VPLE7NDti7FZxyI9PE4F0HMHd}!$}D6O)-$ct23WJEw+P+H5HLtM%1;v(x{ z;^O{ME^D5-yokuP=|ghU922WBM6DpbSc>UR9RZ&BP%7sFG~=}rKk4isA~|FsyZa(` z&yEDioVjEJ8KF(^nc66`noB$Z7vz%jf4zm&S!pHy(&X{F>NqZ{bh7}3$w7c&tdAT0 zzr4M9fL&#IKYq1V5NnNsHZIjm6^K+26%|oxCYeAIvdm;c0Ke+Z&CJcrBr|iznaMIx z6_;AvD%Og)AWfQkYmMT9ODlDab&DoJv_ESUMcnZF`8?bEo|E&_oUb$fF)VZD z+_#JkR^Q7+zefJ@S3Hc}-Dw6dk}MBRh7^$z&tNb$F(*UFZk4l?))LV&sk@ zQR`32R!&{bG|fH}2saK6ls{%`r1e$?VbydVQ@+%rjpfy+J@%L{KA5rdzwuM%<}ROi z0g|7?2J-|%2_^h_Q@et9bi)oQEg%#Yi?n1GayGukRpZca|MI21`1r~mgEu4_>qRvl zB?I(-;ULTc>xfY&xY7dc$tyK%>`HvA`(X3a8tOBh7aiwnsVY1%i=_rU1T>L;9W^k? zh^?lY+_V!0>Si;$RJzP~UOSSiYAMsu*tj-7Du+LTun) zOZ*qb76sYT(jz4rUopD|0v2hi$4KN;(7?y}pa)~<(m5jl`h%e^)Ef)q!Ax?Cn4b;+ zZxJX@+5Huu^ou?_3s*Ufpo*l49wZd`#>TT=@Uqu))xX3~*=PPsW;dN_bW3-deWN_T zFOS}MB3^0X6fazcj2?hrFmc2XXAb9i8aRH2ODZqWg7>RwT zhxII8gO;1aqP6#Y($l$e9yV59`SrST_HFe7x1ehf$D2l7^TGHv7<%NYb=!UaNj?z$ z0fkA|;_s4SXyPpx#2Re@U9}Sn?_W-fUYc(9BURFPk!6#JsFr}?^K@D^ z!EIhCk~sA2ZNdThs!waa{1*~BPN`4?n~Of@if}zvo#n_H26BIuc;mc9#D_t^B}n(5 zk~(l2W;{WRna)QY80S_CvMd}W;VRXQu@N_NTQ=l`>xa(ifn z+}<-Ua$~+7eI>#OCY?(1P_UKlHLZY)gvhvbpW25BR%N@UV^E3fbJKvLP^;!%+)fl=uk0RrdUWd}ymuC}E?pT+)m{ z9##QWeb7Hp^+85s-AEgPPn1Nk#MPAl7l6nLsv?@hP@l5}Z?}X=TIR9 z#)?+84?{NNMpVx`wNifU#~m6!dF=oh*tOOaOtjK^Q{wJx(= zkNf5qWLC@%@$6-=@b4-!hRrz{Sm5?Lfe)0GI_%4Wl+GLL3CySomZe5H7M5Jw`=Yr$ z!W2u*uOo?x>QpRt`AZ*j6PdkA1^I|B_C8!J5IptvsquE5 zCaCw|UXRfrS<0DE5&CQVfqwh(9>^Tfvxu*r83hTIq9JRp(iI}T@uG0}XdNz2OO{=V z_#AAU0P@u8SC(?+vgBV0QWZIi>vRRV=9iEAuS@X!RR^knch5X2$kq71bue~nYRaAk z8R{{^IS`767s;6oL9^iJWlgRSmQK2x!e7AQ18PB$Oh#FWN2jY84VdyzJ`kvHue!RB zHtxT3K(@_QoR|1rJ1jyJ3+J<8TMHB@6%tu7LxFLyHKD(+;cqA=pUkEaOSgd|r6QY` zB^9fz2`0nY8F&cu%Yn7*xnV*s8{k4t>iomCu*@jzkWoh9Pq632OD#?c8th#3gnNBe z2(ZUhK!i^wUBXy~VfcO?aOF8FleJ;|x-}`kt|6owaA%LdFvCge7lc=Kbzo?bA}L<6 zkQq=bZKVN}+GI^NC=fYSpYzd7Vqt%&%#mL-nM%FYTol<3P$J7Xs8zajy&qI|@^QSU zE7rbUSDY>Gd2xlr>;Qy&Vu6rYvA+XT|F^c-9$vFb{|S6pKhm;-CKzL=ZJW~l&5X=y zIiAZF8H`hHR=+?96>RQsqIi_tnbC!y2f|=IbDg%xw1MSa9Ql;Lxvf@Qhi4s~ zI-+SV4p2C##M%uEc_g%EEeZY}M?RQAJNSwM4N0=E)&;4k%x zUq9;qV=b=nTl|z?>X-DT&he_*slV2_YwNzrjaH4$AKH%iK9BCIP#KWg0rl4n+1i&u z{-)jN&WwUg*R~FC@i(2`^OmzNV_H|)hms9CU)g>(_A4wu31bT5-BVd+y5p@KV{II( zJ33MetC3sZ;OU>(AR~4uq4rxaW|$< zESdZ8LaQJciwx!R{S4ly;^dCU*@BKC8o3fJe*BfsUqdDO4t~l?^xfnc=5#Km8xd*Q z71FMx=|>P&EF}>oNU{!SI%A29fE3N!6Dvf7tEL2nI?TVH_SMasPs8_AR$CA10tviU z;(%(n_X7V*;I&15Uz-5lgIm`~+NEfn56Sukya2&aO4Ee#_C{H$vqt3e;3b>^r@iNO z`;z0#xeI6;kSqO+7gmd$vH!NzZ_o}rOc0VZi|7>8zQ<9cZcWVSno`_IaICIJ3UtuT_A*5>r{0({+yLx6=#=b5_pB%B|B3)@hzmnljLbp7*D;fp^`lQY1slGg^Y~ zsM;kHp~I8Pz>0gtA1KsL6E+NmWF09TbY@5!mZvrxCoDY(Io`;2c4%O79m9hb zeT>WTmd_mZ78#&-8`e~ombQUuT@dUx^C+gMNXjkUx0#pzzaA>(1!Q&f$zxVr{%D3qp7&H<=b?FA z=R3GgEA%KcjAaOfVBpp*>VYd@R7nX~jbPQ!t;ELRI4FQk`CoXyIiV=~XT|f_{wtl# z5q~Li(kHN%*#hP0YH{1^AN(S|p~f%pQx?~c=TThS@qN;MAu*O7)B$K4gbtyoD`&H$LB!;<3e=zY;am!^w4pao+Osy4 zAnxNM+$e(hamrW|QS>9^)rw+fuWg3bpRF{Rh#1{MPV+3j{ZE@TttwZ1`#g*6qxfEJ zQIQk`${fuj8SA59P5dWQPgEMlbkaK9sz}kgoZMX^BnyebDKpC0XhIIv(_t*wm1!TZ zpGpFZ%)K-Ifbk}&3(E0K+@MJtJ&5bjDuNxarn#^k0#OnHqvV4k)!(cxwc4F+MOIPlNx z>C%sU<(%8`5S5!P?@|HW3zz5Qvi#r8`EACp7zdtq3a%N(g5%>1TsM;6Yw2SI}*MGQq7M`?f$N&DuA4ya^ z6C*2H84B zdgJ8qlFc~N0USZxX>Dx3pG3w zn=n0&0xD+fBc8Q)ZC!P1Wm=PV3V0Tp7&ZZP5T|rsiXJB5scILkK^R$R0c!axpLsVS zkt*7@_uCm=rXh2??p;`Szq$l~D-@)7K7*<;=U0-AkrJ+N{bSH&lm<8xnpVuv-t6Hi zwosF5pDq#B+=Gl0U(e2ifNvq2cp4Yc-d%S-QBH-en0>Y1PVt%-5fMN_L|Wc=z8FNj zhxCL<3NA<;EqoBXu~8P5UFg&jL^uz5MIHed!F{hZa6{I;#*B~)D_-PfM=H6;QK`dq}SP?W(o1>xlg{T!4E==$W&C_yxgykckIj@(4W_QPBk!g84_kL!EeUE#{ zso%nis>UDhKQ_6abJ5%~(FSc&9?G#*F4P~&A^msulEXUkrASh3_9%SS#LTG0u8av= z=Ka1JraWm7@*;h#7;b1SS+A7gL73FA$oMi`70nPle1S&;lN71nYb1rcC6lV%_rz7OC0<%?r z-^)7Dr%_l5X0soe7$P9&7v_ayWlP7&9FD1v9iL=*=cp`@;tYL-3rYd^@*lt`^-`xK&wO0;tkWEmK<@dYS`MO=R|;K#2O|2v$dE37#3mD_LrF<1nKA>BYZ-k)P|>(CzPt0 z!xER~#`_E(xR3@^h1^d{2DA$2vtdgr{sjsT{Fyr=lG~ka!-!Mdlv0YW)7yq&^)n@djVw^W035nc0> zuRP>JJZfWYg~FYdi3n|^(x{7VmD3}mLB-O?pfWhxVlB?D)lj)l;`Y=H9aMgFLYM|H z+aWB_eWsaH4#$)g1k|a@Ey|m)iq@~gLOA|S+f4%V29>qJn@rs{<%3}Qjv9*p8E;d1 zqdfR+dhP$dfa0u}HNF3I6(Th?V{o^s9J=lZEK&7_lVs&_c7#VK=PQ_B#y3ThtvR=Fn=UZ!UX7zd5D-wT zbG_@k{?G0jrJyPX0q@UFGF#mST4d|uwjD`ObaU9-i1D^9K#<9rjQ79dZhO~|lv`IJ zKV-i`(m|uHIL)_98nr4;(*?Ki z=6xelemc6sV4spSY#s#nLI`fPbCp;P=;7>5gP9R04BV9UG?4{_%phGBFI79BPuOse zuMFr+^*u8f3>C7vthMev{OXa{wi9B!^Ipu6~{p?iM zaZMEhGQlc3INWp!^R4O>P1fS>UIo#iKoT_Vch>bse{8NtH!1k`;nW3e>gTK4bM1Hg zIpMkL^uzs&=Xq6^<9qv^Zz8*-ZG7qs2#4{oG4_w~2U8RT>&X-^{WDHg=;4lETnl`t zOq&OF{nT&_CLl02+zc$G%Pi7~2+g_fx!2#^!ARbCK!xgOhqA5i41<4M$Dz(sLxs#@ zoL5@djv!ZRxYx_@t$~GA5XCH2OU02M!H?q2GnvgP)$o;~4VeT86d+p-SK7*=3X>AG z;-g_v+A06-Jz%j|l*F^xcgV!eIjt619!UB{e(WR}e+p#EJMDaD&=6 zI{PFkuU2fz*l&l3&69ZE3GpmrxyM!8{1_dDBi}yAUnoaODkDKR)*{O=MIFR_N?}AA ztMD;FrietP zad*_cG*60^O$*B!&3T4|YtqQO?%Mn+JYppk)TeSGud$jVCZO90I9V=EUIRf!uC!)& zrG{j#$IYv_$EgE27yPqi-Bd1FZtiEIAIO_X5qhk*1#ToHg?_p; zyqy6&J6c4N43Qx|L`wUCR~$>5!`^q_%TE;ctSZ0npI4E+0wU|7vtdD15x>AViBgtj z;Z!w-Fn`qoV5QcU5_w1k_lt2kSPm_u?xcZt{yBPt4Lh1}u3KDpC0h8^3$G;sQFYAF z{&gx5HoZWJz$UIo9uT=bDG#1~!NhLn$WCJSLI8obbeTzgk%Ww&Hk1L+$Y+erQGA1R z$v0b)1@SaOc0m{<4!BE{>kI9>+X?sj6MSu>s@P$N70&%aN!4e$36&h>9Xz-57R-Kn zh7_J8n5|q@<`x3w&>N8s1uSAmI>;;E7={ZlD&3q+FQbEd!Pm3gA)5+g{C3om@^4VM zWI)j)XYfG#CXfD^G$fu?;e_qPvtzN?)w6IZ{Px2d^O%@V;8JU56eoeS(7jh{pamJ| zB`LP9J<_I7X( zF#QQs_ zny98OodtKiQKl16tZdg7GM0%hrWN6q!1MY zmG;|NVDoBM?9%D+$2SRBw}SW*iP*j@^A2z|l6sjF6W?n=%iH38N?qp9Gw_HoX!N~u zXfk5UMRLXe{>KkKji;(?fU#4*=20KsjBgffqy2Ivcs8M5JEVrzi{1<`x;zV zA1D7rN`RAn3>sf@>f_(~5PCAKFqvhU(>$7IPPoIn@SpZTova}ae3|7Se!r8 z#Q$Ua%|sWw4!S1+Q%!Vhk#`@&{Tsv?Xj+-PBVSv}saXVVS8%F?BG^U)9H&gfq9r{ZSGFZY{Tj3HMVVBg`3x~fT~25wtg2` z8z635HvOprVfj0&6Dkp`Nkl@GA|Cq-ASK?KxF4FBPC=GJ?FLQ=BC=0DjNNNmAT%4h z;x#|G$I~gJ$5zPb+4CwR_QHz476hD-i@F01`0=(yj#LH?gR)Z{bT0wahg%B=P??$m zlJV`;)Fl;yRjXC#nMT;fCDVMLp8$N%W>}pYu~{;&4OE&E{H3k&OjiEUPitR=i~Sp zHxn&cmkgp>k)?HRi~%F1Byxv)dbF>*kKXmY^S^T?o~&`d3UO>t`lI65+B|oH=f~wX zrt;X@+A3FS3Pho;dRYXtLhOmEnqCeFklBkOMCzZ(%c)p3*kbicFpvZ?NKn;Np(4IG z31rbPUNcN2(m1g~AUjkbOzQjE+s2TQj$%5COM_c>Ch=>`ZsV_Oh~i&x=Nbf%6u;A( z3&R4)vwm?nfdp`1C~)Z7!=eeKCRNGF7_>=4N!x6INMyU=@ntC|al%baSzWq#KUbSu zE}r_(-SNw-QFjPdw6)pSo}CC%UP_yILzsh&SUEG^u9b&!4+p?3U!=Z7 z2*8lPDvEUlB%~w32wnjwv2glujtK->DU*uNGbrS&S!SRL3}Ab@hb)LP|BVZ1-q~ixou$x=$F&s)#Ct$Ho(Uy27T^Wp@U%Ui)CSP79w2cUUBTSOBAJdxTB1iaK=JAjdI#lBpNb#*w-KSH9Ti! z8RrG6G)Lib|Lmr1Q-zKJP=wg>gQiN*4|SySR(u+W8V%xMT!w08&#@HoghQ|hg~UL! zD90zxiAH;mw_uVomN=y1;^ZfW=ORA=F?$P(ix0+&WJNG#!KV6Fy=MIeiicT7IrXx$ zorn|HwWq@YQ)9-q;lx{vi$o->BO8|c`eM?*={4vorQ9A&u_zr)itXh3B_T&jA)hSYWNEO43ydW)zJ zUC}LA)mAw;rH)8g9A4`kAPJ1&{eohp&WoZ;N3D7s_*iF-!Q_EQ$}>~=5!va)&0iub zgdO`gJP|ZS;f?E+3oa*6?RPGig>OFlo!rFSSXLnzJKAYp1oJU`XTL~6V}YuKGIGWQ zLk|r5Tc$wS7+VNQFx!r3Oa0FjEJY#<--vYSi~&#{>g}O7k{+;{r!8!mBVRy zQp_^Fu04da32J0rufUDEbnT{a(@4vN;rJ%{Xf250>K3v3oLq)Vf?Jhda#K=xc507` zX{je$fY6%S1sm2B!MVna{NzPfQ6nm2d3Fww$z!E#0rQy7ltE|FfJo-vuo|$CrPvZ= zaby-m9@b*$M_+GBr|Gt`L6yuA;dV~msAvYDm_akz0hGt zuX^QOb5`;7c~*JbL(h8V9Tdl(RG7@Gb8!Fur-x$>r z3GY_2@xX^ic{F{4g_m;FwquhP;1Z%Xyfms(hqrYjRp6!nhqi9It6u9olUF2(v_ZOv zL%}3)$_{~x#$!E(JrRV5_1VfKq|glo0lw@@S3mVMIjf;!5dZ!w^v$#RW}WnMVx+`Q z_Y8ECIMI|Ho`c<;HQWNpy`_4_1egMuJ7A?DqduVB*xG50L^&jhw1vHz$@B}&uF;_E zj9=nP%^zpp!9N4MucBtfG*)~_1yL0=J(bJtv}g9ej=N{7PVd}rM=3Fb9B7YoifnUz zdn(bR$K!$y$IwIEPuT%TQ76*85+9&UuT?Vb1OqVyVp)ZHI!77v9mbKU3cv_0(3~QL z;^cR2@An!%v{|FQhT>pglw(aKkc;Jl2S4v>K3wB2{FJTeO{z}h%sJQ^Pq}oA-F}f- zGabO*lUYtjK%;*hiCm0Zds8c(R{e86MuC1$(<4xp6njMyc@)?u?%;JFgp5H-ev$Ds~@fg^mmgSZzNZ8>oR4CBhC}UwUa^ zEAGFYuZw~~>fo!|M&FF)r2i|}-fCqXV{g?O`y zgnSef0#5s|Txc4{M56r{UIJ&;)zOFd;xktaN#HPGk!tfEX|W~7_d}`OOY@#zN>oKWnuSP_P|2>yEnIBPdw=ox+bOn+ zdEWc&6e%Xt10(IQ9_EhIm}NSKbG5eO!$<4L>m9gRR^Y2r9nwOgXD)zbF&QJa_>?z; zsv{Mz0aXeQi(1|~*j5+k7%TKis2H&u&5cTPfN+rc6e?o*`fQ`IH-fpCCa1skhz_2- zlE-_SY8Qhx#I$3ABU#W!j;z~57@53jUZTU%OEuycIV)|8&C;}dTpF?>1+l4q5~yD& zI&G#mBh)HM!nRUvNOK4U)X?r^$WMlLvVv;zX)d6RKiYKqJ?N1t&WqV^=W^X&1jNI) zCJs-A2=2DZK)un4;i>j`9i5VHQTSkPD^MepauOhzmV&cIBxOK!HXx*(1xk{JJ;n4j zX)Az_OSEvpblm!?5sJW3B`2|Any|@b(>UvUU*dj=M#X6J{nx1S%$sc9kMCVA6kd2v zwF0v^oR^>q0doT42jgIt|KCdE6~uVTxC2eAlV`2!YlkM#8sax6ANsaK+TCF3=-)z2f|(TCx63xHsc< zJ$!4@9V;#9MzNG)4#y=LNrjfa;oym*f^W^#lz|a%LwlVpZGp>IVH35|;A3|F(Vy-A zHCwS7pT$o(_Pt{s1+*OBw}MHK@=0VnwfUUgg5p<3DS8{It)#fC9^>};iCyy73*7B@TLX0FQ{@8i!5?cQKk6n8PCA6eMLc8^4 z6X=+PmLouW7-Heg1jG&XHRN*>?$jD2RIkX~v$+|58!sb@*o7UgERCc#r0AL8z7Vl` z!^yHq!P#>3w(G2P%f9o-ELEAj86df177@^NX{rVJ%XwcIc&UByF2TLSd*1c8SWqQz zXJ^9AgN`v>=_l0&GYCSHe$Tcf5RqUbT-yBxQPW9FuZK5lvuI&!PffRL zF__okRsp+VASrSb7$-a|yVjx&DW#992ksF)3D2{5jVJkUXjrtw^5FV{V43M6l8D4b zt}ds=8?GGRfd_9?4AR~IzRb;XC~6Z2mCSDGM$wzXYL9J3j)B2Fomye&ow!v(u8$4? zQALI}XakSzN@bupsY!QWK%3wgvJPhys-PR^GneBH0%nH}i_F5i|dMu zzxm#OqPVKm$_^=$uszb9f~9shH_^fFx<%4QdIYvY!RlbaYjERQ+1Y{?=)%}&`em~I z+Q=1|B{eLk>FlIRSRRTmYye1XH&g-zE{YyX1+qntr!^6|_e<4IL!Sb)Qpztmuc)r@91##j=*d}dr6wh zwqk<0aFpUuwUgOn1vpM84iOc0jmIu+y=j`l<5?C^JJMG9_p&3#b?wkQ-+Py|@>F#Y z+VODgRN2s;nvIRd%svpP$2fLJAXkkl-;KC8YIN#wU?VUH^w-iac}itz36?42Q?o=h zQT23K*#Ic7|zqXe_OO z6(3dOoKu0_jPL4^O?u(nRh8sL3uuzKt}{T)J39@P_z=%YW?)lF4HN-y=CHH}B>8s1 zWHt!f(>k;N#MEiyp(aYXvSl~B2pjiX`r*f5Rh6?`KdvGa)0_n%JJDQK9$G`*X|jWv z7%j}-+&b1Ct`$mez}*7UpmW+LAEJTBNgRMsOw&FgKq$5ZJ#uuutW7(^n)73##ON{w zlLKOuV7H>QhNZ;ZIL9OWog&|)=`Ok}PJ71guTgYWV<>M{(Xl|V0ndxvgplQ)JaSw;$Y!ZZhYCV@U#sUB+JBs9XQ5J=t6A%!cpAK zwL3b|Z$>~ntG{pIq{2G&dNwWf5Mg5-UTV|4IK4;Tm(lMeUUo@@#6BbWkLWG*B8q>c zmQTVL#M|%_S6x+h{>>MjG=N8{V*2!+T_q;#ET`l_Q~eG1tm#tx$pV4LWI$dSHSUvy*pOZT3MC#X7>ZvWSk@5OFg zG!?S{ed40_Smz>NIFThT@ETg+_1cl>$Cq{S+i|-%5fAg;U#XVucmS_Ao71c`oJSr` zUyq`+)s585q?d_cC(vQUe_#HdJ(vDk_Uk{q!ZrN2E`RRp&Ko|ftA8z455f!-nGKao zPioyMNW-w}!vPH0#?=68dC}2gH|;=1K4xeewu6Xfs4!*EkvAfiDoO6N0$i2R+LpBK z-M4q-Ts&mu&e?A!lfY&hs78?rASfK}jE}clJFp?AeMDTq1^ZPn7vo;c*|&5w&uPc$FMWucR2IIHqnS7mOoeT_Knfld{uBC_6|Sw_azy zM1EDfq!`Fawvfl}XYp2+9HCe0-3j9nsYs%gaG=W?Dr@1}#dO>4eVd;~F;#V0+R2U# zK67?H=7sN9alHZ`>Lo%TIH~aI&SGit^JnZ9lYeuSQriyQ zWYW3EKK%hI6E-;W-6fjAbv%P-Hb~XS z%Y+tqob`;zC78u=@)+v36XU2Uo#g&dILOpJw}rF_T}^MfDHY*#yNe(msAaTfE;{oC z&-y3@Sv7X>hbl;B27c3HFR8^z1gYzCp!C_?05X-SLwXtuO(@6?VBwMzjL6iq(bm6&=gm!zzM^t{7 zR%J7i9i=wE5@LZxn8D1kij(mgf_rg;4a_L~Pt$*4g`sU! zA{Gu}+NUO`ev^pXk_Z5?sFtFSLPq68Z3=J8+rh%d4OE@>-B0diNx5+dKjl2*r)rT* z#OA7p>lt5Hb(+9uF2hrhK-A()-Dla47Jv6jrL|iez%{K%-TYXeRHbL zng1(J>dGk)=T^A#J91Y(I^H>)-8lh|Ju$i!IrtWI#?r`6*?}(E_7O4I&wP@u{loZ> zz%htf3it|ip>Tm(L(Ji!lrE(=vGCWl31fuZ!Q(ghEiIMtQww(j!LtN3OUsm_7I>kd zgdsNGMYi1op3g1r=C^!iSOq3>O@8FNomB!ox^Np}2b$P-ti^2)q=&_FOar@^39$YJDe{=Iee$^9xB zKb-@>Lcd)plXY^wtY%j(bh*p6SmV$2rMNf`?Y`yQ9y_ zxES+epwLJF5ISAY{d2UIB!U(s!_t7)7qm3s3AT?J;N!XAMs~fjb0yZ$AlFcK`F7kL zT|Ng-{lOlSrX+o={oF##*mFT>8|&8s`jhJqTeCh@PxnjKnv;tjHIp<*Qdfj?Ja z(Awu_M$Q4D2 zYUwEDgA%|o?w)GF$zb@a5LIyY;9$wp8X4zW(>(n@x{qc&sUSTL+*bv4ZxPg-O>%Z= zy$l~qhA}qB7V32>ICG4M&1M{E1xkbaqQI{1A4m_Ta+r>0`my-%iK4Yq4|93! zefXp9`ZgY{D!v|Apz@GHC|cB(WAaLK0L@WT-5t3_>5-_&Hz%i%iq^5HcjJp!_@TYB zV-8OUZz1yrH5v3&rc`K`KLOtuQ~o4O``flp@CYhRlo4hW`q^7R&uMX-V-i{se0#d) zf;;s2+t20Jjs~@VuemLOU`S zP!`XNDLE`C4q&|gJv%k-UMgOz`v=(tH(Npn_ij#6{#I`Az znomWwovItO_~oxY(re$Bm=O z(xS+}He0#vmEV2u?Rc05&#Nd4;fX2)I*|2ps6G4#;Bg^gw$tv%<-+fBAn(wog3VW{ z3VaYBx*_1b2JcYJysOEMA5&xJHt_;uk(gsiilb)8+}6D&*;00zy9tJa&V-{~KjG1H z|0}ma!7^m!(p&z6XCM1FlwOtlJyWGOcRR{Vf+G)63H}4VR}iguSZkEmhvalhTO0>R zL}@i&mViQUicNUiqB0G|`!d+85mgd1KM@Ker4*#4l<7iQ{OO5no zGq={1UpWF7wq-&EcM-mE1-D-S&t#;qCnPyQ&Y+zuBm=e3s?z@>qE;uAmC=~9lB(A* zU}L3ZvQ6ks|99U07(7SSky{7sWEj#Kf6%aAQy5=2nJ-0F4ewm-Oh!GT*$idKiHmtJ`nIS30u(wq;p*XT(pUnb4BEwzQDfYKlN;Gt*IJY ze&GBRc6%leUngcUH)AwS%^+^a{s~@yf5e3&(OFv}8@krnwtUCYg?eORy`V${hKsj{ z&FYc8Qb)`neVBVGH}+19W%Pm)P_*O(6$v`qvZ~bHzj5ki<69}2s*rl&JW7Tc&8l>g zPeBgC0qDb9i6l0{v3A6P?){#Wu;D}#9H2CC`NqQ8eKN2zMHd}Zg=upZzL|FB#W-_v z`yO<|)4oojRP1>;&{Cn0c5!tfTAQ5iMvw5ram_V`fQ{E`D9tsveRc3q(aPwEl6n+F z&BPZPwlK4xhzR9VgGk`hBnkWti8p%@V9ko!=CD^IRWF4q0!k9yL1;NKA=xLj+m3R3Tu6~ZyaAsYW-i)ZSc0|Ze5S=_wrjXVgw>L8~BHjkd3bqSizik|gE{1#BVJ=hvy&+JU6J=EGU z#qsQQghb^@TQc+ITGO7`1bikDTAa&=04?lDA*#D5c?d`d#L4jR&DMaXVI1z;&x>W8 z7xY56>(bf%U)#SSLj|j7{ux!C`IHWKvn=z8qn?fx-AyhsrIb9>va2A`w>_~BnEV2r z6Fe7klMML5zcPneODfKV3AZcRivPbS1|b;{_=x z)Jz#h@eGaK7kz5C>2E;_hti1)FuompUfBAYjI^OWT~&!hhcK zsm*xEs(t7OE}lopupgU&D##^yEW#O1I92vuH>ofrh1}Wak*l)s#Bxi(RmP@kJb|+~5g*<;6bl zkFr=cq4!F)Ek`Y2E@bL)0s&bL1?{pj8TCxmCt+$hxS4hY!h9zdycDCp_$DwKWaf;s zL;!)EGSP)wbsiYFB z9|9c(f69v3;kpTQ2DQe#oMzkwb{tNbRt2LY;zaJQr;g-}T*h=n9-OfPTH!T(FRX82 z3WTfN#y@@MU95dn9m{dRj^&tV`yy8qjVRizW<@%eUX;{rX&c9oO~J!pBQ;LJjxKB_ zF@t^$yQz7th7%vc?ftBEIJ7EK>fFFwxW` zzNdhH_~&xAqEXcd4T`?ZA1Rj2gm0jG(V>r>Chb}k$1{THt(qB8gQ8 zjmP7v!5p*&2JL#}$dPI9K!IWAYUxm;Eku|wU5UnQV+69?%w3V@HLgRTs3oM6!B!j! zO*4{#j;tp&<$#&y_e#{%T9D{61PP+XE%1uJXy3IE&)ev)(6^VW1n8LY)zjrUWPQVEr_qyH7nPnlL1=xPOcii0B@VjYAS82WxPTdFq8iX^AfkKaxw@ zAy0@*k_9phxr$zM=P@slW`v_EB>DRQJa?Q01|q= z29(%Nsb4;@RAt8)EAle7s?T?pN&~TcNU+V;j%SYTg3q6N zCy&Exa0_WUGW?^8;l8-s+Xi#g#cnok5eTQ|WH65n9DyhLeUsQqDcq~@!F^u$$Oj|Z zFnXaS0k*ZDg3H%kF^G@uxx7IG;87ui2uo~H!UrWo(ki!XfUFR+d<6iS1O=*%$z|`% za~C`wkJngLAs0J2g$6gr4L)0}gw158l)0lBSA(3mUI7Yl?@9Gz&`kWwB4vn5>@Q1t zfzlk8>nFQ1!8;)=!i4%+^@P`qQg&)ccMdraed-bi3@Mai4t@Bf0iH?OIHy9EuSwBh zo@Dv&_-3I1d^@s(4$%@uP|K5zzETx8U`iG&3w&q(KTv7SjIxZ~-xsqZ|BQU5d$=~2)b1yrb#Lx9tz;u! zJMWVE6uwzeDP#kAsh(*$R}yDqDWC?3Re3HHD3|U^k1>JSM}8e%EBu?b*@x^6yU7+H z#0%P{xl;H*RL7u%I{j3?TCVFoCT@7v?0HQD{km{2dBxBT z55$u-zJs4~1bvGNhn0$6B!1`-T7qtji5MeKDtSmQv^L3w8qnccxVID|oQ!gt)ORa> z-&tdy#H2M);r9$1P0#RXbpfz)(HD5e+P6==8sF78vBK|MtqWwaxVJkofku;jR}Z`A zQJukw2)}nzPYD{Zv1LQFPQz+a7mU^zyuXxgm#2pqR}Sq>RXD1OyjrVKDBYCm2+^67 zdNgqRpT=c*r6nIE~O9Q`<4}3NtODft8^uh z1Q$7+3{(nVN%9vN+o%NiSd(?FC|VMBL4%v12BXkTM=WC|SL)=s{TpeGjvd0EK&2eD zWyr%CB@JthY(MQsGZbBwd$BW1=3I1d!uPF)SHugpV+FG;If$juHRc+kg{e`Rz87k# zOoH#ob*UmLmz_f)90^Yq}R*t#m?K{4vu9* z&}+Q)^*GlE6NEfPky;h@uMC3ZoWz06b=nX}+w}8k60~zx1wJxU6^&GcebG_ic7)W+ zEH#Th627ut>Zr(MJ+|=*5XU5E#{JgQ=_z~mSYQw>H5G#0g}3{w8_$}g@Tzux*!dOQ zy8s+~QF{{xCxf;b9!8Gm;%nj}a!|bp)RE|o*i{PFkL z#Z-05>VfxaIAq2=7o)sNf_W)Ec3lcU&M)I(Gmt3$BdLSCo4hGOy-q|npR$oki{t}E zBk<9d9BI1ZW}On{YxewnOb+9!DvsW$;K*k&eRBFWZHvdHKg4F;N_Z*q;f^dZ-O{d0KU zs#91G{M)>Vh}4oh5E8qZfM|=Zs5-17@w#}^w!9Rb*!|^O(IsPu!YAv$Dq;z95!}cP z`?44Qa>XV&P4tus_hDyE+!N1u4q!sG?r_K92u6#yM_S|Crlx++NiQX(csFi7TS|)F z2arMp5m94BgnX|5v0a*&{59p+z`<0-avlJjt3^k=@j73o5(NLbD_@pFVKT?wXE`cq{W^UX6 zDvjCZ`8a9BW$`fla!Y%#yQzgBjB!`>klr5LJs>0Q-Q|(?jiF1LtHrEHj{|_3-3$g~nw8xj49l{oUDJ3RMy^ zbvxR<=rjM=fF?CAtWc+$vgi!G!QS=KS-p?OjU(;NGb1}(+9?Gdgr$3)}}2t z-8eNdT~ns4m#pv35LRWIpmnu$CYj`%;L)^8&ce*B4gfI$KX))y45hL=4rM_7K-W@i z)A~v?SNl>aAEbsuAhCSmCS9;+9Jg!tm$9SxdpD|;3Tk|gafR&tBkC3`P{4zP1Zl{QmdUYd(v>SoQsN;=2tp_iFqAKV_MGUS&e+XJvbQv_p72)1GL%Y>1Gz@Iq@^ zFVyf~!?<^aM`jckU4inIsj;-#Qh<1cAk>rgU9buLL zgV828U1xF?@W$Zpg$lAVE^|_*LgJ(VX=JocMtf@Nu60W!x}Ldts#UfcZ>x7%?VWwt zNrQOo%H4hcrLv;d%+1i`lDyb7X3fYMO|Q5^2M`tnnc5&COP3n2d3}!oGf0l26iXTe z8fE!*3jKi>*w5nws9Y!`ANt7Cg&wQgm}E2T*@3bW?V_XDf7(2Is(sODCp-x&ja%$m zYqMUfVKC3f?fRZ2)H9>QGGd4!_n1gUEoFw@z9mE;mc}_HQ0?TkAp(E%-XWQSST1mL z*)EAo*FUE3H+Y;zRV#@Nw4X;wTun(7dSbHrxd!h*KvB7Y?~8y0dqPAi@~rU7bd*wk zF7F7&g{;u1cIh2HexflWkJ}sU8HeOVoqptoFRlIyimT#ervu+sYnn%KeE{FQtj*j{ zUO$W{Hb|dn@hp|~iyvgM>kk_HS@OfIU!2V#GiO)uf<9DkbjfTG@pghJtp2>N^p?<%a7vkn$8>W9Jm8?l2n1fA^U6lE5y;r<5>% zddT4W65W%v8)>Ty0Sh#UP3oj6in|`NL7Z9o#^gppfOo?@^+B6R*;aP?|9Jj|z@rIQ zaMOzBOnDTcCRm0V!PVb3VwJa7LUCBC2v*Fi&eR7^<<#>q4L@i3hL>SRU=3it8c`B;pl!pkh4im*SqCI`CtBlixkfnWE}GoG z64ZN6Amp2JQ{h>arit8Ot@m(bm<9pfjV?H^w2dnOcKk{!?;PTfeML$HdZMp324t@iM?2)0Y^~JITxqDy%Lr-V1SDPSw4)pzAJFTWSpdn9&3=zE{CZwr7s&YCMA`PK9+D%^=&!vKj&2rTShNh0RIH zu6ixgKM6=kWNE*T8Z!Wnf=G`6+$iAszxP{D{2Fn6qhi$YK^t>T{XZ9Fx{0dYj9cYG z{oRcG(j{X6syfCwoSd?AaoVlmGxfnKFE_pr+)WmSXfdYzA-BBe0(2?s(V*1D0VzY( zT-GL48MSA};Yp@0s71#-e9_A&s51|DxCies&niV=u?7JVx~io}A{Mwee@rZaC3OE^ z_Fry*E+A<8))7}06=m`)DsKF}E131Ore1}7N4pdV-PX{Uy4 z9^LSDN{(kUmR!!kdnT7N=PLF*eCK%_o1*->nP0xqsK65^)-IN#E;#~s(i3i2(Ai^Z zT8fqO6py&tb?3ID{(2K*W!1jxgU6@@SofWaiTNdLyayj^Ej58ykTF|-ulXG-cXLmo zsSvuFSj!VUEF6~u9J>)8k?LcnQ*`bSif(6@oGitvV$LtsAP)Ok23jP7v!^@3nJPu= zLfrF=AD#CZtfo?kHk6&&{JGpUjCPErs09v<6=|TYdW}ba%e5Nun*CBMVnT>op)=~r z|LE^>GBEie|I3hSkF#9G4vs8aD_+n|erjG;%m9cY;$iUbC%>c>XbuxYR2BJW{=fp` z;tk)}CE>rKFXQ0-k{3I-vmIz>Rr#Q1md)fStj-uJMRhXzSL03%|B8CWud6bF4U3bm z)Q-%%1#&izjZhK2)TDjf*>JWZx&3f@`9-yTIDfb#IC^->1S?&&`ffY?$`k@i@#cd9!ayFr!XKzRofqQ|?nT2;pIfotS2LfIT`epj;(A-Ktk&w35lr7J}F8$TL7Cwtht(bOo@Gn#WXhnGSI0x-;4Pfb^ zvke;$QF|B#+fzpeUVwX-5tk>VF5Ht+V4^b+W4y~e%}_5a=@Mg9 z49gS;XH1%I(=tQ2;tS_L<1Z+OijAHJ7iNaQ=>lLa1_npQM~9*}jtEhzQ|OPI)=M>f z32_9le{Sri%gg`-`iFaPub4qZ1wGPY>3+qsFZOB>X&RN$OCPRuP6rc{t+LD{U#M*O zbo{p)!J_Yd;-vdgA`iho%0}?e6r|>IQmAcNxg6iRin~?`#n2Oqe-S_+El+F&Nn$8N zfx8NofeT#Ao=I7j`eEhtBs5W8+Gm*YUdcD(w5jGYe5JBLnj#iM&z-M%!fl_$Gd3zt z5tc^f}2?P+!xr!=j=e8f%N(v-}JfdCRhR7hu5 zN%dU|Tk3gfQLhJs;l$7a0>I!C~s=OuWrf0|1<=0~_+i(T9?iFOV-wef?C91Hz}~ z%T<3{>hj4E?(#DpeUdnnGb&8yujXa-AH?eW^7m}ez{=VV*PP75h8nb}$tifwZ=uh| zyRvm69OdRM{s!~BfrYVzz9s%YB@n6|((3K}G60Al{gA9IQY^+cbHWSv-SwtjSV+}g z--9Qp+*lf34M){nKRcB*@SKQWBM^6{TJ7l(G$)@jJT(exZf2y`ILc4rQy`eM8gFgY zTr-Sb)~7=$g+|xR-d=%l>bY%(6O!7WR#YwOJEbourESW9&A{q{;Xc#ZfJ4X$)US{-W+`Wt(xYKhuCRq0rI~k>(04^tXgm}Rs zShJk25t5aCO?g2krmMh4^IcBdW?Moi}@Gr5~vT^SUIi0R@A`V*J z0d^}C`Y0lJZwLq}_z?QJx7JAE>YVU;3t@G+tUTEKF-L{@=5|z>A=9Pi*9 zs}@fD!S8E;o=b3Rza%(#9+-`IS?k2{UEFw3Yfn1crp1{9b?(!fDOq9G9dOpMmf)Zp zpx5>iaCQMK_}Ra$XU9<0c*=uzjKzHD0!OKMYq}!#yeQy?;Q^Hv4@K|-Q)Ur7Mv#uj zePU`hPBGi^XMx+oLBRL0DLblsDB9Q-BSp@>O+1$?T$kh`F1U^B&U(bdXhaXH(442v zpAoSo5=qjG&)zV1<2FzXKQIt_1`v2?*GEbbmV=Dh#EUXz1MR4`;oaq8k=2Xp|ua7OR3`yZZHuC!)&rG{BugqxQZ z8`wdpY0zNe344+;ONBub<{T|QlH`gASdU!F9I{e39^it7mEnsB&8`;nduqvJ^SI!B7YjEg(?gpLwwIF)j9LIXh@#+T<57S&9Z@-$3+ zEJ!@`I03$-7I8Q(&~?$!Bn`ZR^c=xh#^|X z%6~fF5AfX>2nGFF`fk~pB}}P>lC?1RKN=?$LIEU9qE0`9Z5AuoD&w4@bReb>=N?j- z)pcptoMs@Ys=+3MoLs$SbMq_vu#N_2T$lCloJ{}hxWV3bY+fR>?uQKyVe8V75BFk! z+Iq=vB!_}3LGyrf5t*=RX-y&HryxP_f`zTtCq_9e*AW7&SeCT4S*7Xs5XR50x7l=1x6*}ia+3=M17yTqEMh*4)+&s0#q;L?0k}KMgBLAKHF)>0*<%8Z<>Djgfai}iAzB`V6!GB;eRc+u0 z*Qf-K!R6JX(`@zZ#EHzuxkZw$;R<9KD+(cUL(_=TaR7Debq;wChb-g z&4>rrtN1u8Vf7Suf1qSN(S|#j=v?F(aT6EEak0f=02ui)!HYFwAe%a|;$Zoau6v6E z9M)k40m<;_s;4Maq9Vl0z@;=$DWQ8aJo0|dc6P%}L=4CCV$gha-z$-aZv;h`8M8Xd z)J3AvK+5$LBkE74hI=0Rm=~}~rt#DYHQew=kmI}Y-Mv24M0885hoYl-NhH!fkveq+ z(#hKDLldne2itcQOA%U?H*@vb+wi_fi6bjGN?dz!B7Jhm?6SM`s_X80Iv&63$hd>g zRM{Pi%d2ORBQklxc}^VT+ztMl`-CQNsWpSax>MLG)H$MqHGS^hEBWD?2IP!{ERsnR z*C26EYTg2}GJkHK9v0~H7a2ShoV#N)ZA-FMy9b)xpsoAly9CP$dUMI_y~lA^a)?PK z;b5nu5lyTCS3WR<^F-Y$S(=;fXi`+G(0?UvOtmD5fL3Z!OER}_0n2oQWUHddx1==i|?v{1n$%Rr=VhYrG$>u0gWW9Rs6$erFT+r?`!X)39r; z9eS-s;M#$Yc9vGPR#S^)^0E6r9dATqnEY z+m0NP#DTw?jChymAnRlE<$#}b9v(t6csK{XSvP5bs>I9c(gj93stowQZ^zW>=kje= zag5KNpSS%9eBCl^bfAmL0$#QWEAwq?)9`Mx1>ehmTIqoi_+U%h>!28xTn9hg@AbWq z`U|*9N6|1e8iJbu3&UA~S~Du(86>?7KtLXO7l^CQ;;}O(9*8AXrV2AELbBBAFgn=D zgQ05SF33`2H#=NOr-c)|>#@|N$a=i9B8N?qnJPLrT3%hB1d>z?PwbbviA3Cz>4KQz z2n7KvsUEgk8b=DKCZ($8SW8WO7@m|B(NJtLh96cal5Am{iu@b|i(#;e+p2T%*(T`UC?VnL%zs675yW0s<^Wfdt${>e# z_ybMbK9zW_w%xdxNJ$}u2_}h2<8DL4EOsNMv|b~L@9c^3KXvZJQ^;G^J^V3vkgAh? z587!;B=7s$+s2RrjgEB+6!av1-P$C-uAwQf;K~t?)NiIx?h6+`B&bCe68tI+A~^gW zZDt3i#ra5<*)TrJd1vn1H7k(nB<@W(N8nFJZLVgDvC zD1Iop>x8W&N$`Fuacx-yRzos=Qn!E*Df7?VlFr!I>Hj_!QrRVK$KlYD`nuB7fm4`g z(>d&vANEXgz&}R^uHPS zq-XQ|oVrQgM;yFMWaRz(FMkRit!l94K|2oTp19mM3kueggoof4Te{Po&8_wr&-@!k zp4-K!C>(%$YG=A})Hq1DPHS|iasHXdmgwg<;?{LOyfm{cHh_7G>`fead+gGL>Szk3 z`*QI3qvPy#(ZY0L7q_IJfZt3BrJr2O5CB>>*j8lh0YFd|LRZo}m&*Gd{l&NQJmAV^ zke4T1xvo83sJM=8!*S7@+Gv8Q)wa0@-?V`ez=}ci>BL~XQv-P5hVyVNiKFL-QqTah zb8+B5Exf4lDkiiZd}A&KlM}zaVFhLJRs58bvp3C)ES`>U>S5oeI96Z=v|!kl>!uziM`xp z5EPOm0@5Sv(o*bby?>)fjX=El?iuYiOS8`V7QW#Da*$5Nth$5$tOB_Qo_$?6Cgu|+ zcc#aI2*L0S)*2Z0Z@5(*T-z*FaxP1zd!2eGzlu`WUjknZt|wQag72Ipe86e>|~%WgX&eb1kk*@jYu~EP0+>i59?3 zn$&zdmqa9w#tM8;X7pb`OJu`2Kw=VxL2})LsXkM2lY;CFJo@@?IpLdoPNn_)7(ZqE zxq7bGKZ`Hvu|{QmNPjuDzBCODFA}6hB3!@+`dA??xIBOcufwMe(^LS1W;p{3oAm3TvCD94I6IlilviKe zVgyFS;@ClvfC_0FBc?EEpn(4Ihos^KViX{0a6Z~GA*rNycDfGiIry9VaPx6xhu5|9 zC=$MhHFg?C5NnF7^Ej9PxBFJW^B@wePbbsv0*=aWr+_e?51Bc_u0TQk4S)uBYx&j| zpE?^Uy}K8&NmPN%c`-FLP`i8i#rKiz1srHl)+;;og#;k<3I*gsy`Sv*G>)SL7hxMy zY7iBiw%boWTsWt~bBctt-A2g>XbCGU$(_oMNai|3ZElLXbHL#%k}n;}YzdgpkhKCC ze2-Gf)+8+Y%TM#NF$h%84qQ|V)+}X5NHw#5z3SV1h-x>!a)22yt9WFXLg%7}15xDa zg8F?ldCbVW_oNW0rhr&+7wRT*)7oo`pxVDb#V*PZPq<_-2majGAHG>aa0Y)0G zDrGiIv<(ZyAQ91#m`N}Ew1Xcj?cjI5{sn74^S!%s{Z-_{yK{}1YL7Hmb#^4OhSb9} zmOj!NTA z2r_m7Yu3GG*y|yvP^WQ7knf4v6xy+%^tGZw4y9T$CqpzbZyYOKU3qhG$nJgC$HuQl77v0PhT!hJO8&CElGG;t4 zi~|+#1`d=|pRcglH-^eGn=F-gl?n#_SHy3PPY|e{vzxl)f|uF3;id;)gQsn9Lt)uv z+p$0ka2cZ6F~Omj*kg(vlrANbGt<08Frb%eXxB}+ThAJRJHo;UU9?>&d-19qs#@w$ zv$X*y%2@>x(}mGs7bmkn_9~>EVHBBCi4x;<1~PIXqa-XJA<)RaC@^P6xvI!r z$xeIbzn%O~?*@?ttC2Sb&xLl|q#j9}dGCvX5>+HclsC%`* z6(s&)x)lVU(TjK?ik3w14#%-;lQAyqV^+-STt!rv;U3f02A9yz9d}$JHL+zCx^}ag zAwBqdSO&)49Ol6viEBgX2|R_gGfn~ID6Pqwr5z?~-pU~^nLt`-zNmJEjh0g|cV34H z55iKpczP9|<#R`+w1Y7?llTwiB}C1vD;(*vwOVO&1RbAOK{Q3cz%s*F%@-^>=CfEt z)gar0pUH$ci-DvSW3;5Q*g+Rr3)4imj9Z7fU>Vi%B*4+)kuNC@qc%6U`== zfQ5!5?UYo#^1NPNf`nA@kvV&qqg(k>5i%?DHbf34s&rV?jFhufH^KOuW!)0NwCd@y z-1nX>7oJI3R-EvB@IU5TmLI_v119Lh1|HRn)!~p39bSlz#^+^4YCwT_Buvp~$mG!u zbYyj$-jIk-jg(Ly*M)JlU?Q$jC5EuxD`+-|96*40k+=_|EkY$1{AkxVenv4qw8E~x zl*G6JC>h(s+B{N(hy8dEVISjmyT(&Rc&<9Iiqe=q?FYbrW`l4jj)x^C4WnYbj_ z1rpLea8IY@S#lo4qQVqjC8{ z%#fLx3G|^k_H+k;Z5opc>R=C6i{#y5HKs<8gO> z7HsAG!>uCRAj)brEiZGmLg?lJyPaPEKhLf99b&n z198%nGv^HStd^@Lp5mTMXy4zT_Vyd_ppBp4r)*L`Pze#9u46mRTolb*I$eAy!W?r& zR)Puv9{nP#eD+=-SOBtA>3~KV+d_rN^#;4roGlP8ODG-MnXmYouV4Rgp2=EiN&l-W zrW5Ib2BPJp31E(95D!YsnQ=ZJ=A?AmV@KqG$4^&v_*dMyLgs4PyO0b;oU6P%&sj9^ zi(b=`pzKjV%>Ab4EmHmBF!rUAA$qo}_%J%z0tu-$O>15Y$IGbI9-nPl=h~6DT^AaOhSWP|Ue@1lzKSfM$3h}B zY2k$p#S)~XD@S_x#N`Gbp0lL6yWZfOr(vWl*Hh36$~iMw1?}VwU3ho?;%zJ5g_Sg_ zD$}>C@Q%Ud9?T&^56Y_0wuSg5fDe9&h<^mp%Ek5`+_#JaoJ2biafz`RyOm18Z{Z~r zt~t+{Z?uF_Ms+}@6TCKshkm7b7X zs2L3PCS!5dMyw~_re}A#IPN_9&%XFtJYj2Z!rqMQlu@NV=gHV6&D*@xPno17L6`x^FwL!wjWll8 zVwH{npdZ#>!xqW#W0IQ-t7V#{U?TNux%_UvzSBGnOKDV1#mY|8aQO|4V`8Iw`&@q0 zyih}a&&7ADPmXSM6vjG(=$y<;ve9cJkx&-nzFf@EvSYCvN)mWMqqrQV<%M$%DIygA zKo`L72TeZb-4sC8{`%jj0+C*E0U+LuPXg+=448(w4ndRTS`9I<89?a^%|~S+){r8) zQnJ-Rd#i2 zL&d@dn4ZZgG!>u^JDf5bVA}jGTd?bRW#KhtEDG8mtlPtNUi^+Mff*AbTa-+)D0gae z2{>J3l+g!i(LX~*h&$6WGPO9G_h2`^VI*~HF&5bTN|!jx<>yI;mz@&guP0Ed0fIy4 z|M(ySeigL7)lTVPLeeum0_e;Uw$Wxw422P?_;m}UR~?`9R@^Bs8?RN9(3B}j6oO;1 zQ%Ur4Ld%97NCsOjt5sq1`{4V4DJ?(ETs3Uasu&sn2S4aJPoBQm%Ww_r+tYa57#_Is zzxXM6?pu#i4V!Zb5mrYj-PUZ}jbd$4G=_1G+;+bWr;^1VV})dgeIh=*0t^|YQO;>k z&}Hxb^m5uur9B;!+ze8zO~|saC1~OzAn2I4KsSR6yoOytdaZ_=A%UwsMA<^b*WeAZ z;NnhGa>c;K=W)lQBVc7L1QvPbYMnA`IEXs6GpPc3LYEZ@0N%`lvzRKF5Kiew>scZ5_m6CH#P~*h zvsf0q4?vk9lPFF%`*be*6ug(9*c_ny zE*p5Jh?Sy^=5%)b^&^g&ppYsEpj(ffcOgyTn;{A*NBY|rsYu6KTlQzBL;&0cWMS&3 zm6n`qG}RgaOq#)fbgS2874G6LkG|JF@)^6ibaqmdy~#s#>9oHk7$H~ep*Ru09i48s z2U{ZuKG?(79%}8tKH-s>BjFESK@=rpL9P{6oRDc_3D9H^E%Gp(^lN;el{ZPdvqsFG z6OTU<{shyNq`=K0kYnT|iF;h_#DyQ+VxV3*6aIf z018qeEgV?X+hSx64a;S;>*GT=5W7@*=tpG6Gd0RHX<)_8^$5=ah97}jhe3T{b)z_I zV{nA$P#hTv?b0ICMC5W*0s^iZaM;PRWL%*%LN=yB1UYhQd;csZ&goDa zpGq==4`=OHa|e_!tu4hPrT@P;Y?t4@?_99^0Z^|-Z-tK8NM`ETQZSHckZ$&FgHE}7 zrj8Bjh1L)+)QD{##l6csRO=&(a+z!KqLBAci1ul7gvnN#F&G3x(-N4;$P8)eQLHXd z2FC88(e`z*5}!UEC?XNUv`_>IE&NIZK`|)4#$~u*?>!fP2+OG&BX{c)RRop|$B7DTMHZxfZO#Z^f%OHxUMdqaa4AB#i!CqvV;EO~GqH0+Z0+FE=MS?xvcVrugemFRhx(F}{RgfU*IEPzf zdQ?HkX*w2@G|*M!me!t2c;a7WfICa2a4atOwy|w+Y8JD0Ir@BRwi7nS0#Aok<#uau z3`2uz(X*_^t;^CbGE>U)NGFKBIK^^yfhj}36GtHQ5#14^T$Kp;q9TG_@Nk^C3Ja1Q zdkI3P;)O`sGZyVwjXh?||L0ZzDmCe<@ZY1-A!|K{r7w5dufxY?bqxB=%tuRvBh#uI zp8$(E&_Xl^PF8_Y){eTydRpDFl-k)v80tf!p&feDMS2n<%t{5WJA1$S*bfZiF&nHm zm%&kQE}iZ0U;~}@4($Goz{b=AN;BRX+y(=i7#?Yl*Fi=TxP60LIGZG6IB?)#Ev*Vv z6vXT=S&Pe#s2J$9`O7&`A}5@xV81n)`J(r{aN(2Ar@>U5n{}&=c2$*_hebah-`kJ( z0=(oIgL^y10hzKKn+I8*lLipanq|@iJONjn4t>eAN(mzS1)_=-d)Sr3PB5W#Tn>}} z^6jGp8UGZ|RDSs@_2np;1E<(DPJ#lI*KFfhbSWr~TC)DXmnL`;g{{Aut?F)zsr!NKwQ zr>in$-w{I!66YeGNf3PqYtixBU;8vXeS@d1l(pi#WJ=410CSN2tVah&XC^pb$+1y3 zADlu3fhhF|_Hnq-UV?80&f@CBj3Tqpij+68sV`92p+PrrSx!}%*L4dE=Yi5+0YKoNLbRIn#zPBKvk{~v-3&~8+j9?aUPnEIEff| zRr!|$rxczS4%|bULN~;?G)ge#UEir~qTsVxenSI>j}cWj{4P}e0Ls+ z!!%ZF=SiRb$#1AI728j5y>MPd^m2SFdP{s&9qU;phUY95Yq-sdM8bLEvQ!xLTt-`3 zmL7YA&gf6;FNfkl#!<%0XuQGl~QP zgwjh#*@`LaRrSwgikIQd6yYpb(kfZA`Zt}nEk+NkqW5ZW7bG@0NMdx z?VcrElR59q!KDO2n)%@$0^a0|O$D^Sv~&9ZY{3c|Cs$aSO~ZU3E}ugJ4`~R556+-( zmJ@XgL21i2VEhR*a&@8ib=(gPZiS|T!sMqqfWwidg=Xl#Hj75}P7*}1yh4YQsGd^~ zWYH!DX8`nLn~=6dGSlMg(q;>fVaaL*Ati&`_qoOs*f7%IzW%a@9##FCUrEvK;HWh| zrRNl2_@oJjQ6jlxizKm1dAV06ca0ihGN&^ALNn}$;okvIzKmnn$dG4z(c;WkY zzk+f(grBlpY@R6VaOX^QhB51S2NcK6j+M$`{2J4u`0E;8`q{X188%C(-GLIZw;k1a zv@)opfr&+omUJ(LVI|4o$$;v#bbx-obUD&X{T5&ErT=vEJ>G$@Z*anLdA(!F@p8R~ zZ{vM5ZX9W264XsMOtrS$^ntOP-nnhMwQ0*uH%?99yx3ZS`&xV!^Z`LtTBdEPk^M`7 za6)#@3ULrd55Izw~qfYrT08Mgp_H6QQ~Gh=usYt5!h$Cg=lZVPB<#KU9>2`zaV^T`-L?~M3$)_ zDLDA(NoKF9E7anp8(;G>JWORIpHz_?gUe8;+2;A!?&apgG!xyk-Ayg{W|WQVY0qW2 zdySLY>799PF$=>^D_H%c__}3iFKAkBv^03A4ppn;2y?OhNsn%l{bs?yc$tF1%>{Dj zC%=C533$3j72`0i0^!EN71+y_%c4Eb{^k}2%rL;$i9wuC46eDD+bE!mo^w7SegzYd z6bX8gx;zlX4PC_3%mPhf<*L=Y#SH1jpu9*jdmA#5hNnL=;%h91i z)_zq7Gh(J<>L*oUL@%M0Q7+Z+rtievOU9r?IQcD=0Wpo!Ivle6*ZYO-y=C=CS91Ti zDFd9RZfz!Dm>3cP(PdGP8i%unqf%c#M2?Dol&T#MxXgCG{~vCAJRZIAmlZOzIjNM{ z%J%4Z=kSB=sbUkOTQTE%3tEkcYfjmL?aA$Jbu{Od_z+=lHI;D?Ysk&FlYySf^2y}@ z9$1=%>H>4X+K3k+BW%$H`~NT#n@Al18M?G+?ZP?Z%#BOgwNWXYSv8_RhHzF{r@87u zj?6SdIWq$aljdWLl~+2LAK@rRL=tr_6dH2@J=Dw6_bl1YLKQ?-80EsRcH!Li?19V0 z!#uD;b8KELG0Vy}QnBX1*lapBj+QpmB_tSZ4Wc4c5A41gclYHTKDuv%QAgY9EsU7Z zJn-UjaW&?36|+UkCB=QOB}Trai5I5Ph%6DfI7N}&Y3$f0$aSeKe#wdNCgEDyBV&_f zRb|LPEa!v)#GPm{(r|=JXoRp!HGI&U@V!0KIPGbY0U0auB<@A%1R3hB6(PXd%!MR3 z-Gd8S>kwBYj+ip=uI)Uh#CM|F2J6cxJ(`_(AQ7AkY4=fYej1TqWi8}|xn0eJkXQ@J z;wf?f&{{GDBfKO6E<>@WGwKz*;;P4y7~sKQGP9CSeXf;y;vwApm@oQ*yS?~D*W$Y? zoym*ldC`~Sdk36V$Xi#mTF9DK>Py56^Rgg=wJu6HIRf7(9dW%$D-ueEdoAw%7hHq9 z-kKU63P+s@HKNb}%>-ymnh4KL`VvnZn0PXDYBPgCxte(oG5G?xlxQE4_~k;n z=FeXK({m^!b{dqGz~(032bWi(R0Q}|&;piFw#e^ms{tc?uQ2v9hKHb3ltOHoM488i z#1IL`q+8&9qL&6CO@YaX1gQ%^?7O4jEioXY7*Ye%q&s+fU>ot&zFSd(69FZd=G51^ zckd5B%cCi(jvl@BGBqBNTL-x`rZ-?;X^`G3w{ean=uVFx(eyYc?cR@X?6KOA>V}wx zf;hJ*!mcz^k4{E6=M+7J;5VE3VR+d>mKYsgNkE*?Q)HSPmSOqA|K;sXz~m~cG~f~y z5Je&&qT^B^LPkx*aYMzC&PKLQ(n$y)jzy)r(%ngSSM2VPwBsnE2)IBLQB;sPGhh^z z03s*?!4+{-To`ddaU+Y%AnM4t{_lIX@4J=zKY#B0sd=7hht#d*e&?R$J?}Z+`J{n1 z3t{4OlBzo!++mg{T=2?GD=9e+QR~#WY%K0VxXG#d?B;6ZqD@biNO-R01z;GtP$5!Z zjn67S8CfGWO|gjM)F{Ehqf)?73J~K$=&CQWFy*|zRnPYQR#n@ZxDmf; z+qgMJA(@Ru>1^p5ggtLia}g2(`!~qp`3?-ha_oU|#!IMC9kP}woUMN6NoU6Un}_7yUW)-R%Ui9W6^_NL z+?3P=MLCXqp)~`8A_kc%SILo^_!eQ>`1lzh)BxeZ=@5zL#8thWX}cm(a*5Se%p zF1!P49mY-hQ{Q^wy)&2K=gI~=-*2;KABD>ciNwa*8(qs;GF&%2$^K+?C{-+=-hvOG z0<%s;mq*>`{j=m;E2r_yePb(|`&ZcW&9}O`Y74Z>h2|C`;7D@n6xE4yZES)okm{o3 zG8vTk?B8OuE&?c~QP$^96 zLa=LZ7>ss?qj7nyUFNhdyIjGI{yV;5m67fM6Uy}`r{Y)*60r_%iF-a1SJ0q5d6;kP zFXmg|B*goQtBIv6E8r$(EyxAu;%LUpzNA7%Vz)XIT=Ua7?leZREw>r zsG=nvyTCE}MIf z{M)aYT-F{@VuDwzK1uS~o*3HDWbHUIDyD> zY@-7N29lf9e;`?f_{#4sx6i&INbJhsRFgmXO*bO9Xel8kms2$bC`9I2AVz^9}V9(pN4uHrk~M z4(N6GT}i_s2<)!(0+hsYkg=Hu!dkUE#MKeYF_jSF9In~UOwzJ~h%uZ~DcEBGi-1R7`QMCSxdvam9G0P0lCuCjSg$wg%TDAL zGJ}Z47T4SZC2JHni!kSwr^;1PR#aYxk3tJ`^qoI>PHBQK)cb0~s)(C3XRnmz|@yR)c{@gbc2n*SZ48sXJ zM5M8PJyazScL*$qG26i#_2be=q-2vUJ8Tc3y>dcDp&@$y*NLG0L^)lsJ#uy0p-3_&o>2SWcAE z@hr6E2Vg?r6|F~kBsU)B7Lqf`CM#>@=pZ$H^#bZ_`_1xf=Th?F8C*0f(LamZDwKT9 zWbV6c;WH1VxJrge-+z0T#Pu2cUQe2n=0ajRfS48AL!|JEr#;DCRN`tA1DP#Lw@KJE zEPY=Vm>k)};{iB`{TLl`7FH{~O?q3{ssL}-v`sfJTC@Nwsr?uJIysCls_4W+50B#L zrje=o$xVz_aQ8Jn}pLJ?HsYNo`(<0KcyKLRhni zyR5-_t>_;b9Uh3>fv{$sUTRF}r3xBz8$KAEVby9ew!L8|?bLWj)9aey zu`wJXhora)@EOK8E@jh(wS9onLM?5;hR{1DMk@mm04f621^haqp`fGGx`}Rc9b2zD z5lMJPrMVeBG~?hmj&Px6WlbBTD+++Uxl%txradt<9MuEa`-y7}8m(QcU`PbV$_`>J ze85`I2Ofc2VIzw?q=*=nU1}jSC#{4uhoFQFGZ)-MBkMTe$sNG zFw%)Q@#$GExB6?2*!eO>`m(I*yP4s1M{cjhFZak?3nkg3J49eymc?r|!P0S&F<>;h zksw|{)QXe5r3jX#o=EC)9Rf@t&4sZ2eII+}5bmUujQ_q0fjPPFD(Jy3t-@~e^)fO2 ztS0!>W~I*PoA9k#V9F3qfofsLResIgA-Nl1BAcEp)e3dVPM0RM1C{Xh+1PCnj$KGt z1bsOYN_>YgK>FXApNaU-B53qtO`9?GxHBlbGCt$pt}75Rb`LhhCEN(x^Rxm!CFz!E zQ1R>)v#-@EJ6} zPN4X+T? zT~0!UV;4}K;hS*H{w-Npk32X12eZ_~Tbh$6CU8PXIO|Z>6k1()cU^G(owUeW$!Pxj zcdGE1xc0WNCM1xlQb@oALE<1OczHP*yh>#I0zN%Q`q&uH9SOQWmP|}p2=qNl!Bn`R z43Q^w$h9X^FAE=8h!bR{tgQbK(zf(P9&zC5)k|93a9Mi2N{b6ZZ@L(_y=D4g(q39J ze*XSnsu&3mdRv2_MpkaX0Oa6B$N-G;bw817?}v=tfRFYC*XU>o(|NSXFRL-ak~J{~ zlHk5i#n-N6sX5s#VsRc;WCdScxaXm zzyTe(g6Z9cF~R+$|0h2kIP2TEzqyW0T}cW0F@Yc(x`! z?CfgzwY<5kkORj%WR@*dgXn^NRGPinL#Oo(BsSkyd0*p_XKP2?YLkZ>6c}^h5VusJy>nFpt1F$n zFg5+bn7y9VQW2U~SD<+=$lC2EpM5q3SuYXfZ&h7bH-oxN!3AM=XXL*0KxAf#rYjC0 z+k%hI^}Yfai}usuw#?#vrLr1v>k5b5r^^4Qw*?9fJ@Shv2$&AJUoYq#%OS#B1!ia7 zO|O&#KbOz+^|!9wAEK!pP$D0j`@HYva~^(hcGjv&wbJF0N9sq;2D9*ojrD{mrF?^} zjA@b~JD9=A8vGKgV%<45yJirrgl%y#OuKkPkJ#I@OT=K~n?(%6*i?mBF{c@0{Yc>B zP%^%ZDJNBi`h5(a?BnDSD?y-z&!)=S^YtgL$p)UHbc{xY2iTp>9O*gJxIF!pOPU~S zNd>M)J0c)HVj-`}EphOkMSr~4|0Vf>bRW5_?z`zr_g{otFB=N8!$umjg|K&=Y#)j% zV<^UM7)u)@>bN+Hiw%a=F%)EZv4S7I44+>%q6g0jla1}>#a>k1kLl8+b|ucqUS-xo z>4gnR1h;k(!Jpo|#Oy`KKfpur2qSqc)^8^9AL2@2)y1^!#O+_^*oNBlJymMQe(HG+ z!sXuK2|0Brw(uQ=7g5iHHss~Hnc{npvZrhZ)G~;O4=)n+X;mssX|py& z&R)ml0y%KeWUO>S?vV48(FJL+P@uId55lh^OMM_s7Ra5JaXD@N`LqMxiaRdreBN=e z%8As9*7Fep*r|xhkaOCkRxF8-+fPo3(Jk-6EtVbDx8rfivU=gCXT#x;2gqeZ%Nm87##sVG zqyl)Yf^I5Fh~CN+pcYlmPTUM1ZlX=20G6`_#*h=AwR4vZyEQ`=|SA z{7fHUuRasDU%35>@VT;t>?B`G9HZu31<%tjT`=H((6FLqEiW3%17#)=8)Z&d@#dT6 z;OEOm2=923E|tM`S#uH_B;cn{ZntB<05y8OUBEE|?STqzll49a8PcWXI5Y+zxeO3s z6!ELm)Bwz|W63&Qt+j&Ciru*q4tuPja#&6(sKZo5dJwb!_UC`c&F{VYqqx7?V@j<1 zDM_hSDC_Er#yJ1o?VL)jQd!qnCs!(ng(;)82EuV;k%=XUgQl4+<2Wqy<_3JNT*W*w zFNK*mbS@tq(JP2~g`#q!M!fJr6&lm|n=XsmIe*;BG4Q1k;i)PMri{y)8%8jhZFr;= zfq^OGdc2IWY<#(b6h4ek_Q2Djc{bI9eGM7&7+H;#w6da9Oa!9t1jn56BR?C++upRv zQZvb5PtAyfZo77PiOxK&OL8JIL*2%Zm@#i!A6JUV zv4`Zw>Jd6}$V{sFU}5N(B3Q7X5>KRI2>Wx{^)1<8W;bw73HY*FYkqY8j>kV&i18Ck zWO8(FM;k_(P)xAYXdW!u5w0{Q>`Da5DTjK9vn`u8e3 zam+kQvVR@YiK%q1BFi&&I4j`Yk67{ET{UiBO^yfgUtf zfLN@$YK}{*4(@aW#A@&gqx7{u@R8;VuE9-|^;_(ik=DK(oykp{Guj@>M!3`K3~vOa z7$3r9oGO5V#cQk^IEAnPv%#$Pl;P!IRc6~(HTX`k2J+*!rNIbI`Um$F;F9sJ+U7$% z?hAeBy~79ea-k)=7I$QaAnfCXz6HOyDo%%W-|sh@cevsFX*g2cIYtHf9wWn>qVmCi zv)~4wA(32NDb}1->;gCj{p~GH?koCc{OC&*Maju>JD#J@oSDb+W;&3M)b+>)9MXfi zpP+N9JnQrE(YZ}y#ys6aYDS&faS>+$ zSNtpdL@|%hdB3Uo#sGYI^hl17!8Pq+h}|(m&pKh}iMaRLQ6(|u1u7=;XgKGhH9ooL z8N{43i<78Z^A>Kai(DsJb>YSwBtY@xWLT zl{mr`A6m4RBv;?NpvQyQcNz4Rtj%a6*P~@``oQ<({0nksoq^*;T@(;CN^?}mq<}#+ zuR$srt)tjX$8@Z}wI17mn0H5jbcNAUv;J?M<~y$%zEvTc8dElotykOkaVty&=ydZP zyCeo&V3)q*J!?dxN~XW>c&Q4Ek=8Uyx8*rVVG4vJQ=n=fWycY7D_|57*in`+Z;+Q5 zbGr~AfdV07lkLDt8X|mixR<1t8QMu^1zAdyl4($`l&QHwNHn}eQySb*|0^E5yNrKp1tE)T8hu!Z>W z`Vbz!x!Y8plz~_Qv}zZ=@F!>E*J>p-u^riI7b~z|Y0m+lT;h0}EktM$7^?&~nB-&u zq{IFV%sXoprV{amM2@y7dN*R$d`}J`3LKWsXoDy{IXaIRy*s8!JiXmPVgC)9N3<0Nk``tyL;CrbW5Z2_NACdgwPt zZxlMEc8W+h1oUZ3$EvaV|0#7Sn51tV{Bgq4b{ zG2lVKp1jZ9b#n9B&kO!^ER_nXK}7vJf~)HYvXVPCgz9}O`cIR!j~(= z>^I?)OT^_Qh@7j0_zSoYume8TN2a!rHX-JN@TBw;;MW0jE6^bPl5K#A-Jot=kaeL9 zvH1s|des5AqZ(&wb;jgg6#>EUiq^;!{1^^SK#dDou{&j!zTl*r`6;IrAn~X1@l|k# zj5crvz5~U}$|(5q-f2A43eiekhk-& z_dKze0ls7()s8cgO|5KB;gIn9d@SCDLYtbDmm5QPxq?kG?O)lRgx3+yL~hc#7lm}@ z!M&eMOO{!`lt1?HHlA_NI~mfInfP8*ulKQ`RqQlZTxN5sZ=|kFX{;r|$e==e<^3A@ zN~?CyG_>rgOMZq$m7VUgG)jnlZ$&{<3sB*_Mo6}|^p za#2CgnfpNcWJckU&`8cyR=2tW7P%a66Zmjl8{B=61S9MVu+(0!?w@9-j?x=>;o_m+V#zy*QjxUUCUb__q1kgr>1k24y zyF(-<+FI|s?}w-GXUm2v?Pzpytt=1=@howZdoMk=MtO`Wp|g|x2M%cA*cwl@aXbyT zBig*A=v&Yr1WyW=B7Fl~sO<=%eZe`2`zqF#b;}lbLzBo&A78WWeU!*kOG1>Lqd`ow z5>td}4D;I~81d*%g`SoJ&}j`ra;1VbaNZ5=9Q}kwPns)GLe3}97$fZy1|2BJhp}UbUa6oa@4~MxHSex1MtE#iKC^u!cH=-8!1ZeN ziBZ`jL`&f^^AiD&ePow?9seJWueKq089-(h=JqrH8_zk2kE-^f62aJU5eMV429Y{W zjYvnhlAO>O(!jYZtt#9U=iKx_X^C5{N+#LS97nZkLjhx<;L^10DxtG(xW4d2xoT)C z?N(#qT|5&FiC)-8`R3IK1~Yt%_X^=%HUmv3-Z7lJ*bY2z@!!~yS}RM$Co)GYv6rJ} zvHjba$&El8!!N8G;Lu;CU$g{f{*>H;QyIh}OtYoL z!X%4jHT-`?e28HxY6xTr2+kmTLU2lhnHN6$>AlxTX8H0GEjp_pj&b}h4lD1SisnI5 z=2FLB*PN=

      >Am($TTqOyLLhV&~%v@g?jb^g#m%i?^&i~+f@4_S0{)(U8SNQq`T=y*Qw?;aC5?y3jX{x6s zDqmh7DGv{3Vv$bI0XL{dOLa1`R=_29rx6T+*?sM&J>dAeZ{ym_8Zj=`wcihy`@q3B zgQ=$X?{>DMl@7;Y3~z2#^8PpC!>h38TP-WIISIv5j)mRgVX<<=1Pti)?f{AJI?;eg zIg5_&%)AqUA<|iT%}1ncMD*m+$h<+ufeT&(9F1pD71|%GJHtASNeoBc;hfHh^>U%ui9Ea>t5o zDf`syf$wxVp8MS6-zzST^U!+bn4PTE51)bkaj=QW!WjW=RBtgCZfmnU(X48rt7Rs3 zkW}#9ob+SnA(!SYBMddwDl(o+6Y^-Njn#kn51;-eo}~5{{PeE=eY$$~ z>+~ZBn#E)&G@H8FJsiJgYBbwGbz@%BJKd*q>8ps%ys;}EDygVPnFP~#byJD?-e5EW z0Iu6xR^qq%zUNOyUnM*CrC)s8%l^!z)&8l(Uf#bzOMjIty^vwWgL)pOYeJ0(8!EhF zpTP&c%zOm#8-ZT@fq#}}CoUEt%Zdj90MPbILQ`CmrF298z2EO2N*R=qw02q;VbO{3 zK;6RFnoS)X`pxE%YK8mH;mhz~*illh%+w}Ax~CcUqdVNN{9G$DnjJVlCx3_Ey5Gd1!#p5zMPc73u7g;R z00)mLR6${~_MPV*f4B@hEZbf5F}0h0@USQ1m4?a?$&3LTKhBgH?;y*m5@pZFhnY>t;*is( zMHN=#wFW_?spLl*NzKk*Jq*yykeo7w;#sm$idxX8-AIX787q7(eXeE?=0gUa|CZ^0 z!_$>^Oxv4qa+1P+_0v=UMK+nUc2gE=!@CZS$1gJU(G;V_-QjdYTPthq$ z)}eo7@WTM1mVR&wwbZ)k&9&oSN<_LDYKrEvIPOocJ#RT4taM-W4Jr#JiL2@k1QJzO6<*KBr z;cBGFW)+;fh}ZLKWlch^LsroiHS#D8saZ9V5(Nk-O6|&T-}CWxl-ltnCYT-ZG|<7( z2)V3e;1T`yBs!=n(HHDAVhfA5$%xV@nk7X8H;z@o^$Jmm-xPB}YaMpt%N?}Qo;r{Q zNXE}{RxD)oc(Fv4pNkqVM7uvBC6r)|MGN$aol;ckXbsgzbA?;{(gWWwoM~B2dWS09 zeX-UR-EJIhO}lGOuxYH(_ zoXfwmcTetP@Ttl6W}H8~30oeB8IInDf$YtBjnwjN>UsE*e)he{I}heSNJO^)Yr@lF zqqtiv-nW5>Ky%O=X5`Df=Ml$#ppM(r4k|I6oBlD&JO{U5BYrZlc>2J}&aO@NphQ*5mi0}c@Qp69gpy`vkVo1Zp+tjgTIGxMH%%5$D`-t*r6 z`Trf6jNs!}SWVidiKO1~Q|o7d=>gams{oXDnJ@!H(Xd~N3D9-%KGHOlvwVp)bS=2% z5ii_1$`#+EL<_#4D`wqfO>+|ah(Rv_vozg}k^|n(3mhfF3l#zmr7t)7@u`)yFkiobLii9q zQ#W$?*984xb!2UF6zU(VBQH?Mm(BVmRHEb%y{D_?)MwyB+{9rDuzMp^VqRlPxSW1b z=tD}~S{sVFxmP0!#luDadiK9JDYU1TXwD5PG*U5Znuz4}&FEr|BVZXsMmmI_!#KFU z3l~`>Yx)H49!PPI#y#8~p%bSKq@RYUc{(uwn~qa20zSSkE6J-j#B4)V=g?FUN%p*(@qN# z6x*A4xiQ0+E12ACai^*WtSXpS;#b!`DTqrp>aPF~I_RSc;&(%5oK1JJqzL1%P?%b| z44buc;{vgSp@%Da=J&pE26Ud zw$VJrk07riXlZkhL?=01JiwVtR%FctHVuD~3^oX$LTmk<*WCRkQJAtBYhP7`A)~#f zxwDPjprA4A2;VNRS5}$V<5n$XIvFY2QS2u{#w;~UF~2Nfupmnq$*_xIa>qr zq>ViV^%dRbdC+c$AM8HbZr2*y^jcMS$hwQDv_?u8I<&AS`bjm*DiDYlDK;$kjkBbo zSTl4HkSej%o>uEGH@PG;cBF%WG)4kXWUf^ zni02+(Y5wAc{2Wn!cl~z9`KgsCsR^oEZohiM=Un4fpaF0go1qW5LLyo!{eZETdj&z z646KxG9!s1=}3TDvl*awD2Z$sGn5D4h)u@?q*mbBl+`KJf2vC6(FmS{l>$>RC2BZI zIBgBhF~2L9(xXzB@$cmVyye%Qdc`ReU|A#0w-;D|oHwB%Cad>}PfFp1g~}k{VGx7`>aIeU;>BC{-gAmNSaJaQ?cY%;3i|7eP1TpSXU00y9tQ*w z*umGEPtJ1q!#Q$T%xtO$SjDRkBua z#gD&c+1ie!yf-edVahet z+2#7h8sB((wn4gcYP4dn8>1O_?)Qg%bt$C$Gc(X&z$# zbM4#r{u4g-EQ+m+$h5;g7es7K9nhX2j@uJ%6j`~FBB}zK;@Jl#-Xe8}1+p>Hk48iE zK!#~(hT;?}&7O(q7^Df+h1=ZVXOH)&sNj`UWKp^0pw5Li_SC;!%>CP?I%h{=Dr}n> z+tIAA#oSB}s|wrrGS2L+wCCbleBKb!a2$LWc)`np8LZE3CRGBd9HfbHw+K{B&*@-# z!5&fMFb&CkWT&a0)AR`u;?(>=HVD~@=-O;TjOSt-y#Jzqpt{xWQsVKl(+t8%FMajNl+o>4${j99zZLwf_S669YDfK zEkQ5oU6e|40o?l0s}B+ymFmqMnXfw10wCn?mp(GGZ|0!g1!+#1aJrbLakx+xR1-IP z={n;%p%t3oD}CM+MOa@zwyJ8V$|zr=7)GQHmq-IPHwUZqDJ;^FWOtTu73)QDtoq^9Af(GNe(r3H-7T(wJ7EoHUjwn*+*o)9Y znkE<+lnpb`dFwS}pM5s%p)7~~t*(po_F51(UCzVl%mmj(dV5@7Z_MEJ3fAy>+}dYU z0Zl&;qx1yC*L4Cf83M@^1bB(scy=gCIxA>T7}|nop2Z&GN4yA3gjOm62)vFbj|eWE zNa~PR$UZM&BoPXXaG<)1ZW%X`9FBI0Qsl;zwJj8m4jGCp zX%4UaPsSp1s0GronEVpx8OuVJr>lpU%x8c(wG*fz1g6<3sO6|N1MB(AY5jZ#G1nsP zJJTV*!0YgDGN+ljPpG6A8@6(o?w#|gi=O#(eErf3NN3t;w|t#>zBjJx`++ zuMF$3WY;#5xwXQf5;&$H6)hnuWfWzMebx<3&UXd;cWc+E?N7kk3x?qN03J~LK=!Qj zR}*usSj%900wONIqfh@&jM-Hd+>RivQkCz$hoi(+cKD>ZIKZ}*{Z|D z2AgvcJ-w2q2vg!;D#xp#YhJWM2iLig(*KEgRRNKxdpls*9^QIR-3W#t8LVp`0?IQhda<7Bl?C+M}AYt4G9z}d5qi!4^D!l)~Z~9V}JYA zRg18qvJDga?VPtGEWo$o(*&&xQ|V}!94XQ_8}qPQDue3JRDDFm3|(G&m8ge1lCO7Q zpo+_oiY*La_g%`+NhS1&1c}jS#j=%NQ+t$21umQGAO8G%pHJD8RBQJ?Bw67RRIaP> zY3pm=jXl(`}q}E?lN>&E&&`Ff8BLNZ6TSC1RtL9!Ier!Uk@DKFa$hJ5GeM z%1+WK{mtYRjZ#ZWlqQbc^rH{{$3IX~CG%VM+tE&Jb4Ttn3USZXx6F03?Ir9TL*T|c zW3L(r)M_OQa(?{)?+Erh-KD2y5Ticbho}m;Cqe8JU4(8VWJw>bz`|I+RNnXSA*SXV zPBKxST3_YJU%f))5b~r9{rkJblNE31dN=r$@4fKXSX8a#sQUfKtKKb`G%v;HI-ysH zPVjTOmkmIS>ILFlu#u`oPzG39xNEttYh~>7daT4jay22FXi2eLQbTOkNl@Tf?zL;n zat6ne(boNaR58gbjjmm(;QQZ$3*%<)oja-E+$ju z*j|+kMHakXLB-yNw-gYi`(z0f4WD|gRRVkzwM88AyH=fs99Uvh-(*~%M?jv$fs8&Y zC;~J^snRVmJvMrpP*_+l6?SnJ_G!P8f-%MBs?ee z0_MEoLIoLJhkMt{iNN;FoI|mlI7-DJn*d9h3+sb z%?S$JpMFn2m*XAKpP+p|xJCX0&Ets)+PaMQ5FO644Q{)W{J`{V&l~pr+fur-lCc{5 z|6&29C`4Jdu|_E?oz;{LByjgcH26KuORW{41>z8<=3+ znLmr_oXwCEGxpgn!IUYW)BWCAR53YT`@Yse$;5fANe_*>|B1QN>khX7rh!2+9)rmy zaEDxJ%<@VFef%(PUOEBt17qi*4qAjw-pq>etT;xdL}Oy_c+~!rgrFVS@cNV&6p9uE ze-8Ue-l{yTwNG7#KFJIPIs&qYZE`#Pldo9(3oM{)v)%sxv!HVO7(R7Crz1PH<2fK@ z(1YYeofs$z1fgoJ+M%~WvHd+0zegF5Ai`W^+NTk^$2mmyki`mrEgaxOU;CAQitb(| zD)$r>9SdaxL>i#z`kS%Oo`o{bd&kR-5$v)*{K?9DaAyjf84fK#3w+hs4UpSSre?Z# zxG3a^A|KpXl zA&Ty2_~~`aDIA)DQ+LY z8}uati%FVi%85F410x}tybMcQj%voRj&@)DeHp?an?O&;aV!>wsa>AJ&V{`QZe7BU^aD&Dq#Ds>BYh%6|ZV2!MlRS8a( zD+ti+|2N0NIe?kLV3&(;V3P@MTIYZ}&yzRbOsk(_w1ujl8Q5vtU--^-6wu>K)MWkt zf|{@Ztz8Vsb!Q+}r4-7J-YAL>sK9-cq;|IDhpYG6rHBbNX&aYqzwV&gs7Y3cF0=oy7m`(MnD6AkR!^j2O0Ugy7z$i9PQ4g6Bb4nj4NomMMs>L^X|V81xQYQw0&SIb_HQUBf1^UeRs0Z^blLz4EG@?^Mfw$uet>SwHm?0&FmN$`giU@Try*VuanJT+Rc3qeLrNYMlBgdAE>a zVQI>7$^|`JV1tZyr7L4{p_-@ybulga`4vBZ63vMX<-ML`n~I5a#b9&C1i(uhbIe>u zq${TJGR7P8S*dl?Z82@m4(!G_}|kmeAv5h zrR*M6VprLThJ&ryxh^z@bbicaCt1;KV^cz7l+L$Oh-Na?XFZ(KHv)A|2{Xi_ZA^F- z_1le6Hi}wrmR4{{IgKBC7u0~v&NRKxe=iSm1!he?)MD|`d(L_G(>pm9>BGpH)j^*?Mpc`p}+6Wd?tx z>EIN{v|hrDExA;|&0NDb&S(Yw`aP7McuP?w*`3Yi%A87IJyHQ-cv)&s&znfgn};)$ z5u6Q)z-}C>kz3hsLh^(Lj*Co(uAf`{^2_n<%XWP3x6|wH$<@u_liVLm^I&JDwXM;d z;1R|ZC?1mTu~32H7AyjoLlCoMUswW zWSv#d;-Latq!h%NysmqK@s#C!QTW*i)EE2^*@ENqn5| z#$3^Ib}P8TG}sE5MMuQ~;@z={P7qdJveBIN)T2O)@yuI?n_3ORyXnL5@><$wOCDm%`5@cT9>k}0wX2iAOo@k@p-n5H%qk;oM8&{XNLuaD1wR} ze;3R-ZyNs9qwpO|o9bVvf?*_d!E7ELn{1DSx-b&DXlC?M1>vv{Z&TLBn@Us$n8nZv zOV=QXG7K=I(HNOklom#{3NPRa*5(wFVsQY=#I$N3oyP`>5`vCaJvPB6Zp!6%)6f%# zq$GU{*3t{BUZnCP6ASr`cczN85VJY#kZK@Uj>}1#Rjlo~xOsJ)Lxr!J2tzK_%}+@W zU6}#MAy1J}JkyScG(rkXRASoKxA;xBtd|DA|14SG%QM3vY#av-4=)?DxW#bbdq*%1 zczCSZRR8nvd3};KF-MFzkG19JE=#(BCkWA|HY2uAfvmu7y*oVc>o!M%DB$s0X@Q; z|DGEjMgjc>KfT)j+N2$uo0FW;UfX4Z5802p>IRnFLBku5iEvSp%Ak@(67pa0Jv{w+Sgw2k=n3%&9$ z@PnlQ7dRlnHS=(QYNwA$A`{{ISm5W5XI1d9EDa{ zLzK9v*$LsNcfs3dL5j>j5Y02B^0jw9T&l=r;n|K-TM$EIcveF*M@eLt*bBgZaQPZ4 zEILG~O-fOMNvw`z><&9Lt#w_93Zx9){gkuF0ve%vc_OdhLHdTw!1ny^-_MsGjN9== zdkyT3s%GTD;DOM!SSUI$y3F9DW|Y^hv$I0xHG!KqlE{#!g|8VZ6X#J0k3%le9<|_p zx@YuH$RUa<0nE$ zXTJTb>+xMN*x^tiU8(MZttFes+9>Ex9a{D$VjBlvHrK$YscyC7bmwqy9}spHiSR7N zLSk1s;r0glSitv4^U40|DN=wO@F2E9J@AOJtCkev>B)J`Ipp>AFJ5=@B^&THYB%Di zS4r&bDH1MQfQH~Naj4GdTo6@Udk09Bn}d-~R|0ISac>$PX0arOgE*!}1r}B$r8UJS zejpTz2pWO8!_{5?wk@CeOT2CEn38At?&SKnH0OAN>naG^t)0$rR$gw9rL3Unufd)0 z`#k5u4(!ca@WsH@@1xX?XUL}pzmF%worBCfV6>8*=fKkTE1MDv=a!c1o0)+e&`(4| z@xn7unE?ol^h4)d^ANmu?Ua%y{N4q6!tclDX}Ch8 zD5@ZYJA90e@xr_u{NXXUYv!YK_eG;k4P5>kAer4c;mtLKN-@yLn<39VakuxIs>%Du zIYQ^RqsaZ)FZ%ospDrUhN)B4tZ^vb^8Enf~3$`#iR^N=Yx|^oxF#urm20IR?8q-}I zqg5pYvTc5yZgvz0l_gd|f`$yZpApBHqB%?IoEd6{33#Wf;EF>Qn{P_?q#gXNpmuKc z=u5mKo*6S^r)&A|RC82unK{dHsTR1dT{HBAU+km6N+v_^|A-nU(-8;^yT_aLRh@~+v|Wf;3(XC@(!h8m zT&dt|-hi7e2{R=U7vt6$O)G9?Eb+i3Bh*M;KQuAp(NldNZzzZK#VZcjGm}j3kZ_wz z=h`p5{_G|Anq_Bp?6-rW#0$%W&pOV|Y6TxJURWo8;*hr1R0YYf&844FQUXZml0Hms zmkxgtUmn1VhcxGP*PLQhrVDq{|Ivvf-6OFd0nM19`Nvw7*hMLYLN zRfJq~bGk7qp!sv$EdcCz zKJ}Go44R$UnsIDwQqfl_rGJ|)v zFDmp5s=@BJkb1h{bwlnz*7A?Oi93GWi6cA)Y`=ljc(c?HmI~*e3CI#T!+Z3}HvcFwKvF(w zo@G-H@WMDnGa<@>urg_Iv+zi6>C+8Af^0Uv3|AZ2~Ux`HRM4kmz%opLa2V|3uc9bQJVo}T;wh{_ir4=vq zY)ck(gQ=!d5DHEW;uoZD9RTnmR#qdMo7-q@@DiPE@#i8SnF6gvDNFxJRK(7M)& zRD=$Hr@W3b2VSq>=PtsneG>CQ9c!i}H7s{qv<(k~=D)0mdVLEcDA-l*Ms19P+MaqP zRf$2?6b)%w0v@FX>7I}_Fxv!faO$epJz{ndzFX=3jqEIxBP@=q@QGw2GgT0A=pV)H z!dNKEV}d>%p2Fg!GHsG_*Q`bDf<1{<#HR=+Ot4?r1&f*kbj`*_Xn|YLv0%>QdUMvm zg>QZb1yyE6c9IDFk_rmBKkF#4e#f75?y5VOH7UD?x>cam-{JO+;z8Bcy%9v_waE7b z_r&&j905E5=ZuV2Z9@}0{MTCAd9?}iRI9T`kx$PCb4LT}qJ4%94A?4FC26?;xAu@yguI$*t9Cf949-Rh zB3xte`@|Jt6O<%&s`o1+X$_>NXqMTC*_e&_+ON9kqj#{_Te|!7Uo}F}gPe_H3#Ue! z^$oj@XKQji$Cc|4`~?sLXAmrlp{X`$2n#EK=4iCjOel5N zrJis;d?Olb0J^yj&p^U4S=Sg*M*Q)8t57J%(YsOdk?( zal!;{!Za(JH)a6}jz#L#-kcEKp#&!im@N35{;lgD&*jw~RH8yZNSx6TT|TR1Lu>~G z(``&8l1J?qi^gvf*YFzBwBzL-0@yq|6#;RuOq3Cg1judxLp+%JLG^GNwm+tfPYUDW zkDV$#?%_vMCN&=C)TsZfr>a5a$)~nXIr~xYggkw zh88Hqu%7)V#f-wr{8_3}Fh$^5JE9kMs(`#h=1zntOArnr3K1ulg+>;>o^_(Ybj+mH zv1^Yla503>#tAk}x$?a6TW>oFA}Sj-K3`KgQIKm}J28%EUGLGdq?NffW3)AaFnu_Y z=;E)dygq?D*`pC|82ONNnWG9Iim$>^hMx|>DP^UYGZ!PI2>g&z?7{v>GAdx+4@*#0 z6F9PO(tVI;w>O+-m{w^v!I;JDoK>ezZ zsrZ;&X^8UjlczfR$mLs~ns-hMD9lw090qoe(VYZt%lako5D?T08|B$hC%pmjQ4pi% zxzb== z`9zoGpOv9!^_pN7BF>1drS=2prQ4hwYm0bWF z7M{SdAXNeljoiioFKMCeoH))yI66qd4#&nWY3l0O4bva|m_kuWtiTD#d5L5K2eE=)Pa*Od~x_D#;!H#H~Gf)FDu2rZhEa}Bf{@a4l;;pfG>eP~Oqb3xcx!tmsWR#)sw&Eb+FyKG@Vd9?__v{zdH_Co-b^IzBGc%QpBR*OM zY=xAt(gV^0!VQ-iQDY|yk91P}=;kr~rMExnJglhp1N`)w$0HU;-+x2C^|7B zKt2NZp#;DSjbUD>peTyjW!w+D47g55Qo!*hsRli!()Pb zl-E-C;J z%lw2hV+^#KB4y2I39zBze*#l%F!RtF+Ra^47nT3c+&)vJbY|n?Zrmg#Y2Cr7J@~TBoL?wpu*$#&SwWKCD#xH%NaBp2YNq@R%16C zrRlME6^Ufd3?-&SYMpi641(2gV4HjHOnoHfrH0_w{Y;iTcnhqLVzxhVph5LCE{A;^ ze?I&@%AussbpGUIFPNBwEppBJ%Ffhz&549$XfL?HYmHI6R>5B0gxfbVx&*bMYHmOy zIte!moG^&)C_;@v7Ao1dgqmDLJy{x?W5p?~kkQZFI9I5_L(XbKew9Q}TSGoBYF7?WUVw z`q6u0Ewu-hn4FD)6)8?M$6NIk?b-7%imN#h$LNZx@mgbBT&tjJe~(YzNRH5PD^$S? zT4`&Y1T>LWNZG;~hf2B`iOxyREdU9)$oR+PlT@WtVgTU2$5)O542e8-V(kkkk+KZp zbTvM9)hyK=L-nQIPG>w)C1%vNmx$*I<4Of-P^ki3nCG=-|GWVM8i7a1`OMziASr|^ z8I&h3NO+RQHxUfP=UB3^U(@+DuP8WfR>;M)O>rp;HlU)IuQ7s3xL3OrI>tq~cO-egg=lVFYvhGk;9pu;#T=8+}p2R%ycR;P{fM_ z=2c8_ytmjOGfR#%$sD&Yx#NRDGlD=&`h(;&TyQ`pw&4PwAAkJkGC5VQ(24XyNXrSXsjm>Nul@zG&F5 zfvDiM3fA{p+&-9j@DT4dby-J0MkT$a= z@XHt zpbyZ;uxCPs+(0O$7Fd(06v_^HW!rrT8UgA0AQ>{v%`!d|U!nWKwHp+{B@Sr_8nt73Uq$!4zeTmL% zsu48KDi)b7u3&4aC)iHINIs{i+qN{a>&_)~@lR*h%4y>dE-{~Hsh$vi_rvRhl3NOf zDIL?!lw?FMAgAMn3R?1N+#7CFx`CM;5L@Q^Yu(Sfu^1BIsZ5!}5Rd@gl2shR?1B&^ z2qIu5%1IlR#7kvtzM|JcC)fP-A9!jX1X3%Rc`*Mxm5S<(NQD!LMlv9zdc#XHlZclp zNahlJE+4SbM1X`^^p#bDp=a$XI9fb?^n5xPg!Gu+MR?L%G-6E|E?HnK`CbX>R45yMOqXBACA{QI|&MR$4RM#ath3^DrET+2U68N@H5CR1nKG z5Q`u^7Kyuv7ci}TP zI<`#!KgD1Tz&86pYE;6_LIfGk7iZy%gWU;ImMV~^6q1j4Yk|lDu*h9gw01te=}i&;Lh z3)CTJOLWnK?KUVGmR#XzL0+j~groSxC@Diq8iU|EBp$OcDv7r3Vv=?Xs|vf+w2GqD zzN{jGL>cduWn;G1Ywuihu59lt%ebf0T36~)>Kib$yqHZQzvLnt9l26rt%P)EV5Ap! zLg*oF@}$&Woa|Eu(P5b43iKirh#i99ChbC1$n!-6cGQmC)8MKls5vBJB9&2ViPLc> zv*+<6FBKB!FG^zcxeF>E_Hk_1cGi@tXjh}V2bC4eyAI{GoE+3T`?i!cBL`}xg>VnE zLh|T<8mLx?7&SZrb^>5DY9XK@Nm!2d>Mq0{i6x{ie#||!OYF4Yes9O)@YPG31a0In zy~|1j{%#QR563IpJAioDsDuLR;q-&LZ}}i@)y*&ZeN_u+8~BPz zypHxQDf$g&-%|jnjO$cPX4Ix@JAVX+amuhYp@dZU5)=^Tv>&H4;oAo- zbLwU&RJF5WMe$R7?e$lzy_tQawY!v9)|^__!ZZ@QEOy|-b+4ddHdBEF*EN_>l?2yV zpL_whN(PaNWEPQvmhuu%Mx?p`uD#>F4W7+i+K6C-eu-Z&S75Y0h#g@G=MlePtiULS zl=I~ZPM5XN&3<5x)qaDBgR>BBjTIJFZ@g#Eb^|J^(O?^_gSqBNn_}}16o3W@)zABQ zlxHav^3Iw$_4MoTwQ8Jt(i?97I&-mD@S(#ePsWX7&26(|*L}F#*nZt7Ca$}B$4q1E z_Uk^@otj~;SfNAXiy|C09?|E)*##C!6U8Nvg5KS>4cjW3qAD^Ox`)?J9=kx=&|zn`1ZA7l07Z3oR2!+Aj=~81-i;P!3v1_oswC)`ZYGt<5v5@q7Ae|Ic0D{40E`TG=kC_i2b- zFwGdp=MD&SCfT!5&-O*V8!Z7j(hPq5gcQw0;k8aCV#|;lOa}3qXy8w+ zMc!c}si>>QSvTCRDO-|D2FT8TOjY9uOM=Q_+#DaMd3k^8(bT!xH=8-4f)aIrgc$Jdu5RrGE9=TqHmd;4@m$YfZGq z?JrFv(Oo>=)+xweMw$Cn!R=#|k8I(|*5Z#GN)H^GIFnRtQmcYfG4t`%$L~ZqMWsMZ zOyX-=@xIUBvgJ0exMY;&{HJuqe~Qa%WHc&#Atq0*RJ;TMNpf zi6JWPL5rxfsD8t|NaqjuhP`;xrZ`F}E1eqy7(>`eDIEPpyV>Sm{Z=JDd%3E&4Pp)ZBUeX_tH(i>dJllwR%GTM!=_o$3SV)9xWc zI$d07Ov;4{_VjvuW=ccFd7 zjO}Q$TP#Ybn&I$ec8XQ0pAw-gXWj;8*1UkwI9bOE*OfsE$UqD1x@A`csh%kwdk)3I zqI3fSTk~Z53!M{!IGOX{{uAh5wCbUEc?!f(+B$cGs)^7bM{;b4(;%#~Zc25#P-4q> zvFdn4<%eHFEsRQ@hT0Ll#X*69=7Aji!=7*-;x@!C+DK2F9S{l zBZpkBSpX7tC@VLEKJe}0o@}M;K;u_Xcaj&mE$#mO4?i#bYsmqJ^Iu+I{bBigBX`W% z$|Y)Z=ZVxu0_X?FC^>;AMtT!u(#t?cevs7z5;>DOZyVC%qB#1gzig9CEIT`T-iDGc zm??b}pSwx6EV~~_U)j;QCpZ$Va;1nQnjnYVAzg^UK{F6CEk!|{k!>LdTx6Fw<$|)?Nbj#en1y&=v<}5A5H}+kEg}SjM$&O@DX$C}B z+#Fa~T(o73OV$5)Ktt!DQnKvp$b7!2q`#?lfVw`Nw&sV&+)SB#A3wce%4W9`8m`4o zlc^^5>vxgZIu%F9GcFf+bO0_?z&6jry?DAA2t$=Zl*Zhr*8WmlO;1}I&$P3^F^xcL z_-A&a>P%o?;H@8j$xqI~XO-3fzpfAczPP*=o7%c_Q}xZAnJ8k>BaiFrjTyXNVR@g% ztwRQ{1bw(EKs$AnQ`&T|9bi(2W2o@3Eer$xkKdi)G3*ZaEp5=mfE&D`Aw{w&b5gzq z&J-vUvNl3xu`XA{ly126_I~%qhj6NIjbv@FdVDj*r6aB$@5N{KdmSgaLnViND{aUW zLsf9JPCAQ<0B$6=0M!=y7xCgoHK{PP0aaUwJj-D22!&%U++AFOmNW2R#Wa`JS@ZXL zEwi4oV-n}TmFZe*Vg@{ap(j&xO0MK+KLJSoa(t>1I`sVX)rbxsavhqDVP+Whq(K5Dm8$u2-U$%WVFU z@BYP$D6_|v$jm0(vIr&{NoL3D%h2_N^D_%YFxg2mJH|==a;<`gdK=za>3;+7BA$54 z0Roj}VGrDZ7hDPK;xuCoF1p7y&EpW25=ZAyAv0DNb7W-l(IPtC{bkIKOKQ(et3FDg zT6;u^q<*Y+#c=^^+mjfaHZfOUi4pVxkJ&IbZdV$kyi!3*Ou<*^Hb#g>4LAL?r0&e>s9(wiUw9Q||ac&-qUbPH#hb1RB_JT+2^+-0+5 z%d)%PfG=4#rGEZrDjNdAwcN1`va{r1XE|7-HPtx$gPlFMdOO~@FV4XV-O)}dXD{7> zBGI-Y0U;XX$5uq5X%FHVz|M2dXipIZX~iZDysy;%k;1aiQ<|*+03aN1`V<<&1vUNS z)_qT*pq7*<(a)0-t>cMtI4T`!{!FpemuJaga-ChNphTaL}n~XFwkr}Eur1#T(z8#|wHt*^w4f9g2mPj^!KABs11I#3ZMQV+`CLS`m68Bd_|aLLcv?j zLnEkh*JO;YX5^B5%YBg`vw)b+i)iRfZr_e>(Pk4g28P>0K}YFY&wgRmTRr7-xh(iaK+#G87NsZ4t$)n9qMUa({GyGhK z{EaMD}yHLXDd zv}+YKpL=MxSg}g82E#AuVX3XE+2V}CezRpY`|zz&#fjla$t04G^gi^AVteOxY^Ti$ZU4_`sq+^xii{&K-(a~?i(kJo_4`){ZFL`N*ZSl*jRdE;DOdCYEb9^!DAUIVBkq! zVH=2Csh}FnvNoc23uDidY~;W*@L!nbkkfBjr$04Zm4Cetl%;b(9zUntN`_w?xSOiZ0?F+PeCldU%{QQL zpkoFAb_dFVvu!v=BQm9CNH1o2U(8Pj-1Ani0rp=XA0__3Q!GPXFA>^Nz>& zDGOf*j#l+yy>kGAd8X=HFnliRozxzlg+L>ot+x5?O}KSPPn*&&0nq{gRdVw z_fz<$rKV-0;YC5{n}Li6Iv8K?wj~Op7aEhiP{DJ59G?jY1EQihp}^ynXtrilVN~Xl zf_zoxBC;$?TzMx4&@lnZ@=X?iMaaQAUn_nKh=kg;!~)O?wCqrTI;wtiHi-CDR8kd#fudrcrM>Oj_pM4g_|kF z%UIOIe+3cAYsk&vl%+(asK`|XI)qdm66+Zi(aHzFnyI?hTy_7^GyX3=zN}nzz$U04 zh0E(<(uG02%zkEY&L<73Qku=Kij7>NQd&Z9u_&P{O1?BJr>pZ-w@XJN%cl2;x&+Cp z07wzo5YD84YMU)KljMSuXcFO46L=-t3tT3<4_<%SWAH6&CziNc8~RO+EbLpMs>r*bnBvDf94JNu4Q=nzzGR2FOZmsmo=A=CkV9&sL1CY z-`gC4{pIB7P;@2H+@xR;J>?9|@m^XCGGOFy>LOVDg(r4DPZ5;Nxjta?(CKqGfO><| zI5agL5r5HbkB(MJjk$MCTedW~IDDaws7ug4b+JY%s1n$5OUj7~vy6L`Y~kHj@+DSk zr@c>!K=43sG0Ww!XY_SyR&<&CYIFiTN!DhDV}>9cntL3LjMpfnaKqKA|99T;@BGywz}s)hyXct4>V z9Hlw(<`@l^$NYCrUqifKwm<*C6Bb4u@5jgW;Ssuy+PJm!>@>!D)g$_UgZWloR{|?G z9#Lw_0S7?S5R`xiBC|AP^_27AVL|+%Xpvx?8K2jk#Vfh2F8J=lpF@hjtl8wilT}u< zA)Ew^v=VQPQAf5gq{*9>lV>j&SL}hzwd9(c9=P&RaLi>VH6B>1(qYy#*xWGz;j|}O zF$aTPqSJU8V|Ms*1^xI8?%W*Hlt9vWniJ-diAeO{j%-g}Hpw$wP`U_95(%{lGF6o|@PW z_=wH$6m6V$=}=Hj3|AU6cBO&{KY>rxzy*wg9#}*oxKufM4?A{b%()gp#j~5`sGPOJ zExz39q~KDQg0rwzFx-|Vxkfsv#FBFZT5{dn z`?#O}j+Nose*E<2R?8RAGAHnP7N1PxW`PPl&%|yg+xO+++l)^7Him+K*Aj_TX<(U1 zLp2rg*dK_)mwU|#*A9Q5%Uxaqgw|%u<%x8|<2c@aE*(fE+xWqMW3)29=WNB%%6svt z>x)x&h=a5Cac`0URAv^W&5JNS@_Pz_bkCt+BK(FsqJlHi)I9N4%ARKRDfMFrkikL& zevx*Ar!x~5S70j2oJ^iUYN4F|_yhl)V?t^?Uba_f)-9+Iuf(TjW}=Of=ywc)U1Z~( z+4A@U59MMiG-@QLrMp)X!Vo4X!6e3du+Th-2;wJyty(FAqXMVV^jzQOKl1I3F68J!JgfWpE51h|mK-d1z{XuOV@8iq;B`{i6FYE14`v>Mo{vMcM2J&=vX-gKk|_(482X=cG9JxR9I1h0hOL0l6vP)BZ=is30>5YPqg;^Di* zEooWzsEvdwS(0N4jBrsbX-Zx1jL-I8_83ahQ$MQneBbnn~z~fLhaZ1=~cRC ztI`p>y39(t8eQ$GcQsDqjW@`7SkS3dk`^I4yyUcxK5777RnnRg1zLg?+V3!w>M-*nCCC!9f5;TZMaWj|M!&2}CvdmJf8f%RuTgH0F>fRS-MaHhiO zH|8^anmJ${W)O)HDOQi1_ZD^mk60)eVW2WZ8}&%H3I;HR0g6jx+ZfcV$!12cErjNz z*4NCgL;0*?lZSNeAV18VQG;B&X3r3IzPUAjw^b%`n*xNMT zfIQ}^h~rJTaWFgV7CF4^Z$d`z&|8-6z=S|h%Ai55z&6%gF@o8MyDLy9 zEDrQZIM=Tqj3mqh3N2~9u3AJ!Jqp|hTFHDsXjU}UC2y)!0;kaWegxsXok#MLjDjm| zO|(#b)r-FLtN)}pN`|r?n9lrfr^5p*3K__s<2D|@1O^k+Gg=d4XlAIEiOk_0Rm&v7~)q z=oWm9+OP1_>pX0FF>|oZ%}GvP)NCM2PT_Wlmna)SL*wbMUEppTjCJ7kh$5THFk;ML^`J4V0K9=MYLX^(; zBcXz~NEheHcFb?XvpUa*J#1D`XGA?sT$yb8%n?#*NYejf60C!CJ z)ha!aK;-f#f}jpcit-KcguAl9#;wUNwoBXJewXyOe+$d#HMa9rZ1+*Ip)24Jus4JA z2QgpOI_@ffy)!5^K3oz(qBl^luqUH|mg?4G?b7VU!5MVrf{5T!{yhKpzxnD~TGN4& zWj$Y)#r%0QT%|`7g4Y>L%A3H%i*bBryNVX<#Lery!_-|RLrGAB#_Xt#U~`Rg6^t-e zgV6p#2{~C(86_acyn@P1!TdQc`S!VIasW!Lq&xY*1q-lX4l+#Jt`d2xYp^<2NPrIR7jJ6KeEYfL^(1gF#&en59Siw`jpq)C!wN3m#I(~n76gJQz;lpbyOVr?^Y{lqzz>2rXs5&9BvNF zd)cyVWPtm^JPFB2b7~6k46|S(p9nfMWGb^JucPRxAx3YNpy>($_SQX2-fSQNSm}77 z8z9%F&H2#h5#7l3Crmx(cNAmE+=2tIR53E`+cMU|Ao0<$`eww0ZfBQEk`75{;i053 z-JQee%nAXPr7GZnOk~+V1)($Y77&=I2h9#xodr3#6NyEhthnP+b|Hu(M&Af$s7Ls~ zMGwk`g2gxq<)DLRuaZ}}nf>G!o9p<_wZAM;x{DWDT36$P1GihfTGk$6+7~ZAHVAHU zzq*^&t;pcMhA9gNP#U1Jba<~!P&0L*j{{DSOv*dav}~j5>RFguJHM7&>Yj_vKk;i6 zT7QYqvhny(vCdQ-r&!Ew??m$kF>iBX8{k{BYF`WMRU6%*c;|$lg|1a%@h@stA(;%+ z1pU&p=f-&_iH1tmS<_+a7RfUO=R&ErJfaD#+%)mj7THEd@(PJ8z6M%utS{F6sLSx2 z3m@~IuTX~nfuG)>_v(dKymRrPs|n{d2aa!PwLSEuC~C65L|5`iXizP{_k+}pzqu= zx9#9Wszv!Dwo!0M1H)Yh^O904^5F8E>0jJxty&&3aFbKxj3nsvzH>L+imy~Q1>?XQ zvw$a&4qGF-*^$>0@N`=1q+F;Vhj-yKHvxqB!^(4MqgXr~vFG1ifnY(4fFNVwMv?n* z&@WkV_!2p^EG$esuG)uVXJI7Zs)Z`Ga;SW^4!^}#tpAaz3A8%NUvC#&RnLF zBEM}q1CNu&7tr6B#^B(bR+T|bJThk^a#(Z1zS|EX3Ez^HaNo9>+Z(cy1`4nVB?XkdnWUw~Dj8Hm@smVH_qVFRkmV3qvh4jbzQ~9QcRn}$=9$O5 z4=X8c;(3RP?-*R(f=mplQ+*{m;b&*IW|R%LQOMMg4u(`T#@ai#S2`2ta@@YbP7qSu z$Ma&d2t`>)1V&H>DbyN9;*n6ac@QZ=#?~$3CiW|Vs^BC_*qrWHm4;N!0K;n6r45+y zT&Pawr5h2ki)z)or|#hrve>|j9!K`nGiE8Y}l_cNvi>#JF z7}^E$>cIvqfo6vN0GBj zqE515J7XBgjoafJmj*9I$&MNCpUKYR7vvWp|9S1J6#dp8_honPFJLv3Gm4%Yo zr}43?WiFVOTrxQ2h|oG&fgId@Abv822H;UNfOO5;cRbJY>-Y3&oBbA zrH=s0h;bD9Ea>sYveTDz5l%mJ&n0YzsC^edy&1_hYN`ZTLv8GS=%Pt@wiU-u6J+g_ z*U^N5*DHY0=ipWpGB6-~7MxPXhB@rad=8t8=oH5+{dC;1F3DXu9Bm9t3Y=@dzlsnJ){y*MbNY}FN06RK^r0Y-{bJ*rE zK&RQodB1Z-Tn&8(>54(Eb0bxp%p3T=a2kltI#w4YiMdTik1ju_Kh0syu-EQh&eN&k@Ws$vNUL7<<_k~5*RDOZL`a`Z9^-7B zBgv5j8+H}dXHH*l;3(57X&Luw_i0P5pJ$pkJ4*TlftVxh(IX%s7!XS)2;I7~)RB?o z7Gg^|^ozcD+FkPBaef6z6v$q4U>D5vV@^Dq*tk|QzUzRUI&oyRhbjGl52^G=7+>Ai zndMk69@s?eTVvtY>J)TC)Brwy@yx~}a+qwl(AI5vne0h`Y5{vq2$&s#IZn_QE!@1`2shDH@~3Bj9b z$;0_Bmn_S0u8go?PETi3L%}ss)-IVnk3Dr_10_@DdahH+u#0V-Ol$m~P0hRd;H!`M z(tE#l=?m^U+uA)_y9#fo-H73mb+rzYb>@ZsiUa?)&^XeB6JSxTCp8}x7FjF{s%{v( zDb^1Ut;|C_O&V-$^S|>OKfB92DWtNh>-8$6Bb&(gh>Y_^R-0m57+3g_6$MFkp&!D# zuT-RBoXEg%khWy))|>$Y%i1v9f)kWOM9BMhoH8Qu>PJUqp)T4@#fPJv-rorE!Z@|d zuetfoHI(3Q@Y4(T{z)ZB#EiM;qaYOKdgcT$y@xk|V&mv`uqFS^DN!!HAE?63;O>p= zDN%&NNm>qL315N{^PsQ&ThIbY(8V+9ONNM6Ye$$Q9YRwk*Jq++XQi$DrhmEd;ld_v zED2k7rUJe9k(xeiYk$M>y7uew)=~7)ZHUJ)gZ7PP*Z=Jlbk5nXfj)EH~%PtbQyj_W%$>)J5TJz3t8pQe1&D25DU8XWblz~ z3o|Z^N@U&My2SPf(j^E*F?B}l*3C&pcyvX&{zcC`{w92rTFDte2fmR^s2|}JO_SUn zGJ-Qqa}l7^7?)&&2rvDyl)^;t#+r)YHTc}+(Et|3(%2-b4>WLO`to(=_lb>W4D;Ut z#BoIB4nt_424(k?IB zr7M$@A}mz1#F~ZzL?rYmX=H`f*&@7ZX~3m5IQ)qX((J*iYOeu(Po;GqlNL6xp$+Cd z7uLf}SZI6U%N1m`8FwyAp}GKUgd!l=!^SFzlLal?c;I>gLXq7bnxm#7j<0CR_E#?E z*p(V7i~_;An#A7 z1>ni1L@^a~j~aq~!u7EQG^!5lU_diy8|o>%7YzZ9*}(uqKGe@}fVy%OrSw1OKaH$+ zaozgsM?APjaovocUUB_s0mSt@d`>@w1SA@&s&hL%5S!O4qGU!`$vDk*Qab|RM?wi# zYO(g%B_mJ%GCr&J$PzuU(c=WOecd^5F0@1?0>YKZX6BsyfN3Tm-b`2ygI!WGoj_P4V5D~}T{ASFEl>%vT+3d1^qFY#C| zoU7is`pdt^_blCCXmiCyIMZFI+A?HkE}VzrrY2v-4unc(!d|D1g8JiqbJlvT+&h6l2-)JuW6 zhLP=q;sU@e;yd3|cK9ihJ1~+X%0o2m_yn~tOtI2hf!Zmcx}!HAW3X9HaAajB%dX7V zYm2j3xX6#7m$ViG9MVK>dVzMjM|4>n`;D{yWCH_KnJjD!HM7N~6v50a<}hz=O-x49 z7tuaS>AE`zgV!;%=Z`fN_E;Q&Wa^4+%hOeOD+!-1M9oT)6i*v7U`og*zKRwIi-VQM zE;{@=hYy-P3$6`spS^|4;?~!%`O|;ISE@ax#D?zFV9oq-Vf5lHcxQ>+U?7n_VF&}$ zWr1oe#Klt`5bljLbo3v{Y$6mn5T>t+{Zar$;NzKG8bif54y&*Y`3kC$X+dqEGP;q> zMG66Chi1HF_NglI!u9HcH(mSKAxdnpM6Z6ANo=Ay-m0%?&z?65 zO`eFcb3{z2eP9&BwzyUSL36mxQWEv;*|zX3#D)@e-5Ero%CpVLb|4DxVlT3MiB%Qn zPj3aS5}Gh0AJ_v$`8y(Yr0$>N)eHsqX5!1?2t2G>V3FN~I-Xp3LhaT|9L69TO!#Lot$6vh+pQ*)3*E9HHZL4KGg1MkqFgxWYD_E)C5e~qz zg@um+TUyd%vKmoPv$Je(iy;Vgkz)9+T&Lakm^!{zX@+s|KB`Ge`SflewcBq6tIZd6^bvyB?`+$*A zxW+kVGPJ5(vlY9;eDw6gn@`Xl9}VP+IPDdfTXr3btW=o7n_v6&Ww$UUE6 zH|elmXpHbe1;4@7du>~@T?ePpedRtjHHRY6g1z?<2x}A*qi}yh(gl@D!~6=f(e_}# zk#_Gc$+h6BhkxP$_oS`=p=9;AQ zDHQWY%?tt5g|t*~URVU1tKbrRo#Gq?psEkV1fG~SoO;g=2MVNpSb}^c(i~lu{6aB^Ny}5 zMChJAX3K|iNjXHC_5|F~6YJJ)K@H-CRG`wIMm7^pTGB1jrXAEUTIiloRnFOUdAB4s z2a7Jg#c$nu91k(CeGfmq@yTZTbKl1@72lf9*i=?4k)}qKALlF_W~sy&o3rt@>xHgm zfRVkZ$uo(kQ3`h>i)kk4A_9>zY6jED6XG{h|Kaqjmp_^mbZvEslc_JDa(n@wnVS4m zyW=5CJfbE901IpJ7BpXP?pr;dqXPJK&Fv)Vi?&tKK;{18eX$wd1{;xpP?F0E-?p_R zcyy_|_?x+!OkebYH@=yI{1^Q6s)-G+rzh%fV!~8uV;WVZ#RfTSf1LoK{KxxWd%Vyl z+`K6zGt3^<7?NjD%|{Z#64DSidPP+y671jv1?M&cQY6}lh8dQK z-q>3U;9i)kqp&uZ5aj-x!5}%!FCIDpU1|&POk}q-3J@n6-Nc1tBm)7D zDa!>P`<=r1JMhJNMR95_ik*Opn_JCY7|t6>4e=aHCXL}82u4$*WB<*j_#P{m#O*8e znQNN`Xe1%6H33hRjGnrgIS$L@3It@Lvs3eecai&=_da9qI{LF(Nl)s*({#-w8INo| z-GaoWcw+&A(z#0JvdslpdLZPyC+(=iCEA z52V&8P8+h5zxf+3o@;M>@7GAC)kM zJjqN}MM6B7Mivh8K7%AiyNcZye~}c-s9CsC9Fr#fEDC-AV`rWG(T@&Ob#Wd2%+KzW z4(C%!oXL|^Tr72fxSvApak8DvhsB{0zWm=GNZ(^Q+&_`W5BH8zB#W6`$Ymon1m5A? zNo^>Us6rxM2`vTfq62knRzPgenMKe@tWQUShNMjW=)}j)W2=EXw#8QvF&5szg|+YX zgFoGg?_O3HI{25FyJ^jE2uFRejZhHfNQq5)rGW>GD-~iBTUUE(t%3~P)4Dx`b1{oD zl7%m`1__}_zN1?KO4DU21!V*-m~K-(Gd;8M91D?pP{n4 z7cTc>&TlhZGG)~5?8a`L7Rn&wtxB*&dd7mBmeLs>qat~aOo^)wge4_0)(j;EIlJPz z2j?C0&?LW3cDtE7+Qjz>uMuV|#I5|1%nffZWlOe2=(7sPxD|;R>^9rS7$dJQUh>^0 z=f>5_=qfuLgJ5X+$S$1b$!x0InvLo$h1rrTOs9CIg2K)5ZLtT}dnm(SnTL@)$hi{2Ue4RcPONpZ&=b@HNV|qa3uuFSz?+`9%A? z=GNBi81n7WQOq{=bi0m=Nci<4(rvj|K?a07>)|*;i}3A?waGF-@fWxvzvl!$U?6hM zyf*?gB|=|DXnTcH@Se5^74L|er3>V==l$y~GCAuue6e1*V<$4)7nhcU`Gv=m?Kv(B z=GJYLExOId&SrP=uo?-y$~umFg@p|EBxx(l@{u@s$Y$tbjDz4pAd+>Z-GjdEyC5U( zZ1KhJ`(XFCoJ3Z8Vo79Lp$=pr7W+YbWPjfDgGMDeK~Y>XcSbgZc#79 z5aj}3DJ*Iwsd(rU*OKMV*7}xO%G~WJ-K&LNf6Ya<``xoIKZhbK*++VC<-&>VL-@$m zEDq;PM~^N?`X}Bm!FhHC73n*;9JbYnS>!>6{Jtkc$iL(n_1IW)#;%D-&aEivuLzt> z)3;Cis~vUXk=hUN(`!?!Rb~W0%khxs>aeUdyqo}tIrLluF{WK5(;UW~@CF5ZCVO=} zrOJY|X40ZjESUzAnN4i{Fm1}&bj3J|NJsOuy$IBA=yC_3?eHvM$|WKWf92z z27?Ipv@v=#I&!6g1AQ-U&YK7|p-X{Mra(c9We*h`$zbLli`L`#EOR_56q(NRT?=1jS<8bDwH*TNNw7!=$3o`$%mf74B`PL@)}IYWhKgC-Dut*0lvM1CS{bf z(2iH7bK`ZmwJ$?lz-jsvh2w_?d+&;*3Q?Dr8ljE049Bch_JneRY>8BB1AB}VLg(g6 z4#pf^uUk2K@(b6TL4lME&OW$F1#(YZUWsTP@}S;~0mn7R8k0M^-Dag;mY3sZA&v5H zXw57}I%HQwZwhnRsZS}(GzVaGHp3NmYjSg2QYI(<^>5Zcx5xtehYn|&o<^yyhVt_U=)Z}F}t)ON4m%%YXd4Y{xN&>CjpJsdfTvEFayz=uOrlcNL zVnJI}VHQ?W7vaN~rMB(hCva?ypOKQ%#?2_Uk?|aoyEB zW*S?!U-z-@)C}4F3hiQ_!+Wjo=;?MWeR(38{HD8H<2BtR;FO}>Ulbw7vsjL;x=v_}RV8w@LrDI2 z_NWZ9{ieS+D;mqu zs@6?>lKA+v=_}h0>~g&PvUMkjem=HDj%Q`A9!)<15tv%Y41BgU@~FWIYDnm{-1-aw zW4LkFi!ONH$*G$e)pbj=C>ZR`po43wYlTucDjhW9Gd+{#{|d+CZ6u*c5fBv5g@B|==${3`(Y5OO=bwEohP4tKUT05D)2)f_(Av5m4G@b$ua8YECI zFweB~vdz5=A#sXAUz#jxEObw~3*9>5_2{_sR#59s^OzvHFeQxRs(n+96`q|Mv8byB z6)JwAscrX3KX~_Zu&T1dDGrV#8(h^vV|gw_8BInAHq~r*D@Dyq@M)V8A*gV`l?+^< z$yJmL`sG)m*tzY4y2@%AOaJbAH9dI#Pd-3#l+6D- zIIH3yVX_80ECEalT)t#4@_J=5pY#8sYMKgIh(_9@N8YC!{cEug3X9`tO+gUWP|tA+ zC=VHtOs+Zz6{%jJo0_P-U}AhBKGY?#=!yp&_jF34Wc2F69V!Wy$kw#BZKILt;VwZN zik;~tbb0aImnymar}4&ph+V8Wh-+|V7N{dUkCi(G0iBwk?JC-!_E>BZ^jMTzsQ@v6 zCAcUpGTYW=Z>1vqgtzxG6aE&!sL~td4Oa35q^=}8d|igSw;sG3iw?D8N|3<$nKre6 zFfer!we}#MRhuR;T5Gs7Guf$v2WVhJ-nYaiPWD&3&u$S8d3}h)k*GypI#WK`xab$vXS5~fdZqbMn+OY zS3Dbw0a1@$d~CCQKdh(5VG6xUvnLndc1-Qx)M~{}g~#9~pW@pERoFTOBeh0JDpWBj zb_{A;7pw@bLZ7?-Df$B$Gf;zcB5mgDknAC9X?g0Um`_8p7?DJ?EK^1)2$@H*3ntP# znyi|wJDSCB`0XW22o8UWpI!mkD0T{PO{d!&>-98Lv39dfGNn~1khgIosCYLH<=cEG zg+9|jxmX~}d`22cRt6=|yh8fqB1|zuz;7$Zf?K4t=L@~ymj67See|`j;-`0^m#8L? zXKf&mdV0W zAi*c@`wD51_yK=>d(PPV%3JX9weR4kcfGIG^@^U7-K($1Nnf3bfD}xTh4yPq>4gg3 zkd2wh{8X{ja7l+)Z?hswFC%&6qHCo7>eL%HCOKQqWW-@|ZEN)!wAfoRE5LYhngC@(@TpF0WUH)J)X|v>gE+ z1!XmF$jt>~L-b{{Zt6zV1R|07g_KS40+KQd^z_B<@ZtNjx;>qAqb4899ZuoE`lg?oGeivyi+ReTPJJL z>zGJXkz)K7iXmv4&7>;<24}@ZBfcuqRtza2{__V{f2vV-T7I(*|OSy`b9N#>ClyNa_NWb|Oktwua`LV(2K4 zRkPEYF;8qUG8z1jQ{#2!p7JlQY60jrOrD$3Y$|Jt*MwQa*pIa7$={FC0%51S zGO~KGLRUwAAgrixE|sI#p3&TduU9s$>frlTDi6SA7$53-huR>`x3yywZTDc>5!?kgFO=|R-8ag5 zbL2VdvheXPn!V?Lyk925aSLHD0Q#_shKb-27`f<;N92}FBKWFqM#(BPps_##WM|x) z@sdSeT!NMS5e$H_Ne~|hNGEnR6Ql{c_Bh4uQn>0#r@Ri|syto!c#jk|wW`7SV9)Q z&^zDqkmufw3oYw2zji?u`gVL8&>$kT*81%m&-ku*z+TXX(lRJP!U$!rEv6hTg0ss+ z>R^hEq$=xeTtTq%ktb{MhaWEeQ1RS)?%$pz5$Kor(!JJTvyYFkHS8AgfDTbDRs16M zE4%yy)l+w&(;AhG|H9%9&5tY%WLr^E4^bE-38ol|FAc`s^uSAh@@{;KQpWu=suP59 z>yWEs8unZl(caac=wutFnlx~38lpvo8sRH(=Q2N|BG+O+%van1@PbX&6-HBep`PkQ z-ZDQ}0Di^O)Cjn>VkmsQr^}GA>~jhedCn)l&I9CX4=M48Ho^GFi-U{~3QvTnP6R4p zm6Q}aX^a&OR%})n9l^q;7@b+Td+k)T0*mowFaNzad(E%Tr6Wx z9)A1{_>whtQT3X}=Tu81hT`B|VZXs?%#5|CT~lOV4z4u_yzN>Acll9#a^c}36tD$n zYJ`LOxZt3Dg8#^=0OX=g8%&o#X%2T0j*Gicm|)~piQtNmZE*6T_claOiC<7IR_xiO zw`l82ZoZn*yI+a)zOdlZ;~1gr)GF?7vnVTb9Ho0m>KaKlngqJaxU<%!DJ~6r(wf9j zBKX6_6MJMbbZP9p^&{{5F{M#fhWMgNgUp1tTlIm~4+5GXRZrL1+1!EcU6mL@dYz%v z|09k-Dhg^cfmYe1fqWaOF@P&@NMA55aLtw=8>IDcLd5UKPDhrVQ8W(E;++JGxkzq$ z;@aIzdrG@}Z#YyW>vrG-6t^wbwyz(7M}G?rAh!z@oY8A=??&vH&casW5by=V74>AqL3ODai3vhX z0%3C^%VY@H$GsXF^m2cvtwG9Br1;=s*|YYS_k9{wsSL!}kY^GOM|8ZkgZnAGai4CH zRM~dWJAK2-tgt&_fkxp-`k6EzL|*$ ztC&HASVPe3PFNg@UNAI#_;W5^fzLD-JR=9e0F5w@=U*`;pE)xu3XMKlxdXq%wR`ib zbO)?v^a9|)Z#&2ZA&Nu$fR@1a{#XB&I9TY#*)uhB*&8VjHpTVI<7Slyi(3OIe>9=I z{mtkUXJUZE-uW^{e9u*It}noy%Z%I-pCM@v+e%;`SQ3_-cmYkC=uUw&bi=mflhir9 z;*^{BiABC-9#n9nZ|0vwcLu$R8_nr|^414D2VbW4gc5D|v9A7sxIEBhMH#IjQ>YN_ zm`Vex>$o_Hiw)FKaIrDPixnhsCGJ-O*Eeahd~Tgxh#OJc7Jk43Bpsv<`4miZ>QS5R zjNa6`7UZwJua(iY_$et;;_0Npg|g%{HVx2)_|H_;&8KzAPw&KcE<5|>;H@e!rU(O& z7soL%C8FNt%A6ysffx^$49d2wI{2M*j5W54J+^?ve>V4BQnl> zp_@PvIO!kRYK>ospz4iPaU=mm1n;A?8?92=HcHS%bj}OvvoxksnDMWi* zn^v*`IwCPC&^Bk_nX8V_c^@AK+=&gyfoxP)=wP8qwu$WF$4IFqGjiJG;=k1{b=p!VlrKh*S;t6(TYG%Ml5AW?}ednKgpxE+W4_4&i248^wxdLJw-Z?+aL;;3B~YGDJRrYGptl zOUWS>u;6~B3&D`tX$8+w#YrQDxh_Ni2N#PwFK7ki1djH?<69W7FIBox%xSpn6E<|$ zZtSrPd10zxLB|?Un!e^JT3vY@m?5%6mWAX-A9m}{cnDl&dH45HradG%7Qz=5(>@G2 z@=b|6uPBFGIP!S`%RH0i02t<~Ie89dVY%TXq($?xZ zSFT)2`$tKNDViUOf*=en%X9xEIs9A{uKwqxF0|~ec=as!TSqXd;Z(_YBv3FL{LXIi zJyp$t4_a8>hCZr!W!&m;YC!|T!UJ2{+M zPmS+s*g`B|)(Q4ucEP-}(&ZpU(O;`r<2yFZsQ`5Z=a+#GA%e;?zSlFUjt9dcYC*Li zN+Z+|u;9*(szx~A+Z*SB%gFrf=c1oy3#T$x5vTlb$dK){DGWiTLhR_nD+?`;ztR&YMbF3rDl}YN5ubEFy z^Jymnn3kM|MDQ69b|?{B!zi}Uo+Ezvu_wO-U%D!v-@4D95E0YjrShl6LpI0Ra$_XN z@m1-iXIt$yXDQ*NCrknbN{V}Kp(I|qJ4o6(tx%__mITL7 zmvbm4ZpdkM`B*a&I8(wp$ibliL&WRrnZBs^)c zp&#<2%6 zsL;4BbrJVDdXi{Gfg?|HX@fzJWpRjO!~toUYDtZnnU(Z*l#sm5S4Ik)%vS!-27Ns| zf~>QiY!}SEmw$GPwVhOyRJZQ8hXwO#2xg8)wW9CDat_ha;e2~?#mXiylKMbjoZ=`A zE5ZTe{mN8oD^v-jX5!(>F-#_daCWPx6>IorVYSgcpoNTc0`qMFPj#(&oWfnNCOO_@6+%4sbIPJB2 z-As|xDyD(99#DvK1P6S#g~?~*WkK`~fwNlMnBb1*F7PNdF_lguo#-k+%gaVmT;woab9|`Ty9&&3UsuC)=i#M`eUnMyx5Di3d<}ykJ;0ty zcxqPMn9Nxj5o+OWy;*Y=RMbg<-!A}L_&1XnR5*cPY{d1C&g26cjIDSRQn_)?d2iu4 z&Q%+CwjLybgF(7lTCMtx8jLE1UP6`Y){2^2iE@b+80NAho

      SEXrAuWuJB4R4laGdWb|q5)gjU!T55{LO`s$b6mOp;it05(OFj7ddaMtm-FFZDe$0qS}~$%j)cw zh=P_3Vh1%$Em(2snn-cH1z?g7#90O|TpRJt62O!xIGGw!y8hy4oWP=GB^dWj>{1&J zW**zzm~%NM#N#MOtp&q^A9n%5S((fIax!&$o`woZos31KirS@oamq*HKQt4C5M_lr z>XaSE3xU}IZe9kDHwlseun}P2oRW7J=MN6S+_mlQty?IV-{DU?ob;{ZQ!bb{;Iozn zs)=tcB~pc&-#ogbq6L!Q3Lf>1&j2g=|W6McpI z-@M4herWLrCPLVwf{BOUqt5->OTLbes&Ov4{Q>))XIjScwOsQ&y!&mEVO)kI^x8JL;0^cL|`bK;t;wP0<=`+h-1}@xLDij-#OsFz9IKWA4N+h9KNp$eiohH~D*&Pfa zByjIvJ?y}vDS?W$a$9|mISCk-!1BJ4yv3a9or_?cKkq^Y7vrU(q?DSGj>>_-!W?fS zMa{H=-F+T@KWbRBV;iy&9(z;dI?Ni{w!jUR4)%;(ly ziTFqO>g}fDE6)inrc_n>@P;duJY*<=rCin+m-SzeQqUrJsFdQc_RGc>zG#3UfktPB z1wcVK6{@i5mESv(c}T5d)xg$yGKM{%3TNXJmmvr5ls#TFfv6&g@G&vq7mXo70$+y9unK?hB#~4; zPZWuYrr^yALc}~%2w?4xK7EXVu8Lmtt-hw(q6BMfbuPzSH`YT9QrshcEH++${OVsLaJpZ+gugk3Edm zz`xqBGQq0*`;OI^o$h?t3EFgug5p)`1<2Mt6Lb-gK1>_35Uk;qr<}OpNWm z+ki$C%7R1ou*$BB)cu`!agmjW#|$P)&zlKay(~unaw2zUnJ<-iTq0VQVfSbXl^PZd z;d_vxAp(CSvbEj)-oDT0Udv^3Rek$gH)MfeV$HUXVJFvcvp+>0Yp&8I?&ad8PTa~H z9zN0BG*P=0pUci2vkZWHi^0Y|G01YejtdDws2Y57FXLV!xoYxW2uUPLQ`m81fYY%$ zk5k1?4Z=L={2}|@`q{FTd1hbx@}5Z%ZN2>r-41~P7WDIP}H z;Q51JIq~h3;G-%ec$y@*FD@_S*bugO4MYe#7(Ya?SPPfd>}?LgQ*USvc4C1cywmUo zD`R*Q(I?gFd1K%_X=pjjxETuA!4YYeFww4S&!NX^k2V34@_@H2M)zAo5A1XRu&Ui=4UT96_0Z1f>kp zIMd{_0e@sR65Dw2N%8EVA7)kf3sulOisjUFc3%9*ILRYDh9s>2`Te$+<6Bo9gtYY^ zr7;A?vvejfIM<>zjhO*FCfs1>M=JmGezG=3_jwlGc?0m&X&I9x(n$2i@rXHNbsQA6 zrOle&$L>10pom!-{k6s#OOXu+pwA<0*NTdsS~PPO8Hp)0(MuSyk}&!s`9>kK6aMQl zPiF>QHPW#4JrWrM-JE{#0Z`r*Xc8_CPNUFPfqLx28SkSVwkUk$Q4$&xO{5cU8OowW zmSz4(xdyE!X-XaJ<06@n(a}jC3JmTJ-*YW^?*tX}0Y$fx6jF7JNWp@fJ^H}MehFW) zvKi*RSvFJJTOHD2zvBu&9ia^BQ2@>+f!j+Csz@2*Y17@9s^mtr6fK$Oqt6f4i{DY_ zt;wS}?E-%mF`-0a4bm5h$O<=s>=ux;KM|Wp-FD{EuThj0s~Wa`K%%4@n>}^s zL4M?ZsTo5^StUq=9h#!2XG*45U`QAx%V1VFv@)1(T*B_LzNT%yEPi8NjXbv1NlDN5F2{~D3h z_~HYAYd#2X|^Y|$1CAh$A7{b!E z4v^?amq~`Km&{fRb{YqXajO($RQqN^{!_phXx zu9CQ@H98=A*#=PkxqL;f(Gk&Oy3mPJx=%u*W1njzbOK2+x36-3>Qo5R(@i6tCF{)&g&Sq11zv}YG-uoZJh1p`@vv=Xum!a^h9ztm7{V5^G+Iz}>d?YNGZV%mlNv%h zq%aFO;8h#Coym0;oNf?!sMt_j$KgHu34yGA(juZ%ow!vl|8;Ze?p`OCP= z6kkFQY1JS5?<;6_wLjudyR>eQ-Z34T!V=B-|1Ei)inpC_6lyf`rQpaZC*(q4P{A=E z2C!0XLl+1X$sdY?HEUO6YLOr^oeaAy8a=32QeTgh^X_}`UL*J(mHE#t`SyD-kc_F* zI!d_cs110*PLGj|ARQ)}K=z$j-31@ky^|F68VCtU*_b&hM+^=j8)?u|rU&Xdc`}v$ zT0l8lEdxGCMWSUjPT(mit+YYc?T|qS{En3v^P}*PYr1B?;i5b0vBO7xm7?QLn0C$a zEq~OUsTSQSc+VxK8m0hpOzC0kpQ#386$d0fh^AiWGoKb6B8X?`@)`is2eGF$1K35R zRsc66J&UlIB`KKYTs1%YO+Q3sT9+!rW4$T~e%5k+Zh{=+{T#OICJl z{g+IK;IL;HJz2w(^;ziDO;RyFMHhPec%ci)uw!c_TOJgkVxI^+N#BH>VbjR@UFdgf zBoC{@LZBkiz$q!#>z}zj%WWMHG3)bl2s~Bw;d_|QxqB0OBpHd@}5`i&NfC5q{Uuj*6!YlGGMWrsuHbPsL9QGzQ z`UU{yLLaWW^3BskiETiEoO0Z;&=@4|c#v#G3Dju65FcghL9F}(kGeZ26LR>KqCv`2# z=Lqz+B*pb<%L8wJCecnM8v3>b$hu@VXaX*{dEJqZYc{1gNxus{|ioW2`)D;_X{$?~z# zyd%Ez_~%;Ja8(`ZI}#jOlAh7Afk8af!Q_UR>NogP?n&y#2fY_BoE;?teB;14ycPK+ zV3`&+mqi1c?o+%@=IP~30Ut+7Zf$T{#;?%vP@?YP(o4ZaxrC_MA&pHpzW&=M!2~NI z&G!mvj7>ILryW^Ff%_Oov3w(P6xdTo=M)62p-h%*dq}KJv`mM14W6pysV6MxiMqzg zy>}<93K=$UJ@qV`hWR`!E!BSyj%}_HrGbGGoslS^yMFtD%a}0KUQ*$kzP|@$LZ)3= zpta4KuWh)mLVR{-)286gZZT6=v!JjF`VXK~?nPLj#rxz{wIT9^3sc$|o9YqYV#q0! zu88vRTCD96KZYh<_0la@KAcjk+Pd+BJt#GD-`4o%>Ro)zR{EP7k z0Yyx0kyzWAO$`uv(6!L9>$kjY=ArafRfWx;>~Sf52A{kTI&T{b@wI|kG$@%Wh-gh2 zpUC@dnKk&HG0oGZ#zNx@a?u?QJQKIpGN4R9)$GhaW{dt`P%4Z*mL{YJ#U2L74flTk z2|Lciebl%^q8*3+R3c=z4-^d@A(%PDR>;AjmM%`L*1-A*tR%q!HQ3eJ0p}fR#t*i1 zj82}^g^`Gf)9}Vb)k|hseveFE96`8w{Isx1vML??Xt0lmsg)c30liE zDTK6T@TxDohC-@1&S`70ad{?iWFL~C;eJYMBrVN52rrG@N?5`%)Y&S4kP?%**@O$Y z*COc(3FI9ik#)Mq8O-e%sSa$EK$uok;hbb^_m10@{3J1$kAkay%ouzSvX?SHausDTJSZ6Dh!ZMjWE{#GZP-+rZy5SbcRn~V=>kfuCS5@L= z$_RxIOj~7taTzaIoC@!SN1zK0+fKimJI`X^)WWN=J|V#eKKJrNo0RRKfs0>c-DB9t8jNo_N4Y%+xkdF|JURQqX2gv2C(t>DJ|-B9|^ffu}@K z!Ynv{Z(5~TTaNh4-G!TPeegpz>r}5Wja_^6`F|MqJco3X@;K-#97xe>?@yMi&iyx7 zr1UW-k1Hjzv1pdqDnxZP>WHE=>9My5p4LNN4v~0K8X@uz3ys+H_$U72-|u+v=f6f6!{Mq~M{XM;(q zQAmY#I9&h-ifUA;u)|PBXh(#Tm6xw22tm)-NghAZ5BMviy7C@rRKyHL6 zCov*Lj^XR4l*tz!2dP->>q_poWzmI*2D<1l-jLs>ExRt^-rFklx6QY>(!)-<{D}U{ zGg^z8-&uGTl&^J@S)j5saV4bQ2nj8fb61%v-+72xtb^+wzh)?H7mW0Zkh!-Qm z;kye`8O@Q?kd5U5adw=#m zwG`wj(Ank9#zt)XPaWLM6G&U^^y!gXuj<)nc0fHIC;Kb>Y4;fi?ommwp*gh`DiYa!<1Y*Fk(T78*?~-3qEnIL&}kH`g!j`Hhhf$C zIsHwR-BqM8+lmdbv#0*KGlhZUWvsC6gT*sPJi%j4l|jw)kKub%bt-T3m8K++bn`8(2kbmWqKkEM-8LRv ziB}exXiyPm70mO6tXj%+3CypI;gzDvU5y+i^tVA41e9cBA*U$Oa7q(WjiZ-Dl$x>S zA7+aUY2E&dy~YWfs`im>d#+Sv%B6KFK5s5|wPG<~>H0+bnkiY9Qeg1t!IBcBJ`T7Q zf-nRMMGs$6#={!a8gK5(>%=mf#D$uZQBfkeUpr!?AlfaZ^3uvx-|T(TMHJLyD&p;7 z5)?}-Q#eQ+R`piA?Ft(eHfp&Qx{=fl(-CSzW)ulse)56+X>($2jdfK^IEF*i;|zi# znum0`B_9u+IqRG?&zQ}C`?v~G{7nwHbNV;(Y!eoniji_^Thp#^4xd-LfU###6qe#9 zXqsEsmBgfb_QqZK31vH3`CF=&EG@yR^71;EkpW@{BsMo?$`aLj>n;mn%o{#*=ze^w zs^ea_y->nnE6*I13?Sw@R!g@W890FQ7G_mXX^agux~aAih0f0SI8>mpr<9Y#BZVXo zYRBCf!L3?zj~a1I^)2x+u;p+Y<0#g$5wSZZ2yypI4u9}I_Mp{RxNVO#FUhKKw4QW* z@v1Qt^nypBDy-3!-VwXfg({FpS(px2h| zrBQG^d=+=aO-Fx{-lCE5d!b;_QWtWX_R4EMcrfKu(IB|(rF&FP@4%-Lr>GUYG4OWjjeY#}+`Nf)KKQcO40vAV0-soq%^92UGGK;yCoq{+Dq5NNpSb zw5!d_C62vt>1dSmQgxczvKDJ{u}gbs!`N77gQwv`H{r#}Evk+cMZ^Mer07ZJ4UVBf ze1;?zakqHRM%on~!vKoUZ6UkHKz~usNwxWl_pVR8h+gw=DokZoanCq$I#~#rMjJq5 zv7TpVc2SSN8n2x%1hUCAJ;O4nLsUj`un702m`Kzjpc?KYv;=-#+IZ)BprWFYl865n#0%i6}q_1)&(tN6jER@j(m3! z?W$e8;V^vbs_m-Vj+Y7%*e+;r?agj!z&if8>onj)cth(}i?0R)!9A+gC&goPC>RN| z)zF%Yb*w>mQ$%nt+9h$ZCQ!hew0Hv5pQsR7B^3*ZMot0CX9q}7Iyh(~T<-%vec^d4 zsXF^qxSmOZ`6@+|Nlk zy|LL->8)Ks&OhvRPbH&KJETGouazJO=od6s222OQty~9bpc*J zf>+PUE7A;>fstjG$8bOU^H-L>Qn{Q6kwSC|!b%mP0tuW&_?3e$5XHoaZwLO!SCwQU_= zDVQjaLs7S7VG+Vr1S%1g#uu zTIOrolli3oaEBsRH8Bb4vWNAh;NyZ_U@Gk&qbv&Ml;%8cf8gTtZBcQ>A%)upB$<6p zGHZwHI8rVJB2Gft!A#sr(1lu@hu2x>d_l7#`41JhK)^=IA_b1{UF15UC*d}5ONQ_5 zp>rDpun!@h>w-7b`P`gE=vU5j_vX8d(Zj6>Te%~8?40tuPgkD?HXN(Cd-lGG%v+Tje*7h_V0AK zeJ3E^1YWqvxJRHCK3z1h34aEpGX=6(%mkA3B)TPiAE`B=+V;@^%7rVAe6PfPF3`}4 zLyv#y=ReJR{<{h{GS+g>sPfep0{INL`qGgxZXFu33ti{|^MFN&rm7_rmP1SN<^ftY z7ox&)7FqtRP|?P|7ZEBrr?OmQ!YOKYf`1TX)apZUVXuHQ^1vw-^T;1E8$JDuOF4R4 ztJsdYZF~>P>{5K@tbE?N#FHGRyMp8+=|HWcy?}AyWGv4ilx>dnAzP~Ns_+?K=Ourl=3uQMtlG~OeqtlOckKlg3g#<(Em)f#O`(Eaj?V;h zs4t{Mg*U{0o-~4Dch%+{l00Q`DQhNf$yhPgVFwQpy)Ev1Va5({>i|?5IcV{0Iv!f9 zw+RSBT(>W-Z@+@#s%Vqkws8;Y);ajho}BL)X%$k#H)kJq%|CpfUZZwIg(jUU(HJyFJ1bKEY2^x$+n$J(QZke@Vr2l{KrzkL6HdGMe1zvHs6hL>hn7Tr}# ztg<^`_5=1B|7X4%f0ev#%qy#nG|N|`E|yXcv0Pk%1oABvzC051W*mCc>b}}S+me?(@GNuF6%+B>PM5ws(e58JC6K@@(0DkH zGch-8$gr*9kOA7a?OGQBj#=FNI6B_@huu4fjtrNPAq*X|Z=`fg9PkGux&Oo|m->=& zM%4{9=UR-Gx$+$vQUBC?PkuQyqT-mJZN8~^4@%^GeDWe2pS6Z2#ckYKID*tyi)>*j zaZu<(u0|(}moC9r60H#B28me>iAKQ}L{@sC8mi*6{Uwowzq)qePw;IkX__;oI%YZp zLrA{|C+kNyCRz`(SnpSQ*YHXgYQxlOruK>T+D;3RwhiB#P@oz2P5!-=8>d&ely_&j9LqD&mNmxF)QDqu z!voW$VD`O%jU;}h3%Sq%&rg->Os0hQEHExQxNOR|@S5bP@@v9xM?pY-$y^bN2iD;c zWKUKu{KT@a5oo7%6XY&DR2OVTzs~@Kw06CI>ysaauU$3NyUn*;Q;YV1v=}E_lp%}B zgSq93HlCVBbVEtlz#v1z;c=7(h#$*40x6g5OtL3y-UC$xgHAuQ^^UN^mVG%gJTdL~ zGV$>twFkC;={+ao>sNO7p0!7HjAOk$_Lx%uE=)v;LwIDs<5Y?>3q_o=>H;*)N-;+B zz&P2TYJ9Xq0bIAR@BTbuqdTH1Om0UG7ftz!nLf&yAZf^N?^C8d{U0d5ij6_r-Y5BS z*??)?@`1rqQaZ;J*6eefKkdRcIXyUsh}LIoqcEE?5JQvBd1Q-{YsRQaJ|Y);*8qm? zFawpl6HlG$6@^Or=h3)50!B=2v&8FHtzGgPe97AX;7@yH?`+A0Nr)YbF&C}#>#_1B z+!h%_v=t8YuJ#LENM;hRZPR|bR(jhO3)AKVI4;3xTPK({g7OfV%%8a!(WwMA8jpaM_7^La|yvgrRwq0xX%s3Ge*F`(8yE98@6#U**oAys)_jd>80pxc&Z=MA9CHc%|28 zt-FDCAHs`~;uRsKU{F%Tu}+sv-U8R4i52x1G(lM_nxhYs6ikAJ5l@F`^(~X?$!Ef@ z+ztgMp((0B86HHu4-Glz{`I^1@HMMegl_XS?t4f&?9wdlgkKH8G3UbJDcG)xxGG{N zOvu8gyA-%aHgsA7s$zEmGfHq`MVOL(d0^xI*M5t)e{_X%6f4+moiQNpi6a|^*Myre z0|8FLxj?;>ywHV#a1g>GsM#I=PlQna;T>7yke{{e|DfT~?iixXm}q6S9YJ7LMRV_ZC;|;u+$FE(G*$yy;>)=aVR1-xJ{m1QAhq zTg9X-a>s4Jp~MtKD7b(teX$&=*$I9x(OLEkT70g9!DdKKhds$TKUnyuiZLAp&Z>Jk`^3@*YJz}36bipzm?>ZyS74Q z&UoJ`b9?dWRr_+c-K2XZ7rqc0GYjnyOo+G!CvN#!xHbfZ>EpG|k2wsRVs&6~3`9sF zfDhu3LCf;I!$Y(aVTyhY-)DuN&_)}xV*|M8hJ{W0hrzfQI(J?q1Y!EeM~)9m36_)I zXWe$k&vM6eU_u~_- zDu=LLuyF;dH*ciqL`P#;r?ZeL`7Bs1(>Oq-QKC=+?<%plwJ5P(sm~KZh#cDy36h<6(71{Lpb6&|zrP9&( z3TsMZNn-;1)cX1{!vky9rWQ3Lb9JS6y>g7%av(L+7P2ioWpJ_w0cR?5Vf>w+0Klbf828PtU5B9t%MjxT=X2lnS7 zn3W8f?*N~2vE7c(>xpeQ#q*^2ND-RFg)72s$RlUw(C2t!VIUoy3ERtZ%Pkj8O<`IR zLp8%&%iuFMr9e!ZAg&2Ej_hv`f_ zp8=eb778ds#+BZ2ztV*cvJf&?H*}l~TP) zM9Uffb@m6@?NqBcr*_+qq*i-TOp^dNp-s=g57v#0H&^#I2GKazO^D*QG837ZVkaFlecB9!tuR<8vyW3tL-2D@$2k^l={6 zdT1g>1px3&#Q;|JxbCej7joPy8M9!w5` zU>c8xxQNsx(-O=82;GG-SPPkB=3d(%y|FSLM`7-GU$nJ=BOsR-O?n}aBYyea9h^C= zRTcksN~g$CPT4`RfqIx@21@g1n==EHH*D95wsH8ZwPpBAnJp;mGQ%rElA%UC^ay=a zE-~J5vzvF$|HV=o(BI;(_88+^aQDc~UZtCbK4v$f$ead%T45L+C>~{z%A)&!I(6PO zB%zhm(qXGO@uYL1RBis8u#e^r_b=?tX1$}+2gV=u4>#vpKQNL8TGe>mse*1d69g$DhP%!Nt9l#7FL+$c1} zWxK`QC=LA>V2hy@9XwWFEF3jGfGRhIhZW62WXE&k@^3?vnAt-qQ+nYMiB@MuMht-R zqIsX9#VQnM^nk-&_Z@uc+E?+X-PV3zN~(WsU_I&|C~K#7I4RCBTH%HpeQO80;?x%7 z^A@7Q?BpQ6uag$xbDdtyASl6jz!9krt&D|glULl)QD5Bp+iCP3b9aCC+iQF9j&8zw8#GD*Q~?TzKuU^da?aslHwzI!y~C9j_|iRJ_Ps+nze7F8~D2l zFI{R*jztv&TdrP9DqI8)Kv9@Jlbp;9SP`aZlM~rkC>&Yl?Hc~dbU6Yx)Q|}&jNjm2u zM=6}FVGfY7VRlIkWLgf%%zdGS&b4CKy{qTkNZIXQA-jF073BPuW5vK)oGiL=AZZ7w z(sBM6XN%&;U4$4bOOTgLjnX+*T4JP%XLb}tMhsO~g~5ZW@*)*SX(>#LSE0U2ZG5pttbxiEmGOW zw6bW%74Z@xnl_{PS0BUotm2}!KP`LY6>wXyY_y-RnM|A%W6TKR3kUD;gt{W7K8n}Q zv&xFm+U6+Ix0EUrLDudVuw5|AfLAibU?|~#NJ^$BYO_7b>l6f=G%I)1`KeCk#&K<62(7%Z z9(UPo(w54hO0R9BP!whuA&kw_K5+9wJhvJ*wY7(3->%HW*cD}Y-^fJbTo|8SQ^xu8 zE>wj`z=<=596HW|JyP8M1!#r<#Vl7V$s?jk8zY`KW`5Onl%-RSl)+lX%w$x`2NbEvL3xeyYq z6x1wJcrWhF0q{o;Ej0rS0O(f*p6< z=m!4Wg4gy;n4()bq( zT`APdx%sE~=;)k;osx5uQ7Y|h!AqM?|N4nzlw-x3$?d+-dC%$EMfhMET8qiVK)rQI z6+DJiEcbLIR47!bR{kP6(ca=f@37-EXY53>t6~x_+#uqKZF)6N5EsHO&+mWRk)NQf z{(wL2-u_VO9PO5Nd32O9%Kn5Ki9E$z&z4q@279Vawi^?7Sb}rdF{`X!{FF zALAj zJ{5#`&e@~)P1Jc=7K-F6H%_=W$uOp%FjdX3&-cwLmSDkFg&h>Ngbw&fe4wD@kcC=h zXOOIqoEila4*23TXUv?7?_bqyvfcMUTd+bE5vP6bmfRnLm-eF({&3EY0t{LbJJjeZ ziRG*)DljZc1Uy1gkSnszg=(!33*0`e1V>wl4T4G0$OM->bo!V0S2}f&Z{F2OF`~W^ z9>0y!4>2uy(={h?7Nt^5N6Hxge~4*m;VrD7D^)A#GWl>vgut9`p&DO|IHVLO<-^I1 zwbe5s(8G~O&T93$R4ZzS*@yn~YkoP0VyalWv;CEYm?n9gbNyKC5@&N-qCyC>HG+@T zd+P@qYr2Bj7f_F~JHk^X;|SYu-aV+E#88@LWM0g@6Y?!)>B)(ea5UlPsB4r^Ts@(Z zEm45*gaOh}uh6FhdhZ?OQLUBv$n5OgSE3vOI%Mu(6Cf&0-_p6CVpn=s>q-~Sos`kB z16buVVi}vxflsA5sZWa01<_deCDRwAX%W&rh1a%Mb2Eq;UNS9oh>zNFB6=DO8gdw> z_zm-HA){&go%YDLP)6*+Xvc=Wf}DA+%LskI&BPfIAG(A_`SUL1^RIa6B5PS9M1&Tw z{t|}6p70`gi)l`_ff63F*9k1R4PRu#{szmm{Is7d2I7{&SIlc z&dEz=F-5v#s!DPqq;|%0F8t*(nqbAk#_h*Sv-UHoVgJY^W@xzwVr(*RE~4n*%ds>V zIB>Ens+P6EWqIX;EP;092cD$B-IBj!w9N*3j2ajm#kN5w&nydW&115MPg(;wB?dGU zPl;KMu<@I)$Pjc0Yu5`8d-ZGarE4#)P_c!3R#;c!V|zR#hkH=K&e({~JBsERCa0NW zXeXKwlwK9NzKW{?7Ohw+B`NVF3ZrfTc`fv)!~781?VHX%^EL{N161vHxky5zU1C0= zQ9l~{nAeS@c5>1LYnnqtjoyuzVdxGf+=$mMqGvXk%zH1GN?4PUewm4pK&dV;EAJ6a zlJ-t9H#N9?MiJ>*xco zqSW@P(7RqqjR^mksasU{vGot1Xl|OQorbqH&}bQO8%jz>1+R|?5WLiE>tygKX!;n1 zr-Up#?_+OB-j3=WN6;Mr;_T@|ckcSv=l}8we4R>u{1i!HUtE6ZbE_Bat((6N?>4JA zok_69v)ZIRMd?R00lzMT8l9Y-uSELf z-I5-k6_P_Xz1UzCL8xIaB1EBg%)Qr_`NsGJFat@j`z3(76T_AqxgbdH(#%pDWIPZf zBgF5e>B-Z`)&I+Oa`|p z>&v|OAl>li@ussy54N_4oAB6`OdszgK$0w(`Zrxl(of8|PCD zkKlxck>^3PheyUbiEiPcPRHw)H%4);87v>(RhE{y0l$|PJ4wZX5Cg0VEr`nD%=v0! zATDQ{G2xndnIT$`$5|NeZLa_HM}PQEe4nbe`t81w@bS1ji)qPZTW4<_7r5$#4f4IK zaez{X2TpzBKcqxtQWk2~JKrCBiA17V%9WCLF&~l3WhFA@D1o6tOJ6P(9l?;La!8A8 z@?-Y)1r9YX(0)j>b@{A)#B-l>9=>Mnu@wg9>j|fsdBHLMsV0@=zI?KwEG<&&rtb{D?y7Seuze8D6v;lAb zq-^CexI6{xD=&SEG=#z2HN;Vvw^QnF4DdQ;QL@CUcN-&%xD5=ztd9KyuKx%!#T;wN zd6v!Np_NE%z}FdJY&G>5@rtf+zAO7jQWtTE?EDKq_4~i4$SM{$Y`<6{BM3B+P0d!` z5FLquISrM550eu{KOlZVY*D8*R*?zesN5ktGUyDO>m{X^| z3U=T$?8i8`Y^;;Eic4>hy0LkSPddCyY_vcL$@Inhp~=&g9;dZG!tJf7Lna?)PTSKA zh%i)EX#_r0=YAO$@T^!`YOpEr;l-yN@-}?Ws>y@xzIKe+*h4ZT<&TvbkaG-#+xl$T@tG=Z@F$?$oRP=P5O)M%VQ^;V8CKR#FXsA& z8AM@#mS)O;gusciNYMd2vQvraN{Hv2E1z`wbMa-XmgjE2W{&=CW(ae;BM<%Nj2hE7QFn{IEBD zj`vjGQcR(Ll!NnnJZ96s6EPsK%(enp^^)UEO%> zZ}Dk0_LQ~X+!tg5Q%xZM%i-Bi%#JBu^V&3nNNG7bp28(bgFelLi-otcW-6uI^Hs5Z zVMEvz4%J4PQj<#}Zi=@>R1J><_m@brcH(&Ro7P--42AU63L)JlA<>Oa(f*o$`6tPT zC8POF{@^vEX&}5O=5bQM%YNU=EX-s^2cSC0IeeFFilElc$h(HSLI0uftFv+DIh1Id zNrV)9e8(_}mXo;d9PsY3elD-6EW-b1cAq^6%qTz98D)kOze$)evJt1FPBa^X9mSU` zj*(ml%~qy-xO|*ZqH=UP(2Z7Q}Q!2zsqq6d(>*;+d9@a-{_jkzUW z=)m`e+-|~W7HkSrqs&hglwVPM@aPOomzqL~SQ{q>cv9hrCX-rGM|01O7@x{FRy;#p zKFD$>QV|Nq`vyo6TP9h;B@1>T!!4h<`)8yaDlPJEsUG3&LR7tm>npI{KEYe^>fD<| zNHNhFuYSdwq6u$0owN1~fvKW@0cnJS8U32&aXWvNca^T7RC zX+pin$R)C(7R?V4633GZ2(c`=;PD6Dj4xT6QK4GC`ezz0FK7%5HFqz_KL?kF2iA`a zHrDm_p?=UDJA5PNHyRr{L4Q}ABOzHkk!?cDBue(_7MawOqVWS{IvEoxSprx~)RWs* zbVW1Dxtba8oL!%>Rt*IGw1b}NW}YrNvY?<%?d|LV_hk1BJ*l~z>Qu4jZhNu&XF&tF zs=gddPEsfG#r-2xfjJ!TJ{`CPDThx9e7B{%;fCPg92bHtJEN<63r2_^;3hx(cb=8S|C($F=&Cf*^UF^&Y0;;W&)=HObGS97ux z)4KX=64bxr)w6$pXk}a1k$G_Bt)(?Uup#|r8~r%MlO}CYsz**Ig~#yi5WO`!UKZ_qhu9%c^kt3 zaA*c%Z8^B*OkT6sG)2a6h5Ch#opa%d+fIUdRV`cGUaUmnB*@fFXoY;ffDfKybF^?B zPQaE@VBAT#p=8kHh7kgtvNvrpNSlyrm?RurV&qb}zR0W)UrF_o*uXbH+ow-eO1;c< z(|Zbiv4CPQu93W1{m^AUm_;%E4u9IcyYB^gBrZL)tp=aEMQZhCywiNv7pd!M2ZVjO zEH1e176PJ7&pl5}NoOHiTG>D!AR$sd$5pufJO+sPpcB+WgUL{wIa<}o-SpJx3ZlfjbtJkvYK|&=_j${pmyl)9(~87vaEWB!RiiA*5_>) z%Uj^s#E0~m7kbz7LI;e)HSdzFK91M+AVqdg&XJPTxm;1;S&VlX>0h9~Tj#cM)wWni z---R=x4hf?&vL%h2h6Jb-elAVYUNA;dXFx9=BLQ1yPq}i3L5j)<_xuwBbu< zB5Y=0g>AiZl}c#AYAiq@UV{lC?fTD4Py64fmmSk2BqFGup~>BjUMBa_7@F+n;N=hz z$xuU3uiGH{O~iq80D*DU6XBei{3NlzDjuQdM}n(Y2(|UKLqER zZ%LC_(&FxHf|{^x9lYi z`Y58snNbP7r)Lntylei=gJ`50A#tBI-xQ793%Va7aK>FElBzqTSMTd|-IwMNe~`@nLS z(XQ`({DB`)9Q>;-%t+wE0kT1` z!Yvff-TM}TUdef#dv!%B3uHNCu{#qF(#j~r1Fs$Vkx}xswFmL1{SJL82Jdj{jsUv$ zc0KW7ylYNV?UB=;wth|JN`~h+K9-XZZy<{e-lcvQ5gN}j5!-Rc*Pr{H*S(g|t)iy1 z<3K%Awzf>+`u}Th(=ES`w@k&1g~GwH*kkfooVmufFf7t5dy}Y4A#x$}TvF~v)&M#D zYQf`M&r#NzAdf;Un~vZ05o;K$n1kK%EQw`*e1Ex7mTLo(!u5sSbDQI z<|qTZ5=6HkyG+ordZ3SOIyTq}FJA^K%x+uOU z6ZH%&EL{!v1C#B}$WFk~wgjKhj2WLC`O*t%FcoF99lmIRE(9&z!$_ygh(HNpryrIs zbs7);^*G(=EqEm}={ScJEhGai&)*>}EWBaGWcD7Au*)ujlz}O|`4&eVITRF?Ld($s z+t>u2teMZ z3urm3x%&Vxi3ueAKrh&mi0|9z?BJ2>R!N-K;^l@;w5BBTAG`5_Bu0q!Ix2+cSyNOh zygV3prdl?{AJe`}%?g=XBqatW(y@F1R%oD@eL(0qLa?R0HBMCI5{P+`wuki2`RIj@ zxCwVqqZ+mw+lwVV8rz8|pz&1O#h_FJ+7bCq>gT-0{J&|YrAyQ6MSar?ZP~#?j?REM7g2gNi5G8$!>*%2;5)Bd zVSN)n$1SuA%;%_?qfgn|((6x?$PB+&$;uxr??3J%1?C{d@_L5saZ?ldLR)8o?Z|NJ z-kB5`2q>Jm)9Y_N=#3}fPAa4MJgElnGyv;E&aiKItL~H~BV~?Fl&E|eSBgN2VsI6^ zP188X!mase7(l!L`WOBlV|2DG&2jP5U{J@?0NxRR1tP$8KWg}O9Xug0V)^XKN+ zL_&V1F1p0jnU^|HmoJbp7zL>BY3LW193*K*5<0Ndd@3e@)}BPafR*;Nn-3< z(Eb6Sz2$UOxiO2#NIM7y05f&%PibF>@BI?rt$2A)d^P3RjM4BmV47nxj{ic0M&lCl zkwOQ6U(`@5HnW{LjhO8^k~WHoxhgVu^37!@}pH1Nc@D=^IvU&qT)2D9b;L$uzDBS z%2@r_4I2lNb}>wF!~0-A4jCI7{c{~#F29@S%TPapS8IKt=8ttJKC%-ARYGkqu3IyI zQZ*)pESZLcz&KebRJ7G-F655iC>{*zKPelG7n*2|-fu19uid%zm!yv>>F5bbh}Y-z zZ)}Y9GtnDs=GCeP;!4x5@a!L6>A(VS?v;et)3#(#=c^XPPic)_@j36QO zwS`M|uQ~4;RS@$_GFS~_%$7HXHiFt3?5U*l2c1z8)(1NWLQP`ymhI5E??*QDs$0wzHz zvaJ0E}F z!ceT&KLTBX7b)0hItI@iHI9`Wx+z(;meM3TY23G&G!2%?GX2*CLV{aJx#D8>vIfG7 z(Ip$348q@m?x8>aFP&RV*Aqe?S=>qc3ZS7dnxa50 zDb-`d1C ztL?&{cAnrgiQ}P8*tk*M@_eby>+wnRhjZHkY(P>y4L*4bv1bnCX~$vkv3Ce{c| zV?8vA^O1Y!04SndeUt(X7}{v5Hy<&%@AVu8u4+5p@wV)w2{kdqHfxY3lJtN^Gd6PgH4J($fT|InwW5D2#>%Mu88`gl~i(t0AQWzB{IZt zcCC=B=wY7 zrHU8htwc}dl9Ix=zG5372pF20Xb|jxk`gWo?~4~(NRaAT0izvoJ}XJS7PhLkYvl=a%Qdd~XusQc$*>sK7c}9a7LJS!jpW$~ zdZ=~C% zj!2s*3q01J$t4gHYSOKyq6}_8*xE#I@Y|gmrh& zExK!ioaOYX-Z5cJ2;B#F1e=8P6W&NYIU+jT(Ywsfde)&odIW>wqbg+f0m+PD`=J*N zLT&?++v#}IrC{6IJdQIS@XuD^V^jVjK_WJ`S*uGpopk>a2M%MsyU_TJNSxZrC$=d1L!!^CJ01GxKIdCh`Y1rWfgjSKOgGTtb3ImV$LsC?FII z0d2nIxL-Vl0@{KHf{hyxjU`Fnh9RipHd^YVQ@ zw3Bq)65>9Y!S~3M`TFU&&s^zfNdbt78!<+Z30V1JYk;!6A>c-#M;376=i;LB%4a&& zqP;Z$43w<(B*yS-$*(|(q>v%Tdsa>#eGq937C>)gTik-t z;7<|5FsA$`I`Kk?-ib%T07*6g9!wm!4|!TM9ODNohxOUs@HvoD#)x5-iKod&&nyDN z7bwfuc z1k&i(s_DQ=a90X46tal>2V`Kk^T6l;s{OeY0z#Z#)~EH}Y_H2S5&P-oKEOXh4Tu`d zr6Bjh|7Vo@_$OX@ApOTPDx%CK63dk53%CD5ek2!d6MXQ2VCsf(HMlD~Xon0|ky3_C zOmO&Rb-t>_265R23Kp^1*X}vlLt8hS`zCr-64}v<6an~!-+TKIHHItD+ik`7T@djd z)0kMx>FVVpAxkE596gdC#4|LGF&?Tvfd#}0{*bII>fkc z29ZWu{P3rr?L{?wC>xeCa{3o^q5lWXQzV#SNrmt5N)%=CBYlTIm9y2AB-g)XYg#x} z#7#)&5`5+?o3sfW8@aowf`u12c#n zJ?$AMzX#u->O{^RpVy7Ehj9h6CFooIXtXg-jIS!F9TpSUbGU8I6- zd&d#F{j2fvrBG>e0wSP_ua1xl5qMr`y=tglJ1A3M07!=Dg@-#Trp=?{2qB5!&D=C3 z!G5Z+$)Xz~1P&MM)R{C(X{s6kgBJ|hZNB-W=i9*^kEw7zw@7wOuBW0c)}?mmVUpTg z@wT(dQ9~B>BP6+Pg?vCpl_?}LR0cGt0K*THq})@Kz+rMb$jU7^!TY9+Jrfv7jb?oL z%zGG}YIosJyZwAAi(<;y!8?~q5DO_^>+UpIXE&fcE*Nj~m8>DqJEUfJF;ZTU@;*Hx z9gizl9kA@{$MJrc-L>D(ow}dBaCs#b)Tf>fD+P}X4>l*(>O9ClH3k_E^bXwzNtz`^ zb;z2)Y}7^eubR2#X3@J5#?2 zR4h~9;Tv=I#kcOEH*Da**@&xbP}r*WQyY&M zF}4L}u-_%cM&5a8v1aw0d34mK-DD0tTY7>4xr}~mdG8|5XzHO2n^@>Jj+5M5>P!d; z&Nyz%-yedTsvS|GMBk7SJq4GKX8wz2Bs?tCf0y70KeQZ&G+EwUw*hp`aPOMI5!iAk z<+v~3BavQ&7cV9tNhZtk8eA;~r&tm&8-f3HbZSwQ>8wB+F63I2^%Y@}leO)k&BYdh z=&Z5aRsl?&PKk6#6SJuipXF8y7mtH0-01dx@fTj)k8fOcl+BJ}Bg~ZY;$Pk-QJqgw zS<95Ac}ZXa(_9w{q(={Gd4muc66mY}N|=n$J zYZV9C?kF~vOwkN?2<~?h+*|O$OJeJ)+Q7US%*RBTb2>4X83i~t<1cMZQB)?>9ZvY&oVC{SeY zu@XDj5M(jZQ)MF1@udQ8&>a>ARGCsIzHCdEl&Kvstu1 z86Bj|B9#b1%IiT8tdQ_Ua5 zZ-?JTaEa1M1%ogP?lF)AUCE$2Rn=;Ml;HKZ&ChagK%TJf?7T4B!CZrH-Q#tomm==A+Z@f~Uh z?XDX;eY~HJ`WQ@s)@P56tQiR)qyilq?1x5%MjD+M&DVUR%}4Qu8g-)VEhg)5v9!tu z_%Lw-@S1(iQ8f2pt##h>ka!!lFvYN)&k?4gcQQW<^CcQWvBsQssY>nT+8GD_`1RLP zIu)nX?c7W1KsxK8PVI#Cyjx0fG2SwFI-2tOJPk5sxmEmsU=|LHwVc9~F%HIQT8_Y` zdq9S%8#m174fht~QQI7G0!M_FIQ6t2z-UmwjmT?ZsG&w{5AJ!&FDa;s6QOrLCff}U zd8!`|?jp3v`tBQjBddCWxzQ5+XZA#epe~Z2n4$#xLfdZ>1U*j#7DOAX)fWR8kfBEv z+iDQ5hM~)m)5@qKqf4Mj1_OJ7X)f|sdfZ~EZq{0Z_MQN$u?JX_cr33d2|3m;S~Yn% z<;dfU+WpV|k|QY$FzyfeC|8%|*B_KDKZCbbGlhE~RjHKjLMF&1Xsm%U%UdlxPFRq2 zsNz+=DuYNedP<7cdJ`lb14s>Dwg@nFVxI}MsF)WsQqHo-F--K-e|M$kf;0X#Kj))cwbveO-je-OM ztYSHkePRK#F(-HYiZ1--@rZ&38^P33-(wCML3RoP=z7F_KJ)(GcBc&GUi!( zxuc-bTV|ZXRra;*_|tA$Pm>S`5SKJ3Cdbg!44^XJx))-gpGiN`(Pl@4^4%_iF}!J^ zAj<7S^Na5uUH{?N(=rt;3nUo;q>!4vf`LNGJ7kjEx#G#6y!V}tGJ~kt-m~-Rx@m^@ zW!BS<;^n4r%&c8vxPqPTeIuJXKs0f?m$lt))C;&Pjz};z7-emy14x^8QeN)C2UHf1 z(oE@EKpK0mI0P8X2#JB|*R5Ys5G17${A+In@72dmIfeb>k8r)sa}NfAe=n& z6T#%#CVxfRGF1SwGxOhZM@Ghh28#~^TyvWM85=^Y{hwRsFmb9n8EWUj(l-n9<7-oO znQDgT2Zd;0Yy5CW`N}t5DmCNMllcx%T3{QElDTR!8Bbv~jg<9}=}aG1A*0WQBbdTe zTE^k69C`)?kc!|3Ov@eq#cpcZdC207f4k)%>-MS`XWIGvYhx?o$!c%38>653Ll*z|7K zus7PSbs)`eykwiB}ym=sY9mmMB6wX%r+kBIIlGIcU-xvqD> zJZi=HPdn#I6jMlxef!B00{fWeYe7Pu%Vaf~d9t@uB*RCkkFZ)D1x6FNKCqsF2cKHk zaxFG$^mNZ`BD9`-Z*ejS5%&4%yD3dUe&Vc}(25X2D9t@5KKmH<)K`^IcOETCO$Aa3 z5&a83s%%@xc~$BB(0h~XEW0Uxp%=nzIZs#wm&n8`IZJRHsjXL0O}k5CBsW^35~vjP z39=)^bm-b2%s!E}wSPsRI#y!Z1A*$>&PTrkpF9sNdMFPfO~4m{{iQ^^V%s$oRI>Ay zO?vF0ShGN!J;dADWsR(dhq^!Lle~}+CQnsZ}K&RZa%h3-% zX4lP%_Y1kQ?@N*0Q}65V`HvcbMvcp;+ie4|!!nF&s2WHcfwZ`6t|*jJ1ncW|TM zd7EzZi+JT6Oq~YjlF9_C;+4BdoV`m`Hr|H=SLHXwtU+Kr!oNqbt37L9e6(h<#NQO{| zfZkxlrD*VQ*II`)ith<}gGcuiWI7ulG~`c-Ta;9b)u1gF2n#!E^DBO|8aGh;A^x;0 z-mA0IS%8A^018UXo=zQTronS6?K;241d7)>k==VFyA$y8meT<&KwJC18oCoyEBuo6 z2xeo1MAW2_F){IuThz{lt(vzeh}g{*e8(Q5Dd@*Aur=Bht()T+3tD65#P=VtHn~;pZ>?`N^sf z&JB1iXqQ}hWkN`%5&lUEZd#+3W&D&jKoT-3Na={g_+~RIf}dsHEq3F{s~W>NW}}E{ zUay>21iO<&@7-5c>##5z*7m@=W?lF^+)9meNbU0T=``i~jnsWFy{CRb$x=lSjStca2jcecp5v&|2?fA$}EXJo$H@67iF zS;wRugF1I$;?y+|;$VM78$vh88z-TzPS-jJH{bJC367h!jgiKU`Pb*28|ECqvgO6r z#vBnMSUS%uT7bRDEn8JCdKR=iyA>D*eRY3@jF4~S#E-Hp06iU+)KyMlKTdJ7U2?nM);Y8#p zTze6D`o7C;7g32{!tq$tqt7y=m(O=o^)2TgpnKR&;iQN4afBt_b=q<7V5>mYLfW0a zeuS-s)Vqe2Mi&}E<9 z#{^VyT*FRZ7G$K~)TLkddS&iXh-sx`7koWEIt>*nkQ!f+d~k*Vb| zCs+#QX}&Kt0Yn7AYwQrJ7MD-l*k-}nU0VSPmwG1#5Dr0EH2?I`xbE6RXymb%wLoX{BQc$158JADgon z27a&PXOJ1r9EUWw9;#T!>$o?M-B-P<8v|ol#@I>6#SgtvWgM@cgBxbNwrG|3Uaj&- zt1>q6aBU|Jqt*b-xCY7zsx@+|l%3`Ry!$u^25KrSmF|3U!PSqXC#slx+j*Yue5$%4 ze|)MO(Wmfn7-zM{b1S6?4#db{AVeLD13<6FJ;t3`p+)zePB=31b@g}`Z77aWN z3%0O6Pt8+2g+nrD#g!_8+Dt~px+2+%PO98RdgzxYFCsxxt8z>iWKD^M{Ihu4bU;fc zrx?k$Bk%fnp#xm-W3TdEj@K3&8-j}{l6SZyPrY1X_SnHvc+E;FEG-HpY^z^Iu~4?E zKyS|?m1N|WDe^!Nq@PTbwxl2biE6l#`Gl_!IYPaT`suTKUP1M$N;7;v3jO#LZ@&(q zEyY{+;A~hEo@?y1VX4CBYv|My$xSa?*3aCowhwNvJ?Ox z>u)xO4`(9{CM|I^dt-E{(NWXdeczB!&ck~svnal0f+LBOELvhL_z=03RfaICwz5@W zV?P<%RZp zyefN0Oq3yS;Lyjqk+forw0UE2H7o-M%QZXGf$h=(I!HtnLagMs6EhdV19$6ZMZnLo zVUwhNYN)p=ivyPep=tWn^Ug$@B0NL|JN`du96pA;a6%x&(zMFJ9;n{A^*pd(@eQw{ zv?>OKcU~iDalsTwP5?Ft4D2|_qmd13QvW%}Lvhr+T_!{Bmph0p_xUlQAICd*%B;Zz z-^u_m$`u@iQ)oh8mY2t>E09=1ir@7AXB5V38AitHt3 zECC&cL|kTjKVrWz>(>7!zIVHZT_>5TaedXQR?o{yLUim6HTwHI)3E!0C=ELfuP&oW zDIWS`_Xg=9!{4IC%2W0PON^LPcdS$`ZtLF7M?Cu^d_>iuHamSk5*_KxsU@!NKTCIa zCf<5Jts&|{UfMC%ilNZ(0R{^4@SXTeR()VimZ?A_Frsam#;vnSbu&y0!i z4_H0fjCJ)&SU|xcl(Wtre*ZEGrQ*DYo!9GG?}y6^$MF4npsvFW^uZ73t$cM{9Kyw3 zR@zaI8|K9hY~z0Sp5*fubGRw;hg7ADAg5i;A9H7HL{#UC*ajF2bgrc zwvvKWLUgcEoZ(X)iKg*jWiogtzOm*iMvPIZ=56d=;kEb?H@-wKG zV7Qq-?LaO+@yV4N@xql#lZ_nG5_mYpz69L^?GoB0Ko$7UHoIFr^pIezTs*q=l+m6zR#W54Ej8ZPvz`9sa4vVor zPFVn+ljhLO5rrg1KmVfR>{zX*RY>AyNn%eyxu5zj%y&{WR<6}@SGO2XL<008z$$oT z_aO^R%#;rON&ig!)AmM2;Y5vXC7>~4m-*$~Yh}4|2xi_{=RVSgSRP*?m@i5&9s5$^@-K4c`gBWP>EqQxJ=69Ipy#T=n34-o_n%wO`>+yTRNcX|T4mbaE9=U1&>w zF%u4u4<^17ie$@XiD3-yw%C{QEP*ad53QMG`zS6kKC7z zqTxw4!BmZ4$(p|gbs|dKtEsk7nQR7~@rbgFLc+1Rm8wX8g9(VJl|&m-*mCamhyDa# zr?y{(6#h%kob|#*2y!jSE`8)U(z{+X%XWn4x4cC+|3SPE^gYcQ%qg~4mdR>7IWGo! zb6Cm#cpD2tZ1$Z_RCwPU-&XAktTcLYDBucwskYgdW85szheYl@^uAX-oO)4JX8)=r z!lssExNi@M@AAI2Lj(O2VGe|%wu%oYo{sBMCz|nvES%Y?hZ#4Rn(SO&`acK+_n2#d zp(Le&TmN8yw!#!lG^l4t*#J7hGENL2xe~h?a7d0R2(=K-?ccl&>)P?Z|G}Sj7xDG% zFok88lRC{uo{=U)6h{SiTo*bK%zsHRlXz`-3R!^wmZr{9Jaj2}$8j;fpS??xm2HVP z^ec=j!cnf%vSG8c+&Z@T{r_;lU*l_3Hm&+9vB%-^0*nlybFk$gM&`fk?B{>}NMWbo zf9C7i{~a$~A%5SyHdbQ;&S z&roCAVgte?{~vGP0j6hJrTwi15m!aAU>^$*SVd&j&7%IBAv2gjdO`r(@MY#BGs%=N zGa(7O3M;aR4GW3|#f}v$tJrp75_1{qbM>?Cf6NuQpGMUGt*k!y8gnx= z`qKwVecp=C%ywlD)*NbL%*@mX(W7AFf)$L#g=5R%ERgcXxkxtlPD-bol8ySVeGoD) z4e&Zzwm(;*=w%YOxscM%bMCc>Y*CAjxo%|Nmy}3Bo;)!%ytUnP3SwM%p9kXCo9x#E zoAK*e7}!sHC83RYr7-|0L}aXhFl)$7UmBuvy4@PQtVgMs2>_8m`rdD_ZN&|#8JUvI zxF7eQPkyWAHitGu9^Zh)Y`^!wS8V^(&whF(-VRif1s5qTA(gG6VL8t=*w~GjU5m<9 z(eMV}89vlGB_{;Ip`4^G?hbDK9}4aff)TaD$J$Pocai-g zubtR6K6O^Au)hEUi?dnZ|I_#Dsqe%qcqZ z2pOQ8RK1d167~55jl8QRg&EBhyr%WUk)=`usPv-V@cCWKF2UWj4sTGWpGtfT+jDbt zu>0trJzQdZIo{azRYY)sBMEAJ)2a=g^Cydx2({KT&(ec789Lmr9Sijfc zwTKns58yzVo+QE}Km5o;f`zgUAD<82Z_AN|HYX1YY?p((1vRlLP*t!rbVY^3B3&Mm zS#aVlUt5bW*|d-F55JORm;m&(K`~AAtY|~7dEkcaWVE>v*xWEe=`1T7Kl_d}=0dz2 z&cb>F?3+fZynMRhgjB*T7GjWcazeF$1YDn!W?Ks-iGQ`g!#cWVtpUCBILS?KJN^pZ zY-?qM`TV*R#yKdkt?jh8O-xQFs+z(;<#B9aa4Q1$_{QP(*lg0k5QcTehbPw4llMVY zg2@n5oRPs1*2A$l*`*d7axCezWS{sC?g2Ye1ErW=Swp)WOM}RrT}#1gCb7eE#hq9a zFdQ8LliE7V_z*J1pDQ-XMnktQ>pyII5yjbXGW8#RCvlSAL`ua0gZ-;#lqk}REyGA7 zhVTh(6qRRDP5ikhSv&Fa^|{$aC`ORpVSXCCDbfgDf-je`I$A+{6+V6u7o?*9QxC0 zbQHC{2Rpb#ZH81l34!gr^p2ZY?rAk`&e)f=Y0jqRe(~4RrZ?d;BXa^-n|5fp$w^mI z#f(}3uh)x(1jQJ02$>y^#u3%%G1IPs3b9#Dx;_H$0>B0-A?JL_`G$tH9|2eL!Zhm5@i;$gI}8d|rQb)S3e1FS z;2g}};BLiztSKfIgn1KgH$P}fTR8osL~r=zA6V#bHDoR`_mqgpna$DS!(aL#oG-&$ zt_ISeZd69zQkr25uuXJ@6YbH$2Qt5wtHg{8WWXk4BbmK;m8f@B5)>vxq!4%0k15oq z1To}s-M1e43bN!a`srG}I&-Mx!A$Q&l%3~pm+>#XF`ru^vSn2i0#JbsU^!Uz`4R3h zv%&;6YI4RQg{$`NRjrEDZ5Of3k5-ENKkp--zY9y&O`S3`zQB?4nX`2~zq+@a3YR0S zfHDYyR8-uQ1XvFbzC=0nnTtz~r?@L8D?);Lr`lF}9Uw548EG7RXfO96aJ>-Q=oYAKqHjAbzi zXcIT5sz2n6I7d0dU31PIzkpp)VsJJIP{+jVwv%0w=_q_`)JYrxMzHRG- z219zhghP-%SBqAD{d!608oXyvj76N-FD0*Tob?lMkRIaRVS&0+(H!QF6EYH{Pstx| z*?ozFc`BukZJ^FOI*YA~D-b z1ui3U@j?bITqJ*hIyB%lIx?JobS=B`tN-{Djzl)~ZqA&rzpN@mcG>DWHHHPDvtR^5 zR;S@J5x|H@!ef-rS;+@lQbUNiO;J2Oz0d~Ma?wD7P=q3PIBkLK(1M*``tdQk;C07!Os94xxMtVRc= zp}fxz{}oV&Pd_Ab>)rl%#QiCeZ{VjMnioqV=5E36RO@@jZ?u6CIs@DAeIWg**<=Ut ztl8VMDmM+ONd^^d7AnZkT5BTsAeyQ9xl!PiD2rJ=GisC&q)c~&nidA z?cYUbkb+Sn!HnrIgelAML@@+&=s$hoqpS=xZOoe~77@)Yd=0sL9v=*+=#3!p5c5CN z)+;E2noUh>f>2LRK5>QC?^5e@4n;)5oOmBIIB`3qG=L&gFtKu%@-gceMhec;FaefT z$dP6GMloOV7t-uG`1qGI2)7!Ro6anscQs?Tu=*jwR@}2Hv^x5A=|!M1g#uPXp3KRk z(7*&W^cFmDX}m*7BG)WgB(}j8(y*>QK7^_845QdXZrmi3*RoEF_;O9> zFw8uyP^3u^!&qa9lW0M2Wls8$cpz`$DVflk0_Vh@KZM`UxjoKF2R__E8T3^ zjD@wQ17~3(a8{j7ArDR(dZLLGrg)NY$vBVJP7(|+lag!JHk_LB)2CQDjOgzR67Y5v ztRM$uMrOV%+iKkWqOU&u9?!t{X{sjAJWJL?;76sX0>2~iTQm;02eIO4Yzt}-?V*8f zI3j6yx*PoWFL;;LjPfG&0Z+{W?2DtaKvNtaoQ7D!{*gL|J1%CRRI;#;=A2C#!t!mq zbR$U&_XA0a^%LKY5NaGoehArjsUm5MfjYM5E!j~OoDo?; zYIn%(rr#fO?8EWxn|5E$_zEQYqQ!I7;1ePvgS_6d!{GLmD@Gp8LD6G-PV8VCIFM%y z*P6!?Cn}RtxzDmTmq^yJGTp9Nqu@{#a;49*?2e=cx6X!`PJh#)*Y{IQ`|wj&udy8O z=d|=3qS}hj)ZADBoJHFJ`#3QZJ{2Zo>vBZ_@^MG*Ve!jT9tVV}s*xz-Vh>x~`_9A9 zKf#VpY$CaQjS;cVyxjYT@Wz4S5^@WT@hWMsIaTIVuEfAy3R}}o#4sf1T313cKII|J za%v|&%N?P0T;&&Jj~>9OoR7NYt@m1Qr@=NHcQ@lZj^<5ruY%+(6BR30_yF<^nnAFy z4~LaocDxD`J|vudf|x1LF(z2D9lrwKu*Gf7b%Q#4 zo(+mqs=#tqX$#lOx&7pOBK<0$uT#d$o%CW|*s3g@L9oIG2w_@fnVBsgsXi>O$)%X1 zSqU7Jomlh@A)WX9!>?XXAvJ7JnwgT2$eW-_GQkD2Xe=D>3{`j&aG1Qr=0aZTBG0%S zZ=6Wp_{!)ADu=D2rNg!0eoOj-4g04VRsA!&_~7_oxOJe6B3#Fnp`UO2mwM;}C(i+PQ#MNYcZ9Hwlz8Z-@ za8vtN`ZEGSD4@F|OCdzhDrn1K!^PQ@0YXDKn8Uxn^$B*Q!1wTF>l*RA(!t=%bnIY~ zq2fRZlGomm$)iblsS78}3QSr}?d>@9qp%`bN#RvY76y><8JWO|Y z&;F|nqBNX6HshkA|W zj%D_tMAS|#xwNIpiS1}F?V!@Nd3I~R!jWE!7b8W_$O@0&;B9fXYBkn|G{k-)Vx(p6 z#<&zdHT|ohxb$BTt9q4e5(8q%4%ESm|0&ptVp&7d;8gz*;e?K-(4uP|b=xO~a6^qS z<-+W7`-ec;0r#u}XzEN?df+#p3wIEt;Feh)x)yR|W?*vkf`j>y%ySjvxa#m6T6K3f6j*1KeUaf zWwEeYNQkP|u`4{yk5{^I+y90aJCK5nITcmWDr57%lgomZBt8017M|S=KMr*k_u%F8Q%24M?A&mckb69!;9xt zh8#axp2}Ay3CSu^9BM{M2nP5b$7g7iUOH*v5hAvL59<@`#R~K?KP&V4rAQL2@GbW* zzYkaDzYeKf`QS@u{u5uX#cg4AxZ?{SIW*aiz6P{-aK=7u>}9XX2zve}+XLscC&y-W zd|z1J$MIVC-+KOO(HYy@J!lvF7m`XRDXQ?m;$CP_{4-cmT=YIlU_O-m)n~(48N3+W zJV63eGo~Lq5#SataU$~y*`2rRS?|06_tE-q{M2RlVrdjxar+UZcl1Dl zc{=5R_;rWB9svJ6tK(ooaD#Z|QZAGzaILt6{0rP_oIvHIav@2c+`59jrB=`Kh?o*j z0m`_;ohS5u<`wwBrkzqVFPW!1yb7PEnYWsoNi>a0HObzM=_H|3!WC2Xl=MXjtm1L4 zjPAwX@V>e8I~aJDmB%1q9_xiQ+DTv=FqIANACDrWwdk)t{2Kb&Rui~>rKDxH#5UU% zZP-jc){l+;tW^w*>-SxF=y&3!%iGFu6kLm^ZGkB4f;Bxxb<}9M$xhzYEJy{*Vj5qr zgQFDTY1pGI1~$3Z#88;?E~W3Slk5g72>NKFT>RThe?mDmEPk1JRrbVBRj}$=xq&6* z$U-S$3`sDI4NTaTE@brryg1xI_LjNekW@?#*(#+LUDB41tjeRY zgG)7w^2J_J#}AF!_3ZXF^boDR_^Er4OC#NjGSf z-lRadb*!5o8E4Z5jV)w?S{?%_+f+ifh%(`R92KP|AQxTe%g(pFYtVLIG)*?VWG$sypfQKDqRlRM!bsu>+^P}Y1RU?(zz z7mfEUFx{>ffBQQ(P>FtnpSu0LPV%6AVbWtGjw|1WU>k0P5qKkhJ+Q@o-GvXC!Yhfc z7!6z*>~YG=MuO zPj~!bd|rPdt?fQd**)3G9v(ue)JIC9Pfim|7JL~1S8sIBm`)i1XuC4~J)tXUHwqDp zW5r-Uga9J08S+uxtN6qa*%cqX&(od)X*I3GpSfHjBbP%ZnV3ZDd1oW0IYUn#jVr_L zv!;iy{m|sVrfWYwdhPqRP7Q3>bnQnb$FaGss|J({@m?#aHXbl?a_v-2$_El2OMim& z+m5UV3d6B1!%sFKFU*{pdcWl5jTS7zb4ccv%P)NMSMZ%$O# z)g55x?krbsNA&p=Uc1y7Y&rqibv#74-?;sP!ZMmm;~xRYa(*7;V{i=73ur4IY-(Fj zDDtLg?$02Zy>tk22{@$z=7M8ICIFy~;;{)d9piDu@6NmH>C~u(<)Jh0lH6FRJGsrx z;mhi0lpTRf<0G4K9`UAuL5!4kCLgm62cfjLb`!|ofj6<{F8CgBU2wC4?nydkp|&>E zmN_BVdp)Hz5iFcx13XHa>@Lif?UW9Y0SuNc`3pYe6Y+Rk$}mNqRp3Nz~IP&Xo;>4~v{ZKG|hY#JHvD${%)UYt5S5tA)2 zJGb73-O0T|5wzw#5-0P|P75i&a?r!O!{WD4oWyG}QItkU`WZSILu=J`A7P`4pCc6) z^15lq(7Se1UVqo%=zV4JyvU2rel=SL%=8Qa7p^0+a04|6Yh-Dn?^I4XXh0A9$#wgX zQR&xnb2L>G4j?sYRN%I6Qh>|I=h7FD%icJ|wsY?vUd^$CrV|Bb-Y?Uf7qM-_XRh&9 zEOxo~z~IvTMZsK@t)T@Yu_}V)h#Jh1Mg>($j-LmiKsYi^TB|ocC1>e?`pmn2{SKeU zmuNaWXXdKXDUn27!tpJnDd&b;XW?p78<)^l=$E>{L}Urqm+k*zF*5^NkSc+MbN>Y$ zjFEjzP1mB4LO3blppI2?_hzhx{@qiQq;M+i5niAP%3%hWZs#luff_|AZH)?i=+CMT zZQH>CjK;o9-=ZzoJ`YmloL|3p4|^+rpe7QZUeHW80v&_NaHuhN6l7YI(QR2i_!z=; z(koLOhTYTKO{q!Khx!w7AAX)X9h`qhWoC;P60|Gf&S&oX35Qf#f51;2kbh80NIichhb%Un<2skt`lpe zDF}2aP$FX!LmSELbx%3icJbfVaNE8aTV7{QR?h{TdJaBqDItov#sUQ+bH@%SR~YL% zN$moD-9G-K&K7@!4UrIAoqVH37r{NrpqkGX-ooG;xM7m)o{4`*VCECQe~>kvG_j(-4x1~9PDUO?{n_t84<=@t+Jl=1HjZ{WU1p}w$7|Q* z9ZqZ^37v-%WvgfE9cJ*X)?m!u5OHlu3WIVCYFXkCY80zVQ-gA$4f?E*#1&tA*$JoO z3pJe;I&*CiL?-57#YyPF3-NjV@O4qIOejU(pY5H2ywX9;+$3N)4mY2{o_P^r7H3wA z9=(G2keZq6_6Y%Y^+EI@hvTk3@s$s!9GcS1FG~)b5t)Mp=^+LBk>$#Sg55&`9JIBH zmgW!WOV#OToi#{pQW6=9!cw%fMBAe-&>3GEe?wQ~9w^4(;TF)oVv*W-^dhm$L5smn z!8vv}c`&-@UY8F&nKElykMr-P%y3LRMteG`nt3E%gp)qT+F*Akq0*hlU~TwDX6N0c zJZqK=b!XLlDS|Si$)sw;G9hC6dVsa+0s(v)hX}oVrwe zBB|^m$ao2ruE3C$mQ8yXW)mTxMgQ`I1#AIpH4Q#|TSmvxb}Yp0^en*%Ly>eIj$dLO zZf9T^zw83;T!Gj1TH}(HG%aeEw{MY1yp+O~5gJLm+_mW`n{ykV9-$$ngk5?Ra7e?T ztaH@n98yqB!HwEhiR!=pkNf=*-?nk^;lJiVH1Eb|F@;uXFS*HV4^#wpD}@8+V7WEx z!<4Fez`rpn!*nOTRTR!d4zeEt?FM8m)M**<5>}LZI;41%Fg`-{x1y2avPZt)^=D9j zn$oAaUZ@-%=(+g3^)cR>RN8L>_hy7C4>ewu+O$3K$+?tC2Z|TtpmbTNl1Kj~7_HzJ zU`Yi`CTIxbxnkkZezytVrA41yN4~yi*}ThEC_Fkh28Sm`Q`TUZj~52Ub)gF*8qWe? zQCnG`CKi2SfvFWT0{}WrDX;}VA;<^-fJ8^Zuthpe`s8AS*uz&SPTcVJXMAzddOq!@ zX0{*7B#dIgQVFPLy$jtECA;*Ow4k#Bv6?n&PaHO%gRB3>NzL$}`a?>BF~O*Acwf9w zT(9Z8wGUaHGl7?Ck3h+c6=il6!fbvofhA89WJQi2&0pE`2^lW9armSk<5pTrA;`MY z+#(rLX-+|{dAtp>dJ>`xuS=!bY!?Pl$iam!l!gprEDSu2PvY&?0^cfisFtZR9?8eY1n4WkBJ)fO zdNl~ZYG9GB+k49=Med?fnm8THaMR!t`NH*hy*fF{(KfNM-p>+(yYdPD@qc$M~4OwzqfRm*mJ^THHT~r;aAXHjx<8R1dln3g6ApvF%c)(5=nCs z=bUm3b1pKj@cmR08LHM}!t1B_)w9z2(eNj7OKMn@PPw+6{_XaInBzC)9=m<-D`VU8 z4%P)#xDbkpjmaGj5)Yv*b#pfy$XiWRB**M-RcJ|?!lO)=GC?048DbPv0Mw0J(-#E1 zU#2D3!dX2g^L=8Tpj{T%J)6~tSISr`k0?s=*&&8W?K*DwDL3E?w|3#D?sD!Um16Z` zIlF>-*5P2aPU=fw)9x65ALmKWeiU*5FZJ6fU2SaBEF#OX<-s;48wta^FSc}`QSAh0 zAxF8VxW6l3^^VCi@L{bdHMrFK>;9w!jLCS|sq^XKc+ntW;$R2u{U{4hV2f&348}+B z1}jsFoH!Tt(KBu!dnjv)_AuFJvW$BZy~CXbfL2MP*&{en3O3}Kf-a*HngdkX6Edgo zvG&VKeipSI1$Eb))Tkls6QWyi#>KzoOjlD)V)x;Nx52GVp+yFSS*Mbjjp@PwP6_UG zv-68JiKQeDm6KU0l6K=Zqa&M8IA_xx>*$5Aam<%Vc=@F88zv}|yFhbMG%Q)_h{u~w zxxmV~4d{6H1LjqE*oNXvbP&Syn;BVnrq0f!umN9gR&-TBMg_k^@8MH15P|JTs~Fl^ z;zP|z$}3fTNIP%45`Hd_U_HmZCEeeQ~Np!d!-#1yNEJ z*i-WYp~<$8bs=K2=nRt9(hcBU+b%~NMbI|q6mH%-&`P9JdMFpjO@n8Bh+A?Sea|B$ zkV7aCdLH!gjD#%cwefgCs3LlI#&GP-*3M`*(fhf014Sm=1L__{KqR9Y=#{09&V_`G zK%Rs(y6u?zuJ~zKtiWOXWi^Qn?|aE-H{R=be3zzGRl6Tmn2-+ELcWHW5mF$<5hreq z@j@30!8CJm$<}e=l^abGAhiH&8UiVsGfhPnhx$G<(ua@+pu;_CF*@VEN^|UH9Ml*a zVTySSkMAiLOSvi1e#l*yLrhohyX}PYDW=CXSk4jisVGFm>q}-U@VyoG*?E&2lhZB8 zU8uE?h_~o#VwQ!DCQPoQ{+FtO;*=^rj3>mYL}*NV&uVV;h~TeX5V;|$f{3s9@n4;1 zZn>eUa`%xEmVvzqoWnA{{}GX6_WM~M5gFMffl!+IC>*Y7RYGjJW|hY$!jV{qFFE$? zMLajH8jqcv0bK(~w&JOz5elU_mW0USy-br85>%58tR6Zxv-kt29!wo;IF)7h(GnY5 z6XyId_z>W0@a9X|g{(V?39MShLK!ttLS$FaE}ah*`@dA@5zAQYj|edrn+=2R^8N03 zN*V)_KI${DrN-U$ai2c-$!AeQcWbc1WBwN;bRH$7EHUCPj4A3_))mjAHoP#FHVG$K znCn9ZwGp>ir~y2W?7Tof#lI>5+EWQpTz$uz-rGk}EN&3RqyHB~!7j>xzv_%vM}~b% zxN+G8!m?8nZXH?!0SP6SZDlWID`6_^(G8!6w{jbdyaSTA4ZUnU%posaTDEFcNgjHl{@tMhrIop6jW1wa;yZ!{AD@g3_#J2p5=%# z88|)+*T$xf9T?=b0nB4}2OY1*%ZD4H7o2=->Uf^Da1M zDJ$5!Nv-!%b&i9AIr@Lk$a|ImgVjQvkC|XD8^j^OL-KNpVs5js$rp)`L2+b7iHfj5 ziJ}McKDS}zeUfnk5h1nVk3D1EkMY%;P7U1sL`jV+w3hEcmcoM|_UqB3!j0q7!1M^I zSTyo=web4i@bcc6m2d|wN((!nDy@pJNCVk^Tc&fc)WNOH7Leyyl?X>KDcdz|fr9xk zRB49UkI~$@-ma1|uSPPLaGxGlRFJA)NTDYrdBZC&|EF_sGmZJ)36dn!n*%@AJ|M)U zc(*>|4KXz~1^{ZS3;q5xGjErw?Trcc8$cyvUBn2fngI&EYnCxa8K74Nbs@5;Ef_Gf zJ>qhc(QWSl;=C7scl|$7APooP?0#}KNY($5QnTp~O`ehPm||HA0Q%Q9=~@>#k5jgA zQPw9_;2^fTBb+IOM(>rh3K7%JeXs(W4^lstMl;If|W@8@r30v zY%I)*vU={orkQLmW1L%Fh%&35g-Pp)Q=EY0%Upp^fsJh}g1gczT>ajo_Tk$!b@J`* zmD1c9msd^=r|K&+V_z&KHrd3Q zbaz=kLPzsZn^M8pnJ4c_{ZvLWMBj~LQL7)|Q`9nG9bocrMV-Y0Uc4?1ZeI7fLl#)r z`yuY6PWCU6z}Pmi62+PEcCCWO0hJ*fOw%5~w)KtOP%49XWp8Sth0cQxVClnH0?%nk z=d&#<3ay#ibr@!jgtryVj5tz(@5C9P4ZvZc6g^+R%d>C82R7E7m+2l!rLAgDv#`^1 z$~bq&hi#Bb+oCH2o9#*$mT?tc+;4;KPL&CzDCsDkaURme{jk;(`%vwM{Iwpr_!saI zYjWsH;l^}B9$Y+IG&vL*U{0#DD+xf0QiB`P%+_me=5ud-A3t@ySRt9QuDYtdbreB; z1Y^%3FlxmX{2HsZ`0FmDbtYaJSr$3b_*!`0KARD}8R1MVE<+%8f&~!~tvH{!Y~5%% zUgIo5zr9O-^pkfz7N6GQ7<~QqR?pMz{VP6iokbJ#5_S(||6g%4Wuj{S1q5%{E-+h4 zV}WtTfbs;`Qc9Kp9wBy~Q^+o)teUQ}bJ$7+fedL?hGK-({ghu9-p+Sj{QEakcz@F% zyfY-cLveW(R&b7vY{8r!{xP2FKrE$h(IpIf+odjagk0o`g6t}a9XU_M*SDM_)FfIz zt>IARv-BJQZKC(yy2_H2m>k5$+*F%2cwUqMAh%Q>C_rN9*^)aP_C~h!wt5>x)t0Cj zkJhxOlEYyQb#&`y9AMu@X|=0ngzNB9;7?S*lW$eXZJYhznOYlXjta=Y%kg6~p5#p; z&nk74Qy<=@(Q9pbVt>RSn6pw6l7TS2v5VPN8zJG#eR$u8%c{DMZ8_83UEih6uip>Lc4lQb$-M zZA?3Q@rM~UCwYa3QzT3=9sh!iIHYp*<==eyQhe3cf8nR@zJ??fvbJjw&X5Y?%=XF6 z;hq`K(Bn7&J>Lwg>~3Gj>3H#4_EP6yY;n5+=Vfi+L9(4dR;=ENItns1H$fqZid#GV z-RDj5oP}0@gT-`oYYa@dHPnKKY~65jErfCi;k+=wWy9T+m_LKpM!J_09D}Bs^b2^( z4%DOuVQI#q;wHs6#xqP=b>b4)JB?19j#$^CZl+?0S0k-^*4oCBZ()+9{68xosiu?- z*w+dn?z-arA2S&IbKF#2KSt(JKZfyn{ne2GP3@cRxH6NRXdqG{>I9II_pOM0MMq4A<;%gNd>HBK_9hTa0w`zA>hMp*ufJh z%`;C_J1Zcg_q}+(V!4O!^xr=719zuUozh@bqtXZFhc2Z3NE$Y%+J>9<5ROpjV!0Xv z(y4YFY?zN%5pYX`oh^WEBT(Uz`cs2P;a?1mu-DYW4Vz)s6frj%U@~G(wx(Vy3wUC$ z^bFKwR>o?qq9RZ-_ZBQsRer^Z5ht^nM9k9>#aJ&>E z4(?*N-QdLbE;Q{^c%g73C}(^n{bkH&kcNL&ED$enCX0>Q z9&5o(flSqxG=;#VbMk=yFj+wC zIj&h@(eLl@&EKEKhcuUYrVFP#FZcHee6Z6-HjEMXP$)W?sBovH&+!JS)v;2=vJ)%y zq*&vXA%w3OYAq~O9S=z>lED^zMx-R*`rsdB-{N!NysE8v2lr3?-K!|VCN|<6iSSOi zyk;VWe4^#f6b`@J03u>=q8sNlikIT1iPx-XknnEAZSUMoYEHh_OJvAwxSAz%7;0be zQp7m*CiaQD=L-jN<@Fa|b4Qv%!^Xnheg?_h-Q#8WpcTk?5_*scy9)s2f>y#(7mT{n z({Uy^=>S7l`0T=NvLkl@Z1j_<4^VS`0xG{Sw!`Jx(k=e{sXk!X6v@^D}ZjP5(yUHU6gv(BLVlBiX<3zUa}OQf00|h zr0!+pN$4gIUeHMc>u^VE!5W$zEtSZ<9wD>^7aZ}Uzo*b1+Yr$GOpZAh8jE}8LSY8x z3bim7A!w>IN%qbHM=H}vnh;Je@*?yK=%foPI9Q-6=&!Uc6DElI0T+FHG>ZZX_dDwy zT*~+p>rtyHufZ|KAANSpm#+KGb4ZoGR~BLy2d(z*nkDh5rlH>I`y;X^I136kY6Z^Bx$jBxSiU|m{m@p*?1KF z@taBebR!=UV-+4ERmL;Xl^utr*95)h)rRQ3(Xt!KvH0CoWo{b+Y5n0 ztF3Sk0;QNz6{e~9OH*?T01*})0bF+Ko3<~)y);%seW54ov)Urmv4D%I_oZ-XDDDJd z68I>k&xPaieFLVoij}F;M&HvqC_)9dANj^Zp2;A&2S0VJ_%f*=S%7r_8}PiCZrQja zRkN7YO#o=)1m!k(^sYMex8b!4>Ppe0910V3E6r#L6F%7!CUTz6t1mpF*f%!rW55QP z2h7tdt%c4xT#7s2wda^)|C)E+)WC7cJl;7&;#w8IVNu~hnHaeYa$;p&bN;ZCkBNsL zw+5`q;APvW3isu{%0i~WQ8HuV$J}h0z?50Eb4SJdT22@06M~!hwKbGA?;EqAXoa!uNm&Q8|!7 zEAG&2#9xyQvSJ@szT>Yq9E#6v+Ecsx)zT8?QtR3~MzO(n?chW{9)^f{+I~MU#ou>v zt1NeB$Xhr8-E}BU?g+D6p@YupU=PMMY<4BV?KEIYX3+(dG0Hr|kI#D-9kYtFg;KXDJuU5UOdnm}OPFxGOQ3fQw2Y0c!sw$KySE-x3uVNUheVt&WIq zfDCa4yt*+=nV_2_=tC4&-|ZFW-w|J^X*=8QHx!PBK&S_+pm%JVNHsp{PKIT3Y&NzFS_KrZ@i60l{NGD($owt--Xv`1>{{v$Dz29(fjnq6Kls_E?w!ug?}0^UQua`E4CtQj)sN#7GZVsQlLYQEpTOQEyU_^h#N$W-jZ(6lC9Mr7-Z2YI3>q{C z4MG%}wXZ6>vBzP^#}&_0ymg)N4ub-|Nct>12#)Ss-i<($yM{w_S4>`bunklF0XI`O z!nc=3$n|fSB$`B09zoE+l4OVR4_xR%cw|WXG6w+EV>;*k)#0@(b|_;dQeusmmSu`j z{tdYR8!F>r@HmHa9InypM)vBs?NygQzW)e(gGTcH9rLC!AHyg1y4RqCP}Xm-NNJ>y z6e~#l)|T=UgS)AL8nP0KKVFoUt%HmzR#exOYM6(%GMkLZswM2ajoDvnn@ANv3U8bx zs&Lya->^Kc{J4Am@FyE6xu&7%cg~~2FyQqj14||%5kN?`mo9ZXWHJ&RUZb`(j8kAvq&h_v#hEDpcbIm?amHiwfOqKEUVHz?QFILl z%I)?A+U${Dhc$V4ay?H4kv%=N0l9w|9O7w8@K=BmL+7JYI+$=h=#}jLC81Cp z=j1#9hBG?!=*iQWJ2q{J-u)rn8-dcg9a!11|Ct#?0qk@@l?}ZP6;e-8C}8eox#cCd^_du&1}{D$F&u=i zyS_cSqY{Gf{y6n?81{foiCtu2pTL_f#ah{5t%BCi#Qc8knfZ^w#rkA(2^CdkCBs{Z zw$ZU+`+ROmRZz6f^5VeIq!4vptsaM*ax$wdlon|9U1SoZz_qE{! z$LrArf&B2KQ5+jNzA=0y&Eg!pGH{lzbb(G@!neg8;5!HL$GS%GwK0)oWttRm9HuSz zYPX-qp;R-ar=j(*8a{70L+XmLqjHjRST=x-GECOfkUp-Jd#pk&3lp-J>#%b$R)S9 zzND^HUy=x!ud6?(XE_Q9$; zeQRM{CHq-IJhi|WLqYIYba{XQGISiNSAlViY_mSkJa7{!Y^HP*D^k1?P&M%#3qSR( zFSD(sv4iNVlAkqi%vr~w%a0vIncOPu#0VfZ!DJyKIS6K?iq(`tq(1~tR8G}Y#2tWz zi3ar+|A6KpPqC_xNKIyrL4A4p2E+h1vgR`~9pp7u>o);(IAxYCN?zG7;l4*Uotp?wxBJjC@P+ zP>i>8Vb<_wldIM{Yr&uYXRpNjxuEr$LgNe5%)bqB^z1(ReXqxNYaDX%jnj;pb9f;7 ztw&2FdUMrb;=O6QzdRGDy52L%x0v_E^@1YofaEYqj@|Vf>By! z4bCUt*mP7wpuyn2_3_7y;XWE2*srq#TZ}RZ$`a#5Bv?i?5fF{(>|k62EaA1=b6_sQ z-;87jR#6L2+vRQSUL3r^s9>EjON9_wHr}m|c`Td^I%=cT zHj2q>99j=GfWg^yhva$Jg=Hx@z4d8u4Vs7YEe0336{Mx_fmYdszEP?gx4qycpZpWC zW$WwssUxx9Wxss}`fciECo+#4xx#5++i+*JefxDMzxm(3LN~t(uMPg+l%#M&MmhB4 z&3vh&$>Kg?Kqv+hv;Ex2p-ZpW^-H{aYuWyhXiqD&6|2f9$uZ|Zl4=%&7aPhG_t zXcQVMSf=tHv3o*k7aKq9QCkVlmj#RN5=6H)>D-vjbly)}quRSCE*fD?LlCsZTK9)e z8Ea&iH~blNPhUZu5P_iFD3;u9&6b~1mcPSKO*{77L9$d`?Ldj?kmQpj$+Pi!ps4&? zYD)^Ku<#5KU(g~GOLyRv1y>614Jf6eY`hV?jr#zsGo z^lOa#B?*4o=`^zgg?pMTZevq--t5y6G& z0=vs@@w6kyQGkO=*r0Pf+~hBkV0^SAF}=vE5{-h?IIvJ8^#+hgec8c%7FwbblJk8S zqaK3ZyehiwD?fSs5-L%{xjuUyCM6=n+SkE$RWuh{#x<0h9N6rEd*mg`Z@h!qm)j{5 zx(NR;ArZbCuTB&zjHN8B>#ibwa?OIqKq6j}3AbaJQ1tTa9s|yq56+33a4-uVIE|M) zWSSi-|2->X7%SmR=-Pty7hFwr*0gPWPqAU}K(_&es6H-Hy$PSVDu%u^qN;(?0-*^` zIMn0(Sa>dT)eOhs7UFVU(#3niNAmt@#6w9*{2rR1=_9ETELjYy7c z6T}6#DjH#IDGwBa4Kd7nXqdpRSY2%WLs5xme1n+^wIvZ?hHVthpsYq}A#rHOqFdg$ z~JB#^*G(Dn6wFI1)7d{98X;FJ1RSjLrtUbwkIny8L$}8FqU+}$D+p|6ydm^ z+;At>Wm}}N>NoA%*vMe@j-yRwd`A!4Shmzw^PtAbYu0YbYqKzl-G3($(6cVKErx}E z$d4Ndh|fX-py^;5KFg@Rq>$qnmi8XlIOHY9FI9*X@d_nyLi!}0i3BYQHH2!wLJ`XH zFG6IyHooXC96o3i+26``=7xWEK)VnTUp3}uG1{uc#!<7 ztDF793LJbMmHCah@hhJ2tOt>iYJ@Gm`HFtFcgy6+C`@@Yg_#H7w{8BGi#28wXZCs? z`C+_peMz+i{;(|j6hdmR!K-@{ zoK1L`AwpSAde{K2EE_7^7X~cOqv=}b3xJk z8{HMwWw*DYkH(I@EO136x9sn6w+6->lE4pSo*kR|f0YgH7z>Xvr^I^=*A&e z*b=gTzZi{dO9w+vm@FLMJlfval}s+jtMSx5oSRcM6sJZPOl83*tu z>e+~!hZ?Fc)e7+HUar)COv5gHKFj1|g)wPd{^ltF~Hy!cQGD`f9Sf z;L=k;Z%-zohvnc+6P*E=!j`GoIq}a__Z3eeCloV9c6N`*3Eg2Ztob}%b} z;RX7w(Je*-YM@%J%xO_U_#mVhDJyihJoDhGTNdM6w^#zM>x!=yI~bSGz`1Z}s|qPm zStfZxGa4^(qR4C<%OBTDMsLJR>1I&{FlI&H*pm5NTT4ATN;Ag;2*}4_YA~v?aJ?u6)wfk9rTjYwM5rsY~W8sgY66Z6xm1&I+TP z`RhO5Sm9pxkFS<+o`=s8tL_y6QWRe7Mn7^=fE=4~(^$nDy8z)1%8;azUT?ZVh~2WY z&;pH;lvW#ezkP816O80*@*%!Fi-2%3ST6-g@GYnn1u=bai=8k9K2~i zDJTgby3u1}x>ZYv{gZ~Mic|z7^mV}#xds>s==C`Fz~Cei(yh{v$~N_!VdsjME#Sj# znxoz0yP|k~xt}uA*G_(v4?ni_47F!Nmj7v?ZhaiDOk?D@3p~uB^u$x?42-00%235K zkV#HStzuw~LwkHI02%r~^s$R^*Xdcm@Nxfe6F$534-GzGB0EgX4sArQ>EcnIZI@iZ zqw&Jw_F2=z*M4YnVAHi9AHDW{Tc-v#Y`XR%ljBq5v}OT1{Bcugzo zBkRe)ov|YVZFEfmhQcT`J(Qz!I2~q2V3m!l0+REBNs6YGeT7*&Lt$?E$}2u-E$&A& zh{E?=(QZ!Z;5gbI-=mwPLA%+^D+9hp_jU*HY67_eFJ7&zPZj?#dB#{rl}6*Pu!*Tc zsT^xoN{fcojy+^?sE0BlA`-ZZVjd>Y2h#)~-`<4e3yCqbnSXZ_vgM7RIQJL$wyot2 zLfR&MncLZ)ny5a5&nEe3ej`VjP>_oHFpE|nfJg$CShQHrSx!l$Obnt5m!p&{$GJ}H z5a}uCMIvPdcswfnyAV!)BC6S%q-RtteGZM=`LVCv`3ws4uNs7TZVq&Fu>(ECxIrdJ zSYz%6q6|u_aHg(v3Q2Hdh3^upSuJmJ$%D8+c84M(2MLn_5%ICuoJh1n09#I7vgh9@ zfF?|Pkp#f>*?IuxpzGR&aEIe01RfK;)MgVb-Gv)f9;e1iAMi}65u(2-6K*{=$xuuz zaK{F=07;gGV>gyjsI;yyVj(}br3DXq!T3M&?)TxR?t6VR5gm@s^j)JBx)q0`Q+=H) zpN+%0gE!J_!`s&S&6UU&t?`I2xgHs@#_}IL>+m~*fvOIOH?qu$Vcv-)w^ReUxs_=6 zU#HJ|C%#1M|Kg{9?=R7lzcViVr8~I&N#D`$cRSvyFK`6u`qJj{U>R1{*#Z;+`s_N{ zmI>`ZV`dSY@z*ON#c?TVYoFR(X$%4QLe&qyoP*Q$hbnMS5k<8aIAD}whIH;1dI!R9;n`U=NlzD`rV~iprvF* zo-F)xq3r~;^nnb;qXti^_h;2TmeobD2Oh;NdGb(qA&Dg730(nVMp9Mm=uYdB*O#R`26B zQ95kgtot3`$H5>o7lWJbbPsaM{(X2`Fl%fBv(!zvz;2KY&Z*}E?HT5EaX1XgqXbJU zDgz*DZ{$;ZLS>ddBdB1~3%PN)T&17L)U~iF3CG48^V_QfzK6{;1`5L>TLT9zI32=j z9o8T*->NVVpyZ${WtSJ@llxeaaa<`L8ZHWf2>Opj6?TS!FBC65aa8OnC-oM2F9at^ z+)V+cnvkKGoWh8EPh$rO$`~97kzDtY-!A+bzE`6Xy*ry2b|-GI34w|6b5Y+pw=^+a z;I)B`er*;ecJQwy5+32pT_T}6MSZVGg$j&nENXJ#$=j^<6v!*B(xGg6IiZXXs%6z_ zS_BdXec=a9umC0A7Fr$>+y0Hip2j?~#dDnMX7^r6jD@48f{h%4S4ZB8V%aL}E(047 zVq;FZX)EZ%@qvw_6Zm?w3Hx{T?h!W3m>$8_n1x7>#P0`fWNDCYme%En%^bIcBX}3( z)?BuXl!0$-uZMEtuSUQFganRz{$cMj2{Z+^4@v^$Uk-E>(4Ed*_efVhjkiQ9jnWS= z947uW3{b!vqY&1stp;(uI(;PkFPbFyIB(;KeoP6QQXrE@P?8hQ>bm1n| z&BC^h5&K^FGcV*T3WfyFe9otKei^sZYAPIkND`#$?rQ@AOn}3}BhK^;!y0+t5v+e5 zhCpz{`mEH)<@gS~d}0tQ8vVJxt-og_drk%4M}i_e-nZ9RKVrE3lez=NynNQwitpf(m^){nJa| zIY<#bxIsi;l!)fChH~R!@0Lxz7N5D)_OCHCsp2dI9*!t<0+@)|nG<@&7F*nD;=xNB zD)6`&JRqenM^mR!P=iSeQ%+DlK5N&u-`+r#Z`ud6=ijqzPNqBV(UFZQ6(}F2Fv1+kGofFPwtHWpILMV0?N<} zCQE-?kj;Qq{khg$pn8;yVtxG#w()^|q7Qh|y+ z5Dal+JVIgw6CJmIn2G!Q`#ezcFN9@|qj&C?B-tDH%*IsYgY^(F#!f z^4Ojw=GVn%mBoL4bV_7GG?(19^%J&VHMTzZJUnTRzxe3Okj7b(23vE1axniS0GLA) zd~EuyIbGwEld<43+F`6EIjB@bHbaYf2!zo-D~NeGC?2Pj$1qBUgu7n0T=?)O-+Dd1 zQX?nu-K-fWTg`e2SE-^SGr>k`#wM#->j3C#yqXa@;y7JMbU@(Wq1~xR zkuEqpSs|qgvSxbBJVX3Dz*^z4LtatzF5cMDMGPWC!v_}XTJF|-T_kE3Yhn(Otq8sedNcF z$8AMUb}HZw;{-8}??^AK;LV`UvP6;jrnj}oO%d8^__*yufA#ANcvfy>W9)Br+r&HA z18m!(mrRU~b&?Y%SmtOu*G0nztC$R#*_4F}j6+IOG7OpF1oAx;nUygJkqwUYS@N3Kvo5uY2>@F+{ zv^MhU(~vQOj88%`i?T}t+x*fjq;!8T8tla9mTa3qnI#craPWbJsJ|82n#UgB1jMcv zt;x*AIFx|X)RZEU%RIYvC|IggS!iRCOf{~Y^ZP+bh38gj#?j&p&;9$aZ0hIUq;SU^PteS1v^*W+`*S_s?Y4blf*<& zjmXa2zUQfPllMQs+b>w3ku!+_b} z0A*OWh2vW2eX!3h@4I9`LR2TaR#;i#blkUuMIt|BR^fgnn$zgjC98np986qqR+Y@o zvNeGS=&d#GX%;7>b_ikBQCwD+?)nbJfF~zN- z8(pun+!XQAVt#popnXhY9(_F9#*re4&UnMVNQklLf}5ATg<@Zq$sEEW9v`W9%aa$+)Co_|Q!f+(+@5Cs`pFUl$JpJr-1_c+PQafp#>K0MR0_A+{7Z0;>qsb-M@NR*FFr z6(gs-FuT6gJlA7Bqks(lCnGa3UM0VrmNI3IeGB**r;6MddYGckhRHAW*40DCQ%bQA#F8qH+L5|7k3 zJ4=5pUs7R79BsK8yACTVR*S=l9u5QD_4+%W!gG(CTK@MQCuwo6Z5hwNp?#*VG9q(` zPR2Ql^~IrXIw-3ne5LgXdyD#*Gj2#z#3(5Em#r3=QJBUCgjVnTB1p(`_wTX?(;7;}40 ztqQQWPhudhb7;k<7oW~KXqj}Su$kg zpR)k=hykg~X1-}9QTJ{)%dYT$FmW>*Us<8E$q?pJ7NSsQ%x&&`Gcw6?o$>_5xZ8!p zM~{9MAKY|?{N7WthhUd7V$Mi$)CLnUwkQv5uwTyt<2>Sny3^O-mFCp=SedO`uYvU! z6sXz*C&!+gJ7Ui%rxDW)n`GkNQXxAV8H@*%000enHMkQ1_2?Ip!KDwEM-8cL-*(2j z8z_~Awe)*eODYH9GFsoqD_tOV5Hz_}$Z0ky>7!mCiF_Jw)=R*`c^%YxEMC@e-&z)s z*~Mp)3Npk)s3}Dykd)mDrRJLtF>hj&K@uiQXb3W>C8@>_B9UZbB(Eerfn8JjtTKx1y=$`lSOw@L)Ll2@7`jO631gTY44mZ`W}#I_cyrmu@!Axg zAw$5^^0onsCJNFSK_~XGW%@WWGQb;%bsCBjJvG+JZOdkiZ!O;#npAdBTN<)BPL56# zNkYvW;)B$?w?91bDmfBFZL>Gx(o@AexR=-g~;FLRMEbwGO6dkVd3qBgyKjsMZ+(0fH;Dkjs&8kX&Ab z7x%YooQcpXOBs%0>C3@)tOdrKZnMgjS8{tdRg^VkrKTMrXsHSg-RQ*(hM_`6!MIAg zJPa}9vGcGOzUtwW$0HiFWP{{!CtUsukJI+#^axjtcjKMfXyUq zx=Y}F=fYw|ji&-pN%3B+*ao7t%4q<~-n-f=3D=admdgqHnLbhZS4imK8!rCYf8u*L z`l5~`#CqbKoWbGpI_e%$nSV8T`M^<%P#(qepl~riO!bK~S6p8zSyg6vlU6t#6e)>( zI;VlsU*NICQ_EK~ykK}tKG4EyunQr>T~B<|H~)rO_9^_-eUVR#((2~0?eC}uON0yg zwjdAV>*hVJ#LKLXn#FxKi&sQJz9lT2;3fd?In4jjUqqgWCtaeBk zUp(maaF8#;m(R?6NK^%{Yqf!eqgdCqN0X3-zMZrQXDw_!z)DbYFwZg?P z6VCxEatrG+O|o0~qTyGJP<9P#!1ns|-yyiH_1PnN(EM=xa?`}{_yEQUZgEeIW@-0smyAf@oG~$q z&V_c*O6)cXRLr8r4*hMS&;zeOBE~ z86v9SKWyGld-8HA!mxkjr=_99m>>!si577&T=}#wzJw+6rekUM`k)#kav$Ct&!Vq= z&d3l(twR!)AJ`=vils}l5k_0WAipjvv2+^su0-V|a3vk^?7>->=4uBK7k&LkR9`a7~db`g)Ss_86_99Y7&}F8iUdDULVilVT{N6xSQqYMd)VC zsbJzXLySb%nrm~p#{^t{j=#NS1gVTowm3wy^T=O+aV=pAcRSQ!$^{ZlBGcE7jGmJU ztcgsY;%{doly^y;D3oQXiFdzo04pHCc_dOt=ljINkAA}VX9{kBvq{l%rfMSx+{$Fb z3-Z%(&MNHKDN83^LMRut&VCT1YKw!mb)o!ob~?RdJN6qxrqgMU?U>aNvOAr>`K|;* z8Zb8-6nU=G6xQ2pb7X?NbWnD#SP(+tdPRUrZo!qZ?vRpu9y;Ql<;=y;d^8_r(+Mei zU#xp2TM$OoJ_Avgv@sS@dKy6kTPr151*Z!Q<&KRd-1r%@g@#=q zdtaJ;XJE6%;PfiK6U*alrR^Xu%)(8CHGC5H-0#CirAw0y13OF&j<95aYq{md!j#=q zbpl1t5iL1opO00l!gds;jRrj=xop)Cq(sV)tgHYW;KALPR<@l|ZU%#DuH^8q|LA6G zsXL*;zrIr9V_hc1$F;2ovJ|*xY#+c|dqob|4dEd=9t&*`2^h3-N)C0l05(ZiOg~2a zFbkivU&+&`tot-jjURTR2gf8DJLveBV0osdJ{IB*IUI0&hobps$$S3lNlc-dn&tPt zMv`M>I*@&@HE9uHttL}~=Lt>{ERDb^ST#&2^K1&w2Ke+du@ul34vHD8;G!93x-I4s zR?9Ub=A2!hwR!L}kSX9Y^MzX0CF}KkLZu%!%HcCUyvzVi!yv)l*Ge|5?)FX%k7A)2 zI;IoN$=XfZem#I%|Lu~THR)WASFXb@IQFM1BI!;ESfVQ%+K-kBn+i<&6Bd!?wUX%? z)NwBl{bA0qOl=76pR|NL&NXyrT)fKRjr^a>=B5>wJl+D@|Hb#M2k&AGdQN3CNns~| z>P@-Ul${qgxf^zTv(}8F+7m%H;@H|@V)E*#7Napl{(pGrD_{TWFA&%^9pbq6@_AB* zPvi5vbEHg$qOelndw}@zFWjR;JG^@hV^h;$-YO8+pQ{WYVSKd$tIYw+Rn%)pyHVSj zx$`2rBhqU<57H40(YIsDlK3gf@0uguaN%i`-|z8LR~R1vXKpn&(-SqL8pj*2fU_y7 z0$Bu&2=<_U@C<0_iXl*=6FO!QC+vbA8Q_l<)S~x@xl_&-qvR)&$q}BRgHmSC zI)vlY)%QqT+X&7IXcw>(A`ftSJi%533EBR?JJXA<%U|78nPT^6}SVb6J6| zfe5P|d~~7?dZ$_A!{2gvdVC1(Jd`r&5%vvecEbsFtN7Y7ts3e{wN8)c*IjUZ?|LfP zkMUENq#t&F5H7((RXZ{^p;K|JgY&L;jNkqkPEBr1!+ZU^Mm`$(C6ERy{w3ogwo|N? z$E_UiaQpZjW?52WDNM+lJlO1!Olj4v|GtQK(OTJ{FFve2&-%i}UVT2h>Niq^@giYx z7KPy68+hXOkX>*b&Ej!1GqUq$5T=N?oK|KQyr6Y0hJ=ME&000plA;*=ehm90f+s^` zFUY_lLbA#HPJi=5r%aqpttcOoqn=Zxq3{Y0GxC}kOWJ^CgeV}P+fjLD^0x)$oinan zVK_v98#<>kdMh7mN-$9!Ip+=LIg82QIyOHIjcge~z6?>4T-6(-X36L|3b%giH*b2+ z&!~${?Z_XM@TiN6FHB>?pVN21eb-f0+YtXBz5u-jajIKY(xF2&(>70%RF%G5q^T z2d#*c)48%ib{^pk7toBz3tfop#dz&f<5Q~v($8I1T(obT)MK^7OeqtycZJhh41;uo zeU*oV;i2*gxDhZVEK>24W!n(PqJRF(x*oGKi?7d-a0(Y-pk1H*Cc$&KyF z9l7pBbk4n?Bkh5~(e~u#+uz1rv%UemcyT%~p0o`Uju_p_7U`}ef_i8M5vR`q!PMZl zSSXZ?qM185jC-v5BX?LfEg9bX1>GmXBWhW|v1>c+Z4(7PdKj+Y2FC^lx8mWCV

      I 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

      i<$n+ma_ObKgZg=q@G3g}odGPY<7tt<*l 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%0AGdyUi}q*bKU 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

      4$ui1<>Sm?mSR-+2gR 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�J*TcXr!~Zf?aX}torK$9-tozwSfjiEOSoEb1n}C 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 z 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�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

      (GK z2l9ZW3~`F3FU_-(EXZm9SjB(HoX9(J8Y6T?8ihr&Mz6heFU{r0~; zMoE1iKZEgWizH=Gab^^={kto%$0M+kK}GvD$CkGV^Wzkem2U?MPnmPVG(72aA_MVP z8i4=MMs&kdPBsqNiE<8($eaT;(Hi@TlegUccK6uDr8fE2C(YARUxn|hXr1~EGCCuO zFiPVcsvDe1f%#eujr1L0nFpEQtU?I3!^8}Qgoq&~C=_rwl*3NuI~ett(zzB~c%SFI zo3nBo8vxFfXw0|bbngBpP4cCn0%p*pxgXzwL2omM;z|O=a4^p5GCkW0iR|aW%L{Ai zD-zg0Lfw&RsBv`#-g8m>8VP1S#?lIC72n;vCdo_q3_Wb9>_@+oJSvf!Bt2`n49}nkBuB1-{dx z_M+A%-5)GhBsOA#TFS89zILOMK|ofOAGcVKH)EdM;!{K=7MjT=Z5!ExJUG#hG9dwp zK9cOpZ$0x;lN-;m9`rg-spN)c+-(>!Ke-*OD{7+QdRPgKEs2Ld&MuVh<+vLqy)4QE zlC$cbB?dlylU^F2r*3RSq0Xow+riR}zGvu+iXj%dAR;q5ODK}J5b>0}MTH+#8w#De z?giU^%_$5`!>bqgX#(`fOK>FRB*6RhOm15?WAtqwSjTqkjcH?y@58574Qt}a3bG4> zM4?U)8KPlvBZ;y?oO;!V%yD;xg0;f57nrdZhF*zu2s_9#{#(OBWc$RSaY7CRoL`TI zStTqUSvmV6gm>k&w|m$Fu#CnM`=8IZV$mKqL_xx`u)u@LFEd}OglYm{$db5yZE)V+ ztDdq^7GoYCc9j~39&|&4KmsUlLh#ms?Ee!@cAo88+hk4jh1jnC-uu3O0>!qv!5+`9 z#5UgBJHQ87)E&02vY8l6zJ045=%ud>B@zfzxn5O*xz zFJyVbRgZY=Qz^^)G{~|#+F=O}Vcp)N0S_GQfWxV9;n0tE2r2U1L)#?jxkkV94$mZT z9py8iQbG;`?aS0i%bhQgt_VXGBA1b{)}@ntK)>OVWICNF38p3lb4>UAw>^`BIjKP~ zyDBA{MvKHGM*HvJuB=i)x*u-c37>}*fSAKj@~VDD)mXA3aRo%YqiUo~c@$M+A%_kufm}$d^TR8iVrZ4;Ee(dq zJ(3oi9hSh!XIvzqgrm%+CSZs-H?o!Y|2y2P5{YV(`8u&!l~^6HLU-88P_%;dYhNz! zt3@1inGtK20xXofycW)7up`f}| zyYO)&OCoR7lI`PabF*VA4avg2`OcdV{3{$EUv< z-@KNCU=3p%;mo3AI~ph0MIhUekQaImpD_HB!6JRc6%T44A; z$2Ti|&1I_{$ZUopi@-0>%@lcjY#VYW@gL!-fFpLoH=;V-Be>$`o4O=);F_QO*eM|#`aSqV`QR_Fi+&LRS_XK$MjqIvF8w&Z4B z60e` zK;%(QN4Qt>T*rOmrj z42#5tVPwVJw0`I?^24}yY49P@f*NLF%TIKTKNE<~{5*T&7Qi9Z=uno14D*a|HbcKb3A3(aDvf-=gy-Hufcb& z?VrCBreeD1nQP{~ zv%8}2G=kKyi!Xcj$d4(cp@x9q^Y!OVNYt`rUg9SrAg6-&7@8*Ds8m=&72w8K*}jZA zH;}CLtM*E?8B`$tp|80Mp&z>FdpO`KJiHoVIDKL0~IVd58zW=DEX@ z=cnn02(En6akt)xC+RfIo?qaz_2;42EliELAK4t(0X?B_LpM(!!&JJ4JU!I+be+II!D5g4lNcT&M9H%k>Wgt${W^%t*OOM7bEZdlFfU)I}) z$J;d0+doz1zW2qAB-e+x?L};y+&S8tXv6HWSzxWV=QGS`)1gve$qwGfvbuhr8<`8B zg}Wl&2fN{RkhONAapldbRF{y!7($PGrCll1rhCVIe|;K7ab$z*dATfyqp_D-hK~sl zINk#zrEIKNpzizOx)=bv&NIw4cI?pM!hU?jMsIQj)rhy9A=z5Ec%Wc+12$LLfd;=jReRfBkAgciP2uXHEGw+!0$1uA_U&Vg z2C}}1zy+4d8&3==Rm$YaTQr!Y8%C#zwUu;rB6HxD6+( zEqK*D>KC(@&oCV}e=Tx>5gYEXO}4Z!{xMiU7e zmS!2WZze-*DBvD4Hf_yE?r= z{;IFj?O5C;Z`HQX?UlF_xL942l?N&CR@g_*DOnI|0}_n>I4v;*+Nm6!BB27ejE$R2 zcVLSSr?%P_*GOj!5ey_8=byIfJNKYq8jeg|;Ac6oWOrBv!_K#%(!^GBFN4zYdhuej z$t=~MnFg66&+$tFR?`b$v~cCD2M<|y8rOnc z#LUd}0A}D^3eiu2#DNq}s<&1n)eoid))Nbs&^OP3&BI3?Tc4y}NscWLeS$gV-fNFy zS7qa#`oAlJIZf;CuG`A`NiCS2x-vXvS6T>$8|g&JT2L=07uf@fWp=VUdjpr-Nl>9v zQF*K#i$zB$3iZK<36vZ!_+X?X;cu?I%jCM-;}JR!$MOf`yC3SneI(1_;1LsTD_^Xe z@MsKlC>ksF^`<8dY1nz>72N%p;Y(Rh6^zvsz-UtS!pecT`KZjAv8GBJpiHnmr7S^K zdjNNHgWuutz0TmOY`i|t>7jDKiTM_E{1^V5XA_3RZnV!}wD+zl07UF&MUPXPoQr*ctE>%;C5qx>)2|{=;DXDh z24o=CG(ak{RK8Pyak`Ay2+uaF4oM?7;?toh;*QV&2+2cR9UdTmPwYshH{9>iEx)}9 zPuywRKH~>~99HqX1mBef8-KQN8eXlDYIji_%nn?|Y>ZwFBw6Y~J!=8?Tf_KldjQ9f zX+EZkuH|O=_Hf!Ei;KU}d&i3?i*Mj((C_$R9*0#HJMcYNr2$o|@!6|HQwZ8$?C8#tJoqC$A>qDhU{Kqw1J&5SV?c;WsZzLo21BuM@A2;vn?DcOnsV-83Sze*s7 zAtgJ9_t>vn1d})5&YCn4M5uhI2U?x;pt-xThYv}nPAEHgr&y*|04zhr#S}B{r>-p;$eFNyO9H62t5g zwK85pi?v;9AuMB&odXU)swXyVLJwiZ8EoGuPS>E7s++lFQ~|*iN440i64f>l`X=j1 zb02C+5w|>eeI!hh_)a;dJw^!WhVwso*0(97CI;|>5)woBDzxu~3Q;n>2|}Xb9(S0J zwGPhdH_Tn?9mW!w@uj;^myZ)yTw%7FiNSz@&>woV4FXT);~EQBCpr_~|s|$}f;XOa2teRZxwUU*=8TLG`?E$uwA~WLdihf|QIi$@T`lO0GhQ z9-1JpgfgK5$DI7CuMKnAs~bSbM~Y85y~hdkt1(lV=AM&|9)LS1$9Ch8s9o5~!Ye24 zM;BgiZyQ|lA%1;nxpv*>YfrKyC;$P6P!H%(<*fr`g%~p72IeX8*;Goc!t4d9>o)M$ zMw-PS6sNkdU?f+wz`*uM5_dcTKQ3f>{Vl(`#U^f%tr=9IPyFx5^68MJOvDo;_!mE9 zgv+b*0Y{glW=jZ?f-Ls9n6kaVNac!ng1U(ls8Y7)j(dF!xwTPo(~PUR?A7sCOA#2uwfZ zZ{r<9&BD((n+Fodid+nB(FtmCOW$nKN>#k7y$a?R6e($lOe!y4I`gmB;ISKr2z^?z zBKBF1W18kr#m2Ev5x9tbFiB^8ZWw@Q>`=zSL`KP+Y)e8`Wq7$~Cm@Tc;skgwKC&hi zi5 zv}-LCgcFolLP3Z$Wx!i;hf^AFs%*}2I$JB@Eez@ykacikio%Q0cWEA(A;>r{`v&&2 zhFzTbj=4EILgBY~j6oN1LuD7(Mud&vJ#^kq_uB<845QhK7g{Wv!G&Nr6Jl-@wMWr z*{^LvauydG03hSyL?Dz1sj<>X0xL^HwrmNIle)_yY!SOwUuGt#f7|ZpJj6uzxs%y* z)PJ6JI-+nRvi*hxbrdd}pf-+e%T1`q;Fl&QK-)GOb4ebUcML7CM8F7U!tjylZLm0C z2-FgNH#4$=s>9gir;`q>Lko#PAzXqEh}_v7vGOf-LL;_^qxI;WR(Jj5x4-?Tc)X^A zM;7>LHjFQ)_h3=ogNh`(`0L@eMH0?UScfw>M$m`~ULP4>6-}9nFntr~h?hw+7N(I$ zal4qU-@yYsWJ2R18(TNPM<>f2KF3DX5xYPEoTGZ zq}i?0cw-|c0{HD@Hqpkx>i`#eU`auOL5o7!R#=pf>(l6EgDU3JSPY5IKuaQ^qJvy` z`DmzAq}`$+4Ahl91=e7mtcUK)U13-4+B0o6-6m!816<})R(}tPubM=)4Rab}^rz@A zd)@F&qW;u|MStVvkyL~V1#+)gS|Ak8`kRV}&r{Ld16V5#htk$ZRl`ZbgW+?cswqxc zwT{dPOI_i}%f9!Rr_#YUB^dul)_O-%Hn_COsr?ZKS(e*9Hp~6tXj(eNBd7v2lcL<< z?ZpzD zwq!=XDO~Eo@cjEe`%#u)+@&Ee_2XSE8Jn8!jiL}cJux+zbxe+`80(GU+*v$t8*_Xi zZUoLT5EEFyJrKu?W`{-Dic-ZuTBrRJ*6f`*MiB|P6~|vNr{MxG=vr}@0z!m@VvYcg zXEa>7>eIjGsY#tr;%5+n|EzZNa2zXpg=ZErKx@t@e%S&(t;YA1Oe-`c$O$m3!KD}BlNah*_|69rGXk0!WmWR~nN$5x9)PRr|+2LJwsSFf2 z^q#(Vu8&o9YX9>K_p1GsKIeJM<{4;B}U>}A-q z&r$;c8Hq_U>9$Y9;}r%w7>qE}F{UuNoKUk{-+$Y;*_qW1N0cn|b8YB4o=A7vgO?lJ zI=b5~wBI`VJbdW-ainR;B)A~uU9@Rf49jN|!22f8S}FPy&nl}mPiY$B+Xdu_@L4{q zl|xGmD~79zU=@kr}wj;`%fRXEln(D8pMUk$RdK`j-#}+A|wLoCRbGM-Nz&>K7gR|1Vs%TSv z)d0FV`os(N@QldL9~^9O3y&%W_r#HXy~%?~Wjd%ao^(DkjzP$6Vh*=I77QnL4s<$I z1$n>I;{$U^P+bQq_SZeD0Z~eELltTbD_fkHszCIrZh4%JSE6rr?-&}?{p5$%8P)zB zJmo;-S?Gt{&n$@ z_Pv*!kMC<@_ZHqoum1OO`E=ADITVaXZeSP9)ZU#rGvat$-sP8h?1o=%VKkHYgzDu8 zL>eA1ZA}qg3uHt88Qny1yM$2+F4B;4YboFQ`;Nt5e#}?C%L&(=+cfCCpIT#YnES+$ z12r6LzFU`C9BUrn^jv)J3U!O&E!$GKjbc2A8#R~eiAmJNdCLaS(k6mx2q_eR#ScX= z=^s}!pyEgW_@nPP75_ROW>CfNuD8#Yxz%G}!#4J2Fh^mgzcUOhHu}foN{e^?WPGe~ zv{~ACG??-_u#%@P6;92-l6S@bYx(wOe@z0!s589-Qb9$eoQMv3`~M& z7m4bv;S>`*iV>*?QbAb#EVxYVkoLc}D2=$>AAq~gvl^}oAs%_k8}9N58p-V&g!udO zBE$>vZEG3fwOK#>Rx$;FCt&-lME^qB1q=d(25t|%h|fT8U==wt?}MZ)J+x_H=_nyS zPswh*&%(P{7SfRaFTB^h2;pN8LiW1>PI)Jby+;8l?hLIxUVny8IEhusc$`+kze5oA z5fEExZ8Abu?QqWRrg$Y5_ntn!TWV*&qwqrK@sXY&^%1;B?tI}9Ct*cRq~^k7BtXKk z)yQdQx;VdPpkrvq*yQ9eq704(JA^X?!pFXmGK3)*Xadb$8%fFR;oQAo9Q_!sMdU`x zndpL`y%nn@Jz$@5?LTIt?O=8(U#6rj)8PI$^IKYIej)X*TmaG}J+hy>ui z6E0+KKvGP75U1g0&~OM|pdA`}DehjLd-f{iD0qZK7bHqV5YKkWsU(r@DKU9D4rK~w zCB0!= z{e}7uf1^0mWuK90i_o~e@Is*Erx3f;x>^4>Vg+aHuJvkF!sC1wVaalU$~74HLv$-I zz27HRP;?E$^cOCcPLX<8gY0cUpGfphPhnEiaBpT5hI{9a9cu;Ux)Sn4l7@qJ8 zE%b*ayk)*69_CP%BV)l#DuF-P#bjxEHtVy$P<1c#&Af_jN&tkkLN6SSQ+*+)@m|&n zQt=G4qgutTOisy>g9K7>&cPZT9aW9K?h6+)&~<)|pFvYQUZNsCUo!%<+*g5OpkoWo z2r1F+sQvD40}GgXEvx2_Y%RNP0)^KoF?fXvl2@>c(Tt60W;$vgl5UU&Gcp)pTe4-1 zISlChC+yp01rZME7+m}P%i0fPZt{98djlWJfT3O@8y2D^n$Kxl){re&O~@%vYkrae z1-Zl)3H*8A#*{#SR*@o?>FHZZNyGdGfU4K*K;@d4LPDeexc@gF!Xq~w#I?{5J7jXY zW@IN=DKrJ3h_XFdU>1%hcx4#cVOLt1(lc?h=-PyP8Hbp>F^RCV*Q&N&O=^h(A}dJd zQR_h{zRhD_+>if=cN?l`ia6;`ffj8MHzZXXohR>ug zz|K&#u?_=^?fGw1p+Up2H^qkbE7j>msTe?t?a7;szec`Ho}RcP>Ol_n?ZrVlkPyQ# zTqR`y$ik2Hd?=d3@f(<2H6~R8vHI76NWs~oqYMjfB(&kCw_N`yo9Xi%W-}dT6AG}ju%?k!xntsa&Y-!{&H}(XxnXKU22HFWTAYjoW1d^Px!$$ zSh}NB`I%VQDSx!=(hYq7M>IIYKRS3}U?WG;((8pOLp=0q4-MT_T(!vRiP?J=1Z$am zK^#_aXw^=aD&uwGAymMS$gt5T6VKS!XQ9}-&q4xcKWpL5)@9i+U2WmXl7O7u^tKTs zkO1oArN>gvPFIF!d8Nh6eLG~ZWIT`eRa^kWE(Y42l{|BIWwz*sst+(o40_pvxux{U z)Q+-_8tERT>@4ZPx7wB^nt-gaqH>M#b@*`PQ74?t5_uziTb(7h28r@ycQX)q)>J8K zmMoa0x10ca0d8Fd2T)DM3D5vzhmp8n7krOmAbf!b1T9n;JK-ceMQ$E2%OM;sydh(R zzYp6y>H@gsxNrUFm3W*+wqQs~a}+MGp*H|km>X!0!!H4kQ5gq<8kxX=s=XtJbgpR- zD}RL#u=crH3>9OLL&OI{y*m)RV&5AdJ(h5G>c-6c77mn05YU05)hYc7zOZV;3-MB2 zK{3j<2Ir!2c3{>{+)IPN@h|_pY=j33^byMi43y6=2%ALY<6!E>P><3-jDJtV|XeZ7Pt;gIZthjH zZALY0BfP;)!vUu5(`r&;OirNb*5;I|pgh$$TDBEbX-8x$5F$r4tS-A!N{T1orQ9&Q znQLF@%ldb|`twhwCuum?Vc~M=3mcu+OtTpnnGI^^Yxho;G5lRzoWR9lrahRbGs%lB zeDKA%e;v1NTfB%99Qt)VkymtFf(MB1E5jx5I2_t(MIU)_#43`+BA>MFPDheQ^NN#{ zRxkjnso4`(p#vj7f6#*|nlIpI5Ob{fUl7eIeD5akg*@(s9)V#QsRG?XwyH!9W}V^i z8Rm&p6m}NHf?2%oTP9w11Sb2;P+9yQ{v7G(c&t6I1rNiRspjiAYHsXr4a2cCsd(*ok z6=T_S2IoE#SG8(B+{90VB*@V!9V&4TFWoaJ(_S`*o1X^~w`C>z5*7h1;l;mL&V}Fj z!O$v4LW<#dmpmEI zn%9hDN^(&>Q^jzjfQvie`?PnTp$&B4*sym!x4>^X1bll-76 zrdaE+g=u`edsc6H|J=4zZNf=RzkzP=z*t3u_cnwh)6At+L!Ugn6umG;%RyXcd!W1a zSUCIQw{jEu1g09IrwO>&qt7v-m@$4f8>$YkYW!8g6> zm$#k)-RP`qP>|`OAYNN&>i_fN!hfUxkDX#$678Cg@QlCoqX^NcpD`@V6@YyQ76tq$ z2UR=M-UpQjJk7<78xP=hs34b~F zLJnH%ENT$vzIhhsU*mf>dv}~=z(NVm&pR()s{OJG!xO&wLE;JG#xr3Nw#BLn6sd`S z1hvR4yh{tcMqbki;hg-~FFl_X+QtT!0}>9Y80gw=IDtM`%>ac?{b6YJZp|oe(F1ig zZcZNxl1yiO6tgP1GJ>zST;uUA#)K~ljA3a599jfp)(&f2V}dew&miD;QA_*w(@LCP zK_{UbEw8cHGup45f;js<-&}VjR?*=O;X%LT=g`cH=st<>Tt**mOGnJYyalhY@hkCZ5Vng;RJaF+aBCs4Do~J_&hbTl zJ(Te5?!9lzh}U!i^1`P}37O<$R`$sB?7{o_ncty3VfS!v`}S7n9FZ?xOVq1TQP4h| z`iHe8+?D&%|1W|z!Pb@-phS1G=N<{(R3ofL?tq%fE{wmgFA2RDTW0H zIjG4Ife?zbj+8W(zGvcB$6kx4==>HxgG;|aD#46k;}qH~c7yssvYE5om=WOgF!UNu zVh~rm>4s0ky^+K!5Mj;iJ}L*x*fDCWIL=K$Pia%ec9@~c15o)Kj1xcy#PMe9eXi{QxTRtB)hQ{5ef1MuJ&n5rdozlwEOAlA6Umt!(nF&|FVigQ#jbWyJTv-I#`GMJb0{0567BJY#SLL zMd_^FNDnob_QisTx9JFs%z)bR2pxcaRKB3p#_OgC@-4zLY;;HEJPjV2BvC#jnF0@; z^kEhwDqIzsaP&K;S3L+T>~IY8pdGwGlDQo&Z=A{mffbUG8Jv{26|}&%sW#Y`Rl7B6 z5MiYB{8w(xeVp7r_s_99BDlAOMXsvJk7ERA;_#(=#<**iJQ2lazMziGm4z6LlUc}o zOxi^eLn7Uae*T-!;5nNP{95?J;u$veCOF@bM=g$LYIz*))A*9<-ge}cC+QkBe}&5~w6Vu-90V_RQ>?U?Wa9%ODxafV@bwZWN!0n?Svwzd78c;*j2eW@;^~ z8o_OnAuyU_M7Ftw%sMyy^1LroW~Vf0QFWxtJP;A@!nbZPL}J|-o=cReEMq}AvV;{m zV44PD7)p*l93N(dtQDRfe~L_$tis)qZsf+*DD(D2_(79vMP;%P za=Ynb}NxL&E*WlI?GtG9K z(Xdrw{hqiNZ7F1Xm)-s>If9&LtSL>PXP!2?^-KZ^&fOkdPjyzyVPDV3@ty0uiBIj- z(OV{8Nxbd{76qu+ixgT?8lIk(VAUsOxr?fRCVQCB%$6rr^BJeJgXRD&GC}bV%{{VEA1;%@4(Hn zCwf@}Wt9$4m#wrYm=P%5|B$Mkk^$+EpiCxGeU3Tm4O!s`2ZRq$As4-wVUuuCwHJ>D z3Vo#cs*u{s8{T#yZK89>2C4b6Fr)-GVP4lL#?J2VpHMf$Ut{Dfe%*rbBGYE!mdz^l z^dBo^mH<^Y%s{N=*EujVG{6t)iZEEAKJA^eFxHo*dy)@$9D=yz1J|s-KLv6B20{4w zE@ZSe0n`L3N~M`W*W)-^i+7V4Y!kJ}`mskUY{Bx4(u!cBs39JEWs5*YGT+W!I82f( z_!ktTWkT;t7b5(SLKgLg>5fyT?wl%cg`Qmx2_d7=(=YmG)}xzdlr6keCU)4B<<0oM zW$K5?nC=gYnpQ2L0Emi4reKEgFqq2*d=mR$`iA#7DC!w^AzB9!O>-40j2QcpLZ!UV zU&)l@$la4c&xWA7cYfV@CsR<&6bF6!6%y3ZxC~|5KgoU4*nkBxC-jPR@(eFAO6gJy z>mrM@-e*|Szaj;cp@^E$NIaGys`QCn`+&f<)kDitT!$mBnu*Bt#9u*=Dpob*lX zG>oN72=L~eu0zpq!Wd4Ht13bXKKCI2b!svg7BP5!B0wP}C9|Ae%%|SvE&tAPU}s5# z9bGxkc0>&{$76P5!3A&J5N;i_z=;QV#S7y4YM)fC6#*MoLF8ij<_fRfFbAvt%IZJ( z!vsqe1P^?s7JJ!RVSJ#0rQI=1Y2_#W;`8TGg7<5X;F}~tayFasasf-%^hS2hWup!` znt#6LX#8 zx#VLHf6OGFqiH_zLO;S~-s03KzITgPwammafha!6ODFCcVz;oQg~+Hu%n_U`wPJV) zU{$u}uN;5$5!^P=2zLEgmU(#77vdZH4x{iE6>+$^HX|0`imjtPd~MCpr+mzlRM7}q ztZV~S>>kNFL$M{Lm4S`v4B#zRVY~(UWK8C`s(q*`HZLkv= zU({e8F*TpLZx=6?Nn`RF3Y#-9*`PE~COH;o)5z8Z@_SDyd}ZNN;=xcB){I<47yK z^0&BkLy{}`J}cJ2EW%hmmY%F@Lgqmhqh`kNqUDK6dnMUE(6eM|qo!qU92uBwTXfON zTn6+)N!H)>!Qc1^QEi)%Lwsg28i8g4Ayrz{8W z9%Lpj^8#c-Osd< zY8=j`KLcO3rgwm6q;M;9!P{Xdl|NX1pr)ymHG1nN>_oh%yA*6gaf#3wRKc8X!Wawx z{CM#f4&Pm^4Gm|?E%f7D4*%+3jnywl+5^v*fC`U}hwLA$x6bxBE4&JFM{vc>#G~dZ z3Meh1d5xb?X!G-xUU6n2y^?(k)r`~(|6w0e!(z07MwEWey~h6$58Jr?`D3yRi_$;> zO_Tw-zwKy6Kao4YF+k079_)5&V`5?c-YJJ@FWuK^viMp?ezYjk7abs|pAi0~BJnD6+adWa6Sq8gftU#pP zhRtWeyHGkIk}Kc8{G2s(3nw**dq{P-b7-t+3p3rCMdr;laR2RtA8SOd> z13klF*mr~)T}bQH;V1m*O?c$Svf~&27Zm8N`0n*lX7x-rmkIGzf-v6RN+<9OeyEEb zqyQO`V$|w548pt*ql}g1q&`B+M7yL=`sxhGhS4$WX;?HB*Q7!LJt4R5FYo=fYbdv- zaa;d7?^<>-zS(me+tx;TBnd#n!@oUQHuu}N^+#>-CYn%_95%()2l=DAtXHT4F;;!t zl6IYiU@p1qvtGxh*v`=n=J#*&E|}-xo43I4z;(JB1kr41U^p4%+8j-xi37&>*X=`b zOZm+5MbwGVk*`!`?O&S}(*?#RypBBi@!4EfU>cIR_G+w@$S zl}Qkb7zFYf&pfxiO#r$Qw}QJK1D8jEu!T;uK&@Zbc2vaB1*_s?OAYO+G!}WY1WQS_ z9aNDUA5<7h-BW4@+OLGf)buhc|3Qi3PG<2a1}N=}p5Tzy`6u4aN31x?#0+d>eb?GrqTs@BGHTAo)r5pO0*8=u2cqI z%R2!K2{SkLS#A`h*&Q1}tojrSzkd3auiH#DY3hLfs?26S7Jexg&NglZD=-QGEBuEb zTHnTKUzEIyJ5~AIFcj~c%bePJ8x*BH^mx(-t-+V-Gs^4}8l`(AdxQ|qG5@srO&`RA zHue*JL&9O9@vMC~e0`+5acVY440EH(oc(%u8ozE4$lrrIjdBX)iUujRvqa-8dWvB6 z$o(n+N=DN9$`HuH>Z}yPy#oaU>iE~J-dg0s41K3sBz^Zm`A1k6@f3+1=uUa25}FKo zWne$%nWHB@9ZTpm4MzD+rBFE0adLaFyKaBK%bC;fhjG;IWDBWXfNxyq=LTcUvb|wr zbCvfL-vU(;FoLTv-()c+GsrlVB(^!A&gcY0f&+D&SOq2El(B`OHQirae%@y(fp6hw z(3kvIi9{$DVhaj4tWBQV8!tQa2?TM0*RW?z*A77v@B8Etvm*y)J5R>#aK79e;TM-8g20m0OKs+2ynr~M||!ItXOW(4n8S~zfJG7bQVznZ{GfHg?vvx^;mc{ zsYgvc1{YP5Z*P}ZWX5yg#Hr|VDPEd<9X>2Gg+0%FQ;%@H!y(0k(mO)ZV+wuxVL2`3 znpaAA?6zB0^#m4Do-VS^^}$24u@ITB8Bf*FV<+R57@VCMRb?OIufC-6Q4yOe;UNjx zfPxSm4`Np&oa0hFqqaifE;;2lx7gVT4F{ht^0N`{fCX*=gvpGGff)}lJ~BIs1ath5 z#>HH7wWLL$yCzQ0gC3#Q2{41FG+`N-P#nbyRCP9=EZZ_vhGanIwK)owi$rkE&b{aMr^NIEs7+`uLD+c%J zsE0yh{KFe15%M}i9+2#b1wYJn2hGh_T9VG9K6E|XFgQMWYik~|TAZvaDpZN215-J{ z!_U7cH1KK~Ob@488?Gv3_UEm)IVqL zdlP7mIyb6kgvHbhG(+*%hX89rF~|UKuFmAa8CKzyEvb&&8Nrrr32Z`{dDl-Hl)#*d zk{_k)P|77DBFjafZ_YplDL$BC0OTt7Y5-6eHx$yju@f194=fn6JjP5?Xn%?Js zxF`7^?jnO(iH~wbD}E)ir9iMm`8@0?lfeoKn&i?d{PkXU-B(WjI6k%0P?cZggOU&X z>wTL^#Evg55UQ@wnFnAdBH%qz&Zs{FafkR+=$7=XCDTgiI4KqZAQEA9OnR6zm($OJR%%euV#BVO+Afuod;Y z)K)?ji`qdscl@UFp7*zQ21UdCmPHSgaPE$Egm5C8>wzcOd0S=HYAc#sp?-PV|1ReyM7#56%e3YsZC84Gpy7Ywgew4#O#)|=Zz1V zVKtzslD^1?gpzeaCdfm1IL~fmd?L%pi*bqLTWsqZPLsgAi$iE{35UsoA<%VQAB&oR znp-LyP%;3TndA|BIil-EQ=T6dpD6uvc;-xQz3(6aMwlNS|M{MeX8FW;x}Uts1Cga)DJU* z1%z#ZQZb7_U8K*i#`P4+=-sb-BF9fPZI)m3@Zu$wjQ4hrbXSbco{QrhFgv;S5_ol( z=z(({{8|ey!7y#9n30CTD8QXnx}0Fk`V2&cV4pKf=7kY+w#9-E7OjLOSR?D$2e~Pl z+FS@^W&85_PN_9A4bIrINywNyUuoW`oDx$kkCX|_IyZd%PCTu)X=B8qN6fn(`VlQ=&meoSlu~lhh5i^3fK1IRUsqUrKtg8H5qzUW-5ip>S3p>2} zvcJAJGmWP1o<)z8pvb^T<=~Vt8ZfgPMs4XE_LcKO3uU_u_XeTp`eN1;fhh>>+S6(y z?J9%+A*v+&s|6;bN6b_Dj6)g_n-ITu!^x^aoE=~zxIli&=Up#eyq1czy1`F9TJj+T zTtb!>eO1#lNqjSA$DV80{dR1&Zxgky!|my?lS@mW?mpG|{zNIIp~Ima$9$|cLL#BP zM5f6!l=(?Vv9}{IAYh*L*0{s3#L5yUU3eGDFo~TcW8i_{!^GOK6{jxP>J$Qed^e5q z$_KApw;Zc#DlIMgllhe8UVLeQ7A3%yC(nF|T>#`+z?z3^MvIY{J~+XWMOFV<6~`+y z6feio&&pr_^SOleom=rUm1`k0KaB?9 zL)woW0B91Q0&-5=Tje>K!VSqT=HJvjQ^uiN`(ck7+y) zYcQV2&;Po)D>nn&#pZ50nF z>NC^j%I#3#eGtH*Wq6xgUvSMyOYqQ5!)+IxDuJ0dhN56@2hPl%-ku=Yys<9u$aM^P z`G3#S4-Fy5vH`X#pmI=WB+IgqK0sxZCPAZESyK@xU}92ePQiIlS{}2Ds>lX<$z)lj z8f@H5oZ!ZD%5`tO>X(#BQ-x({9%Vv?7t<^Bkno1qhg@ywNvMa1hCX<&KVPw4b8OWn zNgT|A2$E8iW4RLJbm(hY_Adw41^vw=K7A}%7I^c1m?XDT?N1^jlhbi-c-!i;Xnjqa zuoo?}@b5o4u4tHe?PD zplQqJ(LOm%c!i?8y>(a;9CBSi(vFhHkf5YYV`h%GXj%DYK$w{V3CqRurQE;Uo zESi!DLal58<~sG#0<`+s8D(?V%GrPX<#S#~!TlG022IrGz_Sjz1h6}4G=|7saJZQJ zvtxYj(58)qLz}_9%e+I;Vt8%@1a2H?hs++doY+-Z1>2mELnW|0hw#Wg+$q+*T^akcbhAsmL1TDZ-Z_|b0?Yz(e7|^JkRIfX#>e5-*i(n6f z4^WNz3gDGXz$`&9{wBuf)_(+n$aSGX$+~nz&qM=Ix!_S~Fd_MR*y>ad_ASIE$OMA%*?O(|FliZQN+Q?)%~T zwsIXWT-RH?^5@|r0Q$X!gT0zsNVu&+qX+K-KLFHMT2p249D$DlViFD&90`2^q_!Ly zd&ur?x9C zWbtO)TrqsYWnNp4HaWrtzHa~vFF`3=4Ac}a9?%Q+5g?`Fkl{suP2ff-?2#&*WB=PQzA}MZF@fWj*W$m;xF?7FnhX1)Vj9={lp(fIe|91zgv(h{JU zVRgA^ftjj`b+P!B6Py42@3{CTq&}j>Q(u<#Fq^rtGoB_ig7ad=Fp**$vtv8i^D84^!F#vC!N-80pg44D!Vz}%0H7sXdVcl&qu%nXf*H-SuM_{@XWc55~eP!|3J3l@_Ao$hx&L{sFPCs;BgUW!MRbEWLehYL8AQ1i`8L zpE6dpJSM6%wxD_shL6%_!}WzUj{NwYcRT`*)j6&~8s`*gEZ@E#)H=t0O=G7^fNP6` zc7!9eyak&(jVS6euGy2x~R zCNYE;BUr5~9(Q|9fFBleyzY(Hp0Jv7{15yL`mAS2(O6Js%Qa3;<#guIGNO;2`1SA} z`*jNml40CZ3OK%gwY(&nS`Rj44-bx-MF>?zA{=juJaD+QCnBMMNZky$^183gjN?li z8_Rtt|6yO{8}NNgZPR*D1%pfj*%IC_LiW0xuotib< z1OF(5Z&AgAs|*L$y#1Dcr;wUxs^>@*NMWv=!rbIg0tPLc7QlYE$==v>tEPfc-0c8Q zoT@;JI}a3*)WH|EOE{OD=+92;I*2rasNjidyveRQe&uR3UA*dj^_bbjg12r7H4r- z`^)F>eVc7agn_Z3sRXKd%-d3*-DRatZr!m?W4RZqkaZcsz-$wuqZjE_!fU1_foRa9 z&+c*h%vkruPd@6eufbzbe6V(Qfpt$)ZH#IFV?r>1Hg#2* z0)-z?peh%ucp3>-ZA&4FvMneiv3|+ISmkxGRiq=_>t<9NRxEdYND)Hh@DCG}foF;To9pC}DG&!~# z`*3&R6ggH1PTY@n%ibZ)XNmmumH3e5=ov2fqECoG2?REEEkokzFD8n|sdc9EMrzFW z`R`-12tbZTprGYz(@mQbG7deo?7AO3_PM0TI}dEIx0lM^SYA3En^i_Qt_2<1z0fr) zs__D6weUg<2mM-n=n|c!sD2_(l&WerL^CssbOt*joMJ~u+a|Kl^rM_&)^{jL*k;;m zpR|jiMaUy5VB{c}33??{LQ;hRZi-jB>XDB*o{H2oSYwe7wC99?(|hNj7jWf+z+`0D zCIFtDni$?c-kZT`JEOfet$?*}D$piIJR^ZJNq8NxO864D`2I^eY$Eyx%_6ihNnVDO z%!C?3tFS+oG!KkBJ8iH3moNY8I!ddlr^IKqn=cyKu>)f@Sir$KUfF9)+_y`YSi9k+ z7Iwzk*d|11> zP*W3m`S==2i^BB87k~?I&68I5<14RtbI)dTG$l=cTR`OLJ=Ax)E6MzWSIWJ1COck2 zLDw&}kliq3r=3-X1>K)$ha^X-z&0YV72Kbj9}GmA%tv%8gz2XsPcS*Y%FCbmg^yYh z^C1mh_zJDk>}dphao1p;*wkb)5G+~mLVU!Sw5geiLpskW?1`nUGx~P?*jrNZgs4B= z2ul)^Bdn>2RmXrai#GlFRbT%{0A-M8wI}$DI6xx4a9BX*vR8k&muF>?(7uq{lb}nvKGXanjW>hiuVb z#SVhLw>}7LRD6h9O#0tAUeF+b&aSopIgr!cC$Einw0jV`{1``aOg4Vwdp;20dCv?F0Q2JnLkn!;CC%>(|QUU zy50`j@X!n+g@YoWWuJjuMOf3iYLSwT#ZK>ns&J>x4JyBpX@?w6dCNEd%%-a~5yd{T zoYRs|McC$9MA7OuMDxy)@9pTu$$OMx5uM${Ou%v2tR znoPL%gRF`(6O7I%ZYuaA58fx7^rH)yB6S+3JuSLg%eEBiu#B<^#dsFJFv1DU08gjx z92htH9oUPxBAqmrMz|JHR?~C)lB>+Kit=;vtLNGRcM-aU11uSL3EXt|9p`hSeCK!g z8GP~ANCHRU(&;>&awXA8c5RG7 zq75e@q{hJpBFL#iXS;sv8pK-NZWSq~6D`Tk_;SPSgC2hxm*2FbwVIQSSw?6C=&r#z z69YN4T^OFQ3oXR(Qha9=A{8VM0l9GFVQvY|DUTG@1_=BH2oA|qN!_TKG zudx>$4oJCpQeLKnM!fLCunx*=lMucH-?=Ofg^cGS4;Awv+}S6>1>k@T0Ru}+1v3)v zMg3UWT`!|DCJ&e<`?{*{$^SHV&$8vznRh+qzTcosuEo!wANh=A!ZhfK2p`jPh_X{N z$we^@+O6LY&*1kh%;*WYl}mIxso$IBeU|fjAD_(3F+Z%WkGwwR3tMk|96qdRpzos3 z>iJ2wSvSJ$Xm{x-l2z=U4R?57T(for4C}(|YrEEB9dF0&L1deU((VsWwnXEkwYpDt zgGuUsvmf5-rQz7)Sx^T8jdy7QyH*_IV5?E32(TcI>dApl8It3@U$}ACu{`v!b3Fdv z;CsKmdha9SGvG%yO^lTuB75)l`_^>Q75GM0X`<#OHfexW^o{PN<3hXRCB9n46QP1> zw2iR?yC|wWMUEpwHgg2MB+Gv@SB83pgpT|_m;BWFtRCDTAs-dZ8vGN-CO{C4&vj43 zp~C4dgg|v=cqgy4&?@=WYWR1GOI-^UWk9+f!K0K>nCA7+ZKp9p0uWT7Tzc(xLv^ce zj|!u(A4EEZ$W@f6=)WvTq;=u#C*+{gMJ$qgjt6p@?@FC#Xn1ZBTr)!yTYkUH{eY|pGH z0~?%oP%jjGI$v)8wd}!mHYu$SWjpn+UUl;wAiYLB^Y!A!=0k)p#@DJdw$iI~THXX) z38Yl)5aV-o2>IC|MM$H`6A0oZgr$|$q7$x*X)Y$35XyCLIribNz{53moZl#+&;nQU z>^97`!k`D}eRy_SAWwC}&@aEz!U72shMYsFJH_%Pm!2gLwp36Ti)vYW zqXMudWKyG{%{p;ouQNO#e{A<{=#iC>=-hM zjce)nvPwee94kI$^+$hk0lvS}R7vxpzvg(bHNYyTi1ag~W64f3_;cI9Fr9{9YoR2U z;r69s^})0SEuB>_c;dRr$0&IhkO5fV(gv1_rJ{l!xJ@_aJXmIgkcU?VQ?l3I$M|L+ zY1$!YOXz5-kka*^`?s4PLMb)X_rF*9midtqU(m8>|F*m)iWJVKSOS!2Xvhf5%8NTh zr1)SBpfFM#u}~4DL4G?MW%7huW;zm*=-g)U!~TPkxIN5d&_cd1Nsu;xg^YDqVDH{; z9Qzplgi*?rWrtsAp($hz)>>N&BLZrOLNuu=pg}kW1U#Z*1H(k^B$-Wx)FL8Vlp1mx zC4PyN!CZ{`ja(G|;U2A5zV;qpejuKwaevbfB?MBlYrtg;cnRJ%J%uqy!@ZeNuxcmn zoF2pcrrFU}9^-}h6lOzKKePuoG6jfC*)0~2IK#Jz@8McRc}*(wKMtN)lk+yk=x4_@~W#r?IIgJPGrs3I2W<)jj;ag|7TP zZXL2}H(B+9xcZ%g?Of%KPWB&wO|o6kERtz)K(u_R)+kGY##wv$Rc#t@*UZcUPFKZe zY`pg9t*ipEd3tBAwq3San7`yhciYNW*f>V|H}fX9591q`(YK}us?v*j zOrbCaS)=Z(NCdwmN9`arD~91p>M4iryp>PNnbD(hd<`Tt4sS|QV||sJWlEO+5gnmc zWw4i2!2pEQ#cLh6fN$| zqj0!uY=hI5N$XkJv~sd_OeZx8?`6GOorZ-|E<1)Q!Y3S8 z2Kno%l_aYEShuPh-+jb|hKe{sYaseB zKC+SzSm7Q>jAgwX1;rkR7(KTgN3$NfMX_Ug0|246fxruRQC@^a#ZUFcc*~j8>>R8X zTl45H0CyeixX024X4fl#BoGj!f&v#H(~6Lg(t+ozPbxtZn`#-A9*0t0@{{Mk{tj3} zQJjZ%FJ!4X z^N8qhJ2D}&L|%#xL?9cj+?|*S&*K_c1cO6%q#sN){?IU}I3uA0$Jc_9-F57`vA?w# zfRxZ|xT@Y*vz#m3_0z{bV?A`ODJxs-=PBHSvYQ548A7de5+#Yflcmq9i;EMuIE)%M zE)GxfVhiPaCho^0Ph}NPjjbi%_`0iUn8Mz+JJTbTJ1A%Bffbfn0#gQL0k9``fh5M6 zL$wWtBp&_!->@p#d31y6-9uV5uafvXeD`MWwIXB&P^u|I03bGJz-+wUTcUp?5^^+^ zTk*b|o~caDxGwWX5$k!y*b@wPBs_yT8-)uA18l0%THHv)2I`JYM+@WI^Q!w_^i_)O z4;#eh$4M9hox%xgDBKJ(_!IW~)(rlY_{L3~lcr4u5%J4gh7`)qrl1icgX?cztGkVv z6w`pJ%wOiHRMtHp8v)_Q;_M2IcyO>v5>}fV=>E$}(6#%K5@d-~ z@Iwa1u9|9e1z951{CYG0jo}sSj#!>h8GgsxT%}^QSB*^^lkq1anzelyJrofhf@zX= z5u=Nq56w7#`%jCEu6~bxOubHv+zv0 zXRA*ojKJ%zr`KY0W0k}^Y^+bGVdlYhk#Oh~0YG%z%-76tHjo7aWn>vNhFBQ=hNLNl zbm``Io=PD#v=%M)^Ahff%Q!z8MGKfecA+9-VOLZL%Jc%4hG)k}iJ*_T6*eMbETlzM zstO-jS%Ohy7PjSrRkC1EgE6r6K$;R181bW!7E_LVA2=Dv9kmJ(6l|a;CeO$f;jcnK zH!V2+1a?<63aBeBB3ZT$UJSA6U_N=fg(b{S-PtC;zno%$e~I^I@d%c!=ma0!3kV3G zVmUhDw)s(zAtoqK@xj1b8v--s(&l(lw58QbQWd={faCir!z?oy45)>Gu73P8zWXvf zZPS^{i;tgIGuw)9HTZ)EwP}xq7P84t>dGHt%J0nrFhRCk(fF)hXaJ|^gP9RrU+rc+ zJda-c>C@i8WiD%oGxwV}J>b?T!PTlNl?@URegJye9kSl~5X~Eu;7q6+yy_AV{60ik z0Iq)fCat5E#sL%57ny_Ox8h7nf`xz$TS>pf;|#^Rd*Md<8me;ROJB0tPNZl!%xAHm zNI_d#-ZegP-*O>J-Ck6(;?H;`4VJ1mmqtNR#3?>UrzY3w;f z0oa1F16}GC7VbStkT1KFL5c{qXctCUT2^pSIabe@^|*&b_Pk`|!!}Uu?hRUXLeZ+j zE|C{OBCD+bGQy~sAM3xZAGE)EQ_HV{$fkcJ^py~JlS-j1xc6E9*Kz{=xeE^NiA{rU zX6wIv)6*Y@XKUK>zxcuPC=hNc+LB4Q;HEun#9Yp552kMfD7BmmkPHOfF7gCs6D8`0 zd_x-68V7LeF$mU*;O<~ZVJ&o~@S6RdA^Zg4^Xe6VvSVZnIUafJr+@eu%JC-r45Gb< z6t67B+TDHPBnNy)Oegq}t?eG(ZC6?t+cw;+{0BfZS^$)m`zufXl{}6e1%sAhZ-gGe z$DVqdi>K#C9Vpg$!_wCsiSNVzH5iZ|@-iwqZ< z3GD@PPXUSzdw@JV@Ia4v78<&cxxH}=;jPAptRBYt&wTrDZoZVuzg@%n{Y(>r-1WV^ z0B@UM-edbpo4npLuAl^=D=pqLGv^`8?COV07*cyxd;4HixPJon9=e}~gETPAOwhLM zwKH7LoJOvNRDST!DTC3wyoaX^HSM@ve6n~0<4-5!CpB0ys&Bn4}pG2%$U4jIq|8W znzTE;z{Hf%Z_j-7WAT`s2Q|p(v62z#%k^`x$A|zd&app!$8c{PJE7a8E^o!He9HwT zmZwIsZflxqNWywt*%o`JiE zqUc;vr5Qg<7F^b9@Wdhrq@Bw&1j}h}3_D@@-~Z-iwwINg1qRpVv*o#w3j2Sz_8$gP zFKeQ=efvl&RUoJ;t~|)nL|OKzwu-QZ3DQdW_@VAwvT^#VO*Sr)PlOZ~$e;EOB6eh1J`winx-1mamb#@@<6H z+_Yfj1svPj$VgXn;t%_Bx#zE_O&=z*m1?65@>Pv!upI%mfes6;ltK*=sF?ZTl;JI^ z0F4MMeigAAF*{6-L}VnNm5Ah#I6Lhiz1EnKcO%@B>T#!8nw>xU6#2TA&t86OdcJ|#rck*#qOlNt6+}28Ngz_7wwoi}k?k+`o zG}703gdz09IH9J8Sr@G+$dBMdH}Fj&ZdkF4Ay@jvP{tQA-B-!62EOjysDgFk z7WMrBiwu?}GM)(KLVi%iwD!mbMe^gxxH*0gHf&+8Lddn`&!?Vw%lB+UL&Mna#Tz6< zmP0m9aYx*esd4nLg@-yGzmE#8oqCBvce^(9i}49(*nzOBh>6@Ud9#!aEjOIsYu$ZQ zo-MhdIUo#|3|JEok;!e9I299x4T{ApzjA+P#IU>WV=n*xsegv2>)f_Mxi(5Jx5MR) zQ@MA65NKou$2M#QgS)NOcmwVt-ee~UM0k!jRgKA6mJTf4ah)>-gNHl3&r2KSOoqP6 z&d9fPYhLB9rUjB~N=o3uSKR3Z%#u5gY!Jbwd9<&0;5%1nOK6C}f_|od_Ku;~)&2{^ zx1d>aapK+(=QDTqF0AMl2}{z;XSEXjUo;l@X;Pb!TU)usglG?;ph)7<>2t%E;gd#x z^`*1^3Xk7(eB9#Ahg)qfz!z=e8KKs(SW2Xc?K};_;;^tPoXc;Qyt59O_+u0}lz*n< zkRdv2?y01bbhnoyZ#wT2My%YeL0Qfy%Cf09!Euq@%{}b>2}g1q)}e71(>?4mn>%qo zUP7A`f>ZxREktmQ^q)qhvD#9IaIeB{D2iBDV34u!qvVT7Wm~A0$N=>E=QkO-n?kO2 zH1y!?vw#1bC*q-+#xN~@ip0Ubp-rfcjbfhQ{xZX!eK9lqHD(Fo*DX-rOK_*Alm&bx z!5Iq4h#Rk6*-dLC)o;BBvE zMsUdE!ec*j-zPycn#O`Ge(F5QgGk3IH+32WhOu&vkjB89O{-SCE~Kr|v|th|iVYg# z`@8J(N;ruRfwW@dGD&MF8{dWT`QfA0vM}%vd`sxmDn-{Dk9z3mnHn{9e=hbh$ke9I zy*c)3u0&ZgOpDqyYrh`Gx#4YguCtP~afCCaxJv{7Q+eAEWM73E@~{qJ+>l_T4p7p& zNJc`H3`5!fgI7nz#WriGJE?M5eJ?`TF$QDB2l~56m!(ZK?w-~^`$b>kjE~O48{E@` z^zZJtym=Jc{=sZ_HzC+em&q75oymqlprdck^c+S>w>aGU&G=-6_rlBMuCMSh;_`uj z5~Z=fWqsB73W`EXn?X*o9UcqLsA@1x8OUwpt!(fKeo<|s(Hqpz##@nRuyBmdjNJA9 zuQ}pGO6;fj8O&X0i$jOR5H2tYcy8BJI&?yz-uMo5sbN||I|^V1w^n6G=pMnf4md14 zc=%lA6l>&+LXMVjqy)hKf&j6W(SXeG-mJGoe;S=wEV}#7-3K_hsA)69;`8QPOi2K^g6H6gJ8TCTR1hB$%}N3kWO@V*)hnmQG5Ra~5-SO43*nVv z%nQJk7J=^lxOo-2Ta1^fb1Dl+p$HKKm9PgM9CGxMmN-y5GHeO1NB}6MQdl%PM1BVT zCW^M|wX#+jp#tp&uwPVy_o}+f@91mp^Y%Z%LOM*p2Ic4DrzJm(B%0|i*}H8wpi#g4 zcx8C2uC$OJU)$!`KA-rYb_fVojQG(az_(va&e}sL0OYj}Ci>2#j|^1Uiuf3w3!k8W z8)-(g5Jq>^NAC2g-=op}06&9*IA2CLPlDjg@#V-9r6SRkSJH7-5EY^;jx~W__6IK~ zLNwGEOV7V?C5*M+`lLsF=`Zl5P4fd5Ur?|0up14FPHVHg8p9(a3yQMC7~VOP1=$wJ z_llKQFHr%M&L`S7nM5|a-F$4-oP|^a^Xd(0vhB*+h6hr3H;Wt2dHSa=qJ$dG%UJ9K z$LB9nv*FQPaN){F)XSkz>U9*>C6m1B-xWphXIu2rgBNwux&wiSYM^h#TR}>E6T?aq zEX6N*5@w!T(f*1SbUTMq-rR+E{RIowoRNd1+TFuUEg(yNF*r;h!{HJi@3$llOyIReZz5=&z z34x$+#zS;eYqn&Jn3Nh4lg#>3iL7lBn3im!pQaF^4mu~ctC*k=qnV>?w@2cc;MSDU zlEHVgx%e}e-1QxJ+@@WLi(e$Kd$RD^G0lCz$G~aZFq(cC`Wyi1T^$eA7Z>|Ny&ZYfTdi)y23d_ zM-B3Lhn_|0WaXuOHY=$jtFAYyyI=s=N4GH#nq{){_@{an)B>-u1`$%FZ7&Kr|oCPGqtLo)~%eigBDX zH@P$HhY)w4UBN-VcBKVGdkJnH${f**r<8Q7g47@(VbByt6Tnqla>UDc!1b3In=8rc z3>6S4kfunbtUu0x2&tUB@re6=3y;^x3;Q5;mJD1f=ol+y7bb=-6ZDH=^U|U3`g#{X z64|jg3)U_YuaguE(5m)}Qkl(6k};P1g>DnQr&yf;kBDtjHovUER0t0X@fns3+{kp& zLPFm47M{w(T>JCi{pxgL+-`#=y-b!e4>Ef-zHzB)Qr;q_{;SvsU_5uO0Zxa>pYKkN zBnMHbPzz3j2``7gqGPfo(@6M2a+!-~Ux#ft6Cg0Etojr8z*j!(*r$!+VVe#LUi{ZZ zK4*a#9V8p*h<9=~-0*(P7U;EVIAGyr1G`}|;zZU+-B%FDV#g-RHlqPu$P;=9gTcgj zqMTU3J_gP_Lm^63TUjrK&=M>5XNFf^ee=l|QW!k?Y|yP zM!*}-V1r;Ag6ieCb&bzeM94;^P()KcAmT7yy%BGjI6DdncVgkmfPFTh1a|>cQ>ril z3B28=6d^*+2?xXBTzmf$Px&sMuydydc~mp}&%z-XliPdUb^FUWBMN0szaPelRBf6l zo{w9Xno0B>-XNZ?1Y3>xs39SvVUWyayPzR<0 zR0Ek9pm9&0rbosbnzBuY0)}^?T{(xK&&ES2gvW>B5Aa-MBcd-hG-v&PE_&N-@$4P; z%nw?Uk6^z$E+6JSY#$ku*xrGUUcnv#(*JDe&*~JGV4Xw7v-Xu6OVS-Mxyrg#*!Lo@ zSGB5i0~#xjYpgFU*>(~nBTv1`oeb5dy1Ng_-FVs$?`Egcd>d;Rl-wKTgD5%dUmBa5 zL~klHt?GDs66SkG@CzhZm0vzOoPA1SYf;g^fw zES+G-d&oQEK+}RB-5(3GxK7w&F%1{orVEFi{D)&G#_UkLUfn7hQ`pOTG$KY9Ocfe{8(p}bn z0{4r)Xa2B6qxUngRJ9Oxga{PLrN%2i++jkQIIW&RR4Ys^^+TaL@u`ra`AXlh|nTQd{EHO{*19}3wbK#IMs=Zt+OE<+tFYTb#mTFZb zorZ~ZpYWZ_&!7f$h8n`_=d|v_+MgK`_z=DmkRIsyUU>COU3Rs7`vv+r9 zcN#OZ>@GI2Bv?=^u_l6I!3yYC1uJ$m8d0N?*wFY@G@{rsYWzOWdCocS_r3f1y)rky zo%}JB`OGb!^Eu@?&nfSMf&unJ(0HBrU?CJSX+KpwAO61iq=VP~vN#n@*RUCmiCyWxFt=%Q;{pyy3$5sE zw@Hy_b0WNv!_siHeSI!OrYPTg;W>`jG=`$cGPG%Q{HlA}(FHf+uKKO$TM`CG5>B1k ziG%Gnb-OtTd|&()hj>`2bOr&gdklu;cF+gUM<$;;Trzno-UZR6e){nx&9Z_!^tl>V zPQ6t%^4b6>h5ZO>gmE_R^WdjH^qSA&vl^#wzFn+l3p5B-^|hVuj#9!Q6*7f374BpQ zk25bSG4@n{Wln|z6XYSiIfISjy(EaC z`2OO1mJz|oqBsx;uZS$fbp7qt>|IXh^0)@);@er72=mn04W#FR1cI0)C(xPLH$3gX zpGUa;++!sqx|YqPyLuY}4O=Bxun;Sf+4;zdx>YAyY?};FO2a|WVX7wJl0iE{F6$X} z3#YWIm=B@44~62**bo9hU(vd1dr0wJ`h*Kfrneea0N?v3(y~KvdD-N)8IY-Kl4Rn> zA&@NiC1|Dr1osZSZar_ots!iuoM~uQJdVq}1 z^_ZlB%H~*rgLKFT1r6Prtg1Q8kkXkiJ>_{%rjj)^$N#L@;<8B|64bZupSFmS8ZXRy zTTrMOTZoYxq6eVH*^mlaXVqIGHG6>mIuJeun!{z57%q@ zmdsUze;O_Xnt}L`XM5BG~?hUJnq0;}h8-M+Oo-4LF;vJ3fjX{qs9wJUlQ* z3Wqw(go-~gE}^387?PSPyg&E7@G&zL6y?K;BYLi zr9Vc`S@fIvAB5?XI|krtrS_ph}sr-e?5N2T?VF49jE}Wf#NA+t45~PpIr5 z>GgQE;!#PBOCC;iS-F8oF3lVO7}a?1sp-nPy}_}Rp&Px*hQpbXnI>5)b9yMFf$;Ra zQ9>bJTe?F^hwnT5h~H64f5uN=O0n3Nm(ukvUl1wn!8;qvrcmyDK0*`8HROqOz!hXR zPm`ruXTp=!=Kzp+Ja}bw_K3Fxwgt~-f zKr0M!7otWB6g(VbOD;YTf*I*fV^sI|NZpLDlpee$RH z=B>LmxT8Ck7)5dQ&crhTMXuHv!O_mZI&gZGx5+>C3Y0n}tEJtw0&d4mvAEMYqwuzHG!td zip6)8SfoV&uFO|wFohkNn6!u&hCx(tZ^Zny=yJ$oEwW1>Rd4BzY|$|pQYrcd%gw5E z9JEB#__LHPE2(pb_M*Yu|Zv4a7Eht``_<;4!(R7 z*jc=&a?UejSP_W!)9sv=E9ZzEiI?s`DH}>VhO?hWMj8F)SMLv9ItOp@cuU=j=hQ?T z90?ppm`Pi;M!+5D3wK!gihKjWVVSV1o&tH6t}5WzM~Sw7dc-m3QUndBL@%y(i!NU{ z5nPE+Prwslg08ZUlJI<$KEY#&fdUIF=A*&#u`+HK%}Lj$R`F(*gq3uGQtlC3T!Pas z!BXMCwJ}WYtRGMP=FOB|!x`+0eFrB^ZUsB6c=+HPNWd_;HZE{zn{H!xduI&gxOs7d zp*p0AR^U7Ojx9s~f-Vf~nQ29Jsj{g821J+C9Rjt?!lh?@hFH9(N3H(r*z{x2Q``yO zK16l!=l=L4Hn+66^rt_>R~rOZOrd^_`F7Y@K|%CR_$XW$2CU|2`~1DrXYg8jCoA(u z2OX@4lo-57y%+-4MFHYphMeKH^K1$8Y#cQ4+1{$79=7NM6>>^^Cf?5`$U`+1%_K+_ zUJ*~k8pq3{ifKL=boRIf%MyaT?zel-F)Dbx%qH2geQ)&++57&%5=#eoTt2F)Q0IhT;q4c((}c@U-4a2&+q2Q9Fa-i^<-gbFvc|MO?PmYuM!DbZb4V-(XT zm{es1J)(@)6uu*kvHZ$32yZe2C7;8mO{t5bzyk$KxbG0!wO{_HSL~(G8U`sBS8MiG zcEC|#0D)+52PP3plOx?L8q9&phDXK`>*v*L6*k36{W_agkv(PIA4c!#5u=#ZW2AL? zv(^d=Ac4@84kg(MIbR=pK{3bL(Rd=1&qwLK!j+?bO0vvWuw)yz{zSx^#Ae^ZWLe~Q z(w=pbRxx{ULyUijl#Y`w3nV}GaY<#kYsfolt6DKlmB%;8hC$SK(VXotnD%VGT?RfHr!l9!l>R*4zY3V(IeYO62*7+YRg+lIoy_L~}D2MTd z3Rw3Zu}LU^Dh))|8U%zMRehwQ;w!K%RyVo!TOR(FJF{!3#d(DO8}${K3-&C5vH? z2xu})@?iIm3@ajFBpJeup)yDBIqUbVO0)7;?6|22fi@q9pgJZvsmeDk!wvKuoF`MXl<6T*lFr?NQuke^{LsemvR_SA*(SAmbH0 zJ$xqe;4u*W!6*T6+G@xU-N6sN_P(2N8?FDuPk&5%f<(udhJ`;n(Bj5jZow=vrtQG5 zho|k=1NgP4;guq#$j4ej+G))LeVRShi5nZ*K(>AMNbfHCQc()X^#}*H+D;9X03(G{RCdBw4WUmV z8BBBPVnWDT6IG_gDl9mR&oXP^hiHC5AoZb_xFR|?fLg|pwA(Xx9eNB$wOZUi)o-`6 zk{I=EA?CFrnc0W;U*;pjPTlBsL7-*Dbt5+c85Iw)fKv?ldV>oG;PfCA6${A`VT)&&$6&HQtvFvJSIu&E_Zi#_G|I`i>xt=32sXROR>wyzlRxshPX*%hU@gJN| zq^=iYP)$2(3<4ztBxB(zy_z|k!0FcatnMmLbdv#aG*P7{oQ>*Pu@X*+q7OpcWpvq5 zCwz4hU%63L&XtTg43wi?$C4cZ1=5D9-6aoCOdb{E67Yp%X6`|+BVt}phje@xs? z?VK~#o$1vTM!KE$`+=3^Q+R1SNUz98Ai=X@)4UZqbo)p)O4^d%B5gvAK|)9&!|=TT zL%GnQ$~Y=6wJ;0@9FWWk1~CU;*==V z!asT;-$pD|(5TQ=A>mvjLllcz?|s7ED2f#g!R5lrtD+*_UOqNEIyD{s!n`VejaBme z^#I<2hO!|hj}#0lRxkSptM4yEs4%{G9LqjPk|%!lw#f;^nB;5J z7$vw8B!@_567_6LV_xrYBwUrJ_Mw-k#4o1>5QQf0K+k6+7#qa~EZLh=UX;9F-utVl>s`kj?_n0X4xXIG9*rNmq0}3dV zOU0ey9oFbrgTQt|z%p0^1ft!P9M|Y((T5-P3Zv;8&iq>Z3MtVMxRFzBzcT>NT3}L8 zOuKiChCTA6i=BQM4drop0J~%YyOJQ;r%=gW$UJ3DLaN0h1wZ3;eI%usj~1wdEE30h z_a+p924I6DbDf&NODAWl1*eF_FSKXXyN>?odWQ9;=GMReUy{)U`24B_Q_(g(kG2=G zL20T=jsXTQv_?{u6JWc^wk9x+r+X@BjUk-^I6T?E3J{LxR!f;HE$Dtvq8lTUSvq%Qsf!Dd7yIb(oNg1iyn!_w~ClVCZ;7KPLW zk>CvQpV*d}RT0*cciJVCM09BY!(w;XGCRbM+o6shcx)ycj(56<4)_2&jRc8Bu)gwyX^M^gJI6< zB-CfFTzXXL4anD|@~|SPXGcQ;U7zh2plepgZQ7g@q*iDkMkdG%+SRkz)MI~`R1$*I z-+l5IhVZpo-@#8mqJ5_%LGtvpE~=gT4djwM-Nh^alabsf;Ki%$nb*P5+kA}8wAzYS zr;L!mohp9IuNXTMYwr+itT=&ymWSS-xMI&n8>eYl>$137>v9@9u`zw#aMYhIQU%E} z|D*oGB|MGy2N>32rw0VD)~0mk$qlbVL{Wm6dw-w>*0x@IIPqBsKS&p==^Dr&@Ghy& z`0v#8)=w^FmAi3N=KaOQ7eoSVj#A!2Y?=0JBM>3et6e?Conu7-(ct;((NB`aK#ZcgM|LAn4R%^p*;a!v_|k= z@uv@43s>c=5gJClXH+Ze?8zfUFjbD&7z)Gi5@98V7fTSazw-Bv;v0Dz2{I9f2$$fL zzV(KqSl4KAU0uIN_-OG6Yq-S#t5488HQQTG;eLbRnYc1QNH`y#x{*|O)qSrh7N{yA zl#NLtUa}jBJxMjt2*s)!vJKhG%*@N$&}bIZLV~3??Uv5>kH04sr(p~8;%g)Yj+m|C zKCJQmcV;mg?(W`!j)h_P=E1Vzx8Sv8%T#W(OoC>h?8GaGwP*0o#m$!G`<9ZeE*GPu zQ5#|D+yY7NP{lhG_>lEpl6X9(+KK`kdrrsY8b@d5<%2M?^IpI9|5)j<;cWZGpDISS z7K8C^?47GhkN3r`&P?sVwzB{etuW$4^pQ)5*YG$mx ze7rM>ZoJviv1Abz=Rj@?Q9a&;h{4sUI-7=Lko8IOyvsNo-pPIqAdwvrlyZ(L8K80ysW99#|5*b-q ztWDtpnD#QXlVyRDFhn~G&*>of>kPy_u@cYE&xPx{BZ z<0hJxIxP0BUA5@e?8cVA$aje0(a+Wy$6?01(a$y5z%c8W>$-FaE|S2P@DX0^%~Ft} zV2}V+6hzwNzNJck;Hwy@EZmVp*hsQioB`dKy}){J`YQo2$9QH8t1IK+q{2}l2#;t} zY0>pi!wa5y=%%YE%T`11`{Mp;cmQQdxQN+S=#^+T(YaPpVjvqgg^>LwY;e`W6R7Nu z{mOaZd{*wrN8!&LXu0Le%aQZ);D6?Q*F5%vy#1!c=qtK^CPr(}M2vp+9$!xGb35ks zaq2OMwL$zhbI>8&w>8q@k>jnSWMA>W0@C))`DEAI;!v}#n4wu&YNzkr$%TsKaz9oaRAELdLP z(+(h?+H9mjL|!-=TAgJ{z(9PCl|{KZnQQU3A*D?uuRPKjSn$FJhX_IgPJHo$pK60s zO&Z|qx|k5I?Q&1?CLM&HlmI>P1g{L^zTu^|&F6HeNSL077pozEa&9aL3s;JSE#YBM zV_p_i0RoVbVvs>j>}7uxTn7+M_?=<`PTxgSO0>~n<(zB4-m7l<@wf4nTEv0<8t|RU z7r@oc0tqHNlAR0!1N!Ns4;wF0x;C}dLZ zRy~p_#Vq8LCiei7R>b;}V;`Y!ckcKU7tKX;Kl{HcDVnCXnHv^RG@r(2dQG(kCI<#x^t3MGXiZcf6bD{>a#LWq6KP1^|iA zh9pl9h*A*`SgdJMri(yt^svT2d;%vAo)ajO!|L!q= zpgJ`TQr#pmFzOtj<>=vW*fzV2oCyep0tK=?Iy?>PWNOjq0j@w1z|l5y02Lut!P}6y z@I@8rxAD}}79s!y4Go$~b^pFIr?enKe?zq^RZ7^RnKZ$+_FsnlZam{LuO6rTj%@H$ zKbQQNtgeOA#BBNKJ~T3;r#}^m`NqWTvBM+0HjH_+!BpwBcsZPGAtFrss~p~^FMwj~ zw593_s37AdBB!FK5%e{rLlp#ow9c7C+f|?|{w;F;pj7ejjBg7Ooq5GqFIbQ7*}7MQ zh<;l{l-qv$2B9gU-1a;8DD=zma&UnTX9LUEB>?*BYS~4lkEM?5M9}8ghKI;s^#No) zVrJJvI(lDjP~%P_g=`jm?VUe8fwEcIAe&nnWOHCPA%_`$2%mhi?^6$(^V|}S8UPQ& zdENq~NY$rkjtGlE(hAe<G6*7aa4COZvz#x^Vn1ILI#oI$WP>o1$|ti#)6a8t%5OeMhS4SjO$XkHVy z2LEd+n5%LHBBhpDyivMlEdoYH15CwQgCuZ65|=&XgbV(Gl33E9H-BC*NnC zBQL}Cj1%d;?f%?Yly>;S(x|b)#Cn#NnmWM@i7vwv_i*+wY=uJ=yGtxh?m7gt_Z`3d z31ffje)|ik?aSmC+tP6#Sm$&J-de_G_n&rO*XPv&;CBLcsvh49=akf0Gyzs#9Z8w0 zc4FY%J6qSWGQ1kbhSqzU$xN+cur<)%G=4^gtVMQe+3KZxA2P=_C(C z55zMhG1ur<2EdY+oQyxf6dou0GiRZEDur+^9~I?_(bfgrHM<8vo3XDj7*6s1ggDwPF+%gfsQz_h^F zR;$B=h!$ON<*%skO$|5gdl!f8%t(7B`eu_JAuHg-2u@PLg#pxs+mIB8adZD4^iW?F zqc`Gbv@6~g=0(`v56gS{a8W@4)vtH9oR=T(Rg=O9v_ABhXHhDxhFuQrr3)yQcjGgy zGOAE(4P`-kW>R1*VFsdvIi0QA)hU1?G7Q?n$_eXVmeWMm1r|UR_#Ve20iwSYqOQi* zYKI+6W|WaU^}pfxw_o@|3alaLZ6CRS0{aL)a|35{(Sw*tsu@DMogm2T&YHey;uNM; zksLatVBPy38>EzwRXy2lPlUA9W>^_DsnWg%_L8a^8$R?AS-2P51^0dwVpP$J-`i zqo2VNq(kN;EQ&*ZdpON-9F7WD$^t@CE>*V!Btn@{V&dj{i7X}u@nxEt_uGH7fEsfqJ`?OBVowI}?DK-Vv7sO}2YI!cHK14oCS>?{ z*6#}y#K}K8rg*q}&;IUzS{GLXkJ$DlZ!A{ez>%%Jra%Z25orR)jdTZ!-(>6`Z{00W z$WAC9_8jobmAgeIz!(Fv#|oEJ1>?X199OUoYFoMz;D2-slm+*(9>`d8sv(BM|M=Yp z-j?vCp>eBG=0Y&(J ze5O^;*#&E+0=j__cgFZxwL(VXK1Qas!&EdliqcJ{T;4Gaqq+9v(WV&Mk$JG!FLjlX z4{w&VtwL2_w8O*Um=a+%z8W3?{^_nP1h@A=FZ$z;a1Tw#zqEas6)BBPQz!}U0u77Y zIJ=Gw7h)8Tm3Z#h8w5jh+9BeJh4Fl*HL1<;!!VR-XUwESE`d;@WbZd9kw+>9OjtIf znIxde&XQzS5y~H5fzJ_-5uKD8CL z?Q56fySEGsb3 zw3nEbtvqz5_SP?2UFdHl)`P1v4Lu{PormyRo4@mG>wo>52H`zM!lPH(+?n7;5N;?O z&sFhDaDk;di=MCC5V8?d`s>;)XV0$Q)mcn(^6T6!XTmGMVb;({;< zhj((db-!dBB^zGs|M`qI5}qiBCE2gVOM!u82^q#}E;^LrPa1^1AzSt60;X;kNI?qJeDz{RBwN1C=`I%^CL5afb`TJWZ)H z2p#kiymm!&&@-}&zAz7*&OPvw+XXpTZ5}LcIfB3FlY~?DZa|!%z(ni@A7@R9Hc-oc z_DU=vkxM>z@>|#9%QX#}x7SK^`_&A6hc>xJf?m{@=(N%`?7p( z2=S_=-9xxvqIErf`W@2x1u{Mk8xtixr7d0AMt+f!)0|%<{8lK> z6_0xJP5*>@Xx*nFN~2x-o8d zW`vPcAZ*JRK;~GI5lpoe4=p9j76VrqI}_0TcO+9j9h86wF*bJ)E;{l4U-~wM)C6VD zTp-WEA?c0m05TT`k4gt1CLQ#ydCd5-RokZJR197AA90UWNGY9ssYksrT5V8S))W7i zsd@?0&)@T6#^_eVVG?cMjkf?H=~{fEsM=H!JSpVFBDkRo2G*!j;wd)m-@YmcD{l;s zh+U4EJXCe7wp-?YQLDr$DQB_e+Dd)gCkBWURNHf@-S=gu|ManJP;Sw4^@pV=FOYJb zjn6ur%z25Y#Be?xYf!#U!sN#zdykqjYKN=MT1`V`Tf}vOnG6I?SmuV0erAk7tM%iC z`+bV;_b^-%tZOgdJ+cdVQn+fC8HDSGx9Z9OcxD@3yeV|ZCrTd3&v{kkkx4c+0v)`rrsA-6rO8@)4c6xj{5qJ0YJhq>9UoylBA#s)c? zm7PM55Mci~J9iI~Dqe$^Z{$<8N9)eE>hv=Qz)VgUPpMpxe94u^$(;pH`BO(~CI133 zlENz@aJ!)gd$0ziH1r~H@5OxbyFQOTfQow15BWZ|w4FBw#b zFn-*XXI#kMht?e$!np6CBukI!66`tHf3(uNF1pB@hPRDP?i%mx7>F+YTfFmznW=NY z#DgFx{!k*J^+bebVz9MP2uQZzHlU%diiLW1#qfd@FqPM@Dl{XK1G?t(H-+B1@png^ z#U(i{(lq@pb(_>>;iSP%hK(fcWESE@@HLYYPEE%zS-VgtX^_VPc@`#sdF({v5})#= z#cu}FOKkFC=$IYm~tM(oqrrJUTs*X=mn4<+^!0p z<~ryoY7m2aEbcc-3Cp(CEKBA{zi>nWUiZ>B{E&>vxN z0hpkh5;=22Jp|&3z=j4milCEe3V4r?DkE5_iZ`GC#0@W_3>${Z+S8ID2d1BZ@$b30 z#1zbRXSj?9I*56?K@{-CcuD>$&dUxz_9PwsN_`g^&s! zv8h9eWtzBH>kLM0fmOl}e^hGomUI~-8w{diT)}Lx zzToG-9ioW13BErf`od0%=)fLS_EZUp!>=o<1y*r${`~<6=!v02Ih*VuF*`QG&jiH? zw5hvJ(22QCcs`miVHpgS_0cj04mjZlBjcrgK+4~VDPwf)l`k6tyy6Y_x_S!**lrNu z)1_l~#pP3Y3@|!L5tcAfzhNI1S(NkH>Hc@_Mt|TW7CKHLkDQnFxfDt9E%TF(`2Bo; zK=B(%=L<4Qb!voKn~)Q6Kpz2Tdo>XcMQL2+d-T5coc2q0&V1qAM_z(&*x2>!TRaK5 zRsgMZ$M%nmbW7m3Iye=$vu&P>m(P`YvEy$;HAbQD?N(75X7=k&h$TmLxU^S65$q;i zKg+$cKAy&+^@&1FG})w zWZP!u*-Pi*AS1a9$5UuGXU+T=KybOhk;q6Am6`*~NZorb9w)|@{h#q6 zJ)`n{36Bi~h52VqiLtTJ*%y6c^~#;Nht?nQ)9H$MIEKOB=MtSA5cnuqYOXuy)#~OiiBK8SkDO>DIfn(8N`60b&7dOrsyE zk6~BS_k7UH=z^PenzVhhr^R}ly#a`~Vw{8X34X{SjCQuqjehdIGs8PS`N8o|zH9gF z@YbE5eE-bk?0kDxZgNeBu$YrXqDH)DX|2@BDnt?Ws~t>F`_StLd+DknF%r0Doy(qGBqy zkuq4L5C zYn|*k-_+l+h(Zb(qU>;hsf>?}pl1LBP%%`LTpIpZFv5y%@H+jiG9jEZPx;wV9Gq_* z)8JG-CgCsxSvIi`D<>z$W=g0hj_yqC!@f!T^?bx~w#4#oiX|dZ@p<)AXRja#GPG#n zaXVR?cU+}wum)uCL+D(mrI?Hu)559avf)!Jj9YmQQq0-=#ErQg0tN_WhMb+|Q$;3( zb%-??ryX9(h~mwxN%W4NKlevnT~5Qk6@$V&k- z*Ce!FL@C%W!7L7-F>lA~e9WV`GGyLWb6AJZojkvAwpXWD6p}{G4&DLaX)P>6A)JAk z1XBPiMCsMG{Ddk+_zBN#)@r$ll9ejo;Y*p1a3(K=bltOW^?vpdwGM93md{H_ggwh9 zQL3KYXB~>uNH4;bGEGCRm)ERGk=F(g*|YF+QL2$bkVR$12+c83MRoGRGJ`6Z>i*1k zWP(to@QBprrfmYTw=8Qm3~5!zEWG;uw_b4&T};D5*Y-b44vZ%uhn}6^jJP3$`JVe5 zcJns8b`6`VpeHm1_qJx+dH8CwhlGRXD>Ch{`!6FyUY#UB1WIEMCSJi{o2LQc1^6fi zZg>zx_<+)t-?#4|elDwY>}7X!a_#@U>4i_AtnSjFGhg0cRx2?1p2k(nYJ?XC&=%GR zmTQk$xR&stqToBhm)hDO!~VF}>;q2VR`FeqU20HcwQOW;{SDFia+A4#atP(%WRXR zB_OmqhT%JDRn{KWK@)EcQ`Euk8m_1KQkf3l^vQ?pqTK!+KmFm#7YZ6r1fpsLlQqD* zGc5dv17e066N*S&C+5dQhuEHkS4Yz`Jx>zP(x-qb;Y-5F(t~qZqGP$dZQ-M^%}|X? z-h1<_9*qxb-H4z5Tm1Hds|FJZ^Dyi(OgA7>s>G>YdNU|Oo0(;)ui%k77P4 zPrdCnHi|>|(SM)55s|D6On?jZu^)1CcYGrIq4*?8GuZ4F7KP4_I*%vGwiaqxFY1m5 zCOjgOWpE_3E1%nkMx3&Oh7!SJ8-{XlkT!PTwk6xcucd|=d5XU<6H|c!Diunw_oQR~ zg)qIbPW)Xd!Ga0rBNPtm>&8wyR$?Tn!es^8d8H~il}BGYNpL6L>q2DP(+gjes><;M z@w~dckw8W*Lq0l{sZ&(mEk}>)mn+zr&tCNrs}naIgxU6ehzGV35!%IM0Es_fmKYf_ zl-a5h1w0nN+4`dBYUR5E)(VLpPJnEID3KIWQm7sW?9!rZUmaR^ z!F%uaX*>U?DH-@d<$A_DySnX@$L7w(vUO~G4)02M2XL{gJB+RCerMUJoE zH~mrO&I^Dx@|Jx%TcCGd_lar6PAXd+U?`} zCg;U}$Fsi@uRR@Lt7kQ@Bk$r5%$gZ+wTL!qip1?$Ihch2N26Yv$wvx*W2r+>=;2Yc za~%!~OKj+p=$zUyPeA3fd2eMK)f&-|)vBi)Hu5Tb{if~4?VnYSgNLQ#w5h4>91fk! z%I}eQ=?>I`@d3d2!y}`N`19-03F*BUZ?PhdB*d4mvLj~EL?so`lpSE3{WMFu7prW_ zTlU3y(z8{pXbwy{c3k&L9Fw({ab_lSyWOzFYOe}WK zV?|gf2?>Oiw$BXdv(5DS2%`uV_ZXV(iuMprN!V;wC_!+u?pIB!8i?>%ZJ{+zx$qG< z*;EoK8;<(dX-;%BQT9u2U1r*{2WTC zp>b=;!IBUu?v)(~XuQ374CRKhOpn+ZeWtj=6LWZF02zH4FWyv@EvzNEB26r_4bSQ9 z2)t!92->=XwGn0F@1!Q74Uov*v57qVrlRS3sz;V`Tki<8(2Bb8c6b2d+bhxao>sN! zVR!r{DVNs0_s1|xZnvNUWIM$wKuHVt*6|HxA)tI z+dHDZJt%Xx&Ao!#DxQ|fHAWh6$u^BKA_ zjENjv8Q`8-Mqbv_t3t#9jTMFN)BuTPCcsg-tc}-aiR2e_0jZ4zCd=daMn+IT6JkFT zR6BA4e3TEdxr4^%c>PG!cZPAe#R*&ZhPE#PrjXv=Z$0(3_oMV0^5rG>ko1W2!KzJm zdXKSW-3;r7(8V|?q5WRG61rk6btWLzwBZx51i(OZ&h87H_Mx-T2zUf{AVxAu4p_Vb zU|jHX?P7wc%NfPQ&mq-(4y5}6Kj!A?qu+6d&zQsxYtXlQNn(Fx5<|%-!7lY|W@>K- zUIXmauI{{A(F4Jd(5O10?H*Yj?kn8bQEQ0f+{hXCz*LB*+aYt-?2&SYpm{ijWdYn@ z)-Po82b`}BX+s@F4`)-%;RikMFRg^uu=;(;l45>C+xFlv7lN9ZZdunrv2^VUQ4OyQ zV16INixG1Dt1APJq$da$kOO4tM&MbI7R^~eHu)(uBLU!V(c9>$mC9=5P2h(uFXQc3 zO^`IXKAOUK@Teph=@qCknedW;dTu8y?vDGiJ!kKDK5nL|-Fiv2S8xa=U9@_m>@}J6 z3vuBX8Ya*Kc}{0$qB96Gem!2R(wf-|;D&nn%@fx_xGIKt?g=Z}>dQ^s=hZ}EjJn(4 zNsu;x&Q*h(R$jy(1_4x~Xmm)peAXTo z$8t2qGT?_~T9BfO*p&cd|Gjz{$lHlARY#V;6?`|is>;%|h}iJ6GB*-FRlcUag3?3~ z;yQZkVK;q);`$YS`eDwoGD#B`%O&eNP@9>lNIqHKXBh>ZeD?bR%y9-UU1hVeb-efD zS)|PL<^6P|Ic~Jz$KTLd*(6{Eg}7sQ9EMlucJuLZ%QqZ!>?!xf=eHI$Xvjl#%j9iN zL7JX;j?M>1{Y?VSP3)eTncpgm@X7yx7bp8)t1TP^97asU#^Z!~z$I5)mgN_6!=6)W zs73WJ^CD8C3jLx7J6KE8id+Q&%_G0E9fMQ&aGtN@mb2*F-#h#X_@*uHuj-R%xL`k9o}JsKo+qBLk>B}Fo8855U+TdKGd)oiO8RfVS*E3$d&9%%$# zbQPpt%+8SrtOVI*e+X->9Q>yvFQ{m5=+GrM-1je@P02j8K{Aj0-;m5@`0#bMWeesD zKw@D<7*U-*6)j;Z#!!=_l*KmBN&*J;m|R7Qhq(ghRR3w(qmS+_W5q*(BB|mRGCS_j z=e_ZJl-Z*jWcFyu>=0b$exmjns7Z(aWfHctGcvVx7%?6-f%#3tgt2`HuU^BdrPlBG zlumHwtW24BatcNqm#hihG{$&Y@bC3iRm@?AN>T#l(baqw?EggC?c%M{Hn=1puOT$F zWujikJfK%6&H`X(mfl`>+Q)d7Nuw`cA=&*UF0V$3xE5Pyf?#eK>rV-i2Ejq}<)>S| z8t5$Wh@L#Ry&4~e7*sMW-XYhiM9)X>u6!w`DUGnWCf#Xc`|BH|xr|jqV7pB0i4sV{ zXB))yhrjgZ58#_Nonx}ZH+qr1IG_^^p;_$HA411N%>bG%l!erGuf?~(#JnD%-EyTP z*zO8i<3=dw9J*>!4g6f$pk={SDS#kYCz<|&uH^*7_)dDn;pgxWfu=tFCB7JoIjscM z)279oR%0K7=CmYsvwtBkPI%MRIg zb1JB?G4MO>lV>{Tf@st#<_S{!2&7(7wVX!Yf< zeTf=kXH8Gm?ey*6e0uk4>db})hwbZY?t;rJtV%UCjj5nEmVn#t|F~fmv{c2i>%%jC zeSn*0O1qi;Bz0Sahi$9*ZjK@z9=GtJ)%aC|3Z}@tv71zdqI={EG*$>XcGlX;SR^5XaB=U!>z0+3 zA6C9JrZj2~{c|tAoHvvnLmT=F<{7~RnMqXu9NjSam9hU`e-a z>Z<-+`(AMLMs$b6n*Qgl4qK1AS&GXz_}MOV4X$4vzHIqr@NW1TV1)prN#Hh3vsxRRw%!5QV6P)X>uXA4RP68wrU^LlBC zY7x*%qQ2G-sEgh#cR^e;P(>K=ADO69tHK7(eAYc4cpEz4h9%ugW@?9l=er8)J40>c zFi^A@#V-d?mQUcbmU&0Kea)?2^6jzh39_cZ_5#lKUn-Z1W{0@gKrP#`z$=@_@Qz8f zTBlNE6|?AWM>#%cXdH2RTqn4gX4ceWP)|r_t$_ij6uUNEwf!@H&rXu2qXU-AE`adZ zBja-g3Gb7>Nj>Rd$1L-(wk2~qHYZ+*T8W9b`W4`lj8CDk0h@wdsS#5g+XXkQ$5Fyt zis|KFy*uMXi;C9oXXhj)1BO$xqq{pS|E0+pFtlH@^fw4g%@aoRGCeNRiM-iV(57ud1H(T4iU|!I@ir_B{4JS`K%J{}Q*zD-k zbU1XG8V?PyUk~8Y--OT8Ju(}D?0U8Yq!@Aj3aJZ90vQ4FDKL?Mfyki}A5?xDZ{yQv zr2)?x8%%GFhb80)N5!%&R#)5JHs|L0{CtRL)k9YQ^nnyn!;wo%&X=B9K9Bh=G~%3r zFO4-nIf!RWkzE?za}j)JSGw>-?LCzmvZ#f5(|1zLYAkCrr1OW zBjW5FB!HyB)`=1qhsUDvv5jkT8~W=#cAa>i?UOfC3{9EB3nd2j{G8Sun;YG49MK>! zul!F263Hv#Y4N$wqD2yEmz*?IUd7VvF4e4u5gw2=qnPw8j`V|MK%r_Tjqej8EHMb` z2n8$M4;HSXE~M&w2GB}MKHnI^I_r*?Z{g8Yjo$lZ5*AB4r*+3?!7TQ08!YYYvfmF} zuzv$yx`w}JP)iSoW35gwFz~8&Z2&LB;!l!d9zO(Y^G0)OMo+uPV;hc>Lp9aH zGsg{Dy}w)HkYapET>Ve08c7d8G8Kfnp-8ti#I))$=U%jrV)_Ms`hlS@K3M>>n#QNC z8QaPxi?k4D#hG1)j7*IzK9Rsm!*g$K(S=OAZ=C4GHwLpy87Xi0<)@AF;WTpWuUv4w zcnLmvt(u4=`_1YB;*fZU6pV3q&@??KN!@4h%7x*jgVKpPW~rnP<--6dY;6|el7AhOkB2@ z9gMA08|3%;qIqk$NOv5wi6Gs%bumyg`+&N;cc6`l&Ci3C4L_CQtBMN7X6%=bySLfm z?NaJrG$&I$GaNE2f*P%ex=u*CAR>!!nlbT7;uH#WJ`SgX90QG6gp2pdi7yj3%^@`L z)yIG9BJ*uc4SJVIk_41%#_%;ab!I1a!?)!01py_NjCHUM#IFpXhcCd3S7uf(R3~U{ zr3cK}EVHE@>icoSEeW#6Jc$6KjLB`9t>AUf$SS6+4k zzE{)wh9z&5IBti_CXUTxV^en3?kF(lv zW|SpM%}@c*BPaU;xH4Ypu`tAyL4-9Em&0){I{zS>B5zn4zvN8|B8QhkfJm|$`#A&@ z%d^MB2A(xW84a0kJakLAWos=92OSGkkb+e0bTzO{EK%M)!(>R~tlJ;=wEu&z*R+dZ z$=f6i^3Q8Pf3mQLHTk{kqrfDLv8rbm2GEW7;Y~M8am!t9(zejlSE{SQv1QSHys}ShTWwqFWx2fIDh9vf6m-qD9v|>FI~kc{H{n zzGDI9_D+0e{lJw(;Z_y#`U;W;*~{Qu|jwm_RjRU;%Pgk;hYZYM4f?39aH$wjfN;Q zoA(UEcpFm<^wUu=O4%%6leME$IZ>JeJd17^2`T=8Dq-YF0>BBY&YALiSxh!;RH6Ml{m+EWY-{#I((?ASz-ZbIFUj?m3w4>2;7WJ zD#$qkXL44W9Utl+oDB%WBmI<3#SP#5s=vI$EAin?XJRe+h#o54!dfn1Wjz}{YFkou z#1s>}GK?FxD+4&pm*B-KEdU1pud-wMvf=ke>@r= z-*nQ-l4@_-0lwq+;}h}x^n|LXr_6#pN6&aekp2}n#K+dN2sQ7}M2BpdEpw#TidMy# znU7Z>2v?N|WR9kjuqBsK4yqC9Ds2ekx$68+@4FX+KvM(hC#5Lz7DSuesul=z30^dU zuQt-faKq&A=oE0`KvCdwyn%gDJZfPAFS8j(ZDR3^+5hF;A_xY!UFLbU%TJsTr&EJO zGDQ;f$k3oqf`dhLfq;zRL8=|Ornv-heId;|e~^qH!o-OJjWqv%x1Qz1J+m@3%xpjj2Isxi*%UVguO zKOJAPMJBvoHlLMjh+WqrLz+d7hn|ye`eNqE6S^>rZjgEq|+S% znP3gD@Vx${)kff13RTEy7&G_Qq zR?0Z#{Q&?Y8T!gG%6Z%^u-A3v~FNZ zAWt&9rudaJsV>v75WckVLs%{A`Bf7Eioe5WuC0h)CB3X1T4zqdE}uEBrdqqT`#pmb`EcFF<+1*SiWA{ox!?_El7it$t1Mljxxr;0oR#agqLoZ z=>U1vgJCvu$r3d{JS@kY0D^KvV00at26zC==a(*1}u?;g;|NW-v=umtEUg`M^ z=mI|lR}_AHZ_CXTZjs}-3dsD(CK1MJuXiX;)-SzhK}AK!D+G^LMnEZ{G_tFq+UB*g z_R^mpTzBMcH~oR~Y1ntUiNvs)TYU ze*YQHKLCJEb}+a#SvE7bad83{hZzVlXFkb`0|`BQdltofSWKGjlSkr#1CYzaXB=l=n;IDZQpba1_rT3an_kcV}rBS-hc|~ zob|?s{_DeV7p=7oe&~9M@Q%2AfR7vq3uIxSoP-0e9)6+#@h%;MPlmxn9)^O(A3HvTC^U}L`~i>Zyzz~|NHQ82q5s34tj3>-P?cg6$-P} zAk2T0Fb~1ib%@NH=Q=aH!azxc&vxb02TDJlix)~i1aZ^GGL^~%0)d=kMs-AkxN!rm11yMoK&+fpl?50D70Q;>LI=abTr`T^T?a?0}3^fFZm1qf870 zc{5leY^#PzUty13#3ZMEtX8L$0_`DqCl<@q8YATB*nox;n7dd=`RtI(s%L-lwd-Ib zjY~nkU!vK1pb_|N9J32bFN}rpew(@LnXw%^24VNE#49(-36_Ld$#N%yQcp9G1vi8} z+zdENV}wPTa; zsf_<2i8xv(kf0CWg+>yJ!auDkiMc#A*9jJYj~oyxDdGh3A_PEq6l{-ylOo5SvhGDU zJ@%Z3QGR!72xh*ik|fB6DP!5e@a-!b*2%*ArZhadxrxp|QSCy!+8r;TP(jv=UkNvt z6^|z3GFvffN%z#LkaU>U!L-<#BETwTs!Y(elI>fn(uECPbod|cJdCf_dR&7MLl1j^wfavGg6$Ygj2UHL%r_%L2ur)_i+c#cLfT1~t9_PB<_JJ}*ye#zGL zJo46Dxj|94!dO+{1-w48*Ia!R29lq2ALl6|C1u(NWe=oh+qZpYfVZz~Evarb6@lNey+ zIn8Lr9_03^K0`3JTrw%jN8|REwOe}0=M^6ermk2WrucVvw_EJS9prZsO8o4~#dy;QFCQQ-b$xkl?Q+!3E8lUx&|* z88q|9aFpmP1HY|uVWeKcMVU)8K~uSi%D33?V=op8m_PAY2{%H8@(t|?RPPZM zx#5`ENBoSEBA?msj;h_e2Ut=}eTQ;3(2{ton)stm0wqJ$Ca{jE#~8@U97vNoU_MJL zQvfg^giU3YREefpyXQNF5H36TCvWC(bz>j=e=eB1yak^qqy%FS0;i74Low~kbR7zA zWgd%Pfb1!`%9~jnV$8P4mT9u*xk&*O?y1g(Ff8gQ)*yp_j=x!m>D9kK?6@PKCaoXg zr(ak8BrzS1OWxqn)Wqu@4*!ED-m~z=%e>0%@w$kimurl~UzJH4c-{aGoimOX+RcQmU^RD&^1io(Ow~STT**%QamsmA3*uL`D;I%+2I1?py zb%_`9X4&2uMy2i*LY7cawE*;hikS29->FM07cwXrPAj6~5R$@;sF)fsJwtfuaX7QP z<=-iqR>L^f(%VQj?CRJw1+>!VS2@8SRKFe3f(poB{`Jjx2OBO6uFv(f$A^Z}w%3~! z(F){+QiE_zqM9f9lz_IQZ31CEEB4`Dk0e4%>}=QsT^ZkoPUgLVc=#%45q>*7GPQSr|W%Hj+E8j%u%a+ucHO8v>QqB+!#_M0~oq# zb)3`CV2fbYws@U7vaf8p%xB`Br>;H5b1}Xu6!OfU-u8JXQG$JxYDz`tR4<5pjW%&TAytxJib7~5>1p0F`I4p_QImhjSg?ri4=1Ffg&EmcybIA?aoC|pJQ+9C)cdgX zkOM6`rd`n`RBXbZxA)cNmp3D6D-RlqY=Wv266#Q}#?mKe0axrDZ?JYwP)h0Q{9nP- zl+M=}!7*}RL_DOby2*HlE*cK^STHsj(mU~4|8YBpyr#*orFW3@SZTv~WcwKSI!IBN zJ%mGNaRfD^PJIf}07<;K@1EXG+AFgRqY`Zkb5R>&ML#yT3pi`9WLvH)YH zl-lrQn0hVhk|CPQp82si9fWV#dO(ApzsmwB4XMqc;@%@t*}qX_++fS`;&x<7NYE07 z&?I=&J#@o@0R9rQ>4~3#t_m|qr(BoGBVz?-rwS6ci-AJtpmzg?Z^HZVZ_MOFR9F4( z9*=$xMRoTEQQdU`M8)B`br{4bo+S`k%zUzp7Qgd^K5h~b-iMdMDnyc5|DJW%6hX=F zFx*0_n%HrgLrO;}0*-N52%bvW9PB*=bIViS^eQ7-8%jt^7fCQ=thWH#&33@~b$9Gb z!j);<6aYBK+TlqDVq8Ch*QNtXPhvD<_+ay$>!*1rQsA7_rDAgKW0%?C43&L(%V>FP ztWjm`cSM_SfFcP?3GpbzTZ;4ST~v#qgEZv?3>W?2Rx5vkTWLB_e(BvMKQfJ*M|p6@ z_GTa5KYTq!{&*Av=L7X_JDb`sx8lI@=cKD7dLo~+RRL7v$Ul?k)ip750wP$-k z7Zj4^qc|WOmTP=TsH0rDpaX3UR^F3NxbME~zH@K66{FfW@zb9f-LohcmOyrA=Fnq2 z1DqV5TO0u|pvRaO2JqWw;`6rn7P)kr37<{BEItLHggmg?XXJ#U+S=mQ{oi3Xhrj5C zhy45;;)NF9B_Bj36W7( z6TxIK53U?mqDBy}!$%fN1-Ix%qFqQ(`7zTH&#L1dubTe!20Kir;rzp;_trhKk6}w^ zANmg3s{q|X=Siy1*{_F3@#_IJ{#|(GYBmpwztWeZxd+$jb#x8h2N~lE5s?#?Y-Lr= zPQyEokBy-C&Zk=%&f<@|4D1k!fnd3Zf|e`qy54#PlRwlK3|Wo7_{P(idp7L}Tk0pD z9B^5EhM$)==b+YLO|^TQm_C(Yh1O+QKB`WbDI-Nwe}WB=H!j^k_0${_1q)Jv29Iqo zAIGQ;nrZ&hbAyLZ0zpc=e7!E?V$TdOLi zxk=$@2d1&Liw)g5;Qs1wEcwZaxT~h)qn92jQIffJ+ub}eRnFm|9=q|*^7jK+FF6#c zPSUXIFM@j!S7O-$fNdoHD!QA}s#gi|x10~=W1aB&=vE7L3&*Yld}_YR+<}wfb?}30 zFWZ2lj93DJ5f0LProf?&d*8hL18i?;>f>JOC(V!r*fNSGq+>fq+naIIGi4($Q#S3e zMRjp{W*=4<4?qI&lQ$u&N=d<`Gt07jG}@w)6jBJps*<5t)`8#DE!*;yY-S@ZVh2IV z7F8YhkQe7dxHwALAfV9KXSP2GU#<0L{PYLD2Ua#pKBUbf4R%gt`#&|SGrk=IzgW-O z9SCMW120{#mg(RqNFnv4?Af)qq0%9S$*8fw{i_j&eV=Vlh{Itq&ii)lT6bjXp%Z6) z@k<}O3%*Lzv3g7WI2}tf4)E>I;UkSvi~wJ#aOj0dkFvlAG$e$BjDabKftR!$`UtNI z2=*2;Fk~H0tH&{4_3jh4Uc|dTy1_9&Ob`9exV#0#1fW#=6p*iTvs*i*$&Ad0t@N3K zaRU>avvc<##_*4LIbDE#MW)}GEUWV6xsdk&t@J)fuLycA*=uB8U#R>j-Vfayewt9p z6{=#J{V~?vaZ{u;h#d?tBzzCc;N3WG{=|+4uE$qxYMWa62+8SiT;8&8543Gf|JoiB zVH^oZ-wRG%#A=^GL`2uSTHS+n@))T&8qK2LDMk}}BTPCPK*g-S$NWzP1VTXyd}2mn zu?LlsY+ZA2LslsjG)r<$(y>J(%CS!Px*+#{`3>*>9B!zQzJAQY3epBekYPh9im!DI zP`;?_Gt&z&3Z_B~BSfcJBuVG#dpR<;+q*H{^qF*X=X?(bw;tc~Bm;-H;lT?$1-28M z?@3OM{?RcXc^##9+Xi!eoTSIVbvi0zz`Y$iLk?B6K<_lxbNt#chp=&N01$8 z*EgI%KzT}oAeJq-AU=vuUK`EQF@qJY8PR07IYyyNl`i#!s7Xwcmw-eSLNi?-&9^H- z_DspEcMc;TR?xn?pRQhB7a*2^(Qu>7M zVjSEZy2Ow#T^gR|?+4JMEAZ0QX#=n_e6_GOrvvC)a3sSdwUD2}l8Z-y=|kUoyIDd=V=jm*Vkw*;3JTQaEKo*c$~vg2L-T-sbfMY}=5jjx;j4Dj%e8Lb zV4oYMZX_R`a1PE??c%7KxomYOQM1o}jT36-MhB46i}A{3W|J2DJT`f}XQD#SPV$yz z66?t=6-#8f$X3GTn@}9Vg~i^ZC||`0006 zn-)kIV-!X;3saNGp(fy*(ODkVC6%+ye+yL5*ORDZ0EC-2#)RfqQ90(~!#Hky#=rl{ zwm&ztaxUFmobsuivq9Id`Wx)b%6bQZ=G@f8@SgDw_G^xf&hLP- zGc$h;yOy||4X;*Egdl9;ac>1e+@45yj5)^nQ}DfI(JcyOfY%U!_g%5Wp|EkT`L{g% zPJcH<)o)nuxb#Uy2nT8j&!rLpbw6nNDhsE|v$L*n4NkFo6=IofHq;P{!gYuZ&s`dA zQI6r-XZs6$2iN2*X4Z}pF@#Pm`qA>G!}xBkgBl#clO+yjr?Cv>|NqX0Pf8%q!JDp* zHWl4TLH+Lk8K7}z>c(QFDp0UxZA{W_e4;oKZpkqiUgt9m)|t#ktw3lfq;UNQpK;1H z_(HAU;HTdMJf$eb5ZY7Q2jIwCmjP4sDmEt1Np~%yUWL!Ye-X1{Ik=T|=1n(`pWv6p#s~7;8@Wp*`{fg7;WE@ zDLu*_gR_3|phJi7Wm`YPPrp)hifJ6Ufv{glLR>QneCjDLAEl5M#S>H{1!q37Y~(9) zELo)AQWlZ(Z?LgV+7#NbcXs`MS^HO02Dn3adlUVU%&$atiQfCGoshe=3 z$9aMS#Q1RTifm}snw-U%TwPl}X5h5=KSTaF1{{w)n(-<_QEfrX@T|2g0>tO8{pFbq z5KWJLRDvKQb3mKeLlisk#%q}7DxWu;lWrlB`X2`Vk2SyRHxdk*KTWm2Xhl zQ#|&|E;;GzPr!#Z<{cBd+XK&7f9-*K@*l$omvR*G4Dbt`fSj0B@Z6DU*eBEd?jy#Ep94s@$c)|C7 zeov}#(}BH9r;D#xj#WSC{O8t>ZOL)7+`m;9coyHb`7F8l+Od-0)p%`Hsc`gQJY(Jb zVi|=7`_nmC-U>G&Qn&I9AqG(8(cO&OMHg^}$>9xJ9(3W?NZi0vljeG+yg zFb7f#+1>o?x7|2O*?k>9{eE_D@jQ?n&X&M1*38t@u4JAFOd&j88QyAF<`Ijo|BR%! z5idsa4k4(v=A@8QB{3t#?+TL|@x9sRc>&r&7v)H!k2mh>%zf+DGt@OUgg&hp)&V~L z^k4r%cXlN{8LJ#j5jZm>4muz}(qGZ~qo<0yWPv19!8pdGIhbr(|Fxz=@PGV`S>Yy_ ztp3}3Zq18VFeN`XRHFYJExsTmcibQtMzN(W=%AbJw6}~-O>|NnXiHdY zj|;;%ClVLtp$#Fk7vQzavWt}f40nb6Q3-uv#6mB6QnsWh0+Mh$jVid zA?7PeY)KwC_1RM&7(M^oL;pl!v>HI#b0iE#qXStV_}Zj&=v=(7LZ|9|J@;#wTxM4! zW^&@84~B)fN`VP_W<|ABi=OIPPecE~?|;qrNX0fy-YtEe?w=s_09B>`_4B&*x8N<; zdLv>r%6zX?C09@ z1e)tk{Md~@#&>Rg2S5Ej^!deR)*h$@V*hr$1ob3*o{Fr7RkR=kDR?+XC9M^Bw?0jG zu(}BID93^*)pYz|F(ral@D{0y&|%D~EMK z^XLu9HHXx~0XaZ@^&=0vkt*LbyS&s-8=_0Vi~$cz!9r;a9ZV$JV2=Tct!N7Gj*pH_ zPImXrhb#WKk4p@f;?*0|pOteqqG6~`PQ3;dj7A*21Y$E+qD9?6EkyuEk)IQ`Z`SIs zI+yQpL4iR;0(iNC!VSGS_{*1n=nwe9O-o{y`Y}ahIZr(h2X=;pK8`nhJoxb{)o>(g z3#7tzsDCgJriEHVPxfCG3m-Zaf(g2lJfAJz;lN7CfoeZ&E+am>19Gimi9jc0Zip@h zXdBp+K*b@y%RYMHN7hn)O~tU+$?gu}W%O*c&p;(VN;uZX(ixfBI;>LQ{H8d+d4zQA zGkD9YCR$b1RU6E*G(2xoTvjD4G@8m>q>>rK8EW${eMo_XSsdo9g`vbrwSr;B5A+Kp znk9#TFDQ-Ee0_d2d>o#_*}Ih?Si&A+JnIwB{K6K-u!d#KOZ{vkrq+0llVe@<0*_A4 zmdPM1@!J(N1KX8(K$>s zM)C-6@4biNIm%HESFiz8RhhhpK(_IPY!?0YQLp^O;h>L4XW9%t(pVV_8w;WTzA6C85wIaly+N>Y#8s58F%tScNCZb%e z#iczs7Hb;6g_g1UBQgWh7MzC61U8eYOnIiLUbX&I?gwq;>)t3)-4>VGTy{ohYV~LVu^Y1>?o_K85rLaMb@6CM2EQ$%E_E%iE71I z#!S!J@vasWlcd>@i6KF4}OLqeC$PQS}6;Xm+|`z7?g5|@_oFn~^bO$uib{vHttzr?1X z`8-`0%`{%OtQ49cB6Xg!9Z9xMZq{XC5um55CxA-Hr8D!f7#&>)f_{c2<5n-adbE2z zKE2WCKdf72eP-Dt(%s3vBU|Yx(N@O`^FFgRwBaA|+7-CbEVb2TRB}N*bH@f)h}~y| zZY?{6WRyVz%5fKPMF`j>WlV5Y%Z-1hgdeV z4^2z;R@TLM5%P>#w3g-p$n$8n4f#ABFAwwv?v>aeAzFda?wtJ|8`&Ldf0WNTE1vvQ+*ZiT#tATZgv~N` z!r{zr%nHJe%zIZ}6UYRriPKx6Z^ZKJ5Xgpi+~Jv4;ktK2r1^{lvVhvd9XbpXHh3em zD0s-yCp+W~LNUI;N+N*#*7=X1WYr)R@QSpI#m)2pYKZt%)=P*4w-!>Ov)CpEk?Xx& zMj@T!?sTuG-4lXo-GZO~DC6gZ9B_5nhtCo-WJD1jdF5Kw1W|Z2$5U3|s(@;NMh-y@ zpZZKKkMJf5fNpHCi_{+;?@j2PSxSb;&JYsc{egivE*b zI7U<#2Jj|3@p)z{UjNZ^)%Fl)W7)d5T>EBwAh^nSF0!B(Bka0siL}RZk+|6lPPp}w zyYV46tgT%7`N{Eu!s5pY!F}k0n)=wb7BCDYf$e^S+W0+ng#z1U_(&=H0mV}c-AgUigT4n(RJ-+1n z-`xFVhJ)5WNi%vmIC^`spBc-*;I^a2*r6vJn0AKJ{x+F#_{jnq* zfhgB_T=e#Lu4hkMTDa{gXQ0&bAxEX zOYknsz~0!Z7yozk5!8BY#1PmoYj=+OCujwbkPxi(s)zP5v}$B6r=~n(C*sG;obyO| zxO$bDuuCpKxAi!Dxz@6VAp50)Iu5*Hd;}lr{xte+c%Nn`p1=4Ai^_wr5yx_s_AtOA zOjKG{0w=b)s97@;!#V|0e~Jwgu?bxb&=PL=?m#8+@2YLH)B~qa9eUTTDZnO->xZK( zkS!7|+KPmDyjB1O)yT$jLC`RnaJay)Rzo%FkywN1!o6w%Dv=Dt`;waVF(UyXO9Cro zV=)Xa88oKIypkK4ua0~$0t|IzP;zaecq2$xVqpX}K;uoEZ|OR%<&@0%RR z`#v6Th7vlaoOs(t#hb&ycU5D7phho0W{9s!2SXgi&BguP{EGj&fqen3CNjhi-5^9= z0SwX|!zfMPx#lFl;L|$rEuC%iD|Lh;W(GXO#%Vmn=rzv51p{$}Ot|TGG8$01Op zdY4QD7E!d#DoCgUd{Gz-KB%-|6yBw53A*LYkNxK%B4@Vz}AAP|j(5dR;hIIsxI)Qa&SfOE;x$Zie~ z;j-o|R07vl#^E0qby(R!v9fWJgawB#7oB6d%{Y#+8Hhx@2rpiTw5zX+B$Ao9;rihO{1uH} z6@EfHYT`%+qq#Z2VDA?zwFW-sEF#)755XM0`5RALNuEwIgJ~-KtdM_`ByL*a?<} zQjMT`ZWbVh9^1T|3M3)A)`!~nGk^2w2K~Fa*1vNQS~hn(dvLTyPmV;VJv_1-5pEKr z8S`3~6dvb&5T1D)=t=J>QN(uvyHv1>mOiMZEub>Q>_bfvs7>8iv&#O-7&QuFv(PTA z%vPC%W%7j=ET&r%o!&kYvb%omonA`rzESOdCD|R0%PYHRo$ZXaPs71N-O^yG(vDr? zx#7Gtfc5?#ym24hZ6Q5-AOo8fNS3i*a5pa$%frIA>NK|k3{gWd?wkipueK&BOH^!T zFh$kVnTlM74?;1aV5$(^nQL$NV(X@BIEr%VZzMVv5WFh396WhBjFJTeuZeB73j>Jl zLcCTS1OgeHUBNEK8!#aAmuO97?+mNRYQj`g4DYJU0~T~e?}s;&K4JcYd5m{5zz1@A z3}mMy82duJO~R{d*PeLF5)P%d4sI|*U*&EdtUJrKW$g`Ph{0JvvM``4!_#(U0Es*Y zpSo64TA5Abt0IUQB!az}N~kQN^b*DzhDDcRg=0X2bZYLaD-2Zen#v@+Pbs5?%i)Hb zpL6I_@P%3&m+TLRf0ka5uUQHBgUZRoSn)+9!_mYHP(90E4tkxE!K zy>jdfA(8tbg3&b+5YgZ4>yg77usod#p$LN^z?9(6&A3H0Msfnd%k|`q`CXl!SO? zfQNep-WI?@<=#RPM5?16i^`}iR}>EcUjS5s8~`amr^Zqf@I*!yp8>8H16fvbi zWbVnHD7>w$Q8qscpPYR>(Q@auaQ*quyZGZ2+VKrS^EKuRB(!(qQ%~;SwXPBIXrW~O z=|Dy9&fpCkCcM7Mkm-#>6-~QjGY`8B;YpMIEi4ZCP+?1hi2nY8`4qNFR4R#C=-GMq z`q(qirN|o4%#nu{_c4S-VqbfRtqNgBbRWzw_6>u392*2je}uyF)*6KekxJP=V#%kb zfp~-7;1vmY8kn~u(LZ$lE~l`(bNC`SKjoWoOgWdIwcx@A9Dk%z#8 zAq|=$Hq}}ZQPDAFk6GArfpC(qh2LOY`yg{@xO{-(k`<*Sx`a#7DxR7bBHQqfAGrB) zeD|hxnn(JQ=)2*L-ZTRa3=W~~0Noca%fjz@}a7S@N zw4@#Q_3*U)dH_9mJznW`G$(A#Q-+?yp->NsV*5YIf_qu zvNJX_5TVJ^=dzpviKnK-2T!iJ!pzQ5nDz8Rv*F3GXvh`+&upsXM$&wZSBTnR zm7fm15@xtJ2r)1%s#m40S`oL{qoSk7w&{&Oyvr|eORdK=sF!bRJ-`yY2A?*BTPVp$ z_8JTG)pso_2MjV^z_t-LDlbF`@D%1thF33&te!_o+50&&>=7?+s=|Ldc-SVT4w0t< zigI+}U2@qazrHnX^SB1#`Fcrqr>;h)eHbORuQS0lSi?BrhlQ6x+zgY=)nw9@1@zio zRBOzi7}ANgPa`&)2Hut}*+&%FHd|r0*o_NPk-2FJ*L5oMT_M=bVAxVUNYG-VsyFXcfA6%Lo+l3u0J8`TH zUHCD3P;2kZYw=q^?N8xNhOB&Tp0}5zKIKZY%8>Bg>i|EQAD^t(NGiERKaB9;2p6`i486h9X5RQt54@)KTXWXk-kxq zY1*kBe2eyGRBtk0G1g;>4t8XC1WikW#k;HUrki}LTO?BEykII`B(7Z>zIHU&3&@+6 z(2wB;5sl3N5xRh|q>ZtbC2Jpyn%AZm%hce82)q?mhTS z*)DD&v$ftbh%h#fC|9U3EA92~hBIWU9>0+-6*ejC4XttT(kNQ`4o}sblnN!#hqm_B zVc6DekxB*I5L)|gPaOLSzJH4Wqu=*Eq~N$yJLDGjBUEwOq?8cZWLU|GJ1b;W zR>N^_P%tOL(Nr#@!fU>TzPt*B5H0N&ufkc$Fk^Ta1!PDBfm8Sn3yM5ip7+GbV{W1Z z?$IED;}=K*uS*H!kZLXiPQug{3yNycBZqT_WfecnY|-0;oat720!=b4vtZ%gNr>fi zQyokCXvslH0+=yyLR!2OlDXkix826$H(GaXkjx3SL7f9qu~#`*!QP311S~-vlx|~# zWu{)%Hfi*kyJo=2p86uOIapWv)+#7^SF?Gqprk7%##OD)M2p}}{pvt5SC%G>e(tVc zu-?0d_R}LDC8@Bse}G5i!%b5<%dB1mn^0?Ia%zAMzAeGThRDMO2(mQkSp~nu%2@2S zT8R|RBNZnhKuMb|DoNyf6T$KQ0xM_>t6Z5|)6pk9e9c~b#nvMlbmq~u&K%(I#X{TZ zykRN=^XJKJHVLA{En3GCC8>^)!D+KG2NA(x8E#0v@znV_VoxlSu--%$lxk^Jj)Q0> z4=;Jf0A&0-{SQNdO;ftyu6WGz-+Vs`t_ifCTnVm=k^8lnTAV7FNyavTZMwjp6Z1L@ zF4T$i#E?@z5mEXk;f;hOkNiir$8EI`4(Qd+rw~uO>x1Me;Jx-rc^PgPuCFBS~g@8P?WDrV^ z5r1=T7>&NLP#?&_oo?j78nW?)Ke#{cCAU<>EKkC-|BreHNr!U#?5nYSuVl+oayV>v zi`jA?Pa=ezotG)NgWofDAqCgu)mJUB;9i2yT~WG1-LAah+c_Q0qSo1pV6!p|FYosJ ztt!BXVCb`kZ^W$|9qMc3`qequ2$NJuW%_>Wp7B~rrD2iOk*7&2ma$-%wY_|7c64ew zQfKm6oN>ibjQsTgd=`6kmtpa!?Whmb8xK^hoEbvJOVJ}|MiwC5F#rs)-LK>V_XoGk{xdLLV-Km)$h^)}w6xx#y zI_TyQ!X*!X=e;*GR@|`x>_2${h45m0Ce4>$9=nD!YGlh2vqBui#Qj{zSF*CKvSwkk z&>9J)_1w9XnSs6#Lakkuwv0i7+JLGWM}Vvl$Yu9fe7p1U-CBRbPrs4-@=c+L+0oq{ zHhd-TDHOq9v)OBq4u)sqvr1hno)IK~@@@$SilyYqac_b6E9ak?5fOrU|FwQ>no*g2 zJC6mG7Adqka#-}-AMAJlZ@yvT;mEDhh65Y`ufV6Ra~`br*@ZPzqfX{|r{m^&suSwZ zaksB9z`{yV5&f=y&9U_Kf z5D{F#1;x7I4yC1tU|BwGTD8y*7ql*MLo8OQE4a}Ab=}+ZyeIGf_s!d8{QVq+dFMUn zeeU;OuKT+0=YCSfU5mzs*VBOe!wZk;{V*P&_RJDTF{GUKdwyNfHz5D8qO&|ox^ z0Mu-RAoU*}FWHX;2K+heqXO9z+e%j|6(@GRWSOpq7)x!v5ssM(zXu=0DCLOAb2!(L zJ6^VAb(2!#;e_2fGOALO6c^4LKB{|zgrvA~>3_02f(2#Y&5^Arj6Z+rP={2HQdYy< zC$0n`u9lP}s@)}4DzWhao~Fe9&XAliFW&MiZ%(tm%xg1LLH=6xvmoZOT=BK9{P>fU zB?--LS&peJSynkpW1}6RUy6@h<7GXJPvbxd(J1aQFBC>9(wz8$OM%3Doo6qU~a-UZn8;K09$Z2Z0U}&wzfDi z9Rp2fY^}WX2yaMMIID6KOG29JxbCPli#n;|0l?3r1Oj32F59z%k8{-))?6rOb(CrA zu$!~KL07GT&uo7=dlAa!{GBqX5+w3p-$L7IeSqhLV#S{PNgBf|jVZfQ!Kt5*kCntL zvjSxkQUH@|Hq##AjLBrO2P|2m2|1yB-D7XyxQ`%!7(gaw7!c6PQXV|p`t_{b4-3;xoALG?D|BP9;J=U<*O1XDD1U_Rs{n&poFeipt~OB zg<}K>ABv)|5m6t^r#2k|Fo9|}le+ip6SwwL1f0Xr?Q1&ost|9+w{ADi0yJde3(e`| z$OlcDDGUOr|>Gj-bnB>qUGBA%gEQ z@k~P1#h{UMko;6jKSTv{ALKH-xb~%!r7}>aPBSVq7Mx`J2t3Tn5p)w`x`lff4l0oS zBk(b3?U8F0e9Y@{`zrWUv3?Pbxe5^>kdJiwvTa0Bp%h+9NxxNvl$O;FS&BVr|@cu!sqi6D|7 z@O|@;X6)3_+fDuAx6Vu0%@vRZ2|E z){ivD>wTT}aNAW!3rj5VPqZi6m0H3szz1&0Dsg!R?V6JnlQg$jT0awq@R?5y=RpR` zISH@an${FIXzL$wJB{v>lMUVk7p^atU-J9ky9*CiJE24pvnmN9>h-OCAZ<2uZ_8$m zE`7MIaU2y`r9qBW+kR~tjS8UDXcf9hWMYd<-XE^1E16bdqX1Trg>wI&(c%(*_@>R_ z2n{DjX1quAL0ON0_3|L_gY%G7(B*Q^Nr(O~n=;DgS)O9U%LT%WPM}nV*7!4U#9a}> z*pqS}DrAUI%j8pEKbi*4}O zJ>gcfha_@+EEU?`iG-oWfru|LIcCnO$apu& zY7;R^3gZUmr!|^vYK#8nnW9D|yY@~wcV1;fccaZMn*J44$(~(xAtJN%N&pGlK4c-Y ztP~mfr#Ia~n9}S^zifm!q^w{;m55o4c^)^bWv_VUN8f@6E8T8#p~{1idjqzF38{oI zJv}lSl|@EwSjK3BsNAkq&=;bft&~JS+mkS`OQ$fUfuXszlEE-5>bdN$SoemTzl{ZywvfJd-et!Mzfcb1 zdp)A)`U!?ej}?r?wMfxqh&M|=RQuq*DWp{pt|LV0O_eP@8o)FG1u+B-GsFq?qk4JZ zG`OuE%S}GG#i<7@`;+YyU73q|or;cZTR#e-^=-4AY;VRQ{2BlNU0awNh??4|!<|uN z=`$nKRifSN@F{DxIY``vwt}RTG_0#gt8TVNW%DlLmmmVmHf_xUlXc;tOTby1-551$ zN|3-S5;AWTiFK&eqJ7t`BNqA=e!6qB*Q;z;mGaFvy$CWZjl)%!RIdAwa zynQANaF*C0tO;@)4D1C(;8f|#LP(EXQ#}+gj)WxoQr&a{4}`fDNX}tw(bXl{woNf$ zr}zXJ+-S$qG+z`iAe0MddFNZlY{v7IR;+Bce*XG5?8O1*j)qC7Vh1sL`x|g{Qx#j& zUxT{^-NIh6a-}d+@)Hwa(4;Cp#Ph~nFNB3jcGQ)AQfdG?(&Cv>f9)B_k}4%GMw-_E zpDbh_T)TY93n`EXlpx|uRa=ONG5T&8y~(p({(>R_uZuU`YG5zZL^V`=4(?thFj(1h z@sQ&EQsauaTthh486-@57(Z6%oPN=zpT=|4%2LR8 zr~sH8^|!Ez0=2|e3{m9Tp^{iRLh}&LSRAY3BRO?&6{-NT7|jB*H|?u~q9~rBix4Z% zTf)_l4CLW2xN`%rkMi)w4EFWfz%!lQP#8SxJcindTAe3R;B+{ zy4|KtaTmJ*IG9GDLbFE754Z(=LNDMj09>emVfN!*v`Ep9yX$ib%Ku+9TG(`9i~ZLM z>Um>|!5SwF<0;aYNPz?s|8vce%8al4gzw&e=Bx1#Wuv@Kc~2HFY~}y!qei`S@J@WE z+OoR4@SaZZ6$xtu2_5dnk?sBTm|0a$YLOI$ds7;R)(GUE0KrVAGBg$-FH=gxz3xg} zLJMBL?a+TyLM4Z>p7LIm5Hq5Fj-){D0T+_7Q;ex_8*-&F!z&fE<6PXlIS>MEgy39y z!z`g;Dx4_*T`RhEINy!~omaxXkU+U+B?2X>49mr-HD4lHl*%FHAbl5{_KH_gSxei$ zY>xjtNr5%0^;RSk?fl@Usap3F;{oMH)Lljf38 zF&PQsfHaTJ(z>URPi-)BW~q0=wdamkedgPoVq5zKe!4x&`{&WV*c~N&cZxb5BcjVK z&IQmYh4)R*3M@i8!X1sSoo3f7>OnQ6s}9f2MnZ4w^<`hX;mZWfk!3=d2Nge!nMTtj- zBUXI=oFzZTr`MiRf+IdKU+eh*zHmES6>9l{81h=dQ!OyEw}T;sFqn{&YKQbLOU;!l`)-EohlzH^*Ux4wU9z65m@zAzO)WP!@$ z1eXD~=)6!NO1km3e20+aUT~d;%e4U}&0)*jCG-iw*WF8kbU7c8*aNL5#@9tYvt-~s zU;I-%er-vKz&@G@%npg`YsR5rppyBZz`T6yaQ$^W=&xyB8XWa1|CUP!tNJ|+7_*u z6oJyuBCe{cL~ZRKaqhsEeee1+UPqp+Z07YT*Ua0pX;7PuuW;qi2UH)VWTL(3gvPlL zbdhG;XlQJF_YyUet0G3RTAA?L=v7z)s$bIudYe~wQ@6HXH|&?e!+ zGif``YZh%mZTUA|@QI(|aZCBzPt3cdi0csD(gSzxR}@#H#YRu$qz0t%+YvlqN#>q_ zUI_VAMoyIz&4gWHfEWpb4EK9nC_rIr9}EuDosw%={V_kgoI@r`TmC+&vLgWMp9S{k zI6MsXfa^oQD|MJz7tPu{yNnra%i^D6^auE&Fyon3f}oo&J_ zVk4p&o~p|-nM+}A0QS4NO-MGgI%OE8n&6c>k@Olvs9*^(miG<)da-@?gJX^MVz{KqcBK;U^|-&!hfK&)RRqdsaYNc*YYKzi(2*WuWQ#h; z>9p-e98_j{DTG3X+@FMCApu1Fd#VUP4AE%m*i%i^dJv%WxzahC09>LiUZ#L|oG^4J zM>^HYN_cjJ#L<=<3FB>Y?ng6v9!yK%m@;sUhmAGa+<6g;xibqD@NY}&XClVNX!_|H zdbr5$1($k&lo;anslVhKb4|MZgIAs`ql3$8DW6kKBJs5e`&1^IUF<0F=MYjglzT^q zhpVuIZ^NA%MKv-ef~^4V=taR8+38L)jY4_J^{m+F?m2CO;ojtIaNmNkajZb?-0l>> z%~3pJOVpWmzV=s7mTrpQ;Ay*4ncFif`(K`d>5Ldl%NwO_F{8HJsrYKb*Jc@@ObsH( znptFCdP@D?4%mcE>!R1yi@9QqEWhZRYw$p|hnJwJ&+FppsW%~}jgQyQZg%$14vsm7 zqNm0bJY?~^F)w-VWTnXV*SMLuAZe?=olx<}KrgFX1FExFsr`;*oLM5h^0T0&xIde8Ql ztmn~G-OXLREzr1OnXJuS`aekb`0L(r-_4VZkYy(to?<6d%u`^dFIdZZ8f(syZo4fD zA7uvM)@}s_h%!P4p(6xBD@O)`Sj-)zY>l;6ZP_3p>S94A zPXwINg0u+8myB(Dj76_*70uJgt#Q-XH!{{3yGov<}OilgP7dZ(VO9eu5OS8(d|)I}$=W5~$sA#@!2~%Yz4_c88E} zalvIg0z?ddq z>&AauMWx@e1`fp_{7{I?8?un@C`A6mRp_o2AH3`nR3Y+&-9kC6LLoOi(A+zYv}ts_ z6(E*~V+y~!CST4Ly{b z3Lz{JPRr-770@XSv>=k&hcA2j!|;TqEv(;Ck%)U~&CGTn6C}UWaS8$5OLG+4a2vz$ zj;%^v8?VB>8@p;q8ZT)i{>lwDFn6Iv;Q%|C@Xb-Aa1~Ksa-XU7IW3WR6#*t_jV_vf zIVtbm#jYGnPPp~ieEFqYOz&1naDLq8*=g<^U0+0V)_V#<_Z!B2pb;KRXkR`TJ4@hbF;_qqPchCE{ z_?z(4Z5cn9kHxRT7onaG;4P<0s3|8VS0jP7ysv_{XfcIBz*MFne6BCx+OM|OeUA%x zXo+e6FzN9Y9CXy2t)Jc=$2)U(N8=vd4>j(PCaIE6Fi5(uqfF&}z_Ix>IyYqlQfm3| zc$l~O+7zLMF8zDBPLXCPY!OLGgC8H$Tx&9ZlmZHEMEKc^@fqeHb9ym4{s zf`|X`lh<5wik&LLEED~+5gJ+c8sCc}Ix*v&Jp>g_J^oAFsz^4Xnk+s`Ewu)^G~e2* zzcTMFFEtPMXa#ZF1C;&$VFCFppU;6To;;R1v-{j-c zg+EchM$W4d z73#{T5)2WzDJr6;<(j;1y!Uf2z#3|`N0b=LPma307y-r42{ck}SrKGno3!;lJeaCF zk&{43Bu}yw;v<3H#19@cV^+Iaj%=tYP^xey0mL;MV@ckGad79s$4^lhKfq77$^2Y} z!Sc=)^dZ5*3ujd_+r%i<1~}TW(MfFQsA4>$xOr`y?0}a{rRMZ&_W&X;&Raw**HiwS zOO~xc(%S?9IqNQ#L|-9Cb_$Yk64}?f>{I{zyp=SRCzZVT`{r@2@4$D83bcf`6s@=U znjrzhwG4Bdc;l&uW}O0@ggh|lBdf2g%_W*fM3#Az;HuQiI(471VKlLnabJ4DzCR^- zUVB`Lfb2M!c~OSf;X8YkE`X;~CDoXq2Og`xlWnz{j4N2SLr;>$D-ML9;9f)Nb+n-T zk;)%V+TgTFFnTWZenCpEG?%~ly@zh4OjeZ03^adno5cCR(JeWYbXHP@2j6y=Y_)<{m{nDf( zYOI@Q^o@nm;wysbT=wg!&)r1%mCc3wwaSl;kQk)5tLR?X2#KT~?_{Vk(Hz3jOI7>} z-R@>B#i;g6Xcpic)nX}Y`NXP%-(hi7j}M7xtUlTUP$G3$O^@xI8OP2LCDN2{Av}VU zbFDh>?_YGE@Zn`r`OW-FCHyHg1U+4ND%Ptq`_K`dG_j~@0<;9-PfiS>2&>Z~p|nJ+ zD!L3AsIl7ve7Q^ue_y6bZ+>21QS!3Y?Rg|p8>-@?itE8NiHG#O^fZ@$nu{&-| zl2`|F1EcSxoq#$f><;4?oDF#%xoGlJ-NThlHpHzSp-TJ?>YGI=pd(p#SD`fOr#UMd z0EN~B*!0Z{Qu0;|^Xz=pRh?JkG0SSm3+?Eud6CW4_|A;l!kU!t%WN;zQ3C9%`*IaR z%x5DiICNrwoGMHTLI0c6LDH=%5+@g@2wD*YktE!hdFKF{}m`S ztsEZTl93@^y6+NCCqueKY*1bBbZldW57Z>wt=J`V&&^*x%n1p#-#^lAEnG0)lDPz5 zoVQ|7T_pVH$K@JX>s(2(<6~)_o+{wXQ~`%8TPALqs~EFa>?bS;&?{#740m6+chu7vyK!Qac>aV&;u?MI%gbN&K*O8?E@9qSUP8I)Xfbgu`l6~ zvPvjn9yGv4R-1N7=ti?kEUi%H4MK8zQWFIg?v8^n37v7NOx=0t4`kB!SMaP|3F*Qo zsJ5^owiVmjFgs@DcnfWZajF&B9H<`p$1s+o+S%=A;nsdEHa~30C`3g&^s3nVBW+Az zA)Sx}iV`J(G*k^F3(J}!d}SB^^rq)=)<*3xe!5q7{5-Dgh4{Wz+Jdb)0)k|6hFFRK z|HN9^{y_Yd@e=7Rx|0N8WayC4<3fEVXDJ?uv*GGyOZ*Cezml>c7S7;^hH*U~3@Xl4aQ*+X!Xp{ zYDni``bsJX2`S79lekRC8vsr3&LXV_U#IsCmelUQdFD*YkG+B2`f*Y&KTbB?(Ar-- zMQ|F8ZX@8~@#_j6fv4ea_MHVqkOg_6yoZvVp9tbqi{k3JJULHSiqjPR%GH8CR{+DoyH7Yl0JmOV+Vk?rDyl{Odb=c0gAz+L`J7ZG1(Y;2C%)V)-{l8veh7peL^2AAQl zan|~Dxe0>wpBlkwz(aT*MB^$Z_;!AFAae#4EmW#Wde5Qsr$9*VzTA#a_*3u3BbN2%Ec}BMua2rrUXAYqw?YUGN2U8_#HA|K4udkr zc#~{NROOIpgj*SeXp&}+o(v}ZlcIVCgELFQD-b!la!kGQM@u-Ixb{2vM|a>pRRzHW zXB+MU^1%#<;n~>sz!G{JSe`S~!0T4xIM2tuTbx9&{yOOlpme&ONTfO235KE%z?;4- zBTC>0o=Eo4Ylk~fu3-M8N<|;#ve@y3*X-X$S@e|1VwuW9 zMlC{feO4gZiy#;8JK`&GFqxvYJ)@k z^cYHk=Ezoq^uDj%UVHx)_=2+iPz#sqqL}jIeWL@aSzps0$Dvet?uce+UTI*93a(V} z8*FAsS{|MKIC2Meo@&XUaS$1WxklMTv$t4TnkcEHwp0(YO<<}n{^!Jb@G8>wL$ni+ zOzi=hWMy!AX|X$j-Nw5lE3*V@YI=CtAJbNzRpM`-J+HF+TYRf_U^p@WRye@3Y>`J4 zT(D#U`uaUd(z>oWlPphEH=H1d;(vF>TBZbH5prNA7PSD4g_@FOttoDiByC)57jD`k z?QSLeQ5M>Ha;kDTI|rb5@8DS04oSLVW`tK7yYxy0mAe2p`vkqP1=jqX8`JbC#Vy$( z1&@GCicZ_|ChUNge-kW(uw>*cL1ESv5tS*;OEM%VGLJJEZ~WTDzYz-i7kIjEzhcLp zQ6Aetj04}U9&bTShjSC$Cs!J~^-2YKbojBdJOQ+_#_T!Cvna8WBoe{Ic9SskV($>5 zcxsg7jjD!5PtbQ+AagaSedATCa5zM4Q19^;2Hy&zuh24f z4emw#HI5J?<{&QdR|$_$;G#6O zbt9H!{)O_;L0kt?3N73cUpjzGAAB$z>kOOLB@b5F(2YnQldX{Y2K{2IT5>9k)gI>f zW$xFq!hrj8N|YRhOX$#@3kF#3Dw|lbaDz&S;6)__!zGc880u2u_EeS9DEiO!S_Nym z9Jd#;xui7KJ1X*!$io5#3tK7{r$&|F7P=sk1gqw+rAa~etVZp5sN`6lLu>Pl?C>y( zq}am}yw`!}A9FrO`;?ssw{Tz{Y>zxKS0I}>g4wkY+J5=FxAQ%f4SibpB3&EfP+x0$6dSke12_pd9b&_{jP#6G8rY1FD|1-i z;mr@6X&soUor{}$g~PK;zJ*@k~`aROkIly{{b)NK4j3Z;T%$4n}a02d7?^! zZ+Zi_xFaw@%K`E;G@GS--Z`b)4S|859;9>%i0O-?4AX< zeAH%U`|2*ihY~7Cat_LADl@hL zaS3v8bHTqB(k8VXm&~PaS+ZdV9V54zciVR>IYwl6lhMRaP$K<0)8J{jMQ0A6#3gbe z?gc}QK&Jzy@($7@mTWZ{UUwbv6rRmJ>Nv+&Sb4JWgs z+uD-T_Vs~!Gl+*Wi0PLrk7W90{aCa&#WO04-ALdCTnR`>vX)W8)#Kpj4qtgX)uXRO zEOrbC#j>T1;gMq)wE`6m3`R9U=KzLkPBsToZk>yod}~Ujaue=d8xS;4@SLSrN05;m z+Pww9AOm=|LNOH3M#8A9tpI=QZ*cnnrb=5}tocObqLwE-loy){_gJI2CXI20l&_vC z=`uXD`!P2^1 zYs?IhD+2`((ppcO$jKM({*(>AQHa!)3$V{ZO^o999DIvyr1K&lypfy$fcK;PB^5A{ z-!8T*&VJsbKS!~ZY))U84Px)bu1V|$t8W`=qnPheiTjL*IT|yq=J=d6@7uqtQd6Eg zI&lr5f{v0t%;+{DL6zJIw#x`G6)Z1SECuUrG7&;J71cte3;0)JmGI5V^*QxMW7ho# zd=oB;70>v{)O{31$#lwvuR2nLR)X3ON#q(d$P04_&Mpg1D_G_3#miyw|7IZA6r!CT zg(Y%3GV4d$w(E6|C`{s=XE80a9{Es_n3Gj5g=Nos-1$$V6rNk+i_TXm9EZ!j7-S3k z-VhRCmoLC6eu<8S3ah6N+H3^kk=(LY4vi{H;7r*hVVs=8qkenB(*@NNj!Es$T8s>y z37}4E0pO#GwE?#gB7{yt5jwz@=i7tEsuv3#w0hdgoiqJ_B> z=b=q3{BKQ&gq4whSg~719XTzhrT)kkbx(lUU7Jj*(xUWes(LxVQqIS6tn5Wu@?*zp z;9m3vu>$FpZ>%zu>>=P$#>L8fW z?*+adM$F37 zyd)D{XBNy|-ohy33!A_ht#mBv9C9!Z>kSoPwi8Fv3uml7O@%yCE1B>`}2095Ihg z&Rwp)c9ggAmrihJv^e9od;l`90D)rB=5z1qdE0&5z+d}s{B(=(ok>Yf$9UzUlCaMY zEg;Ro#t2|2qHA-gu^&UcM&{Jg?m}eGrkDjD(C}{1nO;P4S~8q0tg{J61MgY@Eu_&4 zJG->qM-n&v*DzVvppoC--FOEcq4qQUbT2;}+Rx=9&*Z^9Ls5ff$U!SVFEl`+VQ97v&r!I8pU~QgwjwJcz@t4*Wdqg ze1F+dW(#dzznD!2LqI{uwRdwL!%PedIR&>4Bl*FH1Mj2Rr^6COr7VatXF}*ywEQ-9((hMdswRwdsb;*19ajF9~ zHcg(>jU31_fw0Y)NDBY_H7Iy<`#JW+^M1lM!rDFf>9(H_srz8j@pKS1;dW^^dl2I$ zS}3v3&TVId+YSB2O5fy_QMmz2yt7n2Cb>>lh6Z68()a*4N6$evRKOmIQ4Kg&2yzZp z+)H9^Odk#}x$XSzc!W}jZj-j>fz9^S@5dJ-VZ*bJVhPMjoI%Ob2~E`C9OIR_BUKwf zu#mc0eoI&0m=j_J!tU_ZPkir(x%?F+_Hbp2xGPZwY>ggyJmiVE6|E@fZb7)18?)>&{($zv{jA;ga@D-b?}hkAxJCdDY(b^!MDw2}^i~(n z+yplc8fYbPn+?&ndZGDL!1k2H9sG~ww+W3>#`xQe^~d5-R%+A$syGYC2#j4+jh}?8 z7E{pkw%@K+h^+*@o2=`t01ybLd|XSg`pO_l?rt*)WW%3Pk<4E5t}yl^kO+WWTt8BV z*FrQS1FcFzuA};;*DJ_k z1Rt?An@%L_bd83OGmNPWn;DL9gI?BPPA57H*(Gv-t|f9cg{8jm9pAh7=i(wyD{&Dv zJAIxN;3HUcuZ1YcF zNR4n%jVlWa#?W?L!3k1wrGlEg6*q5`Rsi(eM53StQ_~7sIomshPD2bq9g$u*i@~Z^ zf;)3L`M#rqDO$9JAJUJCN&!w}_ZtkSxMJ-*=E=9N$8*-ocFNeebg8E|_u<*Lwwn7f zH#R^kb6UEY#^7GaXc9*gPRylX7@CKS)Ky=rL7jE7~E|6iX^o>yHT(Mi)3YXM6~s?#ng<}b+kIkQ|ZRM7oh zxObKH$Rp0uPk_`BJSO>n*4`)~MpI;&113&~HGJoY0N}IcKgnvOoal=@{HzC^&22oj z2bM(QL%K*d4(lQdY&wfMy2PqnI%|4c;p$u&ixq-UNF~P&K&o9^Y=pYYbj!$I6qG{; za^eemFI`zinn*$eKg^>`P(pSI-1W&{JVW626H6rU&nf{<0_}rsH6v6ol6Kk$utyMQ zL=2A2?Mw|f<+tNzETGW7D~%Uian{p|1(5%cj@7(MP<*KwWQh#7D_1iwfDcpn>I{19 zbr$P!?#z7MjvIb_{W3gh=|~+r!+`#O)evY*@LtBmi^olG=To|atU6i!~L;2qkyna1PfxB7Wl z0=aazDBx8ElW7B(3C=STR}~2kP>irT|GT);*SzKhXMFZa`0~;gfG?<_JOYhCM8_m#MHAPQuPA8p{Oz({9){l!w(u}GczV^rQ&-*>F!I1;oh zA&2$nA=TP(5%iLAyhwMU~m?Ui5pjXV0uES1(jzNxSL3AlU)d46tp zMWLfpAHY65I7GJqifYeZyfBQ<9&f{~RT0%RZr;qUOe&@JJjrvy>H+<>Yr^UKvIOFI zw~Hz~*c_*tB3XZ~c?Yu)V7Rn*;eax9MuGNH^nd zW&e<9>&us_tb_~e0f$>fKy@lmA)}ibW(gM=cL|u165Ub=+MWh<( z2U2jf&5$&rp~HtovzlZ8x{tsDzl(6ihadIVkED5)jgw zv`IqX2s^;BDSsSOiYis<&cR1RU+9<3f0#h?Wya7GEFam7=k@N$#S)=**7^{>OCWOC zd#1u9Ge8Qs2&Nu!%PU@p=ctt&f3fgqDgq+abxq>bHLcDhmFAqHF5wa?4tA*mK6x!Z zxR2mc_#EHrmOH2X-?f*MZ@1eUxf3Vi)l(|=ZGDMmylSBp=%7MNMKOuQd zS;ywj=UFH(gHW~u@X0>nKqo22!?N5-D~KbnSfEoa?bG%z7U=q%qV-CZS)h1fdTTAI zn4fkjOub?Hnn65FX)(pd@rr7+cH?BkS<>sR&P>!9#Leg>GV8olK{fsi-%C6KJI(+n zU#J;`w&etwnd&Nj$1kA*|llXY~iQn=lW zdzL@*I-e`ZvQJ-difoB3nRL@*gJYT1tZM<=;LzWRcJT=DJs`ZN(Ns4*(XN8%-hhvE zHZp&++2blO6TG1s!qSnPTveRr1Fkdb2ohcrJ(yUaXeRgcE~*QBFNS|yCI=6G=Pg`w z?HNa^RL?Q$I#|J82U>R&ot^d7o#r{%f94LAJo+BHh66|CS_QND5N=;9T}(>rByu<2 zD%S~)D{%m-PKITH0)s}kzuZ#b!NjXz;jHW@Wik(fFNw0aw+iW8U%&x*EPowjO|K`OI(&?ELbtU~OSvI~n0P!Y|MaRQ7Sw3Ous$#bfy0AQ#yS|yWj zgd5Ab6JgKd(-@6i(R|g{zW#=flg+Ae5Mme9?Kw_Y{a{>Pi=H~y4*JyQ1Y<)3dvdsO zs*2&fA9ruZQv(6m+fL8!I1~Xlk)9xR((z(hu9;x37>y>&%%#N`EMH=YLC%HNmiNqm zMLw<79u3ff(wuT~|6ITR)LuMv89wWIgo=m|m!-P;meI7k^91}-M!|wNsj_F_Jlq%a zNCInFMBz)!Tbf`5B+EI{g~dBVV2Xn?z{Ls->;e=Mk}2z6Cs2_*A?OEeV}diG{V4u- zEm`)ISG-w*@GtOa-CFV}6#?6pRRowb5d}-OEvpRp+X_B}uvA{1rTi(|PseAW!c<0Bw!R<%FL-N zwaJt=#TLYcV!KlTjNxSyvfzKIky$-4R3tEpG{&%UZsp3{=9s>?6z=GG*Qqb16n=@H z?w9{qm4Z0N=8IbZ=ZjHwjX=W8WTrjQ*gxK!#`e9DN}hrRq{J5FN)HN4zz89`fsc){ zbHhZ&u#keNHggymAOi$M2h>eCEg&)c#e2m~_{tX?bLp)NlV#9kJ8WQ1YTN>yCt3_iswXe=zCO;}qvoB_;nhZDz^wLvfrq-}>Q_+p#l z;ZXz%lJzgc>UD3Yul~w+zUjCtx%x#Vp~1%gJ`9)F0l;mYOw+9R&c{Y)*e#0^e8s{6 zqk|IPuF=fY{a8H_Li}eSR@M>W%F+tW03!2Lp4BpvJe%|MJR@Bp727AP%u?`e=080u zTXeW>V%?i%^D~FYbz6rG5q_LX2^-uYs(w5bocP}1C`COPmv#IXGFZ%kw#yZqB^wvE z`m|e+KNi_~B?3U^8sol-HOy7a;-)@~iE!*`Z0L!gU@_Nf}xFbN3 zSU;?tts!(lFsZ^GVG#wbEa()$v64d(xD=YuA{y~yP$Y0x*Lm+S(+BVV?=v8$T5pN4 zYzp(d3yY(*`lQyvvRs%hYu-c?-k>5CT-78IkoaL~SxKEBeluM=SQbUE0&b)^K>3%1 z;{qMe2oFIqI^eZ0VlPRwL7J+Qb8rD(@r=f2Se+?5Q?tkB8M9QluHC`ene~3`t(|N- z7G{xjk6dU>$b|}4`zqYqXH`w~V5@MFyAk&z{Qv^S^hh`yE(Z4`L(81m>_+_z72J(N zV2GN7AK8dpr&vTud6P@x(9G=6^YKt+lbw4`QM(gKunbb)h@+0$dTbi8kT=LX;h4MIV1=HNOaGG|*o*MJ3jHl5l98qD0PryqATrsd6ianZm>`y^5mWdNXjHW4@XK8)S3GjTTS!@# zjeO{NYEq>2ga{lk+ktR$lNyr?I7N#WDk#!T_|7$ANMx9$MZj4{`XRxM2!sL*bfO<> z9mx?mk$~RhaHMSyQ{RxK%e4xUyb!k=_T;jm zKyuWGP})?h#7AYqw9S3+VdAi@<^m+4k&qw_N`vsHd383t-xw4qwe4hB5tpV;aA&AdOe!*4~J~!Z*lcGwuUV z`o7w*4}+Sz0Q4(yT3dnC(C)^U0A{CSZcP+RcJ+Ps6pEsx^Q-5N zRY91PuODfS*ZVr{;X*UV9+pxX6YYt1rJU@qC7@n;4_>O^Wv;;8E4?Gy%OUO=@$}ih>SPY!JIGI0Sm>@x$^S;S-(+}3 zY*nSI9G@N#w6t!{p49|%ScKmMQ~px2k8yF`anFms)5KGkO_J}iX}3|C`sa@j4jwr9}&(3CFxBuUqq0ye1%a<{z6ZhQBNpX8(YOa8nI1G z`u3O&D9~qlJg-kFwh5O>A8Oq(?D-X0B+1Bpdd4Mj#hS3Q7248VbyJ9vF?9Y5WKS#JVDsy@)2fP$>gsOs>y71ZWMxN!q#ZfXmJ(lW}k=H5iu zc{z|U+CMT2v1J7GG55^S>Py?%`~EHW;JeCNgL?Yr)iN%|xAsvz!7O_y&?mOarKLLo zPZ2XD_Z*F_JnBplo}`j%_35w`d@jRGVfPY~tz>Lsj9%1B2N2XYo&KB6bQeFsPxt#? ztwLc*W&<{FptYyX9x?zOI&ueH7yUuLdPi;9xoFj$W2@x|iY zQC$p6#~uWUrM8g7q7>sT`35<|TAK<@F$54Bj<|en^Z0Lb!AnaZXf}`=FLzY-BO=S6 z9vPkTfXT$4KDEK}uU)HP*zd*d2wL!OLYyVl$LgeO+j=^z(o6(yEsx-tj1DLLBoj2Z zq}(|7p>FqP9yEdi`DbWdn>B)OFZ_+G$JD=^chj#atu-amvZ>rh-xSzzv^}M9LcAHt ztq<)s&d8RrKIT4>aws*B73wuO=!{2*QE%X(Ja)Wx#vn95gJI7U~Ryr$m(O-AbSC^)u}cckoY(H(}M+pZwjQQdnjF zcdH8PcW}8MS!kF0Wn~y#OsmsqPLH5Cdg^dz6nmj(Mk=}DCO&0APAOr&=5)9=P`VE; z)J^eMR%5ef5i(b1W|?f1@YTtaw$^J;TJT01P$`A5?YFSj_u;$OYW&Pz5pY(Pt684`~hp(oHg7!y53*(kQSlkKeBIpB^@Np?vhe1kT>sC&ZWJ@47pl4DU< zm3X8xRba%bzR#o=8G4Z4%yy<)=o4t{YobKloYV1Y-W7inZl+yesw`Z;ZBzGZKQkUK zg#oPKNz)`T(B1H9Gd!%GN3~}k0(XL9!e%8=tW_#7k$~Dr2g0ZKronICvzfRmpFRkt zTx6^-EKSx}e#%X6lZ1$!@!e7XY!%`H5h8lw(G}liW#nP-x`3Qo7#-cgJozd>hm2Wl zIfBTzO$1&;n!`M|)x^$58hSr`m|pygLilLnvVBQTw!i?vf%BJ$o%j#SrfHkXotq6F zUi#oS(G1F_BJ{jqK2?f=ZleH!FdXm1vRLmgo<)Hi>Iq;nR7m<;xH)!eko%=Rd1=IV z=-1CgPk+vFDYPOJ0Y^R1#&9Q|RI5%dMLWV!O~tZ!;p$XESsk2Nc7B_(ESdJzvr}bB zO0>TPw1YLJrXDI4fHYJJs0y>n2gj-?6{!d@3EkMJbX`{mTGoyedWO~(cy11qu$l=rYl}-PuQ`A6A@1A= zQ}Z&UzGqPskOov!sPL(FtZzL;`Ddtald%AOsBV)?2Q@^j z750dRoRm!bW@1oWf-CyhJZ}KPE1OW*Gn^|L2@1~M_6+AqxM>g-;=vZ8BsTrD5xFY` zO8V0N7^DI9aWWZY8ENTzIXuG3%$&u;Hchn4nBD zFH}&rf53O*O;20N&OI`Rv)C9CGd}B_)HZgc!s?O31i@P&nGxECh<05vsC) zoIxwC13I(l_L)-Cj8E*^S$5;AN7md=$(3=>b|!})bzlfgK)?pzsO7L+%-z1Mut}Na6^S&JF!Jk1t=0zGsgnfg3i_raZz+ZvTSaohK*513W@!dB=i7a+u4ib z8m)MmnXY>K2-prTKJc$MY@vw0ho5dwHm%Ba^hGp`FB=#~egspKqC$jh#S98EanVv( zX)mc~Le(0U7j|UhCGe?$3f=x8%>`*@-FcT@@*kIRnPtV|b21x3_fiwdMSmOfLfqqs z4e15c%yFTD4ZRcJxq(b6wyJQpmevX21JW_1;v_sRS4=51vvS~snk-!w`Z14yJW4#% z6N|>=jc)G8j9yIC?D9d%qH;q32HjsCbAP+5KiTNS*@bv5U?a$pki+$;qhMm~HqWM7v~o zGNT~;lrYcrzU=SSe2nJ9ImwnRhL29%g92V0sb+RH^_uHi4AwPvXLj4wD^;9y>ir!s zM7^klPok%8?_}E6TF1o+Tx=lJ;bLQw7b^(#dfcxWte58~y>z zE>H&4Q(b_+H7CR()Jj4s>XzP#e3zK#5E*tn<}?6!>`|ZkX`MI1y7l z&80(u4*&49e;1tj>=HY?FggCCECKGU-JVm#Ow%-~VOh%l2QLsMB(1zk*;v*jy)o%( zB;oS*1&S+J%5s|Yug(=C2^4Tj;~%x!u1i&%0Ho}8$v|qBw`}CiKRS$6)J`Z7+(jz5 z2jlXlY@kdX|Gf+6ytN0%8tughLX+)E)XQ6O|5~Cyh0MA_Lq1-Sphxk_e2cx^<1NW_ z)wO4Mhy5IAgGRCrmgRunP9rjWq)SF(&7hed#Xzi@#ZRep!Qfpk=PkeWmBNTVyhJW` zgo(&ydL()e2_Te^YT`Jl$x1zUufx5)kg3Q~5(P1WC1nY&9X z>x{BMVufsLhGeiBleDb|r^nzO7iA&HMW+5)IWVk9T$Dc>^fLN4`QYqc$l|jYSEgR?Ldgk?qfR{)uK6yttyRSBz&z(#K^h0cRQesgq;kV#UjNs>gIFn zeh`4yYm}LYQ1}e2N&**DF}1+J?-h%?nZN*I|nLEGn>Y(EAzeLd~!#znw)A?RxvT%Ll9``H1dpz zP~r^=7;z@usT?GPVxjiD&piI79y~zV;j%s15hVjh`-NYE?*yNKCQmY>@}ksZ>eDM? z@C7hOfRhvQ(2PRTRL>F;PGMjIrGbw$>Z`b0*>I{u<4i8lref*iwimwtSES=>WxG({ zt)_4^)!@VUs@{|%>RNMf;KG2ISU?t)G3r@KR#))|Aj;d*APRwpvW5R}qELkZcU+7a z7M=l|ZTGIvNDwIL`ZLn`&UrUcN()OI#s^eNESGH|hk<#PC2h+HBfRuKXj>+$VtWD{ zTA9yf+GyQx+8L$XPMY1PLP>PC$;5nT;#t8r!ea}M285CmX_5;Oz?nOW1R@f1m(jIL z#{PI2W%OPAbUPF~)`Oac2|~Myry#NLcFse`zCwczirSBu3n>d^YkAQX{V zfei~aTGTZPGXWT1h)7UOAU75v%on-iIdA^jUHHPYzy0CADJz=3hSoLaIHqL{fjNCNm%E@Jf7TA8jp;n*L&=3R`MwQo=qjnSdn3*NZ6 zb-}}b_{nQ7>9M0c=0glG#Mkwb5OTlAm#e&-_*|N~@6rGvB$T&fGvaUA0vqYD5DX4v z2_<}aJFY%$&5OCbk~6t`?4SyAnmRU&bAGWwtd%%T_Q%RGu1DPV534A=vS#$_ zRe0iKkJf?a-rw_fe5beS+r!7?NvuLiupEgyhaTv`{VM}z@)kt8s$s-zC_^Q?YBEEN z|BQmK7w#adm2${48O%ZwgVM|53>tN zTg=RmSYQ@vHsQp&RK5HaHQ%h~&A2ha!U}y;EEdqAl|0Hi6~B#?%#|{?J||EL`xy?s z<pa0oRTWjG3%@rp+eZG8sCp6-!wpOh9}w)7nj_wQ{f; zT5(N+p3|D!w{hNXALs4=<{yvXOUou&_S~$?BSEsYISH&+IJ1@Afzvo93N1(o9he4N zCBfZ^n>|nWpd)b7YpD85feT$oHAh$oQjm{~{r2Jy5e#f1qRU-(O`ga{Eo~vXW&T$9 zUVP>D)E_rzSXmMPIYc+zF?J&%~3N0gk9VEYeZZ0#W zmW~k9wvT>nJ;k)5#0l8Z9V`$+1u&*@`bcoXf-AUk94j{27=m3kCo4_AI8q}ODmWi*yZC6S06L0h4^cMJtp0Cmzv27@>%yeN!7u-R+WpcjVp z_2X|~X`;sJPB(P@jH=mu%1_8>P2w#YdsxiTHtMK|NbKK}imKua2`+4E#Oy=K>BtpZ z*{@)Rw(lsF3bmosvKxq7DQ+;s{@tO6I2IFqSU`q6Fjh+(oIx^3Z{;L{luTTnJDxjz zp%lu#2$^=v)6T>ouGt2Z13<>A?2-k3YK5xY5S0#rpM>TN6TJssL>9m`p%fi**k zDZ(;t;$ZCrTT*TZ6vT{+);o}f`7^Brc}X_VuN=o0L5BQ7U8P~TEs18$(~g6v$TEP!?^gg&<`Ic=db_r z=RJIsCDKxNbn83{>IQtLj)>6wMkY`q;k7hDfmq;##Cc>ZMR|;Uz!IS;5RBmR6YKk7 zp_o7g8w9r|a283Y8;gTMR7&k+F>zCX0%(PVkP*p=CEdzX1PPAhN0n%2;LMsTtt_zotj3LOKdCXF>h{QA%S@7#MV)6X z>}ki@E|gVsd^fOSvuYVgWF@i5_h|?!gk@<{0>$P;TpsJhc#0yVQ#P|sEgfb`R53{e zg3rLcU^b=B;>`;n#N;3;DG*5!60*V;6}%cLSGZc;^_sJl6Bh%8Fa)x8aO{ z7Q)w>_BaNAy9E-ig81PT^b_++1=S*{v8qVh7hbh!8Inq53DB6LLh)=&W3$lVr`)Od zX|9r&w0p>S61kEI38=wnAMtvyY4LOUUoeDbW-Yz`S@FijxBRXLe04RgvgDAMp2PDh zK9*dzwB+~&^rxG6gd3CBZOS4}3@=@%VMR6@@t-L^!lG!8T=ip{Q)8kS1c zTP^)a#c*Z*Wucg+*?347Snc3h_k0{rUdk-mp+fVK#xZ$Mqe;YkvO;bC=0S}~BQS8L z^MztD+THH;q!dqu9AfiX?gD*Mg+;=qO~UlZAbx>-iHl{)RlCpq1;w(i#ASUu*CPys zMozPLa4hQpP&4F}#xA{5!3;lzZ;hy=t@H^ZYS(QhDUe=E?ToeP@V7}F-TU`tk)}Nx zZMd}bva=$Qf~U|%`3taI5)eG~)HoKia82vfvZ465oVs4V<3Ynuqa;fX^y;xwh}5AS zbxFP%-@3te<1%~5{D;^V(N9izWKkY2&PQc9oo!i)n2`KK%@cs#x7G@#LU=Ino<2ea zoRUS0i}m{0tCvzVW%RY3Iy6tdo^5@|LsBDa4&NoslA=7ZvOHHhRD7W*Y<;X6WlHMMoW)m!fs%7 z8%{(_VdM#-foz_WKl{~ynnpvLiKTXhe3I9dFe=o;E-5f*?eET6KHwV1DF z%(`n{5QU@+^ieAL%=x)eEO_Vl?*0pWb7{rsr@Gb!xV&w4KYYaoVMDP+KF99tT>*+~ zpzRH3ZB%Ic;047krt6)JH&mN<83N7*aT z7Iv4$6<_$~YN;@kCB}AU)=`(nM<9)U-}gwi5%D+5&krTf*oj=HQm_&$M22%sz> zrz}H+;8inmD3a9X&u>N}BfsHfvbJiAKB_+6Jm4icU+}eOfB)uQF1UmVSoBC;Fagd{ zni2e+r#x_`bzr9UNqpo=ZK)O)DRjS@OT21r{ub_5_N1eSOPNXcu(=q-{LuzO`3ax{ z!RxUaBgME&BEddZx&JtTD< z6$_Ff2gz`&EegsxDvp$-7@-&rM;HRG9@{TrlMtF!Kr|B$7}F=v3YH2S3U(=%C0}7G zPVYS7Iad+?)#!}7;_@Op6NUiB8jAGL0GE$6*vTn`*dNK$1m@t2zk8!fXoeCpN<8p} zr}zZWsu50Yk`J=Vl4V!hY$BVKg5=l%;;Y@Vtw4K{GVyqDa-|r!>4pao{MSnMyexWR zvZ=GtK-En|a@E7FiHT-oKZYP+(G|k;`M7thw4~?@4qs_hS=fUNx{$+fH|SnlL?-hV z`T~RFCaF~PDiO`tkt9FdxEHR~;Gv7+(nmI4dJ{$QCnffAvWkMqXCEj6yp^q^XqTTX z5RG{8xWXx~yfPOZ_>$_tmH605|8g%$gV*+-Y#O`r3WYz5##$0t5lWCg8sN1*7V^zS z3z@)8Nz^(}$iyHi_!zpO{I(SL#0eRkUGmnaevpl@wLdKp+9@iu$K&$K5l&A=ivtcN zgb9u2`-@M(^}%$V=XuKYISBC1Z7M*9@QnXc@7w~LZ0mQ>lG#5wSZOv)piZbDWg2B{ z!;xXy{WLI7a6bx?)pd!zx=)9u!b3$pb1XyZH>>x{=WBP71-7IfX!0upxfXNoUs{{xLM8Ft>Xm_ zS2kP=Boy*C2`xha=24I9&6L%Jq2W+fS87fyn0Fj7@@24`7hqkR1(~Q?AtmP`FMs0s z|F)50duEB)PEC<)E1cFyeM4)1YK3Mbo93?@tJGHaKmn6~%plGa6 za9`G^mN+lilr&{PCsJE;LeaFUlyDZw+9H3=SrG~-!<9vVbAKV0Ye|liYfm`)JlT`> z-&jevvi*@tjS;SQlIK~?*0*AaP2?K%^_Zc-3yo=Bn1kg0<9wAIQ$PSHpZJiIip;A$ zv6PpcX%m8Buwt5+dQr}SH>_|iYL>dkMbt97Qc}osTifxtgMW1lo}@<1+`ar~=<<&u zdi2E;ac$Oi4nt|e4|t8)YWZ3$OuB*)C%#GZMJOB_p{u zWG_hkJ-1xbnZ#t_IR$-}1%v)}?c+*CQP9P^5R-inZ&C5Z6^U>Z^LZk!-YLw&%Kpec zgx^x=m=Lgf8OV-kN`LLb+4-T7!@tC1)&2uN-CAM8-6@<^L;JbE27Tlm_l0T}E!+&vu&%76u#pp>b11>0K!oOJXy_5bobZAV4^QC9rmyta9pC@< zd+?Pt*66!eYSY@eA)t4vGdhm$-SJQX(sNDz7Tvq!bD5BG_ZxMEZ^w2zisK{#$;94Hr#YuR1b4q%DzZ-q>_0XzR_S=V$Y!Q^br87UG4uK2Ve*=r0J{zfIy0DxvR*c zsiAJXQ+FaL4{?UgcAN{=>xHYl+6UEDvcnbT;;;Sic8;B@J)lH3E0S!E5)a{8a}eL? z-Au;5WL-=WRRm;V8R*S`=7UCXUXG4I0G42uqFg+%Xa_+cX2~RFBRK@5ce?-%ednno z+}K`wZixU^ssOml(3(Vi-d*1Y+91FL0sruRbc3|fP}o9eA#;P#Inld!U#*Jr zF?_^!cyndzu-+(RNZgcw2$9eUNZzP%F)KZ3WX00V|BC!l7?O^&1agy^r1mN+`PtA3 z2VPJ-Y}iUoRgOqpb_d74F!Xgie2sh5y4~f_xB&CqIw-ZtyeenI}HMP zabzGNzs*{a-X>oqR|YL2y#h?C%@po1BGhUVqBBsMI_1zVk_i}QcxcZj43b{D=SNov zG~r-@ZeeUxVK62gt(l#7->xG0Fg{Z|YGPU5z^s-JUtG5MvW0y#2u5BaHa{#|)Z)ZB7N)F&h zcwsI`*<-P4p*fw>U>+BeN>d5Jcwh6XPKr6bksy)HRbqj#GEQ#O+zKP>=+s62QY zo9O=O;ydqn7y0$FZr4RSjug}XI!nCUl#H7^NbABSQ$iAxJ(K{g81Q#6TuRi{3K+n%F80RQzdLa1HpcS~-u^*p;VhZIwdl{1>pB{6 z+9dQ!NGKz@vgRGi4Bn+^mzL<*KBib@aKrH%=+G+N1t;eef;IDAD2GGh|0tBak7;M^ z@B04*k5o1XZ_$e~33O(g#qCbq-vaxc26wd|{uNq0ry=>SDgOtz_t{Vw4ddBB0gtzq zNfgsbj<#Dx4p{tzglZ&NiRO!}oCOHt>L4f717*aOx_l3RAS$+dVw*jTzJja!U)b-z|}GTkB@I80umcVhO4GqlLuHz#JRoS@}G{3vdlh&Bzr|0p|_Y``Q?%)-GfevU%=GJd)t=v1ap z#vgKuaz8Ev1p$zjLg>QohFVKo~@tWX}8A;<*Z$LrLjw{R9MuF z_}Fb0O9D?@f~MvY`v4_I%TnMcGO+APsVfVDGnF4s%JQ`gfg)8&&2Z^2GP6=bFw4rE zN6fylV5Ba@+kWyNU*`7-?ak!EP|m)B9QIg3;lZ486wAn@De+L8KZGfrf7)kFVBr&~QF0u>pohzAE_@*A&6zsYciX?oqqdDC$u~d%R zvR#T$(BvfyED0i2YzpFt5Imtq0F5co9AH~)vnWYs{J1=(-txVFxs~!L^TIEgM-^hI z5_#C}^~l|9l7u5$1u1Cbi*#1zjsO|!73LteLi(MIs4ntIc~S@;9Y=6lZCc$m`v-wD z{1aVBmtS!37cZrd%4+W~&AjkDFiM85ufVr&=CfsP!bK*1ePRn%aWTRX1WHy>E+n;C zrBi!UQshxa3P++qQ6#EaU}V|`^8-`vWP~vSUgj}w&V@GB_wuJdpF%4`jt5m}B(CAv zCnKnn2iSxDL(EjzJw7`*r}~XMCFVQZ+B3{EZ2ps5l?7RL;KF>w=G1Xn?Pe?LQM`pC zk;zso!SD1ds(XqO3D14wQ%Z(4X_lH+7X$2j)x^@hD3+BFfkhLgedW%-eC5xug4&}> z9Mj8xD?0Xae7o^ZO0T9@EfN8F(rJR=mxH>L!exO&i{WaGx);{vE)@Yo0K)iY%B$!a z$p*Jjd&UF!WWc9>(w)bAh~g+CaczwGQPrNC@LiI03sx@h%IgI)7xOVi3+BJ`7X_4UQN4wdP#8lu!C@8X2VV|6-FSsDT?*0JAi>Z=yNF^`@oMLCuf1JEs^2{ zDn){;m0%qpCT!)#F&>V)>Bk23LSu**D&W&kzBzXIse`XdRSX(1Jygx-6-agMJO|SG-n1oI7#5<}d;F8Oq|l3;wi@ zGO0glFOaoEXa|hADXY~$(BinIkSWBAYs|GH`#;Me7G?XU7ukevX0$8OV$&K$oaKC# zY)1k460o7z3fyWAVG!{g8W!E~I0tcinn43Fz)&WIXx+5x2~YF{=jJ#F1H@ZbrX|bt za)tw+*Va9QTAUO&*#cJbjZBcP)0c&0CGFIwnY*kGU2@N}F2+OGzJs4`rLcL;^Vpf^ za^nmTfmLc>TBerjTIe#VB_H<2b{_p3$BSWeh9ep4eT_Hn{`|MuxLUU5ZPD9R@tNcH zHBoJEqiG5ck$S=06|-k^1c?s1=&ESM-{ON)YqJ-UocXbkrhD0=_W`fd>(6~e0N&~@ zIYZK}c;)IqiJ4$OvJYBKOm@;2l01j1p6`eSlCCYNiVJSV{j0trq$8tPw{l!I&w~3) z2yTrK&aMIiAA`?Pa*(;M_R#4$BPfWamH;6cy$Il;AA2zcoQ4IG-KXqgY6wki$YpTb zi*J1V3#dF_#ZR{k-jU1TsP+50QJjTuv{Y5PAc2{?$T92#@M((00R-kuH|mTlEYP92 zUNCTXc=d)eKaMXc+m5&B@_cRkfUCB)n)};XeV&FvR=zQ~7Y=k1$CXZ0F$^Z20pqP_J7%cW$_@b=}~Nqtq+WXZ;j3LrU>>x_G)@rN_c- zv?JZ-Og|Kt`;cHYBdMVsblL|1w_1&f!LiodT6v6kxehl2A*gX1YoIiq_(qXHl*r|o zVFc_3)N+9byo~W=)ydNrNGm6K-M&(OiMY!`{xKniPrjxe~o-O{ozNt*Q~>n6+KETKax#|f)%BHBzw)(kMF z=L|Xm3rM4;Mu?V)FY+Ik#RFbg)}mI#!26#kk*tajLolJ zfXl0fz_&uzw;}V)8jtC5c40c?AdyA>QvRPBs`EVx>U{)D z+NlMQ6FcjAjRo{|3r$*Rsqo!f66skTE?8-A=Dl)HmH?dZ7u4oO1aOkDOpIKPJHGjV z;TK{-rT)qWUUOC?cI%we+|`;Hsh@=t&#=A7bKg2Hf|$^YXh)EX75q0_$?|oGiy+Jl zZ<2;jNTQ>*Wq#dLJ4uV3A8{;5aYD$jO*dD*Es?$NrEo?#u#*ry(7$}x8P1{i3cZVM zdHWUjF&Qr1?P#-V*>tc9dV(fE%;ukriYIk%6f+%BK;PHwOw8%XE7!ffxOc73m5TzB z_x|Jk>WkJ4FoQIy@q!Go|Gh#Z@GG=G7A+*v)SICslAISR;yYHn>N42^Q`Xg-4X|AW zhcJsBUYLjJdh)w?@)m#HK;WO##vxzxWw;Yv5PWw*>|5K4P5LlSPUXQ09xMA0h7GBf zmI~zrtRUd~Wy2ckTai4@aIchnPvp!bt;}YVm8*>XZ(Jo-96#|9kxj{gEQ>y^2uM_d z%>o;nc=d@uqAIb8pfRbxuV6pSLbrS7>wtzFnmZMw`!jiGwc|Rc8iiycsPu5CdaGbyRVZ;+64zz71rstUfHoyCXzjo?09thtwKFF9#< zkb8--l1j^JExC7BcL0r3ej<#9<6HVsJ0_OadU$O7aQto>|-d5>7yc zPtS0BRp5eX{VH&Dd1y~Oo=a%Q-~GiGFQ9}k;4GPuS)rtuM(O+SDj~4*D@vTP)x;Am%rFfMiSngeEx!#J z#wzu~{I58JK}hq$F>(i5t9L#LPh8qHm`zhXsvoSsY?`-034a5W>HEbkJ1h<9lDj&$>V`aw{H>G$xPpAifIx_x1QLkUDl)Ri;&5oGu!i9A*^a^x}r@ zt+v5wUCs)Eu=eQe!=+t-yK}T;px8%P?zC4Y$Wp#E#Z^Hz`4hN--tmbiOv{Gr-V)gT z<#`a>ry;ft99*D@t-i_By%UfRoEQ3Xh+sftWh&(q2(IUy23ZqEIQdli1&;zcu`u3G zI)~&y1OH03e`g9JLU`%U^jErN0B2o*SN!3lHms!Hm5eJ|^c58#^OiMeSmIv)4H#gH zjgyX|*iwkv3ol^0X7qk#j&o0#i!+&MWq)*f%}!PZI^ zs!rXH*23oADuzk=L|c*swx)tKe+iyRG-(EYWL?Q0d)sv20*PIw_F*`*- zE1b!^hZh+kZqNy-*$QYL+38#<)Md^BW)%BYvVuQEkz+=2@{W|q(kmaG zMSE9(JI=W8B)ZE|Piun$8R6Ho(VLz7*D={miDP0Xo1>jd70uUi@p1HE;1+Wct^nay zsL05|x}diA=gOHt!8+^y2~;D^n2cg%Yft$(h|2-A zqq6XGVT0t&fJQuKn@YQx;-Hr8MvTDopYb>)Ioe z_0w_Iczep_NIqf@evOmY`0ENH`jV==!1%{%hSmt4xaO6}1{>d@kvE}PrRW!Y$jOI?Le^i`v-(yY=__(t5A z$S1d9mTCc&Ii?81&lE+-TQ%8_B9P-$AjgS7kSwjiu_CSoCx|?zIrec*$Jcn=yaD$~Egz2v zkH&+2@o(k_@*Yd3T|v1e7XrZuP?pWf3ZcN2VOnF1CdPI#S*;}?GWCJtL{=mFGuStc zuM`47Y17oX8mg#0+4~CE;+Ry{<<-S zUstdncG>rl&%?S+Pog?&?goZ}t3G=^QE{?@K;W_u-xCehGWA>X@3CWb1|G!k@l42C zSi8GZ;MQ*FA))R?=m^c)>i0>|%VMp>{w_cuK7dd1#8xV?Aj+^Vw!X zF-R%MJ>3}OT&StARsN+d0qL{Dc%crA{Pg0nYtX@$uYZ>SvXaB27C&0WA&Jah@EY}v zXbf+U2OMLiZ4WOrCiOxEEn;1zi(&J=nL<8m8kTH{tAXKw_<^;p!j@nj37PjiBx%xT zTbI3Po+Fton~AWAP$}L{TNGT+0>lkG{J9Uf0*_pFyvX9mBsr}|IdZaWqurQXsJ_we zpF~b}*bbp3o>E|2=CACyHMk^Z`|d7ifc?rB@E-3Y(Y=OL2ME$DcnEA+Mb-jW+Rork zOL;2i{POF)X`+nLUKTz@@N{&paW~#OH1pS#WJw)w@ncnzgu_Q`I+2xXsBa3Kf{!&p zNmi_l&8bqm9XSH0ec8scJS6yS65|3o0!J7tqwvR~CfjnB)=$^%kvT&uuS7RTN@dHG z-=%cI8+$%FMk$q?G_v^kOiHcsY2-~w^GUMkUEN+r&ZQ(m^CKBm0Cgnv zbRV8eNemVx2&e(-zOJ;!UnR{^R(UNm>*U+4ZVrNjI-1li&gcSRTIg6eHFn|c_|I3I zFi7DMQ*@;yi|d*2K=gKIC-IQeLC%Qq^!JTv{Jw%qlU56K-N?8Y=QfFp)m>?VlENCo zCo2M8M|OZ^n&?`(w0DXfx8&EhAiu$a(n;0XugN0P)00G0B^z8mDA{;-R02?HSE7Q^=Cbs-O;TS#S&bEYyc1&6RE*EvrobDtvIr`M zAhm@J&ylvLO>H{+qF3PYYxNQxv%$jiCAPQXYmsuL^_n-=TqKfLMa2V;9``Qe>sIhfZL+RjV;NR6Fam$6o#8 zH$3)VK6Jao`?ukP`;e32iFxX*remgJ-lnbWfV@-N1YxifqzQCH&;G;7c-{gfu+q26 zdYuvF0*2YuHl@rW09rMrZvp0}O}!xp`(K!x$W93BVLKG@4vC6Ooy} z!ADA24s(Ey%W#3lMJe(mtHY;2kz7zPaefUx06$o?>;g1Db?nduuYElpzV^5hgZm>D z7n9}H=}ek=axnZ8ep|tzvk22G4IOlzRuu5&Z>cdkWaSel^YD^{P&9~v zl3$7!LpX~+lbi;70k8um7+eUzJv?;@g$E{D3SQF}$KL$|3yQr72uc($Rl7nCJ+#c)FnQU0)tzz5ejw4r-V%XLljssMZNz5UVx$%rej(3&oTSn}c?)LavO z+6|ni#Bv2Ec#lHxYP|8@LksLj6uyr=_+L+NanU7X1s6X%d5C_Di9o+dy%){h;UP}K zeN!#`8jaa|v1_kV@%N>;c@?k%*UEob<{h;>(|l$KiuBlRIj9XLN=byT)aZd2F?twm zf|3X_vQCSrM911*Kmdlw4F!`NGH?1a1|TROYS*|LRD7QDA6|zdS1ch6TH%5`^pB5v z_d+bGtQmE&jqql$!FY;UJjTo*4)F=%pTP#Lg0l^r^&l521e?oo@78o&GY<%~y=NL_ zAUS-KHfxJk;o(Dfq>k$UWdi}AapL=!RVlqj_o#EKWb})85LSs1k+{i1hCn%r&OhCE z3V40&R}cLuOB}V8P`GXvbGqsplPHL27_8uISDaxIh2j=g)oN59kVh_PE1o$|#n}<6 z?2JHjR(UM^sQZXg3Ep--mBTO(m&}$FoA_#JtMFf08n0&%8X6E5Qyf+*G6?0H!n9R> ztzv0plxx`uS4{6X6)Pz_i)HaD6(Q4xemD~LV|QZn?33`@L9n)iEx4;moX(C-yOlf^ z*^O0&#XwQGHA_bgIIm@m?LNQ+W|`(pIJ4$q9gc~yHm4pfEs?!siQu6^YSn}^26n`m zB1;FS@W-L_uHt#JRsYso*BwtMS8{C9;??siHEs)6rY15a%Nz@v2N13WI;XhIec77E zN{S$$NbE8!PUl-nYVKJB`WZaIkAD%9^*?~ZE0VE{#Pl5PoK!oYCTqguH@VL3{NACR zH)0uOqYW3Y$wCBm4)19lllUA)Pv`~9?&r>XFwX&Plc6WN&zVC@*6($Ak$orL>UXW~oLbi4Y!}NmzRISSy<7LOk{xAKCxA zR6*`r?e=}^=23|3;vLAwT&ebXQWfH~_ns<6?$=ez?C%4KB>)}2${7?QaO=j2;Nz0G z?WB{JJq{05N;R%OQW9sk_f8I%snaYkR0x#ZNTk(j@wlY=Ge?d`MoWa*3D`mI(zX@| zZ1nO?y3iPaP3S?>J4l^K5s#&fDXV1AKTgq0aW?BQFShff6U$saBLnyT`BKWKtfFL7 z`X7bM{TzURGzd|0JT>GHlwzQeTxrbkN(BkM3pcNo*q>FMMJ}St$q>b3D@JEVCVygJ zonqw{_~Q^vNlEAM!{NA3yv`F>Wu|l#n-)d!I$-axKYonodoHEg#D87IkubG?#ZR|A zZB{LsCn>GPH}(!$aa$Uah1(KGEcBNU&FUn`v}uUz69pl&p_g~@-+VPwmp)_nL%Eug z0Wpiu($yS?%Nx;Vv2~`|8FPCe893cSJcslvMRV>w#2X?FZUuVe+>T`MKBW}|j;}v< z)9^)S;YodNzMWY@2v1AfEWPKJH?w@C1W4{Svzm3t;H6(YljDnOJZrA|joN^7Ce>QC z2T#C$B5c-nQIOfv!hLfZp+>G%(0!&OYqf#W0<<@V+PZ`UN0ud{34HbWnk;?6Yt<@# zRJZhxr8xz1g+v8o(Jt>Lt+*i{Q4Q4LQds-*o)x?r&B^|tr zo5?;@nk{4`$PuEgk6uJ&i3t;OrGg~Mo zp=c9TAlnPT!WVE8DRz83(-EJ!>u3kg(aa5A#CN-ji*Yg4hQIiFo`zC3(rWQw3PziN z@zDrzWZ7b96dmu44mPq^DO+5NZ|uts8rJ%ZJ*zS4{^BzO6=F(KGEF;#Ds2KmgRYm# zgYbw^LDWwTWUT*b_}Cgrw0>qBn#MJ6v!=aka-`;~{@n$4$8WA4VH#J;)wfh|52hka zk3{8yS*|8<%?7@*(pL5l;$Ex1=TI&1N&&#-Rtc&=yA|P<;MH^k0C<6{IaEBiERroI zS|AD)0@19w8$6;EP`moVnHd^*in@>GyR{3NKl=m9=*Rf!_GmWjoH1&kIfJ}xtiFD7 zba*6M+Js)xD~&O^Qo#l%@UiC2d@GG)?SwU16{b*PS2vOt4#r9SAsiswZJs#0N9&Ht z7k}wzzsoeeR>mTCR4Yg#4m9_U<8;4K?22^v%?`dP{2E95@z)jB`cd4uI+d3I79>S1 ztPS>W1zqC@)$^Fk&U8WbBUiC>F{9wr+#Kabu0>9r3elw_#VUxK(8aqyJ8~w~qhuuP z;_2jj23j+-9Y~8=RLlUPEj34R1af1T{<%`@XHL47S@i$M+n2!CSyt&^QK2GY1!U0? zE-H|wg18`cnUOSYX`$&(0a4T2Z-_IcA%Xjbhp6@KrdCqyyYy1oxwQ}RFB152B z>&l-)<#4pIaQ}_RM|UF8D{bS|l#O%eL$U=qXTkq_!H}t)Y+yq;O@YK^_tVQ?{vUT@ z8I|K9z*f_mm?1?Y1A@TDu^CoH=59x8!wYNS``5Hu$kspstvbPqAgd18F&H_NITG{H z$@AotsKh##bN*Jmz!bBXGIsL#6Bc}J9_97$5_xS=d69Zsfd;SPq0LDC@PBD+3vGI{ zUgD{gywrw)lIvb0`@uPr0~C_>tavsc8M?K006OM_SS3*tX~3{dmjsjQTv$f}>Y#F2 z6zF1Cn#+ct{5jHqWhV(9W5){+g|D1kKhX?aDVByl|50qA#rtly6X(yzr&-EL*biM- z&4_%G9z+LZpt70NJUWDZ&%6a+J($V>g44FLYXRVWJ&v6M6!N+w2RM_cMjUqmT=eCq zz2g@Yz`giswVIcz7EG@IUWzZ$(~j(+$Z9K@nDw|Q zX74(wgN-1SLrX+qQ|xCz6w-Sld$Qbj%5w>|+4AzetvRJb+_Xrq;pLYR_MB^FLNTpN zvPGw?mmoypK`C4^cT5>poA<#>_v4tNvJsxg*tmL;3x|p0XyOIf;aDI!f#7(dx1Sf< zaE>3ucdi!R(BOaO1$L!XO$KJ8lR|vmrTM$1e(l0FK9FS!bhO9T-*;YNjZbH zbZ<8lmBPp1gO%7ZopLYZf*L&SyLU@dMOlmeYf>axWrAAWH#joXAE=g*#6>lxm)a24 zmAD&b5*ibX1>R&*dBJvw$AmbR197YttN$t_@EV}G#5XEU=_yyS4;L>)m|uuQHcQE# z7$dYm^dK<giQm6+1f@@rL2Yz&8-Ho?{ltPY_+PH^o7F4%-n z+n(3qcD}_j@0S^z2M}-Ih7L%(lIj5PFAj(8K2rTIj}XubhpX1F9b=5JrmU+X?Yz+pnElQELE^c*v(W3C_dM=~1za#^p0qCb zZMtA)KiEKzGRYoqe5?V8RqutGj<$y~*aW$N^dg>5cmFvU&~79B9dT*$E!jqJs!4bn z&G_AA%Jw)v`_k9|LvS8nXdD1%5}Z`+^oum3pj`&rgFh{H)oxpU&M$ckc;yi#0=q0} z$m-e%hd1$9<8&tYk+@H{OzOc|$8G`MZ6`dRhYv89sznY@heW@zCPUh?$yzu9{{z+* zvn*P)h7~hUsE{^+=(8%NXi9_}Gc0;!gm`zV^Zw(=ul@>;Q@UgD9Z3+YrrT6LiSO(} zG(}uMw`|yfVvt1GC8FNoNjeq}9x@#VmH{0`8g-I+?L(`K$K^eLb(U8~v`iO07@4Me z2Zxo{Mg3fEyMBGsf6G25o}t=maW+_;obl@V@FY^T`8b9U!*CL|BWDacy_TOQ*T$5l z8*#gJBIU^k;)aw!sw?ujo{rgIDMpAVX+`n~VIbC^G%4zo*G^nUYQiXkOM$9o&zWeV zYpK&wkxaPnifv$LeEt*1?Z6t!hF%==p5(CB)F$Cws*CZRIVv8PU-vREY$Jxh0pGVG z4!?4iQ{-nGu~SV&anCaDiKAD6=wOy~!_chcO^_PE*bF}L=7gDj$+$%{Og2apA2=@N zPI7bKcU^d9y+&!AT%t@@&X6>A;`^ep%iOi}3S)V`k=EMtGnXw~UQP-)v<>hq)4gR= zoZ500+e2_pT?C$j8u}P~0Bjl@G*Ou{>$VNJ=&830IBf)|{#W<^TSqaL(OU0QF%tNg zQmyW5j0Za8b|urQG5)>{wfZz}UFhUd@?7G#O*JCwyMy;azw8dt0eN;; zBicyi%mbAMd_4Q}q86U_u{iEBzn}re>z=Okk?y$)&gy^tm$8o0K|IHND8+#_C@v%1 ztQo|<`9c9wH^?vSWD z8)}oNSK<7pT3f^RUXNS5W79(FpHsd+i+x(jm5P(Kj)V&Me$+57#6{SU?r9c)-@^W@iXYvnbBOH!TKci-c0pi|MPSRAKrM2NK4V zLP~PU{3zNt6)SqW=IdH~$1|?ww);wFiKDgY|BTvv#fwoAsjfyM)NE|=SIry}JB1L+ z!OCoIPU0MhHi9`?4-}rf-b6!pjIO3bl<1B0K5ehMqNo>)wRYd z`t#PhfHRrqI>}s9cavOZt(yLTEvddlIaICGR$@rx_!p0+?-aDn_K6RmqL< z0MW91*ZF7k{v(A_#z0)JLU}YULw&?cE^Z8uq=q!+*1&+`Cb9b;SK4rs-2Sp;)Z2#C zscZdJ;Vx)-0T+=@Med{29Q&4|QAjbKxKk*WVn&O$N@%BE3f*B8f(p^ZsztogyI!xf zp+!u(5(3WSOQ9z;hCs<%rjvo1=)?ru1L{1tkam*8v3DIzY3QFBD1U)i#4@h_Mw8M= zV|_=qZO_jBMzR$Fq|p!h(|6u>H33}dX8up*PDv!!1Map+l`1;v9gz!d$n9pzO_<>5 zX<&kYc*G3>iR>ZO36Zd}vK6i=I!R&&t?dcWc%>0J?{w1AquQ2y5Co5gFD1#WM3>hr z-9^EKr6D@XdAVkrN5ABmwS%8d;gz)_-&7D@Q)v8Z&t$aau-i*&v&cS8)va!wB%*{?IbC+(khu(Y3pF1f%PM~Xzho4pH335P?!BL=l zsOwE;a#J zNyli9^j9JY0iN^`CON_)C|jp%Rzh?7{Di|10Hp zKYm)(;|nT3b_uMR+=AlA($@1n85G^H(3#R6EZ>5gC3cA(doR5rV~8>KCONgu)JoFu z<1j*v%y;hp;W>-S#q`z6f$06hr{V^(Y}sJTtz*|-Qz2X`>%rZrizlpHJJg4vf7M09 zIG-dnrgQD*$Q2y)EmztIY%JMyv$z+UfB*(o4G)>9EbXTiUy9-lu%~WO!zzMY2CK{* zjl=JpZL~6J91rh6fICI-5mrHW1(}Bs9azh z$=J*AVLgFOwDFcY&zP^QVA*E|5!(Ki!RBxfm zn;OYw;!U&U0Cz8SicolOics-c1&4eV6dzF!I%N>X3{Ae(aUw=eb|Q6ILF; zPpdchw;2=4%kgbXxy>E$jR3U}MB#Rv>SV8-y;7oH$stW;*dL$;1xvnzqVrzR1+aYN zW-?BNJMWe0Qxs!5aotr{eCgX<{)!T;@l{V_!m^#i&%OTpTL>IEjsaW5XO zwV@k#@S}}O!#lG`VwrK^-=H+3l8bIsCuxI>lLl$lIw3HWgu@vS$-$S%hH3S*1Pg_J zyuh-mEl|2ZDejO)Gpy*kl_{&M(@DdRJV3f(`Hxn0`udE^Q|1d8j!hEC@=LdyNZG{} z(C-gS?7C*@xu%ys4kzRteSBc*)4m=bz9YPm4!6kqIMnbk28zhpMYXyA#J96av(z1Z zQ$=+E^&yv7s0)WwO7WRDtCgi7xTxsWUJrbA_5B|AY=+ z`sK&>8n161uQc&-D~6E|c{G9{qR1<;NHQHLLi7vdXf+duX9x+NC?ig%BZ17&Z)=~; zytlsZrPp)0Pc1Q*UnO(FmV_Z-<~_g|Nm89o&_9IvCAERSo-q2#|Dr4Z5bj>?!@|Q~ z;Qawvm=TG_dUVQM4HuT}6Y{#HB-IGyTXofts1{MgWkaqIWnrIJH8CV2Wo=A=GKI?% z|KldJ!}^{(Nq#@PQ+BfVRoezfO^wgnspYmCy%q?=lG9 z;i@}b4O$v#@!$x~z7<--G{O8@RR8ra?Bxrs)lVW_!Y(7lm@}*h?L%8 ziF2M9NII=qx?_D8P__BM`|5b+QfzO-sTt0?5vJ-xd+HNi3RvV?FAkLH{~L!HnW%nK zQ&BM`vjAN*Z7=P+N(p-+3Ly*0a-1XrB)?1%ImM2XwzP4;V4uz@11NyYR(-Qreo_DJ zwTIy;%Fdnc*e4m&{3b@ojiPI81AXdvblX1(w+?JU{i=c1=Q>yeIrL#l7WLa-st{g; zj}XA7$+;mF)(?Zl6S9POUiQQ&?IThP5ITj~UW_?BBRKk~}0 z&)(bY_%~)bT9!_c+)Y3W6|uAOsvp!(`Zuh%!g)O{sH4LMBvb9-KOg)&NEghnRWRq_ zb4~AMom%pc@Bv?-{!b?uq|83++y%0i>b0%R_b#Pq2~*H%!FId{+)ZnV$>q9_cr_9a{I4 zGOGtt!Ii1(D0KN(!~S>FH&C`8V?g~qx31_ARd?LI#T|qEaFs>Dtc5yVQ>AIe|`34~i`d2*mmO785D9fTc=BhyG`llB`yCz(WPhORZ;989IcZsLh zYLdVAY*SOPc?uDN#?9hk=2AfeEf0Jyd`Ws40!^8+aCD*xW%j`*F5_T{viZmzHg}Xl z(W8p?te_l*Yv{1q)LZNC|LaXQrY(Q?v|0umK0KF_2h-*uTV!A$+jSsFkUcZd6+d{P zrkMj90bP!CY1;Tq-D>E@Psr5Rb|bnn1!VdmXoCURxlj(8XNAgNhGQ(`c`mklC;sEw z-(dx1GjKX=x)+)8Qwa=Fc`DiUAP0rv5cw(WdN9%5dx(mT)w?cfeY7zwLfK`}(Z;$9 z=L;X=(h(3H>HtNNvXHJdkrq*5%HB#|k%_X#rF+ivRN(@*2=-X+LbAU@q5>)Og7k zkjtJ?7Yo!a8Ld@SMo_1u`4to^?-@`pB)Oog!WCcq`BJtbmd$qSu)#>AFjh>0n)7AS zE;csC>KoAH1x9-+FaD1g=pw0h3u6$fzAt+T!Lfv5bC8b=^GUeWBNH5pj2HJXte>Qq z-J&*LImioj=89^BO3En4p=i7GkBc}M9;{FbaH$P$oqX1nSV`p%_-WOW9@P>;J#>RX z7av56oSDs^UZ~O=$7goQjz%%=jPN#K3z&uKMT>fH=NT)x^_ulVpb;Gr!%7i?YXt5` z2c;IU)O8?c`Kqt`$nf4Weq(-#+pr-~1ny^^Qy<6It!gALgM$_(<<~fLaC~qIR^bZ6 zOo6GIZr{$rg>X<7Y_03SB7mqlz>OZ<;{Db}iA%9T|8OKtoljH`J0e-7^{hp@Qf&%! z1fN2hlX)%`TqfKW$Ghu`CmnMQ7F0Q`M1t#+-gE;!fipxK5j?P49aDrpz0ljw3saEd z{c}`t2%A^ImLwCFNUlUEOpkNsi?6>$eZm|?d)RKhBFmSvBS(A`Y)fL8$tN0IJ?V7S zy5#no9{(;1=KJ_*H7Fa2L#Q)78$8XbTsWuWgSClBs1IyJBXME+JuG{ell`@C% zGFA5nHLu5)`+Hq3_qD9lh^{n^twNg*}X9*?z!wK))Z~ zxrE&$ULZleL?4;exhx9gtcqG_%4#yz!um{~6p1){;~(!kJW{B}9RR;d4?$&+vx5bN z%L|egGIb@{x#4j;NDq|F66<)Kii!JNFj%&_dNl0=VcN54XdI_y;*`1pjO>^K`u)a3 zf1?iS1GsrL+{ZY#pQZ`c@)8}%auD5Gbumx^p=fa(VI@+7*w(Nba#h**&4HndF&H$a z)cMo|leAG-7TeBSbLk7+kWTCU{c~wZWFcCkvTcb=tfijk8+#k^z?hY1 z&gvt8J*+Gv3vm_&U0Q2o$WOkJSaShb%>t=riD$xfal8rFYYmf?0m(Og&9l1Sw)#}A zxnw_m$GcQ7h(yrlOWLId?Whlr1hvTuIHvQ#dDMpoak|iyik9El+v>YldT)i>U^?N&T@**5ZyY&-Ot>1>a7of%cTqTKXl?~(gR+|G@Sp*mRr-GxoA7ct`> z>N3Hs9-V^5Sy!0^-W%p~PWQ1YI2a>!V z>_kvAn|&UoX7dqz<9yPd7~%!+VMZ@X%?WV~+ge+}zma1^AEd-1#c&zsPfKK4ZPc@Um?>As(jCiRL}8U|qU!j#3X6?us|Sag^|B2a z%&0b@6f)V12;QuXOeKOp;t49U8*uMJ)_o})6`1A>$$&!PNW`F;MCy^=7ZQ~IEn8GE zLJP$8I|U%xehMWqfEQ#gkQb=zGcsFM>1x^o;3WnB)-3ysD=xg7Mb}D6zf#91lA1mE z;g6#38_b7jQ8B>OY7IqDh=n-yI@*mLc|i(0`*vxC#>W4|=5edj zni8wAJMjg-Y#53&sW{`?Mh>)8?{@zAXU|x};Qvhgqtz#WMg>In7mVJ(o|(f_aAmNz zVSMnm8=AcvZ@YQ;wreM_Rd3^MH#SGd{?DVJ&xV=;UhkI#f1@tO>B%CkuqabwcW#;`3LSW=HX&(8r+?4gb7K3!-F=kbI zCY&ztK?N>@EB3qUW!(N#DVZP8ack0>E|>s{5!E$=4a{3|Vvpn~%S)I~TpONBf7dtm zeXa`OHMnynIf?Wt#ge>PA?4Kye}&4jq$+%qG=!q;sY(Xy$TQ8XeLx$Y3Jj3Nfbpd#DqStq9Cj}r8YED-?QWIC|nvH+JvIpMhyLA-RamZwc-BS z#8jNLi{%UW5TU&^`^Kw_oKXw68UJGA!*pMRl^{L4Ky?vRx$WU88c~iYv(%OdP}&6J z1Pa@r?+{yPj}L zt=RnZR8e+ZLMNrF>w=j#{>dZeQ!r01QMG?j!4L@aG+7cuJ~UcGsxw+Y*TqxC#SvWW zMJ|tvy`#K16(OCWLSnPkLYZRM;ye7+rpj$9kkcKLipQH5f1b5iI4>!{tDlj|F@t)3 z=|JI>43iMDljvJZ^njpHm(i{tT=>BY@tCERD%)hlCe>Aq*h4}BtUiYJy! zXC+Kx{)K*eVOFbAJ@AeBvKTGZF&0@D1+b>08&u(J5RBX?)d}rIb9f0{pQo_i+2gC; z{Jb@%e;?0MDcMHTVY`UPfyJ>7r`Olh*SKPE8%-SRutl%6p%-`Xn`7D(2kxXqDJKNs zXK4(nqs-xNp))7dtuwe+=rYmM1$f%DL2ZQs9uHH#VUzmwGQmTa;Q0szX3%54ZO7%g z`{5@%K((kGQDSLdQ%hq$H%@oOyT0WImv7eqDajc@IT&hA?K#Zf9nV$4KwEL+N>VqO?OVoOptOALtd`4($NuikznG51Voeyzl%$CbU{|HVfO`lm zOW*#9fzxG<)H6!7^5uI@~ zrf43GOf*)`34jbl+{>zMlu4sh!)SttOE5T?(keLslhqrqsAgT*ZiqTOJq9K0zG2I( zg?Q@HZ4^IB2DP9Dywa#HtKlirkQ2r%b`THMhkFN+&;6|l6J}ETAF3L|R01hFY@SWw zO1~H!_GHe@GF`3)A5R}zdJS~bo~h98uN-_C z8y70O@Y9-&|EJ1hZ(REOH-@_mW~&V9_%QL5l0;cosIG{MjrkaC53xkTvjZ5KUxr&L zj&#duUQ z7EhUOGew4u>+7tpm2V30l;{~r9!J4?Ibv5Uk?{hib;-AS}J>&_{pCpqo0oR zdRz@IRy8;e-&%;Gh!8QJQ)f7+TespFxTe@}2s$m_)a^8`kptj5m-xZagkyvy;VHyV z!dF7~V(-MZv-X-rMyG7NTE{O`3Jj4Ceh1k%_P<3}&pxdA*klVG5pxe3NehMUpoB=3 ztX+rXd2JT@hIUh(h=bK>dg9?UJ9f;bok&qn+gk~%B3l#ZD0K%$(?sLAf3dG{JKKEH z;a{dpDBWIQ8+0G+bVk#XN83h9QV-g52t&b(#CQ-h8}O*wgr_G7*v2U!Y3)#S?mL8H z&O_rdbQoB2J^0DOc20LaCPvS0@!#Bx)b zr@RRr_^J;5z-{|)z!#Kq(f8@9$g6gZOjhj#odDO&)oLS?y>@)gRG{_jr|Ozm;84Gs z(Pn<|s2`bljhu>8bUh@xeW$CaoR3^7qK?gOJ-AX+;oC#oPD93W_e# zha1b(UpSz`AE`~Sj_8y}E|C_J1GXoq)pnx-W61!A>Iw!=X?A9sm$O3R(fyDfu`yS# zb<1zB_2ZdKJIfwWQIS=gmfnupPgmu-5g!Q3fe|;+_T)#zk7%ut$Ge|~Vc8?jL90Iw z_nbg_P3;N7gGVLoX7^=5e9nN-0Sr6riEjxza~`hppo3lrWrlr{_bEi3 zA=KS*3cxwF=E#(guZ!bWeCBc+lcAvmd8$jr{mF`aBW@s5gSshK5#ET!Wk0`7@Cb}R zAQ8>RQX%aD(zKANpLMatC%a2CPe*1gftmDjTHs9es1Kj}b1bK9W8fSc95AgSe3@$0 zC-Id%R^bfli10=&!Es4~Y2nPNf}*Cvq>&+YB{&> zY^ZIj58zpbj|00|*=MA24#>!%{>tgkInc1+Y?Ips_)gzy#yVB*U)gj3PoB`4j2wXo zfP$3p$khNg0jngQYwg%_mRC{_NxAeR!64vQx@pA)vHjfPJN~zLKgR|wP=BTiBfVGE z=W2c=UX+m?x@%y4Aicn~Ikj($;~E*|@77A01?MDdrO9!xpiOB!dqSg>3q|6QxIy0# znQA48sK0=c+K0d)l5wq3S~VYek;=Pk@L>6*5!Fd5OD!yx|Ey z!$Xv9=bK}b7^Z#IXLHpuAurqpkej?Zh(U9l^xElQgJVXejFpl|K-uA$UpZr3um*-2j#-xMQGwh4YUD%Ef{$gn`&4=Qbh)?(>PMmDx4KrO( zozDB}G;Au!5Z-j9AS-E}a~eH+W3o9mDYE#~5DA=dPzUB+)1Ma7fntT;q-05FC<+~^ zOKbaQ8fOk;0hK3~Nb8W~M;+00a}ZDNM^UhmeK~!+(1z6BgYR^*6%$s4K5~N=^{4X# zu7xAeQ^Ms{omPYJ|Z{W;Zt!AWH=RN1S zgs#~6%0H4=E-SImIc!e}EuLtO#lb3syDp(YUT8x?SK{8aR{F!vMc?y~V{`h8-7Ke5o$dfz--XDD5Dhs%Mw$3or)nt{a}&bs`j~ z@{|%SI($zVtsX&&S*Ar}ywHY>K8){N=;a0T`3%8ywv5h*F2G@lcL*Xz6aeC?qX(~L ze^(B4t@xMoG%MMPp1*`h8dO95bQSA_r8g_cYS*g0x1T{-QDCk9>4_>U7UtdJ&?tow zA&mep)J0b*n4Vl~Lt-Dr?FD3P*5L^{1Osy=B}2oXrOA6dt=U20e{*`44E+4-^i1QfsWCcwX<_0?2}Ht+A=pZd_sn4GV>{0U@Zlfj=Ch9#*4CycmLJ zo~ms*^2Hx|dji4$b;}~Y`f2T9u_CXNw4#a58U{V!%s?WC@{!nH;d7~-wBL6+*zr(y zV%wa~8I;-=@SV$?RQJqFZAY4$y}+tmmR0VZAn`dWscjv!hVo}xATM;xI2O@bt%Vk= zpwps77jbuVpJgr!MI!8l)lL#9I}2yxQSG(37-zre8FzgIE2^-Cq*eKzmR#C=Y-H-g zPA<%5LG3U_0#*;La|GwLHnCs69SuAScP~;y!ZW6Xjn-)?EUeT|@!+3`ZH6wS@|N{- z>ZT!GuP^b8%B2U<4OJGD*jG08Xl9o98GLcKI~aNG?x>|yfz=Jc2XXHc+$wx4wrJ{0 zGuZBgH0%t2;4n!n&`2K8PRVTdT_L=ipilAq8Q5Ytu*q8DrU+8pjd__+3W^yIWs&dR zN4;*tr?HY!fBwvwRulFaY5ei^119pxZ9hSRgb3=HIiz(Y=o%Q-yFAmrA@^9KOAwX> z6Xn|M8<-O!7jTfraYypXG*vQLZ9n08$KOU-l}wkI^Q=r(!ytUBi-yL}9ROuM9Hb<@ zIsnZk45p21ZGfvwaQpn>*iGaTgEzNkqL`o{kB)z+YDMi>vwFE0P{@h}XnF;Pm;P5E z0sFj6%Kl}7;zO<75Ia_$zt__!m@-f>PX$Bf8cz?wU_a+D*i(;nLfVT|a8ficv>_5A z^zPtRTQ>@&&@8yqfmO<5028x2{lc>=MY$kQC@+wYwQ8J0bjNQFv`mRE zyS(FVQWyG9JbSBOexAyTjLCfNSRl1H7P*X|0-Iro9HAc*Oxp3uHGHZ(HL##1XD$*C zZ65WY10oW3<-|z_`8E#}g51oM(luOai@f{Lt>5kX-#qhzOd&V`3#Eg_=ueC-zM>F% zfxEylk!}hEs$s=jvBsY0j<>=bA}WKVumIr{ShMg9ojqrYh=gi1Kdn|^+)xIUh`4=5 zhtu)|2yjtR{(%DqEvs-y8Gw=z1udmo@%m_jGa1hN@aQ>0D1NO(QEXC{7!?PrmXXlw zj_Ew#a6EjItSD_632){$tGJ>t1I#E5@fq?_T4x@6NnDuu2*3K zdb8nPmcFCUuVF?MueD)U=i>HN-i4!YTk0^mZU@tabtnhMU0(<{ET-ajwplgTpkOzg zd2={zAV4QgnL(`k;X}T}{kxSVB_dd=>NA5P*nw|eElqtbcB^G|2m6lLKogN&lqkH? z1>yxMVR$SFiY04So9RO)sX}|CU_5D&i+XcX7}dHwcSs4Z39@?AQE#{(tEq5iXsa$Q z&+JggCu0%=YU!>>^v-yEPETGh7uwLG_u*c(8Ti}$2nOAkM0H6#E4dpc1x%cjw;}Ha zd0OQ04b}LivSBsHz@|)~m$X<&9|ST0e;D2$p97B8wN9|HCK_qVO~=14x?1v3&Kz!) z(#jc>(zTFMY&zAVRgE>zR8Mh$~bVDcq*8gwo#^9phh#N`|SW{*B4Frsi>~E z00$hAiW0rH6RT`hg#OM9CaWLtcvbn*oBRHe=E<(~R(Y+SL3v$>?_A?UN@RbWS`uV| z#!AnBq}LoV+W!()HFf3~8(pN%#T18?*$)7K^W;E+dOEm^4`R>CGA@a`Z#%Zxi-#&Z zv2M=kDhY1fnASe?Jl1L57xgD5f*}EAEbPoR7=vRM!yQ#bEg8yeo{TDBgFWHdv!<|Y z#i4(qM@A~KyG4s6=ws-Syb3an^cOD&rl(185OhL>xcoLBan#N?QhvX{Ppc-qAeY}c zSl{Y;ZA&9N)`5|Zj9G8r1iaMfz~Iyd5V-uPpNBN>sd3r)=7M=4q3@MB-D5;nGse-kh6Dd!|f(7 zs(=TjRQ8jZi-|&P1h%jiVX9z4I0Mwzzx!ABUdG2LJIZ0s3zOHdDJ}Csm5vq)U^b&= zytMlN{4;Cs(p);$<*O(<)oqbAi9nUCbdf|4rY5eHge+?4NBxuB@!9Vj10K0R$Vm#0Fd^$ z6YwEN$M)@}UT8zNUW)jOb9Fcl?dbPOg&KB00hOBj1laFboeW#CRcjF?D9$*;viC4 zZk>h7avIg(Q2}w2^9@*;V*Scnd9pVxQbatCmJRuZ%Sg)6i|Mu)_!X;|%}HExj?@)n z_hFmA(oI>EMW1t27Sr8tYb?V{@TFR#lJY>T$5|JW;vQpD=T*d%Y*jE1pOz^YIMqrD z%HZHte3@lJmpti}$5TfuoNU_aDqgDV-v^f-?C~1GMD*aplq2zXtK~TX7NBd1#3klh ztt~JJ#;|1kx8NxxNd6wHw;%fh>GLd^t24(2!S2m;?Gm=8X(C3%5#)mFZIh#eCv6PS z57rqTu>lP5B*ug}kk$Bpo2ff+15AVeFu(;UZ;@Ck`K~!>>VbO~P+IB|ROi$?>T~F3 z(r~fnmaK*(y&7gQm9N}?#I6SqHjV>|nLtJP( zG4Qr6BXLItIWV_JszYn2_P9a`am1zuT_pdCWoi7s%xrYmBGLveAfxU*4>ItcT2Isu znKv4*4E?LFpV%hro%3y_O#1RvH)Rs(ryZWdXg>YJfQ^8`TTWSB0&NKYb?-*%bJd);G>!c&)y#hCLNmDwy@UfdWb zBK8=~ep+q=8LVyD)Sj}j9@&))CyTq*8L7`I>&T3j%18bmOGYORTP08p=EzNqdAQQjOVNkHAk&PloDXn?dXz5~FcgWAaw}fJPc!|q;gNliC%*+j)bGe<3Z&52lXj5j-v_QeTmkv{f z(m@LlCxmg7WZ;bSA8Lr`+qoKj6?WQrDNB_M_raGV?mfm<23&dP9`a#{Ofqx@9@ye4m zIT&EpXdoaDm9Q*Ml|buK)_y_mSE^O`BncEyGWlZaFpFFM|L(q1xz7c-^+)fx@E;iX zO3w6|^JWzwq4Fs;ZcJOuvt2QJDSG_bPP37haMY?@YQuNG8FwQof+c`DsY**JYvpnn z2~EJc7v$^dYaT5R1^1@fB;S^j_PYOi>E}6B zx^hT~ZoOSaLnNi5DYWO(RjXLqZO-MkX(MJayqO#K@Q!KzQhWrls7ZJf1r*^Jm9@Y& zsZodU>QlG2Qot6ktZrpxTvH7IP08!w_;QD)Mu>NjN_M;7dj6S`T$E+q@61fDj!~CA zXt8P}X6x}Hmy!AyhxCn1X-1eknb+agE?5K^EY7x!HKx)EI~MXBGAlHJ3iqvQGzuuz za!FXBcCx!5MW+ywRHD>_=X;2>i`32Mvc3On|225B(k)e2BpsQKLn$Lkq4c{*N9PVg zl*FyTgRATdfuv9pD0UjjqEmR1#5#0}btCv2_+~5f;uDM$Y$+M1x%hYgai2ly(EcMH zuGJC0PX)0rF6ktOp+xd=2g%09pv-e>hu?cS?ptBSHUv&I$qZr&QszYkQ_y9442?IlhriIV%yMK22^pgtX&6P& z83r^_kp;A*>WWLpp3iq)DcM#(=bBtJ8xfpW)$7qxb~J8cpMDKtHUI?L zR=4Jr_>{F^y5TVt;%nBV|1SPCJ-)YzL4a9JNHa=>s77BpiKXCA3PP4;W{E8Vd~B@o z=Fe8zOFX)ZYHRios;SdP0Tgd!x#yw~uq04em!?cooN%Ei}OwL__Okjade~JSt z3Oh$OL^Up(b^Cw#!{5OpRt_wY&2=gp$p;!u90geI!S}5Sk<ymTuAf-*2pVXxb;-6mlaSguF zd`Yl1%;IzcMHqWQqoMI;FjO1BaafbTbk`YmN#R=-2!cb@8bQsP-4V`B=ynFLb+57= zeFE~bFm8_A)#Renj``h}D69X*Ppg{TsIt0qX4@MNT#7>%c?dpHw zVoL^!&$%hHi3yOCNa*_p8^clm5ckOoy*j_Oo$|+d_|7hG(y@FMPC!Qbf%e9FWEnJS zYd-NP%`ia?!MWXR($@JCxENIfxDe2xh~nD8z--yK8TgnJNr(J}Zy$T;Lzt43mYqMV zGLUQz-X2K*bVwi3F{B{boLox#bEe*;x((kO?=f=*L29Nn8S7HMP9>okpS^4dMG{wJ z!5m8ivk@LstA(mG%!f4SMyExgrEbM*uDsxOieXks#Q59{i-GE}HnrBMb=LfKd21l> z#wbXValCpaBqV#iqO7d9vOhuzwH71<>1sSu_dy;&K?->nWH;t3@7i(B<3}lnvYlGD zWhQ|V#bmX+hSu6>-kZ=YUh!w+z$*3xt`uW@|Z9}w;n%O*)-WV3Cc40jQr)N>l! z(%zjNDiCj9!Kk7SX8*vaE@(;@^I0O>!<)h8Rd`}&r34t~{Nv6$es;hRrM9p{d%mDj zV}v;seW%UIQOqtvFQz=owKjyw{VV|~=z^Vw1{0Ll2)2Kj zoTeVVr0SIti7#xLq7~m<;3Wq5snp}_o?YKrvi<_?C$pqh^N1V?4=5ADytxk_sl2={ zB`ijySjrJ;X2v@kjjh92P=&iLTf?{wV<*#l>d?sgdUJTPdU6e&lP*cpoSW=Q?*Ol~ zAxEZ~3*lW9wmHBxcF6(m61G67_m&o-qPz+$Og?-$qP+OOtREH#&?Bbmwdtm17Xkuc z(yVT|h${7$|K(SB)(YExT19l1s@n{Sh(`%v4>v=#H>-qaN1%eEm(+^nlw^xWuW7T8 z8MQBC+r2-kevHc~o6ute(`RTIug13;iLZ?%Ib|k*jRSdX5}oo6?r(j^iN36sHuCV% z?!SU&f}cYvBv}Dd%n-z@-u3xO3ZiVo|JU_>63Cp&!}LHNtnM2e8S0M?Is%zZdZ`!O zJ}1n;s*Q`VawB|R70iX#@?N3UAito%(Co21Iq9q`!#w6K;HLKMCvZWh5L<5je| z4w2WU(@?DN#qiVg&u}JEB22N*P_;xh^ie_aFzQFA+NB;xB#r1XGM{hVMi@%Y(SLFnPY`XvU)mUn<~;6+2|vlKBeM7k`U5gVG>fAj5?G zp7(FyVKLb@zZ}irD=l0lvyA5q2y^_QW0$kG zTAEDRK?P)XmkuHPvAZyKC6QsliA~yC*v@{W*W$)*yj<6kcqrKi!6YH?JHQ_bZmlj5 zy&=nMArkt8i)v+pH7JZO(Vdip306tulOz$IgWx7tqaB-G^&L`=Ws|1o*f9k3IdUlD z{NdUtVB6T>&}PRU(zuS!(O#0RcC8I({4#v>S_4#AlSu^0VN6O*x&a-tR#T=(Sn+z_ zoK8k5MH=XWr`XURZ>|vwqG<`qXS;=63Y%Z`p({?L6b>&jrXM7KGHpjwI@$kDeCI-` zSrpsSgf56AN0S)oV~N^Em&Nfyl}IWXqDAIE#ZkfWin1J6Jx##r7&$(3x*E*XUcwJ~ zA=|v|;vfFyQ%<1auM9f_xMXh3VHs474QD451lm`C7 z)hZ>U){=}X>K)Lmv`Myd!NacZ#&cE}lv{&Qc4)!0+fPGNDQo(A#tFhOD@2jM;~-Mb9X0_odMG?@uZu0iULlHP~WEtZ})Pl&vJ;{VNTA$^@o@7qA}RG(#rA6)-)KN>8N zJipY0mFmdfuz1+88iriW0~PMz;}XM=Hlo3qh9*XdMci=DLG%Wjv zW-f>ll#}tibgefF11#Dn5)y!ECTlyy%+=rh@tg1YG#8PK zR3wKgfCWH*>STN2rL*wPT)a32MJiH}McK9;H>m20%=AOzAVZ+g2&RmkNB||PE#zOj z?tk^(Z1pH(aXM$IRCv7yqy5<79mlQF0D-p92m-iOAHnf}6ZPSC0OTw20SjYVePS%M z-Pl^E6dLPWj|pUwb|Nxz?}fW7s+8p_lp2SmWR1Pp#S>={LO7g+A!)wr#ziA{tj`J#K@chjw8@ygEp>9lhrW=3k)<4f1r43vON z?ol)U9eH>j7!#BLi10DQS{#QDH-jR}B>*A9fz~3(!bZO9nU4Uq9%0!S>liJKBuiT8 zsiP--Nbbh7uY`a!|m^r+W*~lHd2XyMN#l_(}vTK0W$1*(46;&3T$A|DLm`sNHN=N!~c4M1|f*N6Om<^O+ z@nac+DxA1^e$6f^Dwoo|uRQqvM9pqtH83Z^KnP3Q&*Rq!0@ye*PZWGVZwdazop0Lr|b zTw%AIFR2!7X6!=S_U*~{9f>C|8-d&T52{4OjLQK?M{6y76gPYI58(uM97#Sf&<-@Z z40kS4wnP+N9f{^zA~DI|EfI4<7amziR5&+ik&47)xmMjxk5WfX#!1PvW%)ARDc%@w zCYP0XA{Wfg<3IBTGUyeerdDmTLn>JKS)L7GsN%mlq_ctD2#sTq6OA_7+P1+0GFt)Q zHk3f3`;<4xx2E1Xe2{388wI;xJKIYfq|hbZFAS za3<_v=7Ty^qA1Pbbcq#c=oXYH$J7xhxD?@9!jUiZf^aTRcsehi8Wxv4)|r{?pb7)A z>ayjJw6i1eQjSYK*K@_Y?D!|VhU=-6WpPhZ*^%m;#`BHcg)!JI_kK}_iSX-colHP9 zGP6bkM-EOM(Jf^mOo`Rc3mpKB;1Qc_o?;#YC4^ndXnP9McdHzTc&C$w$9+ zOAj@wWJ_wN9lb#2+zxg{F%uMXnzcaY+|G8z228os20FR~cdt#Yjqc#ZnS|~b-y~L% z+&M(2d$&FMx8jOf7>oWNkEIN-r3 z6@`=L-_cs_uPvHeR^0o+U%!WPwUyftpQLK3nyJ!6BZ$Po;1%4F z5N*goMQ}&MAV#2Y_yVms3cwFLhD{1nka?-Vaw<+Yzr{cQ)YhA@kh1p7&J$E{ag0EbQPE)N`cHtM%~JLohB~2XlQV`}_su*Buxi+nd^OwP zdfi!fK8BvS^4t=1WCsK=z)zDHB)%K!Q&6ZODS8Qgncf_!Re)su&YVGpD05h35^SI} z29|CcIl~rHw=N+9ZqY3ps*|44!`pE3qeOz7fyrr3bB1n8>-IY2XaSZbhfZ|0$4X^AzKe1}9qIINUyI&O#PjWIqW zoP{VP#F>L4$@Wh}s*>_UcV|Qrvc*XNzYAvPA=jPoPt>WsN_6V^Dj23BIBavQhK<0D z;cSXEQ<0%9NbsA3_4f7vpU00x!YxUr8ouptmQkOq{ICugl!hS|OCmI75lLcEE+WW` zL;KXh7tJ#M1gQtNqVu!172Z{PB{|`T{Imi4=0uAhT7_XipyL)qI+ms8v z8|6Y90OtkxzAmacBe_FoH8FifY$(i%T)7po`O+04U|W99n=S6AFS+f^`S_m7ktMI! zj*wt_4!!5%Fr*w*7T%?=j}(r~9E0Y!HQDanxUoAk`-mTGH_i*|{BJMI=LQTDXTujr z!-P~a93NI-nvtp=5}=W_)|i$+k=XtY#w)y*8lb=ZlP;ORirdFZf&XHC`z%neY5<6| zsQ(l3`>1>M)rSXb<1mhP+yf(x*Qv!1Sa?Y69nHZi@@apeqSY*Vrc zw(w+vCKv=FtZitcx*mP$qzIl zc|hm};woz}(ch6SYT-vhMabY;$jPRa-{PlrO?F}gb7P(yk2aX@;W{b|Q5@#- z(1Zti9A7uumUV2#tqYPGYidUPfagag&VZTXD=X@4Cxn0Z?+JQHIVk!d#!DyjkJaSV1aEzkp6n1 zZk>>pU>UB#VY5*jENfVaK!SfzCRyH_YjwbHC-VZL`c7527njFXqrEpQ!?RWH!B49S z*jX1dA&(c~>sHnKCRiheKVYn2uvFfWp_2P~v0o)Q3h6aBjO9f)Zv)ewQ0Xd>lq@P7 zn_sf(-gk0&50or#MgF>*m~XMPzGWz^mk?+SQF9R47Jl7E_}_**R|hBU=bS*XJsPG` zg>>}UiME!;rd%NuB4<^h_|bIBY=ygQQR4}GDSVy3-EG&*JNGI)P1)d_PCIjgAOS~? zO)?0!f&`YqaPDR;Kai~rrGGDOU&$hd=gCFvmV*MX>pL5&C_wk~=aiu;Kr9yyf!48F zu%+W+A}cRWy2u3|haqS!K|BA?5{=gP8ROYDDJ&Ztzg4lqj!SMDW6_tFK8|O?E zXY75%zkQRU_ziwqMX@%CVl@Vcj#hj6;I9Fe;&4{xRUo3bj509jr8bO*&Kb$0RC)U9 zo8f7PRDH}z2B}LxEfKI2%`~NtOLSUe96F5e%gaCF59W!X(y8K z<x7_ox#l&CpOMH$UZZeY++m5f!orbpj zILn+Gv9;7GW~RmFm8`;MrHU*i3G`9)^^T`QXdV;byk#u6J1l;I%&?WM4OxgtNPtv` z8SX_dKD~JiR#93Rdy%@T{c(8>un_PZw#W=j1`AC-wb4Mi6&@W0<+czk*;^s&p{LxY zf`_)8L!j8%6H;6NpN_DP?}oS>eC5I1NcOPO$V75H7hTCQ(lq~yC=uztap777Rj_Bx z6GNiq*k<6e+kMDyf4+>`w|9y5y*Oc`HML1L!7s*2ojf2m8kb-9Vt-^igPpj)J7a$| zEXm`A-($LrEFZ9e66LhyfQk4U>-gawP;E#{?$1$%rNQD20T85|!qi#ZtMia9g}cvs z)e+K!T{5JlbKML{;dV$NI?0q-wjLO5aiRy$oVosMY9mV_UuYCMyUbz9Ut1>3x$m-X z$jwU}Sjw?e4wijgqMfw5t4`0{TfwYdh=T{;{@iC`O_j%#s8Vf)g!m?WpP)->j*hj} z@jcO{U^FyxLSdBgcfpuY&d`nGYLI2=NqU-j1>90C)l!%P%YygY{@bm%Px+L#}#S-%>q1k|Ws&G3D=4w~4J6a6M zIaNz9exdGcCup;5!IV7hk;s+LJemZ-%y1>}l6(+m%hhJ<@Xc@JTP*e78&pc-y+Lxp zd#{l}p6-L_y|J$m7kYKVXB%>&_wEvR00r=7D;$An!#7Yvw7kLhwH7?ClGKXBQVwn? zz|jT3k(X_)W8V&8f$|XaM$@ee|s~YvJ`@D%oK`DcohTfCpR|Y zycbHQHoO7!4rUd$R}8uix2|=_$aoKfDvqM}wMHhQhTu&L1uuSB$~(ecOq&o2(4#LCj%O*1F4*HB`RflNkr z=qx0sfEP4*$eAOo(|QUI{O^czr>=lQ@~(R)2ck5#aAvY&SZ$}F1cus8q(;8?0xmHR}2kRWqZHEJ>;r5%DB;^a1@THTfN8~~q>wOu%Qj!miLH;hp z;B~z@JYM0)5=d`wy5b3ox>N;33{JM0I4KfK48Fmb4KD6GcHBK{_rG%aWnBvsh4nXK z$Bhluo|JsC{Re_1czod2Kg%O3@S=7~{ znNuKzU3m%W9k=fSQ5(~tEG0FQLMS7zR)CclucY-n#6uU|x|f{2jBl}QuxRI`ijKtW z8Xyu(CEJ6TeKM}~qxb$;l9A{Jk`xwOs@f6cx%i9)hJ#sIDUyNQ_94-HHE8*8puT~f zH5zS!VwWNo=%uF~?Sc_i^D=gt@}7{n1?=tBH$9$hx|NdYTAg+T@e1*QnzyFspmhaBZM1ReA~TMo|@BFnB?a-I@+%@g{8q7BdSMsV3+#ikj$~#H)@7 zAX|FcfSUT*t_s_3UHGr-@E~Q=wK`v}szB~>&EyvBHrhi1beygP*d~IbP1_*oiItE- z$%J9Tezr#&WiZ+h8qY%X zNSPID@;yy;)F!)R{lvjaV`$V?5<(^6vSf0U)XN)uR6?-Af_u-PFA0C$3Pb)0zD~}* zLF;JRCL)&SrIqw63nF9=J&_Pfq%k%w ze-|8!Wx8(3MO}1>%|2`RvY%06B}Zd*+BtMQrteG)?HV6%>94@-e8hL`nQq6gzXzXo z8iwCm!+{r;ur7hPSfvm$)?5PMpPdD!iH7p^*15+Lv(WMGit1=GQ2lq?ng+gz`yvaBPIw*zIt=5CYq9_;#)`sb zdC6LVX!CBjO#gh=ff}wa^{(5``m{6u(hD9`y`?<-bn{A967e`k}5}hwh&x4f0^pC zF!t;Pt*W73;FRPbiFX$6(FM2tkpFpZ4^~n61%6s}#7>r@uU^={g@t)wmUMS+q;?r=$+`#TU=}W? zJ~k^(Chrz6%i@EnHiI8PgI7j!#N;sm_+2cZ-~h8=qK-C60utiPGffb}`po6B(FxOP zAyt$IQ|S&dUC4GfoHLFd-%eaz+T-{kl^}ciR)BtiyBx}BIC>CaW!B5Dr=T(}yEo#_ zCDO6#bd$HPss|7cPh^H*8qL4Jtd<;c-y4i6%p+BG=_rGVOZk>rAyF_Qaez8;sg^^! zJhp!3*jw(yEOdveiz^)R%DYh z(n}V1Yf8ixtO7qH#GCNda2C$xXmLExoRxCuN&{09*W&TcQX?13;03Fn#ls{j+*8yV zi$0@bnQofu;2xC)^*1(Bs{(})MKf&L2SW5NbS`^~tkj|Ounja8&N8h%*Aa13nHLIP zDtGQ$iqz}|3T;PFsZJU@h_(wJ$>h?T{n1%3CdR7#4nM8ZvxB6_bIxy~GBe6!hN^37 z&GA7;c2uYVAUk~L&}bcOFLiHfIpM+GDnw%0C9yBu;tY%nUe`da1M{4Vip)su&N4dk z0}S}#b}dVmEYa6|#`-s2EyNs~j9S-xYtoo$J$mEd*XwHUz-rgRQjqe-64;~Xosyav z1GE99VHT;5N=qTtQn%^?^5cLnVsrY-jBJDGq_*ZgHragFWP4e`Mc_~N-`;6wQl%=9 z=JZ~jLVxnSzPo?94vQ-7DEX>NlNvP5<5(Vdw#xHzd^A!x*$6E@+=&sQVD;uvc$3mJ zPS8lm$QQ^zR{KTrhzO4M4OVaEHOb$QsnJ|Q{!@&p=Ka6!nSw`7Ehw&YyVgBt;kA@f zSvQxRdqc$BHHu>6=wxwP77;V{SM$P@$7Mb4ttuaGsnxx#-nby1#N(7%SdD$6StWr6XK7kV7L?i^W?*TXciR|t!FMzz((%dT*3w*MYWv=;cN*P;@}yF zJ^u=2i4)ufXD{Th{C}2`17F5ipbzfXRn)2y#|+g2eS-ig-m@oucv5H4uhs zeTb^fS_BewYlW@qQ|}vN?^mT-BE!39NQPJ9`<$9IX9X?N8mYE(;c;Pc3%u`H&_Y^_ z{!QM7LlBYg)0EeeP^+`*(K+CZqo+TrYDy_WcxjCP>=!(LmykMTDC^%4&7o?uKV818bNtSeKXt-5_fN?^P@!r9%NlLT0Rb4GZ!9Hgs9S4J6sOM zgeP#*n>}~-8PZ5u){gUC6$?|9E{?XXVZ)M(|>8y0{H-T!Q-+*)CFzb=F~o zF*Am#_3gPQ6TvX+Le3c=EJl?UD-iZ)^!m!4cuk9~mrf&QVi92OqFDUCC%r{Z%_-a1 z|HC~sq%im}*N~}BK6FpSX(mh9)eWk&=nTU90$`IBUg9HH4E|&Y&{7r$(N+!Ap?937 zqG>Ow6)nz0sxNk{jesI*3{kR99~aD3v*zt11WC!+Zk={U3Xy=vIB||qE#w$=8fd&QE}CbSZKlotQyWLzFBH$P!+BV zG!j3_1#!`aKdxi%dgak2KK5s-Ap)vvO;Eq!2pgm4f)_p4ZH9ut1zzhNuxo7yf*D$u zwfY4?;hDZ|Xr_Y=demZeZVC!KS$|_SS6le?wHr>-m=?t>CF1D5r0`PUj;rHm-zB?w z%X%qns6Som{NdWBI+!HRw2Z184F<>*Q&qw2q?;d3u>0EU5ekS z!HgMNMqqigaMZ0k{PT<}z)+%sBowK|#mvINgCF^-hfpIG*-B|Ry18K+RBtI~K{I3NA%2wMnKZd^MKeb1~K)>L_1 zi70=s#zh(yq8u&mlRg^1#b%pYU+*9$?xI_#*5A7Y6AcH)r^3R!7iM5Gx!|clrw5sl z+fO8*(J`4E2a-F~`N)ywn&c2p{vU<}+~@CvE`24tVKmnjupSLzXz4I$x9w|R|MS!F zbY%y}cm5#-rui6Mh&mn)AHiG__c>x`a)AxloPG7T&&76;u=Kr@39N<(PX)4wkwH1} z51#r$3v}~KI%w7{ip^@Vzs4mYd6)VwR6fTx0~Tp_3G)|CRMbm(KXUeZ3V7zaQ>2}F{dwz#I<+y z!0tGr!fL1D@rs}^n{@+zX&6VSp@j+(i&F z8Q(6YLN}bKbg}aa(t!WjMo ztSIX#G@eMjw6JiT7|~L7R98g;PoahIc)sxMTOWBjT});9o@O`K&Uc{xbaQZ06Imu` z{t@^LcjbhSeSQrTKd-gnp$Hhno2RLYc+bFyPQoOL!|7SfH^`l*b2#VBA$4> z#u}NjLS9+TtFfvhIZqbyP8^&9B?u^mP2e=sDwn`@2X}s9HT`%=qsrX<)sl!l7u0YL zO#}S`2x@6V0M&^zr-pFW${_sc6uY_I71eS3O7rDnN~#c|D49PAs25fxJ3r7OM~Eta z2%T|X#X^az5)x5hDPQZMuUNC_7_POm#CUALKG)ifsm()m%vKxB>tjUPpzd%5!`0+U z8*iDL9D^xLVIhcPcIZQSQ?Rz)wNMPOt%jvN@qnsfCL}xe-QPOyBR!3j)hs17{4;Zx zGFx&_85_jJ$0c>yyL)zAiASy+R3a&xqpn(U4r0dYdTmQ1EBsI^Xe7OT6A;%ZPH-G) z2Ss0u+tq2Z5t&{UhL5ykGnSOJBITaer=Ep$Co;U7IW;jUi;4m-Q$I~9Jf*Sef0?(| zOvq(&#_7#JUrm{m^pMVdLP9(XAV|)oX-pjX^4#2?D;(O$h$k7egNZib-83ZVSJ7{`9A7qMxiSQ*X+9??lQg^yAq4W3xv02TDXp#tpx{Dj4#&>DD z2ykF%d)~LcRee7eR5mzq?vbi{vvJvUZ$S-%>N56>J5Egd`t4F1`u7gp4M{TVETpl_ zQN&fdw^hIG=T_12g0;6(tfD(FN7y1YU#qDYVIMr5(z{s`F5XlW)vPj=W&XP_>wep@ zc+Rr+p}9w?fcC-V1*nYHqC!oV-fV2e1|4iI?%PzKQv0C?uS;>W)9m7gi)jT3ekF}Q+MxVKW~vI*{Tg*oZV&))w~n%-CN(`tG)6r8|k z;qcJ8we{Fh0$?*RkWEXk;vyW1UIea@i)|=PH|{qoL@Hv!d_`*H_>MV2G;nHYG7m52 z>8q*iy5xoZ_`u3v@YA}Qxe269V>hk8Wp+a?#F=6?`1^+1{!Ir!1A# zQU16KC@4oE(krVjo>;v!T!8$}S6}TPeJWY2%DfUcdaSN~M&Bii(~|BaC;`g_ShW%_ z!V=ku6th!fj)OAxUDID^1p@c6(IgEBFtwMI5AK%aMCv!hCzHZ4SKVR@?sG|*`6f1V znwJd!=09Igxt&xZx8rA2Yq;NYMOuM`h!iIZx}fO`s*#H=nZM1p z3PD6UCFXz-LQFiE$3giZ+@QN3c_@QqWN9ye>s{rA6CXI1KIBOy@_V|`(?U1gqqdH|9E-`vuo zK}y|NYE_g!{tMLue7+ktsaqyn>4j;6>+BfcjH%f6*IaP*sd(J72D7=(%0z@Qd&r$2 zij<0Te*~gIU+<{?z76O4S=_o(GHA%i^F=(al2jOuN8pTg#pD1clU5nkO)}v53sOL& zHp(%;i$`@i5k*eR35*yix4T8A4%}~&v@K9+<_n0q87WdXN^{2ZN+i^sf*>R` zu;;ksr(n5*H5_ts+YQa$jkn!AeA~4XW4-G)-gaYibPNebJEFS^pVeb93W}gCS3z1Z zF>XReu3;z(DiL+bzM+0XMaz?*T~dI@EeT|YTQaDjRiC`|N*#G*{KPM?KSdlUO>r)H z=H0J*^Isk9^ELZD1~Tg!)Jy1ZkxOm(__yQkgs8N< zL5hYAb;Ss(oTkyTm6b5NFy)ZL(rN~>IQGqc?Abgojj*-46VD^4@I9m9C z6DIPaNVPFPnKiD6x)G1~>UW)Y&;AR!`jSqLxi*!4##YZ>ny%!9iGFo|kJnOC;6Xa! zAUTl^z<+``F$OYijuN+nVlo`OorEHaMjE=Ak&LQG2wEyGgF>@@ami_{JXA_LIp*42 zcDmxl4UA>aO=Od_g@ZgFtqnEX@+cSJ~8H8qpFxy@%u>_{1 zZNLislB1qKj0&zE9USbI3(=i^5}a$q_FsMN=ZpV05v)*u@o-#Uf|)wG1ZpFs|9fj3 zi80g`RK5_O)+J}!6&$G=u{t{oL7>+`apDq9_XCmPBH6t9YDpZRN-_hV; zE_u@BDT(!C(EYkGN*d$(BHmb&e%3r(a@!vFoC(%o%H|5rJ?;NSav#Old+FDg6IDoe z3rIPofZamCoVs8F5zi8(W^Vnkj_&+#v~P+VFH}bY`*7; zeLj3XU2TQcomPJ6j9hlWEY-#J<|xcN_0&;eH`Z_o%|CXjjX-?`?p`h}O73%TI+ECA zxDFwA3hs$J4VJPk2FHrf=;>jV{Yl-IBt4@3X|Di z9f_Kb=vfY!lfN^^7TXLoFd9NuT-2lU>-CCDzOJvOpxu!ay5P2+@b<5=W1+MXWV3c@ zz^BwVY`}m^?oGr2P*G$T1Jz61mdHzO7$_@2aN zBcbwr{It5dy4tX)U>(^UruU6BQV~*BaD%0wt)enKifwn;Dm49nKqPcZSyttCl$C{!MQNH3VW&_#I9X z+<=Zmz^0IlLoaY|*(jUVJ_z@JVN=9iF0bu}zihos=_#v8XR~9cU0$q7uaSd%)f+%> zBk=@_FThaJEO}aMre|c*EG1fCrMc0`#{$Evj@v;uYb>jkGJx$C>jTW+nX1Z0D@*3_ zGO~UEmLg5VcD?h&8zg5f8FD?hsrIuk7RTm~D$Y$QY*u042hKUiyt=73z+Qt7TV`F; zQXOYC-MvO#cR3qQ3^|CGmt+m0is#!qH!b}x-d~vEC;eNbv}k=111mx<*kJlfo8?UO zYF}aHR0ax@(na+J6C@x?dF?GKCAQ_`_(2>&)Z%6i!-b*R&}i?#6ekk9leq;qE}6jo zbTm1jABN5)6`9g}HC2G*QE5M(-N^iAucg}#H}gDsgn~Z;_Lt8WFPnmyy%`CaTFsY| z3;$GDOn-Bbo^GQx@IcS!(mUyb$3A@?)>4^M;>B!GCJTC}G&W*R=Bj!%u*h)g^n4HFdKy4QO}1K92< z(hzIXmJZhv{ACyPjwE9=bV0j)BX{id&%aWiMg3$5);28pICeAB%A*JVEO}2Epx>4O z`o`GcM6G%%%C0U!0rc|g-c9&*8xDnI zibPYVg5YgVA}4B$1>7K-+N8hl9mDV25FuN6daMKmFM_5%mSKQp4?OgVXe`OzFY2(`k335)ekgmr!F2hTc zfTn69*{|lwmW8rljg!59=|NS<$N^SM~s{ibRh z^&3wxJ@$J<55IS#G@HiSQ&`pzFNt<}37w0z0l{QpM z_mGVGATyR+vsFd_SetTQEeL0tB?*gdC(61Zf3{h5=JaX$4XR>e9&tZ_Ie067p zTi?1rm=40_Q&2nMgaaPi1{G*b3`7Ul6LEQ?UFOkkcDW6K-GEPU zX+Wb~ZP;;vjaV`dO}hRBhk?wZMBVT_EXvF=5shNdKnw9NqBN~LbJf!AgBK#PSH@Np z-iQi+9C5BG)prT*c*}XOd>s~0;mnfOZ1Cb4RkSbQTUX>2e+BG_WEt@Gig_f`1}MBC z7x=E=!?hJvi-dVh%qR;h-mKDwRx(DSuk1ZlyvP1;4bnaE_e>06o6Ni9U3%i`G1wyM z)*W~L8h zW)?ETBZ|gJaL~E45Rhxly+8f@>;Z7=@Q z(b7Zsgc4JElP-D&-tfDyg8V57R7J;?xRM zTAg4|javRo_+`WwBRqkO)Xi81nSBWSv8dNdcC(N?SJ|LKnraRL>eb7bbEqyGd*c|T z^NbSdyj4|)`P`| z=$ZTW84?*IVYkpFMrJc}12_Yr;87qt%ayjuV@%P#B3UiW0%gmN!cU)Uf$gByX=m9* z=DkVaxG1*0^!k(chvJlK&%0CuC>8H&DL1r3}FByshJ5BjF7JQCQQ=2(^a!> z-RHY_^h(KSmAO}|evzxgIie(zs$EFGqZf|3hMq-oP7ScS)>i+;`M4S3Ji1IZ?!d?H zF+fvay8crs0OG~@P%vf;t_+8G??=N4#mOXa2uHyZh7}^cFu;l{;zw}5g)vnD|vE>{$D$jE4cz+ zy1@7BWQLBHYW$Z25p|$~Dy#)I2pFR5J zwC}r^6meL)BWUMnGbfdwr0SbG6IOxmO#NNLF2IeX^wfiQR>=-PD2ydcDNQchecijC z@h1xF*Z65Qjq7GqSWI!cteq?wZ{FCU%%~P2ob0oqQ%ts%(~&TatI}8@%EAm?IjxXC zS^zztJN(vbnG;u7>uFu^_4$HPN9-9I@599P2qBEPXb_(49kB~-&1IrCV{?8BX1#r9GeLy2d-BDn&~`9 zmkhbr3OBV-==tXv$FA+zt~0Z*dgF?f6v|KV)2cH!%%D)1mM)1Yw*eMZGi(Y#+CrKN z&t7HjiQNpzS6VX>6cLeAQfFW0_7^?t_PT`0pW_X|W%pMu(a zo6cpwIP0G|rK0kWCBF1VUA-hQpxLVPhijuKD2)vcZT4V$1a9S4;a=hiyVizBWg@&V z05taiaAA^RRToH|IKwIGAhJxy7;lC|jkv5%YOX9Pumk=Sc&*kB4UjRn7GsFSEhH-+ z;oMC&iOShd>aVNL-7A;8?#mQj$w;!fHkqB=K~Ei>EGSc?S}-vRf)d6}KxX~uI@r`s zGIJU3_O&VEPOG*K7la7+AQ3@a(a_bU+aZ{-7+_P%MP!TQCv&GzK&NbDDpwBpyyj#f z-t(4g=6!rGJZ0Gl2XnWpTCqsdQy%~eiB=47GW~@j$q28oA49IRp;BA%u|Q&20tAdu z<4(mgTs9QM>FCt7s0^iJ3t&oewsRJ8J)#$UinR@Ry60+f?{h!-8xoO~N0r#r&ANDI zxVrc?6F4v@n&wF=>C(|Pir=@fa55w-b-yQiv0R1OKLc50U_m7#<@@7eI|OVC@7?57*SjJ8W+ZHWCENWTS~s$pn0_soD74`-DWi99EqFy&_CN( z$2L>6?=}E(+Dc&u@c}(34#OwFsaV5^yx78%f{4W0ArJ0g}~(?lb0 zPQ}HhE??|PSKPZpnnTJq7467k3EIPO49QALQ*Umd;5Wz{5LOLfDn9 z*&cqShT?_MLY>|+8+u&OYg#V_OXi753!Ua73)$t|F3UbHpL?&o{LHW6QA>-0Hi3VJ zl;N}Z)~-ah0&k|*u7tgHG<5GVAthyUE{e>Aw8@KMmo-8et|E=N(iR?hEMit;a@(2n`NQ{Rv)yGma>G}fisX2Uzkds2RgIHlh;Ujv#(Bj<}#19W|pk{-5V;?|Uov@0a^cdVW8HN#DLz z_dWM4&w0*y&&y8}`DA_wT7Z312!e7z9{v>*Pkdaae+oB-dmkcVE$lbGkoW^&w6()E zY1g`6AMy??p;VJ>qCBM+=Z5r*YNPa~VU^fNHv9iDtnG!keSm4RHXLJBr21i~GQOnH z^dPyEr&mNf0i31FO{hR`H2|UKAOiY=_ku2IuG*!d1#VA3T^37r-~Ssz)s*3dTaqR% zk}Tc;SqxjV5Z;+m{Nh9Ls@3(X<~uM{QdjcRfDQOn5ly^td;n)vWFPD{1z(i>nUkp5 zPXbE1d}eO?%7tW=O1I(utICII#71nB(GE&iG)ZvQ~AAKrbTd~8a|;m4va*W6>Zz}Ev^DkGvRc6hm&PxF{2muSh&~j zV}X)gy!7aKLgL84JoCQy{qeuJTcY-~l3;HG_^B^EXb>}P@R4n#7P-FgtU;UtZC5II zWtMdE%+m8>hl~QvB zesBQI`B4lcY{T**l!1<=FURkB2eRweB|m@clI2)O?bH(S{UVv$B8cyU_|^gTS_)UA zyG@DFw`TO1DUQHvU$GY)H_9eW&G9m%q&CQDLkcdP;7ID|-D-eZ87}~EMW+V!a@S{Q zGsC_vwLRB=;aGNNmQEhML#0N}b+9$J(8ckV%>AOrk>!YH8}FzwMjTKnztwpq(Xfb@ zs-42JXv7|C$Y&;D=M({4Dk&m%pS&41R;!TF?I-OS z89(PwzEOJ6ZRX z!QJMSA)Z1Dh|_3jNn)j!9U*M0v(f5LzG!kDr)1#Jkcur4AHuD+?aE(Nyh`W; zv?685Pj(z9)p~+a$mBc(33tDrWNiJS_k1o0xH{!^T`4og9CF2pPM&i!%$ z>nXz=OYfEo5j_6{5<(>Dg=#dkuEBl3D=&+e>aY~RQPcPt0agSoYclG$zThs;WAT4x6lF!JGnb6I{Oin_NBcC zie%%L1}59+c0}ubZ~ToiH#`B0d5~6Cvv5=#O!8H~xa~v|A+?gNzDsSi{XrKH0oRZR zK+TWoTLMg?tmw&|)g-k^%*t&Z=**rxgHEY3OeV-v@3&(~Q}0i|2U^#R)L0Bj8%6du z_ri>8$3?r|&Et{FPWfHBBq53+aGdVfnKjQM@ts6zasoJ@UBxHS5pI;j)o4}bcQk`Z zuMp`AiYf&AT7@-8#<%Vw%70mj8jXax8>d&7zGyP(iC>zz>qq{T*+ki_ou&6#gf)L2 z-?hP8Je^*Qwx!&L`n(ZHI?%me-{U@lH%`HbCQ_sxP!u!+f#hA8`e6JE^5C8+VDam8 zlL0USi9ACdLKGWXbLZ@_?ASjHY-UNmw!Xye9Idijg3HjC?bF<`g&7p6UAyYAsy)j~ z+^waTD!8BParbIyO_sh10|zPC4oK|?lif53;ui3XMuAP_16~Bdn_>~9Wo1gw%+(B& z4|75)d@{nQ%1k;{S-U}I4RdtErH=yakV>kzt3mBun1g#qKJz@Rsm58|z3A$`D$GU6 z3opla4#2{iv?$Mb9Uj24bhrsZ9@YY+qYXsJbfm|X4o#sYAzA#kP+t}xy$UGe)v*UE zX>ETN;z0xj9nJW6m&<8~@3>kb{t+c|c~Fwe7R(|;$meO1&1elE>O@B;E;Mv6eFX)3 zDem2z&K66kI#13BrJ+)`MJeY5jOxwMD2XlRJbE50%+$A|ahn>{%fJw_1dn>^uU!(S zJb7#F1UytJbhJ|^NQG}1#}0X%S63fGc<6Sv=k}%>B#{=+bQdtYq5=Z?I6irR?^w%j z!t=ZTP3^v}Ki1!E+Jm?j=R{}j8{Q`-$Yp3=QKS2G8mb;N7~G0zOOB7iqosovQrXAF zck_*}KaxyU+3_|@?cfBmeX2qA74st#mqH=_olBtTC!92%iB z!C2`6F!frSr#g{2D^fSNtnpr4m{fJ#)+~~rd&}hyVXj{q)lN{O(Y318tnN%=7Ep1m zYBngG;7WzHQcwClH_dChnNL-Z;VUd|H)qLry__OtILO^Ha#5(Ci-TN?H-meuvYbIZ zwG||jl^F&~AV5-^l(@N`%$z^`o?9uql3C|VAC}9Gp5~zH38^Qd9nTM>*VT;7$N=PL zN}9M>dXTaA5EROK!q?^Rf`p#Cc*EwBjsbgV6vNlh(D8qWhKjpL7?^s^48HIULY&{N z#3!G)s3KyBR0jdFH_uDcE&*K_dLdW(AuO6Bq(se`Y!|l!^7trhSKk z;avv1@A;5Bhv`lZFOh*AGqOnTghfe(%^I`?&og>v4%OX=Z{%~woN_WIv1F{H?Nfnw z5W$HZfeW_1P};T!iJ@q2x^V5`JCFP-9;j^3(b7k#F0g&g+$x4kw}KR+i!!G=#-CSk zGne4j4aLz$0{^JNKzoUVNpS=zDbJHJyyEuf>g4vCbfwWXxPz7mnY%5wfL(cL*ATv|q6g3G}#hd(K9Pp?%TKrp(9{ zCS|G`hRmtdH%}gM5kKky`{9F8|@e)wPJ$&*~q;dx#+J8pfQ|BZwCy`q3m!<+!T-s z0OHFS8S!V-WpVDi54oD>0M&TZdarUlR%JojV#@-y3GOcnW&*BOsAE*iqMn7D&z7o$ zHce-yXNy%Gi}Nz9C}E5#+D0r*NVzt0a%Xv*S9Okvo1}o5dmYY=5BkRP-{L`PeI){T zoC@GjTpq^8w@3;Yp@6q0aX?suvxutXjvTDBO6tcTmZae;bCeQUGHxWt9T{J0XIrXA zO}DeR%=X?ZE*2wm$4*y-!m8E>wJ%xxjIi+0k8Qh1~1^}0#S(d4jmKmKr_LW|C_5BXN313^*e82Q`T`5`e^Db)5!7py^%td1Y%Lohd zV@&0p8?Ug=Y1}!O*Fg|0(1R|0s^UIXHQ><#T_`YTUzyB1fdF8q$`D7)((VE+0J=~> z`lTG^^w~GwgXNOi@)9FhrHefpmlxr@-v@r{kh#{5xf&}dX|tbp`>++z(RRvBwIHcp zQ_%$UJ{Ov0)IKs!-3oeuoK!fXU(8M=r^Cx&CFxmYZkr003A~0);$I}vJ=625-!qKz$`H-R1-9dBeoRS z6%e?Uc{_fKJFdULAXP0jRl&dsTXMpu7)0K$6E-Bg7>hC9!8 zb6|XwJ;Vg31-iruxO}&h{I+JIY1=`fa)sfOGJ&h0SQ`(0DmXU2iHxEs?D=RHxnB`jD2?QwAq9jjSE~ScYoxn}z$b_q zk&Fhk=$^3DP1AXqct;nWAWf*6Kwt0igp>3vRDm><9gWn$?RB& z+$syh?{cd=(4!$-UfcqcTcwkemUI`1&{fuo2s_J){=mVaPxLp!YZ>5#Gx90}!6N4i zBn~*G3O&jso!HJq_i(IgXxmQ&Je=6uus}k1nl~PxLCDFUkLLWRtO8!-oWCbi=~dT~ETAO6igFRgjFF{WIP6B>d83gb7B@CVz@U z4kiyIMz}V<9ybngY?J2^nGPis5d;aKHjR%S58Y;|2f2lypjA={72*$sphL8j+&8pO znyR9IO7%BhSHi-sTPMBpiT^Glc~FU&j;lzR&4U*~qi3^zW@q~1=41*8+!TWgyw(`A zYZambfrT29m7Q#mm8T&xdn2>VqWM5t#wKSbC&*0|0STf+nI`O+Y0Q?C3Rquc3Xy{K ziZ1`gmt6VSCLXX>at`Fu$xJqr&52h1jP~5cV{jLfF?U^L!)uKT;#vjSyb<3FOkJ2) zNIb2|Ar_UKG?oaI75^rUmOA_Wd_qN!OPR8RGy_K z?bhJNnO>#Qf`@B>7Cs!RsWqXf1=38~7~F1&s?weY-Bp!XGZ)BZSD%0A0v@aOpZL?8 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 W54ls*QgWF5sa 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

      oup#yaK#JAmd{%&h;`^6B4 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�)PHuJU%T-Z3a_ZU{7Wi4ZUI@0?4#V>Yz#I$ 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 gK2?CH$cU*4qevvvm?+T#B3SN_Qo-G*#6}TDFh? z#z6&@L0nK2WLHp>MP+di#03VIQJircbo3WR9h`9#_y2v*@_k?3+`;Of?*DlP2kQ2% zy5G5HdCz;!cfLa(Q7S#QQX4D%-8s)2JM(eByy@D1nEuHln^~h;dQz!W8m_iSt7Fwp zdChda+Ack^+Q@44(z9@-VOJ_$URkgq+f*Ir#rdPHM(MGQ*5+E3Uwibc_d5H(-m}+N zuDEm20gvofw{}Zc^2>wzF!d+U(Y*8s+NN$?6#HE_bTOPu0rp>SVQE$4#}d`Q=5eHt*?_8?|Pw zk(I0XU);biz*CLk8~EL|Zn;_O)XHPEas2;ItrDJZt?sNZ%r!O5=AhiEcp*t7l<>NlYHP}*d z-GDonjFqeHcB@^^)|au!Myp=!bZc3sJl3kW+IY}fbF?-#)$GnMFK;!=cwf~v{;NEh zNKF2;+Q6bG@RG_aCcCwki8sTmsF$a@6n$s@9>cXJ-p*KU6yj}8H7EhOQk!31jW6i7 zy7*v}7pi=k>QrNXc`XFjC{NTz`8Cz7+{hqRm)qI#m^g`$a++*+iFy{)U(d$L~SBlFb>^pZRk$4Tg~~^PNAx;s;lg_<4ds`DnSd{ zQf_V7P#dj9&A^+UUmoa8R@=?2JJp8vP?Or#iE49<%2}>bPixK1(3w^nt8G-f<$5+X zmWdY5FAqU!rtr6_W9{nbR3~eWWmQwKP7SZbl;_d|E_~Y26vEyGLU?u*!kTOv@3cHJ z+Uj;)d!B*Yy7GCY!_WIrpXFDn2+qN+OQ!Jb^=v(iqScX?*(zfp&FW|sicb@SeZi7o zJJ7Tm|9Y%iua0*4X{$cf&E}U^nN>y+W;KYUQ---WAY8n3C?cde1(T(;Tl$Oqs`WJ* zc}p~|URz&nw_GS^PyB4dV2r>!3Tu62|dz7uBodS+nXZc@eHmWKii_uW45{-ul`4tskH2 zRMv02_1bo`(`og!vNyb6SN3^)*E+njNjyFr!)E(e8b01U-g-7lC2io<(%I3n@$R-x z)@!3s5d0h5x~N2}S*2ZfMFhb)XE1O0N;ql?#NAI5rdVFyt4?AT(NnpHDrYn|Rh?$F zGg_mc3V-JEyl3H^8;+tpUs52?ohr{K;_{k_Rs(KuxYdTgcX3iNx^kh?kPCg7%fuck zzE9xZmDP4<5`IELlg5|$q^kAv@ssLr8xAvqI4=Rx29nlO|KyjNHFk%}h%+-pJXRMYrvr4-*KK_v2+2lC+ zX_ez8xO1e6NYsG`Hd#S_^ULc3Vhj)m>dMuavi;oa!6-FX`(Q$u0o;_J^u2Z)NB^ks0j06IM@*T8Jn z2jpFY>rcH@aNWSuP?4++9M%Oo2+rrc|7d+|49`+%LT1x z9UygBMF#g{xIZh`8j>CWu-bBb!2m4LtkfSd1h&TV*l>P%83B{UIKsjyDl@U2e-}(o z0OVkjLEx*Pffh976$tJkkg%ZXI&;ud|Mi?7QD`qH5ZXa1w8!D{a244QfOmDw_2zH! zDeMgS)h4XFT^rrhkK(-L@wMw^|)%!BB6F;Pqx|rWdzb#8B*XngVaPZEWa^eLrHC;karAcM234H=4 zQDbQe$m|g000ICW3ow{$G2w(Q={F-#;szDLsG6yyBN8kCteCO!OBFeU3wq6vVdZfkM^vRaMjYXV}rZXJN@qw#vBZP)w21Segr zV*4V#Vp+(MC_l*$#LIZ17(u99Q!ywWP4X019k~8I);W;XBuo+vpjnIh1ORsF3SCI69|zG>~srsr547 zC^4BMPWNu9WWX#T<|Y}UuCqL7S+0Tn1dv!@74Cp(fJzLOK;9tWvjAvJxGfjx80;xgDbN5!ZS_RW0-6v*huVEC;a5I1bj=~Xb(?D1R@@6sW3UeXMv##%R^_66b_5bo zFfuX1a!=M_rQjSA+MhbqDo^q`XDlTQo}%>Z0>$|kT{&Ix%517$ zUWkH7H87ThqLcWzvR*#!!@%CQRhNAs?pzFVJ)}4Q6fK|`_+dEXB)KTB5K76D<`i_N zLCc(xrn1#6aCwp*p*k=?qFdw|#NtR@emO~jqPe?nTyW%B-`t(L@kjiV*NyK*(^}eU zgGetAqma|g+!0YZHp+!cLoW0qrD>JYH0~X6nNZ#J*?>iqZ;{L_u=z&J3AU0yj2ac7 zmeMsLV-(u24xRxi5?2H?Aj2(`FXZ=i^g z)YZCrr7|H`X0ZB?;cEp`;EDKj@x>6`XtgYm^*Ne%NUBT5!)c%wxj+RvDEllE(q0up zYh>^{DhIbX=6a|qk@rXS20x!bBycAYrn;ock9g-_{s)g-7|6dL?PwVGnq!upi@Vyb z@oKx0btby4=E39b8oX$CqA!5`Hq(}O;9CX)c>quAJR=mRhdNTm$4h3e`XV30b}BJ2 z14x{a9S;PCM7_8NEA#b8r>!svG2wTWrE|HI=6z`AS16Z#3jE6tR4$LksL*65~6>v_Nm%~oG9?`@WAybt#;cQQU$yjZ%w-^oxrl{8IYaz|2L79@=hNOEGx zqKT9TEVh&jgR4rEi>OExtStF)61fZ1bYD+D^ zKB61O>iSp(WYHw9_XC3eeoEcSmAD(sqgPA8P#ZY&;7bC)3b1^iUid=P1X~uXi)t6l zF@>Qs|6_T-tCgq(?sNQuU}w}Lt|*(3sA@=xHEk0pZJy}tcf9vMSyd|?u&W-O_$U?F zUbsA%!8x|4QQ^s6u-`zFMAL*+@qjx&qVxly(XQ z?1VZHb8?*2qg%di;Jva!W-l9{{s=KO6)>3;lk7vvIc{nXuHW#;CPg$)$UF;`xDQ9s(5a}&Fg#>DW^({5XA2`#ViXhC6pCZ z4y>9W1%uaxS~zD5#ULb3!jw>UybrzRg53R z-O-1;4FSa@W~W-DT?-C+QEVX_w-!ZC3riB7`Z;J?9NxSb-0g#bfBCH`IEkV(^A??mMpRfg2kukcU) zecu-S3X`H;y8*~|AxoQPCXU)rKX3Xy7pj!#%oe5VaVO#c#g#e&6l4PM32D(ku^q2n zBf$=2ho|$@e^-!|k7)exAMx8o4E>4Ujy_C8TWhH;BPESk$U!tS|=;P2}2DD-Xn3N<< zIq;_ru8C=s%|XFeL%rvYXV;HD4v$+@C_C}T(GjdcPYpVuc5wvH!L4J}tavch5$+j7D(YwDut)u@=^eH^hxciJCayuND#*B)#_hs zDl+eT?kbhYhw#N(g^Etq1*GjSAST-AIYO?ugat%hibPq%9o_{dZ9&i*KpJO4J!pzP zk_C+oBB~mJHIF0>E!iR&`_?@B{^FKjT!CjTE!kB_Cp{tx2?TkQoj1D}7$Ysx2b9J@ z?m=(Rq}7+^oUC$Uy_?{hUeH zhv<^BIPjrxKGD+P;-GPYRf5gQpDT=%@}(v0?6z=0PTuv-tDj44dq#mE|3(E#c9f-7 zSa54Yd3ZXsY(5tYQ=OQ6gMGl7Sa`}J(_D80{xz>nPzG^Q&mb= zq2wTHN%}K!PxiwaiN$`&;>y%3v0rZ zGN%*<41eX6BlM2$+=62u8u-IOze7nB6mU*Dd=7lqyS0_? zyc1O%7vrZH#d2UUuEOO5*DE|IoOlhd9wl{0nOYmIZk5JI=Z2C5Dyeqi8;moGz&#{W z9!RAfu7|>g0=vAn4t?^qFQ*+68{|OtNkb|xEs3_X31ppHVuL7o_zv=^31po3_@S)N zg>1^atNz7Ceew$K&w=WZ6tNlKV!G5 z^fX%QE0h3BM2SM$h5Q=oowCOXw=3+OFezZCcT87db!k(kp4sUfQi-+J5fWYlz@H@G>E!L z3$T4cUMNDCXo8yw05W^1Tqq(D1x&720GFYhEbhn`z3r3P-V83K#})*iM%0JZLUy9( zZ)>U#C|QyM9c^u$!BYPozcvs_OkYHZKB@{ZOb}A&ag^T@%NaZzxRTJyv_kAAcFCJWm54_WO2~1^GF>PupLF}0CsQf~&AKNY zuRj6k^ z0f*u-3ggLiT>HcCdT^E4tZQcro#IRN_DR5$VCK8($R;O(k4 zSBd@cA+YiU9;sU4ex&A9wf>M7oi zcS%-5H!anRspD|i`-Vm>>Ci!kEh@05T4-BgQ#E*Pg3aj;&Zq5f!w+pY$me z(bI7G$ToBbPYK0CEo9~ND11wh5?QN_Q%FggAZc328v2pZ2bZag*n>6by*^kt3S(j4 zVrUz2Q_=MSf@Cz(cR41Zn~$cXia01@J(nHdCb#9l;W8L|)G-Vc zVWU}MO!lmyEw+6E6+;%z>9LIhvC^2(!~xp&8=(>5(j;yq%s*PajSJlEPnX}`r3?#p z#GSmSD%Y&#hacWu<@YZ99;!=GN4#{D6jd}s0w@e6UDm5Xy99#HYL$iyHD)Di6wLv# zW9mzzHEp8P;!a#TDsA|wHC-NuTs-fEZ=#3VcUPS{d6~+C@l7_buda;-uQU%I%GPxd zFx5VE>4I}q79YlaOS~;2fMe+jNz*2K$AM2u-*xC3=_x2!$w6J0S|_$Q!DtiAZO$f% z4N)d8XP3+c-@pHj^b1AX`cHmObVI{P_89uxK{Wg0rcv|_j#kmh*hI?~%E}L2jIq%F z(Th|@*We3=*xxB}K6+burxDH27Em|S$_jif{zch2!A|KS6$wC>yhbH|=gC#vyMz+C zBP^gONyQYHX>bMD>Zv2bGBxoRrqC?x?vr1>Ry69{SVhi#pL|ZVu%#K|OL?R|-R#M} z$68FFMk^5DUu($8No|Bu!~3S9!)r*UAt^J$o8mn0&>_Db+SkmtXyqorYWG>L4SQaF z-s!Bd6!mwWob03><`(Yq8fmF_*UQpvgP(h={X-PEZA}-hP)+y1CIE8tW*^%TNAtbi*2;unntO0$qhvOrPtEcx5WAXznvaw|vk++^9Ix9N3J2|l!n!2!gg@Po zmav|wV(_(ZJAJ=1PvzPRcD0=ROnP5h!3dY+=_q zBIatg{p!$VucKV{FEFkDN?c79@fYBoRb2!V_s1mqC7Y_&G0&x+Z0h2tt7yoAtC0ve zV~EyWU|PQpo0Vu1%J=(FA*b^oJmjXfD@?mU$^!=J1hqzIo+MCWn)p)G7?Nb2lD19g zu3ILc#eew1tGUV|Lil9M6o~2u2wO6gL0mLMb%JFw6hZnhnTtnMFmK0wE67j=#dqr_ z;}WB)&<`Gt6V-6GR4d)uJm3i!KuO|I;Cy2174r`&BX<56?A0L|CWgB=-_jB>{D`9H z9cOj&A5>4+BeDW}oLmCTlYovu+aOV@HXnK$idoLZYg7swaql|E_F_QTfa4oT0G4Rs ziH9S6gBziQ#C<9RF;PgOlZAERInG(o9G0*ypC3q>5H55XbXW9ITWKjcq}vGP{J@)i{icEL~NuU>}!U znSnq~z|8_8v@-=_74KmkCrs9`Jx@|EE5E9%aQcMXvb+N4N+QXd8zo{b7;#mt*nRBhj}+Y{n&5fK}wG=SpQ3+I!MBcO5{=ki_~p4m8&O3S{w8l?6w)90`829X8xB(c9QUw~SzKZRy3W9@%i?$hD6iBx z5)43vmd^w+#k7Ow9p0&QF)0;*G|df3dRMViNj3orBd0QPT0mJ`wK6k?gYJFC-yDIp zmkurvz$>CL993&za$9}6d?eU^+yIXr2s2MMoxhTo zPVQ0rB)NkjVZwSR*hRPiZlH-i0tATYbQ6$)uVY-&P6HphrENdquejL;teicETh7kc z-n8itcx65yC#;j4$v6GWhqS2mHGYDs zvf!1|Dn~QGikd1af9Xsc{Tn#~?-o?ohlIhy^RK>e(RV2=PE^b*$4XTWGWUbn=a}`* z3Ska_jeeLp_E$%R7^1(_b`pIacdn5#Dt3=YWG|9ZjOM}yN>7W1aeZN+-PsXE_@X<8X(&mM!D4lJ%B>Ch_KDzZq7+gX zETK)>-{n~H5g5V3K& z$^r+`x`Ubg^p@vK^Kn5(%qi9^#1J)m!wXDxE`LpQH?hS4sT8>-L~fUthAc%g5f_VT zC03|ir+yC|E(1Cl&4EyycCaH(#*)(L(pZ8@SU)71E~2}C`m05fS3IG>-MmW`ictC3 zhdGhf1!J3C$xp83WG$j&Eu@RbC9gt9W8783TlawH^gq06n#sgxd_j^<2ow~TBcUji zTLY5R5a_}<@A>7&-;O6Mapy=L(wsL3)^){hswbbrZ;FeNSD)+c56L7esYc=n3CCoM zskO2vS{N2tVh*2#sbCO2u}5mnkq1?GCJ8%Tn5h|joA5L_>bIwl%Ns+@H{J5*6JCBc zrB{@qzAs8|Ha3ZvI=TFqq7E5j<;08S2Lkp3>6!=;n)oVI z=8*@N7s7ajS{)1K4WDIC2qe#-IkT(U1vfqFr+n%Xdx7(+c5$@3A(YJ@)?_A^)Kb;7 zv+$GaV!o-NOZU>o#lS`NY&F*Y1vknFX=tf73>&J0g{B;V$`_JjuHsYUgf|s$ow!8-%gYgJa7 zcw}6ltepna2q2j!E|}XUKamk8puTUGa@>xo8=i{yUV2u+%fBYR{DH=Fc_pTb*5UJ= z*b|7?n66+{pnTp(48OvF3?W{^Z%h0Yt}W2Dnj#4uBP6Hn4ubxMZRO!jM!Flx5(`c0 z#A8UdF)BcVo>jRM(rST~Fxk5>s)u5jaOR!6`w4%>lNL?ZIpr%VoTuRO>};VmmALYU zsuJ{He2?CEkt#I7us2AhC`bZw>`8>*(Y_CnuYpBnVcl z*C|IyD@J`?W(4_+7?_FG0hTZYq?^9Q zL>N1guRizl!!N=kl?pnNPqA|P9Mo7p@!IGll$JIPmOelU1rpkNFgWt&q26e!Ro5W6 zURKVXr3g~uu5s-KD&TmMwyAu2yzTS9|Jq6lrXbgy*tja3rw5LhNGlbSc7;h&AyLi! z$vy8Iy7qF4=ux}c(6)WlhL}Nn^Z&z{P-em9s)JNKq;*DoUr2cW9%@(+W5}@ad_86( zgHkkElz^@KHHSk#9P13cm!<5)oh1J%B6Atsal@i_eVj6QUV#i=5M`hp>)4m`|9ozX zOW>m_fs62)Lm*F?jw+0juE6k|F<*0d==)vlPk<#6GZkCt7leBo=(YCVj;K-=c*E8T zbyL73>tI(H2Cp1iB24>CFgrnj+beUa!=F9(dD;~e}>H?X) zQdR3oxU40kD)v5ss0?_807nZ(IBP?$^dq(ZqssLe+?>E$^P9cdE{w~WeW#%!xYcN_ z0|2yJrM!yO0uie2GSP2?9L%*D)8aX&)^cSO9Nd(RD6&30LCI-oum^C-E#BwNm5Z^2 zqKt6c>!RdlW6YhKr2##%F|3fpbjKq#xqtR%3s)1Y#8I#bX+_T=bzXp>KT>K!as}=9 z?uiHJT8<2b<^%Y(ph`POe)K3d6c$DKZR62PEyZI@WArmdYqooPgm?js>vEwFMf#+* z!<>uXROn)ax49}An3_fx8lWf#oHh&#bPTvXWlYSmAc)zKU1FZz3}R--9uhkYMZd-h z#euF6Od&3dXwx<2zPG+*@z3y#Mf;AnO{idIk+b{cVzn=t^_p`0Z) zWq8OxfA{emNl;XR+jgqT@bS3JZP=K&wFTuKPpVkG9LL9)X2OsAP^?cqK_$2ocOGF~ zBk;o#``iO3JNKYXYjG9H0%Bdr&7oSlTULl)lH}efZUy69LXv(O&CL3`Tnq~iz2m!o zz*7|>0XwmPS>?)U=%fpPDb>bSr@8@ECT!&GC#Cw-OH=|x9qZ6a1pmo|F{qEvkl_2} zd4Ivx#GbR>&F5m0ft2AHdhUbM&1-gki=$D(q)_YDZ5%y;(w`?Bml(wK-#4H9d^~!I z$4BLnz&oNVT7gWnnH6+?_j$sW`Q=ZYsnTMlM{!CLf?zqC7Z3!SVMz;;*oiFB%uj3p zh!Db*sb3Hgk8XoImMxy*pw;arhAFkDa0gtpV=13*Z{XHBivYkCgei3}OOKCLQ%>45bhiRT=M-b-jE zu(CoL+CwC?tjPb{#dyf7WlJ)wr7)IV6~(x)jzh4^M}#509@Z#E6tFi{(*eGJy=(TG z|57#NUX&pLGl>o)j#WsazNk!1vr}@@5JoT_kiow#76?J&&o> zZ-zxD30zDUT=~W>9dn_W?A!---3&~&ah};C-0lM62Cj^sVm47CT1qxdtviP;Kt5jvhLnR}mz|yVd+EmGFzLBX<%$IqG z=4&pd#ruA5{&9Hj(&Gvo+7F{co1KB#=F&cMwhHVt{H_CCQmw%rfEoob0zU=dNE+6h zvswmilLaRM1aLrQ2gSml4f}Q<4gDfJEjvR5kORGd<}5CX2S-jCJ(lt8SNJC%&mK@w z5G%7>wHo^}+SRwX$`C7Os8+T0<37C7Xa1-nX!8qw8Uul^BvAem1C&|QQ76Q>6-iS03{X~@-NzE_%aY-f8(qS%`~mQ_6S`&6HG^AqLErbO`3|R{ti{3<*|t& z^@WV#aV<%+&+Z_3iYi~*X2M10lhKV+A3A)UG8R#(&-Qba8Kcg_b-bZi3g1@!q=&lDz z(AE7?Pe*mvw#6{_9|yhie?Bj%Lcz?;Q}vwI<3ggy>KNH@e0{EIe*+l1jS-TpaSfG|?uNB$FNy&U{k2xxDVFU;MZU zJbcmVM5o$8z2u!|jrh9mI+fTZ_|he4P{VV{))eB0xY$_C6rW_z3=|g{dm~;HhF=|x z_JQ=)tvq8&VoiBa>x&`!;95L7D_Fg9LN2L2|8Vr-htbFi<~g1Etmvp`D+#^s1{Ksb z_{mj-4B`d^JVYhv$(g2bc2>8>q#>FcHqfe29LGRz+ANK~a`)CVCMEepHU^lkYK%u8 z2zJT%AQ4wAm?yxH{+D&Ay3i)B%PyAg^QZ0V^pUSl*&RL-p8c9joigUzND{mp@Ol4U; z)qMcOGern>Fwrj2nI2OJZ3`~X1Y>wWu;D(@xuF~^jv!qM@nOcqbtml6)Dm zOKBvley2P@Xg7<)TeiJ$@OgVvn7_wAd2Jks+UQm40R;P?jRc^RRSa0bxTC3Y>>=-m zp}oN-+-%0p2Ex$YAz{FlExqo_2Ay|5IL!v< z7Znn_#$pbiZV7M}i8)vDm6SHpI}*8`w*@*jk-nSVE$dg``g+RiH~1&7DI=;WOwMLy z8`cefQF(2_7p{=;64Kciag7&M#l;Hb_KK^ZFAZF5^suv8RG<-KLy*=u>rO4Ce&Tz4 z)fc?$%A3aV5G77?%&&UwoY;pg{dWAQxodI0qQL&J{14saoV-xa5_IvgpcAFWUNFE3 ztMb#oV16pRyiguqY)yzXYdBq*?8p^39=Dn%iqgw+1_H_@dG?-1Jc&-G#Dq65NgL8k zG%%7iSncBZbMZvO{c%A?`mAqf7-BJf@D@~c`tdfOwe#oRjxUg!y)Ig_w#@VNR4>+X zdSRO8Np&NJe!@jT1A;nz->_B}W2}R%`Tk0Y3cY~cWit7#?e94iPgXQs?9@|KyGUja zR?%&NvGp>`V=QbtXV)cOIxpd18;toFo9-i+eQved)(3F+u*6x3BzV{A9aKVat56Kl zJZeZ1^1XCM;Gi^_r#+%Bx;+hF%+_?>$P{$J=V>Wu4Ci2`}goY>@Cm32b3+JC3i}LxmsbIK?c!b-G zP+!$v1Z$T~T9VrfgW^{q2#@aStp!?2&O?GV)?me;aF=#^SUtc40;-mY zzYArfLmETbTkyc8M;GYPC!!x;Gg~86T}s^4rz|OSLHg!mA5d6>dF%*k=#T-X(-IiX z5;YJAB~E?N2DK#dcRVeOvd6q0af%#gBcVjc4C)qA5aTzLbVZR#%C{4D}MN6@No!Hh(9h}&lY=7{Rz_m#Tl zCUjH+!tjY?AH~j}Z95VVUNlSpR2%6>D`UOv;ho^;(z;)5>|^*+Wu6_Pu|jI}n<$cW&N${6+#AkOy_;%~Gq*Vp3yAulNe z$`NnZJcIx|@ya}tWwA6_5&Zfhtia`tL|s}Mnw&4timtUfxYi-hlrjhcW$c?~Q-JJh z=MK6M?xY{1_K z;KpsLXy@Z@F9&GeuAw_JAR5p-JR>XB8T0Pd#N$xJrcM!3^`HvR=%KGR6aktfQ8E#v z=7Ib&f)ZYJ8Qrqy)i*wd9;{%~`l-oT^0Rhe!HqU&lwc{8bzpFOq5i~Bu`~_QQlT;! ziDOfJO8krTpW!quQOTf$B7Bq*v^zA4UpY<~ernNXzu zmuBeB*>wjCsqQ17fniX7k_pO;se$osT<_&E=r1A1d%t8?;^- z={pl1g)ce;Mo-^4|1UC4`dx~S3@Cu|u#FpVTLv1u?KZtN$%~Z|?CDZpaK!Kb{0lsG z(V=6f{y2IqjPF6CHOetZwp!u9Vlr}=-y;_)l!v=t z@I89g*i9!!B&q%+vy394wS2wNe=_Pz8YZxiXz}5X{>gJGqk_|>p=ZsJQ% z9-O2|3TDZlYUSKn70HM3TO&MPN@0lRs$$c~A*^nwwRh=3WF|@nlXQY8gO;d>GLRvq z1Dhm%IdR|;r~o>xs4vPRqH(OH4 zAEWVC=NILa<`cMgiR@kqUe&#dzir(ftEqSoYO$?%Og$}`^{qpRyi8^EOUMW5WMkip z-07lvAnqBBTSCz$!Y}wW7ubRW?%H2k8eg`nz_veHtxH-!IukgzmMAVv9g!9g`M82a z^dV=CxD^O30j~9D1oYCXrPM-x|=N z{-vlReA-sxa+&^@+GtPsdhmu{zhVJaP!ztlKUPI1eO8#(*^9W@hz7TTiG}eD_Hit) zwV^wK!{O#*uHR!DIH|MB3A#tWdas<=7`{TuS?woDy>)vYQx&Pvim!q|Wd1c_w>vSt zF{J*Il7;d)HonS6}H{|^+W1&%CZS}1No_EOnYGj1*(E0 z(@$Wt9@v^Yh+Juz0_Yog%Rvmp19Xz){s)vtKSM#$05YR@p? zO$qs2!o9IrohtHMVTojnoJRQMccoeo2GqDbcf0n?v({r(MTN5MPn&CdVu|1g<*}T< z@rqyQRm9mxkpdKy*0Td4n3NOwp-~}va8WXxJLg^F^eD(YNy5QT6J{n}oKwDGuHH1O zeStTB5k?C9mO z@EifltQKXWY!nP4=2&+z$E32QT^pZx=t^sD^%vt?hENg;M&j)%UW&KWbP%(T@y>;Y zjjeF^;xHtB9*c}0ux|_LU z$;~%En(Ho@ZL-~_-aiJHVHnNO@xzpKBk)-R3_S?^hi>@EDaMCz?;^YczJ_4xN$2JI zWC`$`(gNi$K~P@Qei@RP!<7WZBs{zriS`bs0(+Dv;Q}=_YWqx_H~iqUKYz&!Xg~#{ zKer#G3NfpKVdj8W=pjT+os<%uH=olk6 zHwKu#l{!~`>Rl8h3p@EpZ4I%+JF_u(D<{fR@wLj5N$n1skYN{)pGOo?HTAJdTzCea zrfe>Efi)75ycG>pt$trGH|r&C)mxLo9X~ni^(RmYJZvy8g`}%>k*X6%RioDD`b4~9 z`ouOVT$zDFU4WZcwrmT#?-B4JY~pHdRjZR3`2l&DGQ__#CXiJJaaGD@sF)LY>{&U% zv$C;)0}}Nyep(n_SCs|(?Ddha;%STax@@;WIRtfsfcH>-u;1ub?E!V@lE;+_(idKt zfsoF?*ADgUE4ArRiI>7kJb7S~i|q$A#+<|!Q-aWiKzpK_>E&ZR;%QkB_Qozx6p!61 zT@>d%{*_<-B}MTk{FB$0!_@uEktnv}7d1R<*PA*N_m%SC@CXcD21CNbqc)X*GSwU_ zUw|$p(FY+V0h-=TdhI~FQxv}V3x4w-AAd6!zp%hq?A(o64bfl1Z>{o5oims24CDzD zh~|^Gd;|uwK<0*k8=-BU?-ceA#Ijsxp)38Y$+l9Wl$E9q0m%3-Ylj*3rY;8 zs3r}Q64G3PXCHXk;X;)bp}&QyKBP+R2q;dR8cX~Q*)KZ;iZiEpX$H2$aT5bH`*wzE zjg39Po3}ug%84DTLu_#YCCD8emM_Jv@hTy7ed!P+RP!r{48c zF-!!4_=+IUR5wk9C{MOjBY$!A^mcv0OEI&!=j4m`5ze_Nv#?`sh^)1Re)SZ1x;PDp zsh6H*($)(zkj_cCSKu*T9r6s{sqdvs$PBf*q*m;-JGWXwDk>c;Jz-=Lo)Yc{+L233 zQsZ`~bIkfTEF8w86rI7o-Oe0maqr=6A;@7oLd%qmQA8&27mHJtFnCgl&;u|6>>Xq2 zDgsuy0p0_$f*W$o2QThX&ZHm_J2rReH&BCg*P-|)m&d)!&OAxBp!^Kan2+Jh)pkft zJe*O~IcYTTb>4a9j4;=v=QL{3GJtsqz>%+pmr|Ez&RR>uDtQhZ0sVTfWr);f*FDyScr8)KB-a;}&L5;w(mKMaa1J7;uH@^7H zAO7=Ec!t87{u^}Jv%Kvg_wG-|kF(KLP!~WF_W(;Srhr^Q6dP%KqAnw_#aAp*VlFI- z0|FAJUr`1#B%ST2nPM2-uTj_~@!+fP`OG^hi6W@~CY1zZ#>1PRms|X;_`-o$N_K8Y ze7maxoF)M`a(qKg`~Y;l#euYOSP_}^C269wLWigZlMrpt5|KB2xYj`KIQ7U+PFu$! zhdEw;mH)aSI7yxHBs@6OOz4)qulv>eC_%#7y!UvsN|2c%CAe$z`ipR7B11#St=F_G z8*lw={nn39bt>yO-g<4j*&*zoLBq&9@LdAtYs`hTEGe>KY=o{kr!c>~w)cn!iN!?f zF;E*Sp|sso+YE|iOn@a6#MAIq>cYebdpi0q{mwP}FMwjU`BY)0F=@F};NKrLRu&IVchKrAeh4&k6~cyZ0UvVR;z# zG!IbNtl+5X z?Hg2LWO^RXX%sm*k)1e#yc=CpuKePwR%uzmaUk^Gc(qoWZLxodG#G(hC|#*E(DVD|IP;w#WISvMQoo`9U_ESnxS{3Jc7Dr=qVMR ztHl66iuulMY>AjjyklSKY7cb4hw)4g#PnF)a;>4>!+Xit4fRWG>k*F+XAS@{68g}Bot9v5 zQ8Lh|e@Mq-1BPr)6J|boe5FhR3#}#wg$cWB&%5Wc$F8F^*in~%LT`Z}bls}Wo`#Sn^Z2tw6b{f_4u?(M{Sv7P7xi*) zQ#mm4Us^@Zf`da)&I?|fiT_4~hz_^0HCi)q*+gd&ilRpmPp!~Loq&5+8i>5nMALj3 zmTa)NryE7ZsTjed&KkPq8szqyVlz}NTo!w__xZ@ac(6j9uo?1mAPc$~2gs?j4f<}} zNKCkb#&b@(l*QD{U`qiGnOQ zy5tqI&nmbJlcHAbTsb6X-*rWkTYo$)%tpahyzOV{iXMj_UfSANZK6O{4ZAj) z7iw9pSs6#`!b}A5LEN}#sy>NrcCo2FdU|ypSiZn^5s?9YnvLQt$&xhtOiSSaXJHCF zgAgTWaa3|n|2tY)h;5FBaz zEvazgk3t*D-4izry`JKkS0J7b&XIWN@CFS0C#1S_r=eoU&Iy6VW?<|ZWe<{M$svR* z8|^*k$g>Qo;SZy_$}Qq}C}xOUW??IeQQv3mv>96I6Bpcn4<560c!69lQn?VX9F<|8 zA;*BUI^jGeVz*8Dd8LETXHc|ZKMUybaHgufSLlwUH1I)5_1X;%wHo#|gidp+SWXaUHxU>sI2?P3aFnUTqC=v`VilaNF z!b(~&hANAQ!=e8m>>o+~DCYW*e;#b9jJ+Gf-PAEpyno+sQD_CHQEtCXg+?536#RF2 zu-zK(DG_SQ)MzzYGa|+=!WXWN*bZn$p&P<^Xtm)W=+GD@bwSxm9QbLekwHUyAtit? z+ccP9M~h7Wp7I%qW3z2Z${0GPR4%|pboXALfATm*#Lo6S_`7`0^or9!27O0)hQD66!Dk)Zjj;b}*S23cnd?bb$_4Jr-vMZHwUYUUdBXC>fTULC}BHI(_ zPjchH2yZY6j74MXXwyW*`$r@Ca$j!@tzw2?sxlNroxUUvy}jc0XFw2vfK)K29If^@ zXunj{b8}@oyLn6Qa>FA{yh>|7a zpm>TDl}UwuG4p~`(k(KKU$D%OSn2T(4w$S=uat(>cl-kS)R4h6UZu_UAtCD$rBenYG5Eu#0d5jZ!m+|QgMDh2yQCphyS;3ymsU4ap z3RZ?0NkVBlr+lBuKwYjvfJnZYu9#gS+lko9k{sxUH9cV%q6b(P!!6$|f0RS$N~;QV z!v?Cc=YO^ifXD%JZodtQo4QR^Yvd?`7DDVE3T+8)SnlV82HDPR7lj~EHy0Oyv`^$5 zP_F|I8#=VCtFa{5loXNZ^#XJ-uF(a0>6t&6|9z~gXwb;^o1)j!qYqZ=d9giSt5F@t z>;v1lRb$->Y=v9R+dm!0Nhh1 zC8RPjhUp%X0U6{JkSXQoE(Y#Pz{GmB-{ej?DJwxw$?WrQoOazUc<#a-khdi&famO> zg?MQTp|nQ@^g?ALFU&v%&c$yIF|I2Ilw@&iRcD4NwdbC!!=n!2ILee9uanrAk00jD z8Tn@O>fM>#@q>M@=Gc(J9a(qmDwtziQ}I+Hu?-WC6@WR?(yna^jP>03FW>4F&tPZT)<&TxsK%vm z!Atje)g%8mDSUa3r7$RLB44(HW&ArFLhQ&@?B%M^qbq?S#WgULvqB8Z5ls2IkJbI4;Exu0=>@#DoV$mmvQwAv$9hQd;^)v+t0U zwjelq7Mz<+$|%^Q_p#_b`E9@KoE9I1p%47IfMjE=4zD6uugmGMElZAWQcguPQT|!g zhSdEq12vR1G(YW+4}tqY{9vnfwb96$Q`P!RRELd>s{pe+&m*=qmOhCYj2~`xq9e(F z!(e>$g;|Pq{9E+psv%i?Z`z6C0bGtT5+Eg!TQQY93>!Di;-anDtMTpFy(G{hdmH!3s3YhP(z$d#Vn#1?0W%JIadcN zx)~Ji&6ckVxYQ1~OBs;HjPb?JP!$D4q$E7 zxHFwI2AjB4>DI<^P|ybKjGT%2P2qM$F5QelCekb>9x;V5nrMD`A)*648h2`;RRtmk zbG9r)j8hWFa*^t9o4zd9=r8~%n4CnhoEUCQpv{-N&*P7&_gwTh4K_ z#1TfQx{PLF=M(!)#b+?pcddk!Q91O#hRO)Z>Kb!L`_8>+&?U~N%6s9TsEEk9tU&t# z9PpayHXMh`hXv&^@x2&HH9iv`LeUHdl@2;W5E7kWL?HrSrCke5sTEp`zqYN_H$hg+tgRo;}K6~{P%hs zZP*&!RB1gALT{h111;sgfYTUzttS5j<-+^CDIFNqme6LHu|I zzJP#hm9uHFZAvjLUTz4Y;a`OG7I#KdmU0j+0GUfb_gJY_!^OPq)Ndu8T(RR2!%Mfn zVDhmHod1P?^7?F((&j263Y?OEG$_(B&`_Pui z;39$14i$Q<%E@e8QXYDyBxxUc_gY8{4m(9mslQ9w?>U~tIw5E>#y_|;%9~ER{3(3@ zMa940%%MMfH-2+nXcWSGXO@pQ52p~KW8eXe36U~9Gmqs)tTN7H0)UjsR5DN<#3F-a z{zXPBN))7qN&A}oUi2!gHo8zsPk7b+7vTAd4x!rqyHrJZp2Vi|QB4kCbbr7ZPkPeC zrphL{G6NOahMR{xYj7v8t`1OHK7fdz_f&o$A zDv7}i7s76v&VS3*c$(55@lW0}{61>N>a5YprppUk^<-`ugGy}+>r~7!WEz?}o~ zLjCP~T^yQ=2F#dCgP-t0r)ubtSsnrb)O)lUwwEweAgzn%w<`Z7Xv*1F;|zCu+)L&& zz?XO|a(?Z09KfEqyb@yx=D`2rJ@@ZbuG37N0_ zji{j9C6F+@1wF^cJWAqb#hsWx5*kSHM^N5WqHbb`UG>K!sYay-@J~+7c03}H(CnI6 z3%@o1KdAj-woMcTIac6YZ4$m!;*RXeaf|F#1SjT^^gDm%(AsYB_1^M}Z(qVqY9&UT z{CXcXr+)Pv_*FBiuv@Vw)0Xf7BakwrA!s-e>?4q+=iG_0egS<4%z+FYP(_GSEgFVh zdunQ;O!2_F$&E+7?i+ZtqJw;P*fAOe;H$Gvh%e;V>rmYGuYUF1#Vp<2ZEt= zM-YwnKhG*7o?MG~AbaXW>6MO2<7#Bek(4jfrb+^ofG*)`TRyb~jz!HXbd{y-sqPPQHj3LIG=l_$=fR7jEy$Z#$1%uK?a)O7Ktv9g7A zRB~$F8X&23p9u&coX5K-M&)daqzZ}U#RhLn?-H?laVj*I$XB?yssR5(B!n~`u{R^p z!4Q8;J>?l(jK{tA_WCfER5V^?haDs`7s^F6;`xf2yBzoAietR)I^&;UWGKUO3JQIw zlqXZ7`jP{UZ>v~1oU?|toRNEG*F;t zPnkPCyBR+@Y%?n&&*#>l>q^dRz`{j6Xt#!xA+OxnyWfW~YIc^aM2&?5VH^3iRcs+>w}tX^>F2 zC2-JdR$au#lp?Bq$NnmTC*ktLKe0H+C!dEejY*RARCp!AQpOPWAdO^yA7FrCpv2Nr z_DNifbdzvg2%VX0U!Wb}!-*<5k26eVQDqAwWsci?{&jRkrSIaOymCB8MMLN_GLda* zmWM~dfZ|xq#n^hu4AT)eRudv#?(MAM5 zT2f1x2IP@p@}i{IFcR|{Hm%5g0Jem(q1JLt@dy^|KtmlxcDv!l#FNwyp%2Gl_)M8ZMA}*5EpBgp#!uc%aj;cCZz*=f!CZ=i z@n?lM#uM^Nka4HSQF}|gNg{N@fNY|NkhWw0OK!cRipAlCp_uLIBqMcHC+!rE*jhoS zCa?Ba;IyK)dn)33bm_jeN4=ARTU;Qx`Km{ZKWp$FI~ja?b$mJ$f*F5Wh&>eyYeEa% zj4}>l>$NiXEp*>mn_ogq30llBb7?RkEdwqV1T32s?M~MGOcw{Q=W={tzw2ImKbBPb3;xL~;EU%_ zjwj;xwAamPjLc=rW8T9&;=*Vx-@LW-DhElC>yeU z`HNrjg5{E=4;HA=A#=F=FJSq)pWmHCC$Wy`Yr@1vLpTA4`G!5t0bw?0*WDo5*BrhX zYQ!ctckPvjXkgO6SDGM#KS{VW ziaKYicQd+*00S%HI<(u(Z+ycb9;YzNw<9y2fXlZ2kUZboluUByc;v5>~-C zA?!{QiM)1Bm@7zL|H?2=+M+hFQ7;;vzlXDnUW?(>0yr4Nd}Is6#OT_>PpNAQbvPJX z>f`ttQnwvUG$i==3#ej(IbDp$9s0sE8x&)~@hm&+xDD~>@LurfYh<>FD-u0AI(=}V zqC-b!Ajps6-c?9RO=Gm%OOq&Z%?FaptM;Yfx~FGwz!-Kt+AJe z?Yhm%WP5saM&Rj#xO1qZ0&QKSf z2@T27;ftklJCqYb;-ubFRwD8U46;yXRWIHmF_)b}TGWZ@nY46+io}5p28c9Ebv@)4 zy9q7+Z1=ljLTsqauY7^7oGB@^Lu_bqtBw&~zJ6A}(O4=*gmyw)nSl|#4>t!ODRn1K z9|DC4LxOwK4HEDu9-z&%J$mx^Njz?@2lL|G_*3)KqG0^uZ`Ls3nnJv+2Q=;wZ72;>>2a*_`- z04dXGSOsQi^TsJv8OALLB_(c?B+_FX9lgjeQfq?o-IQI15B%U4!^^OkqVoCaVLB5^ugpNhZo#jD%Lrpn{n6FQgoGX8N*D^`|0SNsUR<{tFoMBv zSjkM&We1@oXc{32*&C!5uvh_2Ca+*eT?tdI&aYJk< zA((?Psu_p0>zLhdKTw8+{2Gs&R{=ZIM=+zHoHFKkR|DV7IAxR7#`*aSY>4f9t4Q5R z3E5sXdC#3v3P)_qNh-7@fuN@TYAV&BpIaqND3Wua0q0S^vBxX5pk~EIB4P%Z|%}M`vspn z>l#Y0U`PIrRdX%93-QC4Q5DFW)cjGINY*SG;iNeu%xG;)xt-AJFHpz1#I)tj`5(c> zFe-4_;KpH(fQ9bWqSs3KMyZ*(s1~;_dJHM7(r^JpT&<$o6PMRaZvo)iMb8+)IpG|< zCYrmNGfN-7#GlpXVW%;oht>j)I-Ou!J+%t~B=SGntQDk0pRD*=m`uRJNJ8hjr+xaj zNDz8FT?Ltr6cFSZT2uE=03XSr^RMX??1Rz~xX*4LyPQSQdpB-@bCZfs68mEmlf#U8>5M?Ln9yFW>#j|43#VQ z|NG(A&33IK8&KOb2>~oQ48do}ltZhbhIh}pXy~{NkRfJrG1%*_3=4vTmeus|25yRw zpU)GukD!%OmPu4fl-VUNIE$%|i>&mO@6=eXD9l&vTpq@RIT9JmP2iUlDiY?fpq4sp z4HmsLQYbK5+UgvX58~j8p_A?d9dwATNnYgXPMXIF<)jscq*ktukOrL&z%yyO3=jM5 zcVF{%%8|_G8-vl;OWOc~&J#&=QZ~h{ zRy`<=b%5PDcP>LW#d4#&jN#jL>X>JK`S73N`AbhIklFgVli8X0$v`3~e3F5{(c6b` zC9fL-4TF6X0E$e7rMRS8r8!)V-efx<`rmOPMiLVsVzi&KKg@-3-xojdrXdQ0%^-ON zvXhABLV^APKe>whk~>^vFlu4JXndZJnMVqy5~Hxa+Elt|WUxseN&;~iucEr-4$9!F z-vcg&{>#Pkz>{t~xJt1UoY}ggn&=3&?Ka1<@`^3J`Q5aBUTNX;8Du(F;1@aOK;NZ! z2mF_MN{*ih@!KC;6vZ0ZfMIP>+ISy*x7nFMc<&H_$LYxfdYdC5jx-hUpM$Gbmn9^M z(;dU_2-`F@;5wTJ6 z%5>*#U|o3n1e|GVgFJx2HGn2(pe!zkV~4?^4jM+hEO_DpBV@1(SvWhRXfBNIR{Z3k zFd!bdeW~KJ{Q$iI+oM9zEKA#EE{tiUj2l4Hy@E{<1n#j6uQ!?YkqVwkDjbNj1ACmE z#6I?O3)vc5}50wqtdxJKSuo9ZM}3Z@L-!@6dnkl)4hg7n&MqgWgxvKGTNNF25|U#l zm}heu=rqT4FvKnmFrw{~l1#V^ArsLKw7-%i2dEZ~(~5xCpalQ=^@wQ#RZ{ z;c&)%9v&oT%nYI1#j`%QGUCe``qSH41&7Nv`Wqd6_anR2t=-aDxL2?ujGj%Qd50bm zA+FF3d1;PgOyD@8QlY=i9Fhb_-BTmfw-y56?C6VP9~u2lNY8iCmOZy!_3_oTtD-#k zt!h^!K?jla0HrN#Pbc%aC=qOszy+MC!3+I(o?od%NF4ytVaq5BPvU*VP3r3lDQ&*5v^}%HjWJX7OA}r}%lB3-7 z{EPoZCJPmef!lGWii|yS>mV2KEaf#BW-GO)djS>bB@7cq8Gm}Lufpzc5~=B#^-RlB zJFs9cOHl9OmVhQW8yaI-u)zoIEC_*KG7tASU9>d^BVTx`3Y^XO+hl42`3k7I`&I6=~7VY`M2Dm;Re`WB(V0k}2} z&<=!CYgW-<$obm+b-23(-;J+WrR1DEq5MzcutWb8OS1q`GezAo z;Kxi_SsVpqtS-|TlBEe`r!>E~c+Sqg_35YK`AUCN;Lk5ntz!KbJA&~jBh_q6D-jM! zJk-4#mC-5GFPh^MS)(u2`kJcNiMU-$d+tn-W`MJV32O0L0k&{x-j?GbPAcQ#sGYA2 zwA`>#(g9RiO_0X}aLg6UdSvBY1Xr)Tai7!hB!zwdb`%0VxNZ_D55q{CVZ=B+xNZ`u zG~_}b9{groKKuTW|F@^$D9j-wd8|R*00x7I=xRMU#}CWe2HF$1sXNkxBAKjK0ljr2 z1_)!sk;(;<#6@%8J703om+_Q^!Ocdm6Hjv)-&os=8cwDPHEyy;I^L5W?cd4Tl2=%#0BR>Kz#SD}3jzqpK82iZk$C}FHo%pSl@Ioyo zi=sbehZ@@;bL0sZLcE#s{+^NHHCv*mIl3@UWGF#r%d8-sngMdpa`>iF3ek{V5NChy z9lv9IDVnH#+B0Kh8UU#YoXGysb~C66-4D68O1GNT`>LJaI;QeqC{XAoXvRTofN4mK z#A7G@_=aDCok{Q&CeCz7qFM;aIAtohebpMmp|Vx6)Q`Iq?zsAk?PpU8JTxn(4yQd^ zr9clnj72J@)$2hnLEd*I-0s~PEFU6+U|Ig=!h zvHSz4jP8rv|7t(G7XMQcQGK$yQQZehpUxyC$!;SjDcy1OMapLSi?I;bOCq@V7Cht7 zZ^$Hn^0r0 zW^6!a1HqEWOQQ#v0$@ z)wJ~_sWj%?zO_ra+#Z;>digZv_UZ!9WR+NE4zuN-Z+nG`?0S5sA$)tHAQ3P%L@XhD ziiI>7m2G>|<(kuQmrRGHame~0*#0NjD19jc4-E(bP9nrh1z2>-bx}o}8mIQbFqXLF zj(hbv7u}0h6oH@9tVTN*djwsAXXB?AB|H0E(RA(1MukX{rH^*2sC4wys5zvJjyi5l z^V|cs0wk&dC;2V2Pso!pN8HE%p%Kac$afN$6FThgUi*{9luW_SqtlF}X0mSXdY8$` zPscSh`){gX?nqz#{v8a zfQ+?e0!s@fga{HHO^&)Mz56$>z6p;~dToJCwbU1J{fn^Q1Kc?1iq)+KxDp4)#7m=o z4W$fT>m&2J?L?IVV||o@VhZN-nkGfC>qs%n$e2PDF(o__KvKf z*wBvG0X?<_PhG-ZyrRjWr(L9KLk44@i8kYA?g&gW7+{`xq3<#EUwVwLyoGz! zPlEFe2w8hwpeJDm0uSNp$)YTUgi>(ws3G6T(F?@|D~aT_DWJdW(vOdOGVyIuE7fVn z*$6D=Ksz|J!7OySFf+h#0)C8+$9`tSerchu_BPy!0x>q!#I+#iVlG)&I$k3qM_QR@ zJCkcSUb4JJy3pVOl9Ukv*^e;_`$ZBrtT(594`lJ7LB8SJzp5t{$E%^u2428rII;N^ zFTIg6ENHSl?e?fO3+vgYDyTmY$FY5nS_37<=rfD~;e|fj%$L5ba=aAxiqa=y@%&N5 z>7N7fr%9t~3$jjBDXfh#_>*4vukKpFZ!-TYd~MwF&?C#(_^jCo9FfJP-Cldk0o-I% zDj1G(x=qWYU!DUJ`O9~y(5CS9T4>f#BuEF&im@p{y@46jO-W$KIow(Qj;;Hc*DCwY zgcdfuq|@4T&LO7+eQ zZ|X^WCv=@elNO3~C{DzI7RR~IDs*V4h0#!FH{7Qco}6+;=be-l?PpD4E`7rHe@I7D z)P{GuZJ`!UIcwBlTkyX)A;Y7%aLT;EzF1!9!?wQqCKVSGiXkr~xltL82_DBbK!;Xn z3X7wJl7*#0@!pVNKXypGfw-gsBaoOLT~m7pmT|fPo2oGXU{aa{k<5wzGMOE7-^J^G zN|_Z<9jCu4f*;JdpT#W`Up3n2I{dJt)-WimcQRMU*>ctrB!pqlS_j04JPAQe7NDaE zf_PjH-@B8ohSV)OfK#u-6-S#q(1(?lk6kjy~9*^%uDoMLZ>9GK+r9HE}mgQBZw+aCr z{R&(@g7v*LmH{5i{&g*WxZw))6v6qjw|(YiC*6UcFB%Md`bkk~mZBeJ8biNu+CaP4 zPw_%!R4??QG%ME@VlG+RO49_eO!&%WeF9hHi zEf2QP+=xwmt+2R@p82uE=b%_dzWo=1V5K*u6PR=f~c8f(nJrn?XH@XGrxWZDP`9Ao~w|(?@9cLFp#$h8D8N*>nX=>DQ3G z(Ut*HsxAfDq|r?ggSlVnZe(Q;su?B^nsoWGrF@n)GSciE z1$3uXIT*vjcqIha1PO_n=;9O~@WjdUgz%{!7G zms7?U>iJx@0iI6IVx2(~m*E{p9<-EG@=MPvuu(g!P6&|6cCC&QR6SJ7$eU&Slr!?H zeYo*|I$m|~a@@FRYO;o@rWszY15SU*mZe4G6A;D!K_VhySbdVg@|@2O2q(|F$xV=X zYcrreTJZ*C-DO^mY-`u+Ft9b6B3jOK#sH%}Wn3euc7ZmG3i;`T_C=cgK zN4wG!6{|r8N-PTHF4!6%i3zNc02MCD)8Nqkm!JF zqt|(?yrD!w9Nb6GADo|u1I;jfzzafjx>ZRM0>>1=S7-~0p{&w1=T5$#LM`asKV!c+ z(6+npS5bZdzqu|X!l9BRJ$FGBLT6@TVF|0BW_3Jq0OTIC5LB+=7158AAj=f2aPzx6 zOilB=vd0n(Ux?e{eeXW-vRBfv7tl{<*Z?GYtXXNp`nrY09r(h*1Wxq4(lk#AYluAz zQ45jNnmE*wlk%-1dU!HqKA6~G;F;SQ%il8omW5(})-Z$_-MPstgNRr!Gn-2N) z|55$;2&JGiLL~RnwlV2Dw5X#U9Llh{D0(ZWh8WcI^z1-D>W|hBzH1DG;@k@9M}uM7 zvE#kp!%;zS=L!;3SLoneMi0DctbQ3~RM47#hK(ShmMqOWE!6NE=mc@biQal6KkmB% z@OA4#XK!nSlA_*N4L3(6R7n|dNl-WztHQv`1*mK)5VuzS)o?7ap%qcf_q+>P2MNLY zl4Pgn`(q6pX|D_9?khK(%GylPUg0wqt5YEfw?>C&p@9e^j$9;UL}ogG&XtC7GeJdk z2-+Ji#T)0YBW_bJZ~<fEi&PaCiF3pawHp`2jhoG@QER(PtUvTBr&8y7VNAz*i96jfkcsCZJwMnR*9@2rcUqf67YG%7BSA>hNSf zD>^If6`z4g$tVV}y0w%(_SIMaBjr|bHtiW7i`uZdHA@5FzqMVp;qCa%G|<@c09~V1 zN9E|PzpIY_U*6sXPS3JB8-J}85v`@Jxcwci3l%|JT5+RfgCt~6h`4olGnr&2nI+6j zNJ3RmD})3B;)Yfc#Sc*sQ9dgw7A&@+U$tmeB5vSP5oJ+PkgEM(*SXF)_x-+ke)gR* z)8EfvGS9rrbDpzY=Q_*HkZXPgLBrBjfW;J&A5fv+L{R3TKqAsA11x?g#BuQ-{oP`! zLsKilX_rbIkHpn^HV`n5_0R;` z;Z3dIr(LG|C+~Ia@F-477}?Qx3=+Wfo|N2XztX>vS9-bUZ|j~f!;2U3OI6&JD#Eb~ z*;@cD$(diGvpxIHD1nGW4$S9mJ)7v9`!SxxQgRjyWqF>S!M-xBFk%^E^7d8@=$Rph z${h8^6F>iReD|ig=hH5)Eog=go%osy>?8Qh`O#xi$6$f(fR&jkgl$-QBvk>N^<>>u zCw|9=MnH==Yh9Z8g*v3X0&VmP2##_iKVajC7JRgiPf_bmLYXS|BQwqaYvX&)~V ziwHE2GdOjGMt#g07Y2Bt7Zv-BRE%Y^`SEqC?6A_fbUBXmM7tX-2Or_1TCO%kaF#_D zP9n&|_}Ss>H9sqT|nnIDN4f#eZp3U?SY#n=SurV0ljaOp)1)wX}YHzGU`( z%B+Mit3~LMS4YA^*AQ^D_rq|V`(~Q6Yi86`SzN1Wh!QBJVO~9qGzvMVz!4t-&e10A z7Er3r%RHkz=SO$^{a@o7H<4kdeWCa-6|86E;Lxv6Nl@>@r*;5=WCR1U7=8)eslrfL zs-=U_l{{|1{ZSR%Tue2s`x8LO_X%p-tB;f61>`(gI(E|8!%( zf0dZni?|q11KVQuJ-$K3Y8*hlab$21v9A}Z=j+a3v)}A!?YdDtJ`s^Kq{%Z>GD^o3 zby@_$8g-?NLfE3TnP+LrLtJh#`Xt>-O2zC%(6nT-rKI2*cEQ_DJZU-Zp!LTMqPw9O zB8nkn?Y>o8!FrbQD2ffI<>1JI30>&Hd42sV>DTM_HwLF^MZE*ZoI?}_yx z8P>{%bg6$tmwJ%SH&#hIUV&Gy6#O$N$Tqq{aG6_xr_~~$yiMD8iZr$08?U#5$wvxd zJ;BK8Gg&z3rsq81rTC!MH}R*-ZJd6;qWeoRw+$X~Y5)tRax{>-k1pLE{h%Q1LN9mc z?Lces+Hi{`N!Yfc+{oz98vH0!&jA@1(b^!K9AT(>m`yyo6MnJehBK}?R3ZYGAD4Ax402i(vT*95FO+lPj^>$W+dY__ff%#%#?HcJrgRVa_D`H3%KQJ z#Y7v}*C+8f2Wfc3!UFEBi*&4da4~JqK|zkyvNYpWJ~zT5aOqn|Mo}jO+K5`MMX(=a zPH^$P-@0=ih1al+?R4)noO$Q@BPq~n_}rKjiLqGcPn_osOEDx5*C<=G*s6{L_)w&r zsZ(l(HePpL%-HzPd?jh|xxy#-cM4-@?dBIRr7&*CpKd?<+~Q|fw?{dA&D8}X+3EZw zyk?U{*opRfY;8Yu8+ejl@YxMZB#jMt18ckB*pYG7(bBDe!nGsx0^B8R+LJA8ASiIj z*OuAyjijJLa`4zX(m8y`mVf!Do36oUHgy1=?p>4g9W%KYB<}T-c;7|LDXLterlU=% z_dS3a-WWG3(#1qz{ronZ0AUZK{A01xGGq70sCZaKh}>LsNXmvHD0zWSza}${UxdSn zA#MBQHYOoLeAm2w=vizNZv6^>x|QYmQWlC2DZ|O_by!#1_tN2w8^Krw@aV%uKq_6t zD1=??!3o{qQ#70K`bC)SiFR~IhAb2%pm?KJlM0-{7e$BzX3Iq>h&u4AcoG%guRy1^ zNmPvDrWgLj)eo^r^2IQd?wfwGZkq05!Fp&O)OZcB5B7h>Efb5Z!4txWC9{1vDR(2=an2pSLih~TYSJuSPxnLuD26$sW?@} zCA^muKAC+1=&nVJtr|=7QRH7dlMLquuNIQr|B$!7hjUj=#QEt98%FLH*D` zpf|UvgV6J!8aFB7jD))l?c*t8h1v0_7Sd!Nl?Q_C=7|o$kzdW*A2-rExZ%Z=#4BmQ~Z!+WfT~z!#*cMr0Vo0I-ilno?97!JzEKht46llOX$}zPR zDeY|k(Q*ujTZYWR7P7}8l#MzcfA0p~M||Ln4}6SLY#1j!{iV`A^37_ZTg3sMiS_BZ zsD-108_{s$O@_Vj%^^V+ZdiP*Jx~pqytgiJFRg5C1VC3h8>}vpfU0Ok#u&gM_av~% zyM9Yc7l{;Djsu*^QfC!r3Tw>*VpR;md+~vU-46YB^3zAqZXep9e=nEhW~@74@BY%d zv+;Rz%tIy8G3RDUL1^0o4nk@FTCFtBLInL9r69II6)Iu+;MHw79PtW0YWf^ z?AEyDyDu8BeQXW;S5EigT4Ha|qw6}S0P7aj-Vd(ddz1u1cC-%Ik;2h&SkmpT1}+BA z&QEl$H7@1|f&`|q=6YB8eJj_uIxJC$e;?zq=Q_z(ynDZp~C26h-?E?$M6K z*FG1U${X;-O)8k1pS{4lsX zjpoRbp`gGdSpZ4q(bK^Y(n0_A)OURX-?!<=&C^dQLYlGh!o7blA$<;?S%u$($p(nb z5)9&uY=K>I(pSHLA%XdRWJj|n=4gBn?QnYD0x9SCOA1})a)WV?0}#f*bW#< zDdSFn&%Vkr?qTTctMoUmPMA37+^cVS9L3nsMtS<*NsKheW4Y=O`QJR88VP2g!yq^7 z8jn)8YrSaP=OxUy;;mQs@I>W37>J}PX`RqP^nbA^*xAxTY-JuPyuN1y^lCgT*j}fc z3dC+YGy+Ti&7|vmhz|-FN_PFphdkkFl+M54Pj{-gN79*bYI3hP60#P#ntNpfQ+ueY z>?&a;4+2aZE{-IGh+e#n~#zN+3d8cgV&Isr1fhQ#LAPP403%&h!sjv{WYBp zOE;!ifIFq=<=WNmb2sc2AXuWgvB-BF&s_KYGseC~ar8B$5buyUm_n>*Zyf<+KU^IF z$uiy+{1|hi{BaN7;+xNtDBg=#E)S|G=s|KG5r##FR&mO6N9ac|+j0{|s8q5^g=k~d znkt2G<%sD;DdV?IS0iN(=$-6ssLRg7-}AEh__|HIcTc}k@?mm1gUtjty2&vohQj11 zRb=66LEdMJ4?Bn1>?KHNe}xFploTkfAa1f+bFh!8`R2MRUVGZYcLQ9lDO{}OpHuTu4|VbA0ouf+_*aq z_=wZBPTI7!mt5n?mV90%`@^2m+|W0@l0GYQXS0%jtNS_(P}@%BTSX`+HM z&SM%mGK?`;F5v=9$Uvvpim($d0=^2{4LL3R&Hf*J9=>Ypzy>+}lhlhYeFizq8$BD_ zjkjH9tvtjW_-@hYm9~HfpWhcaWE55znWuxH9LSXW4*P{rnCYe{9At;3+nhH(P(IwM zDoSA!8jVED(Kn~nJ6P%?>KZLgZjyqq%X_lsj)zfd0 z(3q2gh8!H(G1kd_^x*=R;&7Ks|AzK3&I9aef7XpY2CxIKUujuT=uc+U!4Cm4!;ZC` z4@xmGxCMX~E6}Un1Y^-)cRJ_?x`F?J>=G4QXpXc%rF8CWw(o!HZN#>%pW#oJ((HU- zQ5q~hphLmX8dlnjW>!v8g9B@$1A`+&!+^&<-T$||qn$?sEkNj!GAFo+(qT3-v&Y{S zq1%Xr(W-`msX~@Jc`DXbgB9adwiWFEM=!tbPJCqRxA@b2uMgL~G9Dd+dquIMZ}~cI zH;<%}WGNQv^Gg4?UFjief9p0G2>tn74Wvf*onk93LR)of*j1{>7O>)J^BE(EyUTQ{ z+GJ8*5G)O{rkd_N=PQ##gek4x<4^a!`$kkcOQ(qYRu2q~4zJIGPtEe7$DfyaxchHE zquf2BX$RCIKnKx+*usdIkGk?4yw}k87~u~|m}hac2E8e9o}6!)91API`0eMsc0b%* zt6>k%&V%*jX$3hay%+`HswJHPbqt1%=|gsruTF}1GXxz}?K8ijxg-#IF!L$$hLx`s}(F-_{SkfJsgaYJ0!J>hL9vyY&u z6Juw!hexwNXt=zuM-+eiBngTvr%?pB^6tcfet|j}{N}>bA7MF1of9 z(T~L~c6xCaSoj(0+UVqA*bahgX!hc@UUcnZiSQb{{5Zo0cH9j^)7W|diZZJaIe#?i z)i~MhE7vMRr@T|4K;GaAVs=C@O?+3_X%xlgWtpp@Pc^hR2t1S({n|Bz79RNcjkj`d zMpK1wr&nlZ*j;~TlZ5zLe5ybjww+r|4(?Rp#EA$vCqfuFZ{2tilzCm)Fe+nC>aY-{ zIU4nb~1KX@>!#;iMhk5%CZn%FxK2`va zYd^;@(19XD+&qco0dxT3LjQVR=;h8|qdVV;*Uo`nbCVpLxAVL9rR#{Lt)Oc7z&7~^ zaCkvwv1LFa$IM-*_T=%)!H-eb_G#LS#PWhmZ{@8v&5i8z89!nGsKU%)z3=RjIQR_a zIMp4xtlT)=vVve7&cvmAikV*B(rF1k5sP&BfaQGP7&a;s=PYl@lB*@|JC9*z+D&f6t121EGf^x!6*3eU>{Fo{~~qa!)06nD#0Dl|PrEa1DUOW;D1 zD(9V)u##;Uk+mzS-^%T(!X*Z?xt@&`zju?(PG7*I~e+EUUtVE zgCI4LSp~`XP2+?8u!=2MFWZyQoJ?PYm#$>pmMJEjwlHE8q%yq8ZKR>p25CN;ylQxm z^Iq`ct2W|oTaRe)ASX%%Xg0^vXwaM60G*ADLBCY*(D^$)$;d+Ca>FzDj#Xb*=&GR{ zQ&@vIdYtjl6&LhqSg)!*obmJ4(1cB zfN_-0lSxBrvVS1E?50RCmn^7f7j&q_oIs7bGd=!~Z+pTi_&TkF8nog~(h54;85{il z?yDsOmWw=#zc7L2eF88)FwGtvDPHrXk^0F;$q!J~HA zmljhoE2Ua1BxlGtma;8W)ETmM|)pC%i*CUHi*6P^oTT9J8x3iJTk2?u%1mut6 zl!O=}+y7M;_Z$7tFq*p451&)fZR-feXpqznV-;BqSXr0ED2-p~!I-{xh@|%qke)is zloJQjX?KG!tY$FeuWW7!n_$}vp@rfNqL8(yMUBL0sg4#?7focy_D{nocn@Y#=H-zC z#9ow2VD`JVw84X$v+g0f123AlABSsO&u;M2*UQ?-68eld(j+(?Od5vpIEI9Nqu$Ta z_}=Xj++}!S#gqt~5^kjj6$;yK&bpu*bneAWV%#PqP*H={kAsjwrU1j=I?Tl6 z+x^>+IU%#|!Ax)RHd-!RiH;eiBCLop&8r(;r71$h3_9$j$a0hVLA7fp2nac~yj#RX ziKz=W_5y%@#r-m0&T+aY)s1{vorxE3@4^4eM$7y z=GF98UJ{R!B6X>1xY~Z!gIWjRt27NH?esZlW){FLGqaNXrnWR=0&l9B2nDSAd7D4T zR4d@2tcaRT|H3om7tsm}o@PAvYd&BjC!Et*@z`&9`$20S#z=oR{&W)sck8jUmxhIz z`#chV(;IZd+wq2TO6e(`DQ?CHIa@@i5G0>We+m#6+k=Yr=po{6y;~w9(ESRF3+AztBU$%?e3L2R+8avqWR7D{2HVJROo=k?qqa z?K#1V^PmLRxq}yf@$G#0O{L&7ybMnNW2T0BaIOwI2tQ=;lhZ=ItPQ&P1ZmnE@VZPv zGmQjstEil<8Rfw$duG5ewx_yaJN&F>9Pn4Hj|5CY2n6psQyoNZ5hU7_=y!kpMQ{A_ zoAHI38bQzSovBPT7q>A^0OqP*_-MSO{k-Rmk2m}BS@NGNS*?K@b94tZOoh`7y97_c zP@qQXh(F;~=uPok6(2>T;C*(OpT8Ow6s6(lg{eccztp~p)wp2AHgFp+Vuikak?LOia);GQCbBT}A)ZN4}A$v)iXi(n0K3v*$z2a-m|g;<1P%w;bC5{)S7 zLNRa)!&L>!DhjEP+J*w7!O>a(q_Cx7lIuuUB7FN{h$Xy*Tnp|CJV1YEbv)MWWQBZs z9RRf}{n&EL=`XT=wuYJ9GoD_AI>T+~H-D$ZgQZ&TBBvut10W!~D>6U^j~Zke?$%Q( zvpCN%%1`5w;0>$_!{%qN)0J*WA@%$fq=H0QVdh{tldkt(h)OxdE`)j>GGwY;NnMN2t^=e= z!HCH0Cl$E#9Mr+~aY)F3ymQpHs1dBodD#fVP@s1F9U`{%5)xH0SKn6!U|vdB*28Nj z%E5z{j|y9lV2g(q(p)(C#eZ6e8)}ik?3QL#Se?|S zna-17lTc-9VOqkrCCJ8Y-So1HM;}flX(;lXu|Z0rR171;ecn0N!CFsyxcCPTl6qJw z7GRXs^XieISmhmX(ZPa%-(e!P&oU7JGumKZ+9FNP7Btafe3i7w0NV`~5;*lKkNo9d zPy!9xUC*ehzYErH!$=~x@~}NHkR_ARLA%1^p?IYSXc-dNg%_{pUUVI9<)O!-b>Vsr z>q85P+O0jD^S%u8DI;MF^wEgg+B&3FkrE{~GN@8&oS!nH0x(9)!4k|MQ1m zgga>(ggC=1$V_f$WE1@l&XeeP;`7mZf`!J18_bAWRrE{i*JPP9~9a! z{s1Wj9Y&jVogGC2Nt@IP&lu$KOlI%0k9~nf*2YX`o5Vv9zN9^d?(BUJ8)4!*xOF3D zB(XPZw6`6UA(^ZBvDFeExSjfYM$gF{AEZsPKT9W&Qq{H}cb2My$Sb{Y`zsop92AWk z742Ar6NbqeTbyvCU?<;STBwZX4VQMp(L?{trr_2A4LY_%LL~jVVh27ce46EfA9}~{1^CoO=0r_-yt)YU!Q(bsx^lKb zA^F;$Qqay$7*S0re_=divJJNZv zN@=5~o7+47aBJOLe(~mqfANwp{pb^lhL_`o%e)K?D@j%WM4qUV(56Hf^w8w15FPmK zOHme$hnY@g?@ggq4CPiI0a7JBgY=6{)`+;=C&3RXB#(MqyiYOYb<+(yAATUdeIp<6 z?=nu}*3~%PJbXOC`{eLC9CyBXa5L0-_z!yd5S5Rue*iBAG7o+n^2w~$%`??viSG}w zEL~8Zk*{`P9s_}J4bj5)En|+SWk2#u@{dp+z>IYut^ni~DC3VDu!<7_nepo(q03MC z=sY_`xS?y{jPFZAWJTwU?%1b2iP5k^j0oxI~9x z*FEsx?|KFi#6ud4u_}Vku;_MEbd29#B7j}UNsr<2J8x9EYM)WT&f0s5i@dBbZ1oF;mx#=Eb7@)zFl5`5uC zXY^y48k0fl%c}M$_WkB82Db*#(y-r`KmJ2(LYJXYLaVA?a@;2&XiPB0SGGXI-svb# zry>}Kt(CV%GKPuh1awU{s>}pa-ab4kPZeH_?kIZA17Ow75JF+$jE?%nqqf|OFWhRF z);r^;k`RlcalXaEtrL?;x-hGW^DTyWVH#4p6tDHxT6>ro(1_v8)a(ZeaOJn1;)O(lDL@pWvG4BrXVV{Leih`QZFE&fA5!PB`+my)VNzZ#}lb z0o^Ha5mkk_IJLK>Yq&8ahI2ve+BAgrCcd>*Qdsmh?;{Xy5v{gANX$C?V3B^Xdj+Sw zWvrkwdjf$&fdFi!x?FOVI~iWWhfqLS`3%Wie(?1hc>r~zB6%kT>jZP|!_lr?hQ`Gc ziwt^;2e1V#f#>9x051y<8CnGksfZ*q&lG1S&8!G`fu(kLfkd;5Uz}kMb;QSKu3SQ# z0k;rW>-5Z zZC`NFXRfhr(n}h|@~dKBV1GgL-uDT*E{$TPghTRiU)G7kHVB%EQEZ7&tXkw`e^)x9 zq5yx>XEpE?dC&R}isDHPYIU#F%5cEs5YC9Sq zE5X&3rzOSEeKGqY6Zb6zMX2-V&t8px~TkO?Tvt#g!ZIxwC?oKu}gow=A-IVbYR8 zbI`^nh09h8kM&}Ba{~7TxenH70+Evd-ZZ%mv|)AEz3ds!=EmPv19h^?585EMoI8T; zqTF?Y7Sb$f5?dmt+6=;67p4J|K8)8^y@o;uYO%;bt!lprUN6ItH;STlUHB4HQ2b56 z0&;$_9n4hJ*(&{h?an$(Fg;ihQX#LQN8I}1zrt5<-Go0~m|)ifrChTjuUFyoJavz# zPb}#r=hE>I0%5ckYIp-YiUBM9C%y3DD<8Y&B79V%KJ2giBX5h9c03HC z4{g}vn^PfZcI$Mdf1O>KhDKb17tgB@uyI=PRKQf&V?+{wZQwq-3#^j200_ebfw;GV zlll0t57G(*edeqQ95e57lwkRM-I(a4nez!2wJ0fL*iv3swqAMHbMVER=CpQs!|E)_ z%M%R}G=WQy#7eO}O@e@sMGspE z)ZclJ^X~uNuboG!{1|__t>nS8szvMYiEvilt`;t_t^k3O@F<<5zjZiCD@vL~Y_5wG zf=QNe|L^Vj6LSU+*f-MbdT8YgCJ?FG=%e``FXinD#>8z)V}jqnY3Fn3vo`ClpQUqT zLT%-vnD&+PO@jcK)+3G#TTOr1PNZ1Ff^|9n`IMxAn2!&!cxRPmQ(Hp1($0wwhb?t+(C|Vr7jUr-l01&+yM1;=Iq}Mut zcX8yIbGYP&wtoH&u5fNzhrR33k{pvuZe2poFgAD}j}+;W<3Hl9=Zn8m6)NDV)n;X^ zQ~?^Q$;Of&TMCxdEv1R#vkp680c$+SHMgLmD!ui5-x-R12P1vU4ia=>^9mX`XQHrX z2c;V~*MxjIWeLitUHoa0 zL=E+B=?*7v=3ZWo49Jq;kl1`Ux5_-J7;5obm31PdzqI(q;@ z&5Bf@w4(@zeu8|b_foV4bWeC5krDwT#IXHU2OYnF_W0rkG5AtXOU`v}%6&LcrON`j zCn09gl5WVyRdtyW5qWJNcWO=8VK+wdPzMz3y;}iyX*;^snQ0maqyaDe*SwL2qXwsEi3Q=~*(C_1vZI|q*w@a;arEa`VHL*Ir z;Y6_-CLNK0_$&RqJ2s$;C=Xf%x(z-+z=3@d!=pgtU;t!+lQmLE3B2M1b5FvTX?0g0ME`gmnz%c7hSg{Cw`P zyu#*M?Yo%cu_6bovxXDtw?ceZKIA`d{5HkM9hKca=&4d5G9j)&oTjXbu4Inj@t|70 z?33+MAvPMWjVCLTIWTuMb87b!?jvEh?#&g&_!#jDGcx3Y6m0 zietL?2}kbz6~1KCR_R?n$~H@~*@#bFD*ZR83pdkI@`_?<8XQoRjW(*Lg;p}-d4h9H zFGZ+TR(e9*p$9kZ{KY%W3I7bA+^q-CE_yJ(eGcRFltOCq~AXzzOy|jN|E0keu z<4}8aI+fEwynH1x@Z>t8{|m0b_M>qeKlv~+qG$rCQngGk;(k?)0LdMMQb&dOy0gzc zk=U=rjiTN6`rKK*R|cI0_He>UxC=nTW{v4dfUKmeG);~ZEwO4kTA%8iVGs~)PN1CX zU1GAaB%$VS%_rBL9}atJ7nY7mAO?wFmbCg_|DSKO2H1uX&t1M)nT?9`2XX#id#KMw zJdG_UbL0j1@~u1Zr`vXql*CwX zMj>?!?H%>pJL}CjkPj*SB!4^&X`P5yT5zqttdLy(pmT>~D2m^QZ|$)Km|>D8o)fpK zz{~`W6iPAOxZlH{`_uuNS<|rEF5kmFaZFSLcxP4Vm~ z>B$3eoA>2F<1WuMj<<6_sP+It7kotyt(FIi1~~Wu_UmRdwX1@fGb<*jYV<5Jt=wMR z>k0Qh=7h&lM;aD~?3z0(_xe$M+Az7d}J8ed6@ zh)pH1QoJ}?sd)G#11?Gl;5wMFcC2fvyiJ`Yu#$w7!kBR9zb-iV-T$>ezJ7}%vE3eI zzNE$IH4_K!bZN-@@wPUPQ`q!sNrS=+H73~7j!>kIC&1hh2nJRlgqOBpedWxT%nX$+ zL$)x~@M>7q4ME9zFapcc%ETAhzi19O^CPm@29D|LjW z`NmP>c5n}3r7O$G8?^XOuwYi`@X&x2*O?PrN`a$^HNk@A?D?-C6+<-J55Dkna#^h# z@uyofN6)Gb9fwbJ(~y6$2k6#gKZ(@QB582L;lq_U;l>D!0@omh$DIv5_A~pvoOkwD z4G;a8S-ms*6kEJiAg*->(2Ydiisub%wK9hrLXquWrOFtVGlnKoq9u^?llpJ z&Kj-Ky|5pyEH}e8!Q4YpMX4^S6^n%D5x`yIBR`fhcg?GmDd4Pr5ici8H1L+6zWzq; ziD~h~n{JP^Oyc9r$^ryVY%f3xJ+?mTIZPymktySBjFZ|Eqknj{L6_8aaA8N4tODj?vlZf(mI>OOcGRT3TqS-K_pXkj+_V#K3jm2X##4w&8$5&SQr}g- zeEAl9vBu_x<^K!1^dWq9FycxS@X$5*Y~DsIh{LII@Gt5-vGxoq7Jn_lOxv#WtsF@r z8%Fn3Nrq$bs^!Qyr6tR<9a2s(A41#y`%~U-Q%?emX7lPs z<=CZUrshhIeXl&n9BhGP7Rr%qM*zkE0byuV9B{8CrKp@6W<5)-H17YJ|M;)B*_g#s z8Z5{U>S4#iG4P+c|CIzN&PpBwl`*g*@!4rZ_ruzX6r-?n7vSUxEyix;L&J zu?ipL>_|vBgmBK@U;px43gNf-(=CL*k)bfyQwSKJnm00t#X>oe`%GLJYHyety7r2R z{!Q0@YUJ7vZ=LL4x9Qq{m>8Snfoy+h4MUe?hVWiuQIhg@qL5uc{)~|=*&|0iyxeXn z2qPs8-d;KJ*)vy79FbrhgeCEy$O|ZMdc5EDNH3oQUwf&QB@Nxo~BY!#6LDjhf1~X ze%6y;iHF&GW`kX|C06r2Xi4l?pKOb|d7$NgcV=go<`8Rxp5=`7J`lyQbTH|eLYA%o zAVwZpq>4?&%$TBd7G4}QQNPleRrNwcK1CIYa(vR>R(+%P70a{O59q=D@EcwI+FZ8toNe zqhfg6NMd3R{y2pi3s*&?f*3+VyTLN zBJ+ptH2mNB<1(>SI6F;B7KW!QKTtb|xg%MbvPPANZV{@HoBKMu97vk0 z>Et?8Q5?3IQ%SwMG^rDO4OwSrgIFF~$G%$2E(|lf*16VPcgkO$V1fN<4Gw5hl4KQq zF=nZ(>d#HOC-}Bqy^jU9|ZmQ(j00u_RiyzJS|Q{ zvfs_J1HFHg1#63BSOhm2TTJj~m3Kc5YRLldlZm3peW9 z)GSKr^Y~12x(aW`tX81dW|X}_pc=)nq|x$NW4z3@$|HBIa@Kp=1#|rrT0}Iw#b~VF zn}?rAGSTq{1uIlx66ngj8;!hDeb=`W-uS-9f0>dzra|9)>lf42#qASu7TLn5qoSN< zOUykrKH9%+q>YovhKHt=uYL|MUK^!52RGo9*l-^3h;fXNo6DwiWedh5H68AKPVm50 zAgleG?Lvd7a%3f)f|OQIfUyn=zS1LJ7`{D#;OqoEH7;jQ8wXl&V6$wyYJK#Sxle!u zTQ6u3qwoEi6)|#jV3|&(t)8y47@~jB%41DICvNVn5 zGWXk=kb8ft6eQ;6BudwUygexL6mES1=Xs$m6_lc1Bk>~RuB#(y=pl=tSFV5gP54?( z#}n=P+gX&w<@n5%e582Ri5EioGp~CmwSdF2(z+dMaI_VC;M5uI z!qAz`f$A^kme>yf@U46)CaE|nijtF&cH(dbS-wSx?E2wfk60Si)VcX;iA=x)Fsg6i z;KUd)Rc=5L)WRh+m;0q@gv?VRHUtCGsoWix)e)}?2}GsSp&DTdWJ#e=#0pfTg9(QS z8*RP@8X&r^Dv{Vw$)y}@wc@Lb?{AdJf(G~VhDr>B8#WMb>d2v-J2WxqQvbv_rf{eJ z;E`}$z>CE9JoR*0@lZJQz^^~j_7n5qkZwBRGzsy~aIcGz`VHeqn!cka+9zYF zf8ciZUTyMg{Tp;`8rozIi7=}`*0ja&GiD%UB)!a(cEx?5jzLT4FA@ORjkf@;U?CMC zjbqjkW(#TvycO29cgy`x-h#VooMzo6i5M6K<~^ojq0W z9`b6v`t!#!p>Nt(wd+jDi=~sr_!2ZjtoZ0W@{0ukq<)+GH)2P_G!wsfm5o9qb#W%Rpz>v+m_uzOk~+FM41{o1+xs#m%pXY zt~*YEaQS>f$xgWX4U0M0)N0tzuGtXG?+_MvqQ0er>xaA2>G26%=pVHU)9_&b!q0?m z3MyOW%p@n~7b!ASC|$Ob|Ju^rMVedxgS|d~-5@BUVK!;G!K#I=!V_q?vB}__m5HU1S^cix-FpZjXuQ;QRk-GaPGf+U-@7<-H{7&0;vQBkM- zOb%kT%*e}F#=%Z78+%24Ms*)5`8TV_qqw8qlkr(;S6?=D%$|GyQKI2G=%$#PK|>~i#wEtT#ilr z*U5ou6O@ZFjOOgq=7JLoC5DeH8M-TaRwC?|VWOm~fdPR^kYsD#-bn{L28(pH*Qy&beWm?{|-AX038qo>$o1-naC?UUUvmZyX#!tz|ku zassbhWXFX$Z)7ZMetjQPM1=^7J2j5E8ATKsGAe4+XEsK_7qBfEi!{O?M6wn?fRa0O zikt5H=Z8Fi_3PHx@u&NyKRJsxy$YYVHohnPyHT-0e7NGuP&-gAJP@8?I9D5F(Jynj zJZ|cQkKOO}NAspg=yc!I)w(HW2FC(P^v$0b-#8u^gDV0ywMpZQj*pH{i-u;@K2Du< zWz&@cm~j@6y%}i0i>l1(@xvUCKPruefeEuP;crkWvfp%&WHo*%X}b#jaBB4#m?5O& zx4!8eKfrfxJ)%KK*Gfq2d02wYFxdAyiN*n>z#%9y_BgY$jg`NCWf~FmY`nN?mRIoe zj45I%na)sK1Wj|_i~-f|4pm^OFoX*teT znXFktm6JdYhYDNDE9q5&*z&jmbM!-~oFFVp+3<5QE7(Oe-;#5ivtmC{xOQxgRZ;ynah^c2G5(#lbb&gni!HMs|cWs;|__CzK z*0H51ymblZY4|bx?%+g!dva)MeC*JT6T^tnQ$y1d)H!&UOgvmv<_!uF$^5MR%g}m& z8+RlS9`J+wDNbWy1=*9G0IRP-SY& z=Fm2^qaQsO(#$XdZhx9K!>?d z#!LEo@He(oki@2^YGxueE)R?m_zhvn2C*ZaB6WdR(0FaCQONL`Cx2<@F3PZ}XY1Bk zlp#4%1P%M9&LQ(&ohga$PPkE4ti#UZLgw5Msd1;It;8yeezF*ZcdYt9gZgq!0=F;T zw6nex$1;=c2`L@_&lhP`@@@Fm-LArq;gHvy7#IX#0`|bNky%rQ)Jo16CnA>FR}or|;6ccnL(?{k|r^3LOm zb>o(HRi{vLFMl5j0EZy=peBLTwho(nl$M7OU2(qE0 zHj?CFlws!J>9aetqHUtWERNFPyGYA;e;ZegyFTjqyWhDCU!v95;6MFL5at@F!x0R0 z>_H%HF={`b_96rVc!!H>g!WugW(Wd;VIr{}3O(9zvYTeGHfIhVL3YC3JRIXFTYv7l?I-;6n={PT)_W4wj{fIbYlt#$vn%6D3`$T;4 zR>R34yZkf@wht_wz*nCGy&Xe^Wb0UIXX?YnQC#fjWFgjTjPc?$90+6bf~dLGMML@s zK3O}CC(;Q}{?>U>R__~DVW|W<<=HyLqlN59z_}+Se$n(wU=bN(Hlqi2((6K*4t&V(-^_mHCV;p5ev;9{aT&*A z;%MZN_P&ihRHrdq>Yo}WeS+?vp3cgQ6OAY(RYSOxFV7}&r(d3Kf@h1`1b)bFt$aBL z3#)8QQ9o3jjJ%|0_7U7fJ|GiJ^1yyo{p(e06IuHa5Zt*)^JwJ0FLtRhWdjbGW6 z_>=|sw?tuWC&4A@M-@tl$XKslP6rvKoyaRc_r6crR+xsm#%@0og05($PD1X=E-9qY zdSpPN)jLp8x?c70m@L!fE(DMu9VZel2+NF>E(o?*;4C8V;|+2lqy(WF!>P##du!P* zNKhBjEtj4AS2pzgGko2y>|pl+#SP7pkOuIn^9hK}FCb`nLzsZC+X#|Ej3VGp<7zY& zl81x707tq-I_c}(NtrZ+LVWSsS8c@yww~W$DAn-}y4S(3$iz%Y?GJ;~k4qoJi`6#* zM_MqvkMZaPc0a>f`E)!&RA@{--ce+*QT3b$+iPct^0VjZ&;fcBqGB;ha<55Jw~F}Ee50DU?4krTwJtJ|nMqdOin;Jkz{0MXl z;)y;T5g4v7J74{bi(ZOv(6m8)w=Z;Nug41X#ElGZK`9OYH+OVdCy z=i=2yJQ0m3`l@FXDdYGQo?EHyr1`V$!z4f|F+GGup7rwm>cr7p41VCpndn-Sdbm%7nRHWrgIma7J=A}XqMc6wgE2Yrc|7ket46$`=? z6Bu;gobq+sI&kgNFXM4AO@mvz50MIS*~ZEp>$Xm09i62MOjx4f08AIucsjo1Gk9&O za#lJ~o*b;E3u+0*mtSW23pWzI3COX+bKs}d_JHDX@Hb;j59>P)2o;jiF=;qeES$_Zosb?{A-V2w`bc1KRFqN^oS$apv%38?El+BM?_)SJrj24Ze6{XmEPt z&7Zpql_?k_JS?@kv zl6e3wqp>BouaZR@*@{E-a9Zj#OZFecOXpY%6LrE-UUGz{3NVTiwu@(mD%FgQjbsswN3%|hEZaP$Vx3By)vm=8% zu^zx74lMb2(w>Q1S}M&wZ;KcD9$ZEx$qxfL6d4YOJ(;9q&SRkUX1NqJuoynygqe^ z5Ge$MQD$D6hGi=xnO^eoVdsK< z=g@yVE|2sMkj2siBjzp_U4Va4bdkB(#6;&9_Zq{QrUaIr(X+C@#eTy6U(=WL%Jtk= zi08aZfA&oFC^SuG?S9EDis!xf%z4!+fJ8W*`4=?19@v7ra1yYq;};$TD+9e~K}~_9 zwfw??4tiQ&<8oeET&&uDu+ zc41Ek5b-mYl&RQ^NVrQ(St8j0ps@(VAd3dW5@*srI)%wRp+X0Vs~z&)GyII3zKqXo zL@vH}mVAtcWcTIrNLSgqAKdA*){I?=7e*nb^Bb3*M&nw-hFGQxpKIPCy5=mHI-%~9 zcE-;*aMB0EL=YP5*E5z4VCWQzLeCW zj|~y`Ew;jtWI8`+b7t3U8Y3|Ppe#yK5LN|bZ^}G|11P0;t*nQwM2BaBT zdc=K(G$SbB%g8&E&RUes+wn-?)-se4YQqKzqB@Qfy8bQ4^t}RKxM@}R?nQDovm&LB zQ%b6HSLnneZFmh2rU<&kHmVUS%o?ea*?9bZDUDjvikn9DJNx$%Ey;(=FMFj3395wz zQ_ZM&>Ejbq0flCgddt=C+)W~`X~t}~FK?CH)=vy?M%e}+HXApkU1R-NEZ@d5l4;R9 z%wwYP@9Dd;qISJgqYxc1QdGDghE*LTnr_XAV>hxvIC4ZePbI4Ba@v*fAuEJ6Oqa&f zVmPzT>2S~ckH6{Ir%*cI#Gh{W?7KAo7?)O!C*C789-JHnGzRZAFg_ip+{Q~+l2q?t zicQ;DFJWat1RNdTZaY^!$$_YcsWMSZKI6u=yz`RbBk5HB9RKOQv6V8H znY%Goh8N*0SCA}bd+UTZ)RoYp`dtdZ`bgQd9Z#sEKnKTerMVD_b&44EiDC;#ph^iK zF68lCB;!UAN|#ANi0Fb3EP53;y)+#Tw0n(2#CDR^Z65QnWN=%-{7khc`D0KO`0+G+ z?z{2IImm>E<5nODF6!2oMNAI4sq){MD8qT83D}^{fWZqnHw1YUGpBm?X9;E7U8gNSrsZGy<{O%9}_xtsM?o zfro5@M-Ge2`Y470t(Ly|;K-l#4Q}*M2)_bPm$1cJvNj@Z; zi*`UD5?PyRnnkQN<)GJ)pF1HEig*F+(tX~1?=j4vSR6kd2=Y3yB@rf^AA>XP)N<#L z=;PdrUHr&Dxs^nE)5&4G*GovIRY)MARcmZ*NQjAAg{>jD(64!yMd4^x7!0Gbcw%O7f%T1}>jVfg8B+G~@UCSo<^Jz$rCk-xA{ih~E0GPa{=zW{; z-Xf1+m^NJx=OFCq@zb?&9Kv30Rn*e#n6#^b%q~p|O^fG(H)VTK>eY2eTyyIy>E;_| z!*_3#UOk9%85-<+X?u7>s1#+gp}hkY`St|L9nF5t+w612 z$2`NEMxUDkKrN~yEXtwrLM!5M#o8hqTODhHYYVFXE}+HcviJ%-Ja;8MedvgsRxC(D zoULboj{l1zet$J?s1Xlrt{e~xTz%Z}yJik&Ef(~4?bUsTz>RDkf> z;u}&7huKKc@wsUx{2Tv>uOM)e)#$fHz{1wFZ6LW-i+&}_(R1OKSm?k9nak7bE#=h% zWvpbMhiD|Zce@gv=b(2y=Keg=rfG6@_qYVdE)KcuzPVcmHe;oB*cqwn*a4+0)9^m$ z;l;tf1;6T9tauBxPgbGZAd~9M;g1y35a-MPJ9TTxvX;l z(A}zcbX9BKNX~%6T64nGe5Jl}==6g0~I%B3K?_N-ZaYc1HqEWu6lZ3GL zUvTHLgYmta_Jr=*bzC*Sq%2E~s0F~J2?m}cYed+c`T5Y4LCPAsJBz6q9 z(TS09w>IEL6GjXpL1zL8CJw)y4Qk0?TMp>m=CsKOn<2J4uX@2x?0{L0aCB31+y8gO z_8N$7HIHr#FTxrZ^L}|?rK@D5nYo8fKzhY#Q4omUB-(J39_7{98M#>?tb7AgDn^A6 z#i_^s+oAj_O=I)BebX#^z}J9YLU%;pF`!(hCfBvgfg|hz-wf|GHIA|t610;xO>4jX zIe7V6*9H4_!id-##X@rdLFs;wjZrKe!_8(-6^8Q6N`5}EbY_7F0tDqhiDG` z)Ux-Si*MIR;J#K`GOMCtUnBP?Rkb z_dM37#pgCi;Z#ZCKz!FVJGOydS<-z>1i@eUUz86ArX_=`@M4ss=q81c&4$8k)MUdG zjeN+dr~-Ql&1Z0JiTlbBP_AFRJaeBRzp4iAQ2hVR*|h8a~wk(u70mbA#OY4&QjtS+`PX4M%D2 ze!YaYA1<%OGK#F75mdr9Mh2&bM5aw6(vx5JIxO;5K(H#xS2tXLePgE&^WIErU#$(Z z{!JAXg4>C+i(?L(^(q4rff7t~j0FCLs<0U5=|p=VGnd-+hn%~E=NLDwL)iUBNsWox zT4YV&A&(vzgxlR%Cu%3zmHrL7G7V6^1#cT^W+^|bidbt&C076PF<-D2U=&L(*tZCj zsnoO+FNxXCE{IT-hkWy$R)YQ-zCt(PIek`ddO2@8$S&wi@_htmN~cw8#Tnjs!kBX+ zYfYd?;G`DIvwG&PmS%8}cdz!F?`hL23I4dHEgX>bH3DP*#(0Z56h2wZk}-KPsKngPBBK_x&@!cNV^5W8V38NrYACmz^{S zf#8sVsiANO6lY$SFUEO}^F_QfCbdFCBe>A)Y^LKs*-~ z+nY(Y>qCDuHMo7MbtVM25YZrRJh2MCB@5Q{9vw9=4>;N)UEFRRhrF?DZGaYLRz4{Q zSQTsq@=wW6@=!;)JJ{_f%=^!G;hQx!V){aE)=_7E#{CkBg745AfXi^xi zNMbshE%-4e0{G)z1o2=AVh3Ki7TGVyraQnm9v{s*{Uh0#&fl;Rqd;K_EijG>0HZ2V zM=@*m@;nj}PM+b2V<&%M2O|Bf;lBT$?%SDAgc%S?eV95AH_O&kyYtPcMfJi>{rEMy zaTcMLTQrV2BF|z(Q5JU13r(!_l850T@Lqt^Vm)?qAe;t8pj*Z-D*^H{UOeMlE*qK8 z1G5^D$v1SbkHY0+CU9yGTLbV2Ci+(F;E;VPJ+s11Tnf%Z4aT8uJ>B;ex^H%a1urYG zP+~#Uq1>6ppm-rifMDVu(H)U`-jV9@`IcmuT^dd^6#W-OHMeQ8$y5bh2YAGmQbCup zPjcbAU;CAp;EOl%EjJVu@doDm-i7;Pm(~UN%%wIr79D^5e&r^F&`Y54aIwfX!`PZ< zVp;VQ1bd}KhQJLBiw3Nd97VgFc@I)4RJPm=8bLk227U{GALovQX7zph>@Tsh*<$NS zxA*Y9bnIoHGqI!H*~?Cr4lsHW#kp6T`rasV*nf?_z_Xz#Ms zHUv>12OHc0^1Z)1I9ZDyaKo^;IVh7G-IYE%U?3ldgtd=D?K}TVLl$}O#8>PV$@hyx zUCc$wor{X-P_&0jt95UK!I!FJ#84~mt{YflZ1?7$sQVf-Z=X&+w4C0ukg{TtfD z;QV_k>i_sRy6?Zo>(^MH3_zjfq82`A#Y7V_f6^K14>sHIE-mM%A{~+E^vXZF&&!bt zZb)7oV)xr&u^Hj8q089SaFve9dp>m_{@iiSMn`z{eO)V}(*~5AiV0OrS4o zWIZOzxAziYT`o*kD|da3o!trj8J%? zgHrhyIU-(R?_iC0LnJ%@>&IUu;ApWSxm#&|U5sSz_%@V@mZI4sQyg;~zPAl;y&m%E zB@*4TRT}dtd}u6xuF+Mv2Wz6Y8wGIp5YLMP4qW_~ZD9IWgs77jm z<-D(f=^+f)+%IVZ1}3R2{JLl8@NxKY=+sUB_4LPC$HV>imCBiql~hPSLLB$)O!1#Q zQS#V{H(QAoo2bZJ_?2};GFTKtz|0jPZY-u{Q~}76ZZyS*tr{&JM^H#k!iyxThzCOi zcg}m^(^=VXYBxLcamB1=B=-E|NfHAyJ!ZEMT9wRk?Eo^DT_YJvpUqC^O`8!dZX%VQY?kY=dglli=esH1YD2 ze#wT7c#*{$-i&+8(F3&6X(6Q2cdgrw#z#2-!M!Y<7M)5IT;TCMYvrQD>L^z-f!TnD zZ*K)HoiHn|IR950@gZ-;5)x_r5E3G)U_=Z}w#wfk1_+>O$i&1w=R)6mI2p$k2Px1Zc05pq3Aa8368yfH*0<4`>Yboce< z+d_swSrrdc$|q3sBr2E^EVd@nH+CJyIaSoF*b1xAOQNqtqGm|EOR@A#L9HtL<#?r#HyV zhh}Fq7roVKz4t>}$HlT2ZZzSOBqIf{1c!@&ozzBGy|t6uLSANLAjPe7d&o&i0^8df zv|6I>qnJB_M+7?XmM5EA3K(i+kw8a?>83RY{40sbR>N%ZnLgu2`wALp4hlE9P=+Ls z`Xf$iZ^aq)JwfkVUns45A6{%7Mye**!b49EY@J}Hr$Bw~!s`U4i}oG#g@Sc@q4h6l z#_>}uqrczZnX41%-2HJdk}$^9<{MJla`MLCag}b1d#}0;@Rc$^R%Pc-wAUkN?VCF> zKE64N+7#0|UEvw3xYC31-FlqF^ai|`%sIZPz9{@8zBuyq)O;Vsnx~p%6`fQX&;th; zOaJZ1s4|HO3xy}M&Vqe?eq_9#aYf{P?(;^*g_KQHwx!zU(;^PTteZ&D;CsyhcY^4ND?npy~cbk(k~#? z`0e7SD5YX`W=|3AV}V?V=cxIA(f4wE%ciydXL=*?fw(+lr=s2ZJ}Jp(@uqW3DdPJx z7pM?1>MRK18Mn>AqHL`MRC%Rpw4FA9(u`Ir23j>XiG8Gsi|$>J#n{*?KiNvni7~~E z*_LbU+kgX`Y8T=mWEnCXy5f$v^5ndxHBD!pAyeZrqU9qa*`MBrf8((0v2mQ?JpOdJ zfU)tO_~@UuBtFtHOEe{x-#!=sU`A7nKzd$xA$)Mjaj{6By5dukKhwQeT^3`*#8>4|EIrDtUjvNWrSGK$7Mu;Le4vvnt`?rCa>@CRs z^mvKyEqHBKHWRZLD@ps&nnDZnQTDV!8rJ=iDl=nszAB(?}b0d%_meSv0I!ZBU#UV> zEU7(Ek{yb=4tu;Yrjh`7e)Fty#OWX{DR2Oc92CET<~0OrTaUn!DhKVba36?xu!Ezo zfS`DAhk~b`zw$O~m*9W8rS)@3i;2UWG4RV{JNo8fkUXo$bg5|6=Y{?OUg$+qua~4I z?M=BL1E5Bam2m<6WPr%t7E@)5wms8U0vAME{GlDxPCTPBP*yY@+GLmuBRXf*@lU!Q zU!bYHb=CuP*TyPC$rGLs|06jX!#0r7trHWy4XXa^KXtno;l*e;tnSD|DH@{@6s%UA zNGn>-U|3GOhDVG$Vav^cPNC0O8q5VMW_bGG$oRgBsLF{{CTH9)F@=l}0&R9yhlGy! z>%$yN2mv0#3JaH2w9vm?G2K z8cO$U;mE5L_$jmVuD43@fXd#r?Z89s3($!2rH zRyIy6vTs>oRLyAyeHC1@TcfHq1@wZPu7b8_8qpnHWt|4?(#n~U=I0v%;;Ms+bqwvg z^Z75{#^$P~qixQ5n#4tzGlMJdZ(AXeeI9SSz?eJLE0V<$knM7`Kzdd8k{&rXpRn-B zmAP=xq%M&Sux8=@$`eX&TrfU1MOR5R8bCTEM9o8Hr{*iA4Uyn^I-8&3s&~-nZ-4kw z%Cg~j+p}I=WXaArG`GNI4&&(a00+jD@k;-sU+E#@-L^-vWJ%4`&(lkDCze$e_Z0v) ztJH8wCK;+Ma;_E8F3DI=nP!qz>8_o+Z6kjm!sy_Orgn0ZseYkpxBTvyZ(K|1{PDin z=`5$|scFX`fk2yb-*OxZP^!?B&PHA7AGa$#NaywmN#_*2cqMUBr6Gxj%wpkrd>sjaA`9j=&>mdy?SSAgbm4Uq5-!DnL z4xhcuylS9C*cBArL6PcVrVsApq3UeCU2C1mKz+7Pkwsg^gs>ZVc{;tQQ=?!p$f(c$X$=r(XDeQPk^o8j$AxL^&nPMRLN4bY>P zAb0ymB#5negEfBcjI$~oQA(k>0@qeQhdUUBRpH*4SvpT;i6=r7O(tj^CJkgjRH;BT zk1WMq#XV;~#H*J_ zO&3oj`qA*^VlzuN`r&d#9-EV>(rC}SSzbq69)!!q)AfZy$Po~iJ1F+b162j9i^s;RgW+=D>5FC|n}FV(`cTw)lV zND{?sIAGJTIF7}phVUc6>1qdt$egLLr=9m6GDvwg<{iHHgaV!6gL*=sj6n0L1Vpr* zffS}mP3geLbhCn$io@_I?p&gy&afd%VKq6(wU=7yS~H5KZr+ty{4?HCmK_p0;nchK z{}X6i(^(s5`7R4e2nWy4;H>W*CrIPogm+$|GMo$uw?C=_(xo|Be8{qvmun0^1~G>$ zg86rJB1na4ul9CqUx2UCD>|&uwLEuxlP3wm9R9#tu3A9BGz`O><->I|MX2BTD2e0E z__$SrF(ny~)q*is4siqSI>C^d%sLJYwlR?49Rrd?fhcgyhF&a?hX*D+ltI?IVs0*I zXU4z~$i?5e;#6*vY81$ug$g*P@! z0;+9W^{wL4dM2pRJpXjx-;j8gg_R4@YmmX zG&O`h2HoD;C(M|#A3M~>nYk0=8^=QymWZ-*xqozgbiCb5jJ|W81aT4Ga2^}3q1sHO zqi_}MTveVkm{O?*9tyon2m`Lb4JMv8v_xD+#c4&aiN8NXI@Haw_ms7%miKgoBM%`B zeQ3iAo`>(;w7>kU&q!+w;Z6*0grA%@!ei)@@FL4T)ZQ>PbnO)r{hO}+)X23T-a6U8 zZqv2@FflgS{T`?w6L!g)U7ZE?d}aE;6IK6ED6*>YgHeW8R3s5kacfhy?tNL(Qw zQiBoUIt>f(lGbI7h+?2bADI3^_?|+A==Q$-sta$U=o*SIXI(AP5e%+izumxQdIB$1Yw_8D zT9MGuKL?cIyuc!<7O!Mi4x2t1&MQOu!cC89KZsWM6a4A6y6cKU&9|EeNI_^U$BQv# za8GR`&Qm$- zo08NFB@RD-t5o6d@M+Ohfp3W}5v#jd@N_v4k*Fz>)d3q}jnj&a3ghwvvBlxT8J$hE zCS^+-A-RMDmQzJDyoIk2!1b#hblfErz_0M9+a`QkhM{>zw@Ux~s}jW+-guF%GggC$ zu$bJVdo*=3atEmGdy0l4SwH~%l1vriL0LDmC+BcDEa2(l!VNo*vNr98k@r1*2qys= zZaU)$&3_Ud3nTrT2R9R-^b&f1@oU}a+wo#Js3dV}XU57i9GV9~WkAt*4jbUgnf4Y? zH`P?8nTP30hnIvBAc$0}ML7yUQc1A_nL!StxOYxg{Q4_?{N?xJOSTT)7m)0E_>9`Y zFOQN;sCB^-1w$RN5Y;8xfWSgmDZs!itR-DO?*)s&EohWTYYu=eR0)yrTaYGte`SgK z5b(kQV7NcaqEmLQm4iX{_J8i(M>B*poc+7!iINlP@Wq2bB-q}EFwwD3b`z3+EL9ty z9PR0pf?p07{aFiGD&AE1Gdx|Igfre*R3y#BahE!fRz9I3W8i@he>k%34j4`euVPC_ zm+%weKwj3!<`#9-vrfB_-C|AsvU{E?xe#!yQt!fjKd$SS=Swml#hb1q7YT|C@IEkS zXU5FiTN`bhrBgHRF`50~|dn3neqUUQAzYL{V%9S|TQ@R%^mEC_Vfn%2GYIg532dlG{Jy)vMtgVLY}) zZ=8YA7O$ILnTJvH00R?#3!KWb&Pnjvu<%RtReTDfdE-GuL?T7ZK4j=lwO-I46d@EBsv+Tsu?OrW8Bk$ZkXVjPWT?VH z*}ZAu5Vu_!uuxAzne9j3^KabK($u%V#|I!(2Ie*eY|PA3$z$*$tyADndqA~!^+|~| zfMs67$vrm;aRZ7_p65Uif!wGm1pINzQ(YvElS8ULBTtMB5Yf|_a;4n-%eL1>ndNw;Fp1U!o}RP_@r?Hm!{UvJqu+POrdAAd-$%S zr5&WCU>=589fJj6gK49r>RmCye#(dhe_-}rLFv5tLVbgn3+zxFa23(i&d0K?X-QQR zcSX7K}zoE*^*D4-$r2GO7zW;tLmgv6;4{!eOgu?=@|X zX*yNs{dhbfwnQ`g_})6EM+=JMd-z$gnEvj@^|;5)@UHB^F{h_Q=oTpKRV7u>=RzD{ z?p=EK48MH8pHq4qJnzaH_NvfXcrTDxB=`^4t9SbZ8N64D4ptk7c+ z;r@x7TK-Bdl<}JR_2C zn{xlsQ8BS$q{I4**kA_Q1s20xlLtP0$?)%%QWg!g=bowJj^;2Bqu+1M&^V5|4Xb0I z<~Vx))F3KXy`*2idXPjxO2Y9UkgYM0Vu%8zf!{0>QD7WkL)n^_9S%X*1@P{=Tf$*A zwQ=Ii7I}C8v|65Fnege6+(yZh*-qHj&QJa8TGq3hHb?F81-yhZGqMoqSBFVL{|9ea zZaHvpZ6gX=OjI36Go59EDU@g=MxyK(cePDo)oh-U@=m8NnZUyt^0P+m#Ml)=6l8M$ zv*mTq|92Kwnh35vr%92Rh8;UNGKt}!j?R2C=$q~5{k^v4|H`)qeGo5&RaA77;*3>v zljcUut6eY2nuvRFKPoI$Z(%is63$Z2#Z@_9Y`t8SL@Lk2)UC5$B($k@_jeck1HN{v zVcKku*P@u1t(mCU3a6Wd9w{yCR$ZBGI zJNis<9?HPx!QOn*E?JyWLec*bG`2UziU(svgIQQ-Ww|ZrmYPPwyCU^vtAtD|^YacH z!@IycQ^ZArta8ae34cL;9PKWvg|F|e|4;cLUk5%3~llgEMs=_(*#bnIm-P9=Z*3ZuhiRJ;eEOyveG%V=)NFXjiTP zp9M&TCU)m)v#~Yq`}|Bv-8hQ`VpD{*PrH|^Ci{pNjH)43IXQ81$#o_;tuRKov4bCd z&QIs#78)JCkB<;=&eWOBzg{jaycq8}A2A6@J&z}p1|SV5*WpfHxnABS>f*}g;wOxg zkkTU4M&lLDUL6V;%_){Y2*{M5yFcS%9F=ACMa3*9yv6yuvTeWqibvZDiQuuH+q^eaa+fhjBFK2=>wuDragV`uYo3RcGU!Rp zS0i+HNG2?h{@x?Kk7m0nA=9ym*%evlHq5J(Psl2}jz}rEPX|(^K_l-QuCa*Kws5kd zTju2(KXhXsfdkv@y8X~ilAl$Z+9wSoUEU|n*8uS?GG`3X zgq`+Ur8Zx)IBI^$weG$of~A8AsuFj!a|3t4ua#EZWEjNH%WJ+nhtsL-WF*TH8jFXzUkO0%w=6IF$7C^ zQ|E?N5HM*ur^8eGQ2s7kHxLSy6x4td@ZRlf%dwZ<{C&uwkskkPQK=d2lezmwNs9FN zGNfc3FfzX|ZWEC^>O)T7*1sB~G%7k7t~Bl>`)y41yhDb4V<9$$4dg(geTg6hgUDip zWbWCu^99CQHq74axlNKG2{j`t@IxZ+p+w*p_{}3y8~C;OV%SEY(uBj`iU7~t4if@W zFx&Wps1DqtL>j*yGbk46hsSL|r!v*5a$wxCT4|!YKZ%x*&XpfI?4B>;%eEfc;FoVN z(wUKJRLKxXp_}N@;|KPaB?k_*7%vK7Wcyq~e}>wR z`o~vNVsz5oasAHXcNU}mfI03qHmyvw>-=I9FZ2)SLJ#>x=n!GPs*7x^^V(^r2P%O@ zcn4ObSQHg^F7r)Jyz;fAJ^7T}5kVHd@^&8~bQ|-}OT=+Y)lq z^O0R3j^ple*XBwyC`E3H(i)48tOEm?*Ql!atxi3PfIyq7SmY`T$=GRbuAu0HpK{C1 z$53wH!JjT`JKHx1Fq@wt;CRmhNsI;_T5JI zDK3BK!%zD+d{XQ1eU;+uKb2C@1ZHdj{5`&m_``TpFn`f`?y!|XIdUebL))E(BS2$m z;U|XCbCkCQ@PW69CK_12V6X)-Zv%8+5GufK@yP7W&%=Za8dp(EP=JvVxS2${L%v(y z{HZ@Zmhxg=)vXK%N?rsub0&vI1_%4#EVF-)IYirj+>Z?>y&MOB&zVw%_u`ccj0m%+ z5~bse9mHRRD~d2t3@|XOuu@=4mXhExO%M9!#P4@vrlLSmFc3&i5-y|(;nQ=ue1^_g zcNU9*O{v4#-Uv!#!NKrAYWMxT?-0>N6j3}>l@!?;!!?c;ON?cuYguPLWoQ`Hi@LC6 zqZl3GS_q*2QP)ne;*0V@)Sg8?4H~TF$S%c@(=88q{Wq3UPCVD6TaO+uJz~XZ<&Je* zC$iIu+#t5FV0s6qW}(8}OCoyD$E8G{!E1%qfcl66)1T1qde<)kst@U5c@(AxVJem|ECWE7;I6;=^4C8Ax6*Xn z*x65!;H<1PqZ_d9`IdyZi$cscy!h5;l@X8<9J9h?_q;S$W|i9u>!}k`04DHb%az2N zXCw}Ha-U`3<`V6li>UF<33OCYpX7SmJrBmcP;I3wAQtUUrIO24CN>LYu zHU%-Iq6Ep|feTp#7mSF4|0=z$>R*=O)eNCgad2e$$bxhAT-Wt7S?Yy%AN)wNuT5(r z&R#OZ@$NTola;*@pEt)mGPEByQ1|vBwMr|Z3U!?{D?d|>OjhDr#zG@JoRJ;1WAADk z2m})9aru+)`t(uwN-YlMcKd4Y^`m+$$C5E@M!-hGZ94|?h!j@&u^|K8;RZ~@ZN=uS z9!^LNeYgfMUI@#_EhpXS;}`|#`Y1d-M8zp)A_k}HTi7#B6(1Er467pMVig*!E}UAG zvUfQANHjQyzsRtc`Eg8J08vDtr0j+aAzu8VwP#P@Zd%;R+bzUuA@5A}Zr$6GE`10e zsi>b3g`teXGT6kjP&5H+X@t-Ne{LzM!gpl$l~feifgO>7ba)}RHy*ed``IiGKw8kg z^hYtVL$R@TP^LsK{`ZBC`4(l>aNNP!-t#wG1^;{fa14_8yt4q1TQR#hH4LFRGLC+} z*iw^RV?;LAM3z@fZXhvZs%eMJ&(w-iH6_KX@raDgc7+Npx@Omterr3ze~+)%twkG( zJDQOLGVXo4ROl3Z)=I@9+=RYzXDIHtw;EUC*+Pkoj>t~P%ss^L#Kav{APEd{m^tR? z;QGps{L`A>;mfq?Cy{>Znz;XBb|^$+~cT_8C+0YK*5PJIH+R_-^?{7<{Q!Zc4XDra(SZ z6}qRKpg5;6TT*G{PAZcEnFY+aNIbTJF5m6pOKA?H(zbf{Z%;cB4_cYTPpdH+((OoX zT3#RLAeLpl&9NW@s7+(?``Rdf-;Oq!Y#27OvJE~ZITO^UYo(vZ3$0uRM4;(n4dZQp za_*tM_UZS&b^Ix~b%l&*>uO$`jLSI#L#rB?{Zu_0-QUsDK$Nr2uGH4>N;@lhzrJl2 zm$fv9AzfLl<)opI{<0R!Yh9Nuf9yeHD(IopH|>XRXp>ZKsaeM%T%@I2=W&KuSS1M0 zn`luqLnT1jpG)rY7j8NF6OX+1A7gO5KT0nr~+sqoi<_F-_%(z%(*~lJ7v=Y3!<4Y4>4Ma**!5r zGD}?3qGn+7zsL8vJ7BbrmISN}_J_=#{W+XsU@_U!F34$>jUN~CsATNK6?T-k3KI4G zFwm)J>KKTk7f__PQNs+sT7MHg@olB)|7;!Bn{k7#l=uyHk*_+b0j-O#NW)SsEVbQa zbq^Oca;lUfvv~IUF?{^eE!0vY4SqR4>DC&H&^pfqy3wfN3+G zJjaqgjqFS;vD>sKz}J8J;j8a@I@e!Dm3>&(ul|S!a?Wjx3_~^2WHRnCJ(Lq8p!HH4 zrs=^gy2n0^PcNYlV!#lwGL@MH1`7-f@jsLDD3ReRlwhv0(P;-JxMvf|G~b$Z47r5QHbO#Msn21G*lAJvjHa9LQtt;RBspM01tvt9)zz8WZH#? zoVAGpDQP>q;%ll&B&Urjn~6hjQ~N!+*FNRRR>_5SwCGnV4weBYo?Wszu#;hL)h;4R z0EJJtQ`j&{R~U@3l1#6Ba;Bn%8FbDzVloFoQC#Kr$>xLzBO-CHi)!aZNAIRhEISzZ zif^c>nCI{k*4gzK2FW}J&xEaG)?$* z&lWFIO?6hGB{}zH0e1p<@mJ0p5>lm2=`uHfwEMu5?p%N;tQ=8dhi%piy;G;>WIuGW zO6Tpk_X3VF!Sd;FIP(M5Vff#WL+)z~2x4g@@@0z&%@DcN9Q|Y;^i65aXoVSvsle6s zWXC_ea?AH9l#&v|D}JPULL1Y;kksYD?r~?fEJ=~prsHE%9e~+Md8JanQ>4lY!w~Ie z3QcsX7T~C8UW6h^OYqk&jOquDTm2pigLHf=5d5(U<3L=R566tuU^@2hNc@uC8i~Qd z!8SI`L)PTdkI&8WOu5E8hKGd-4hKc&g^~{hA#Mr8F2ZcEA{S1ar=I1sF_|xjER7TP zCEowC)vsTOZ>{j8*48EdJeklgJ4B#RQ)=leIYgk{-noZt`rP&SPSJjSdkN(#4VOmi zyQ?r}f=R$^Z~$qiITlG!D%d*GL?Ek;|43Cjh_X0LO!&JlX>5^Aq`U?{Wa%p1kX{iJ zzTZs8{bOf7m%E@8!u?XEHVs$jHpi-q2ci{#mUI;wR{QH4*R^-9wo8i)`m8MTnYx-3 zak-EH9m1Dr^1u|txm}OC;;)32lZb=B#)>rZOrO`S0FuPU*!hmPyoaN8OS9&8Co9px zvE~o;snsNt;8sE&JDsE&s6h)UG=;*5SZld;iXMikt0yhdC6A1%3$p9)bpxy$G z&j?=JBOMHJ7wTDjSM5Ci$%j(G%Z^~U!U}E)OcpoB#z(3%;aLYpqm58@)d1+(+8Q{_ z_QD>Q&b7E{)}JI^Ria?VJ;eeVMYY+^5c*t-mZUSlBp~!I%%%EnS06xqf}8;vub@=6v_mjbsxsBj3}meq$x>(ymrXo~QdksQuw zbA3PP2vn1!qoSRt@u90!E(D8K0kFx!x_t4;2FH4Y6OhVcM1sI(a+;yU+j!S#x6s{Y zppC!Bnv=za*rITSLti`s@bpzyld|d9Cw)$Om`^Oxmp>+vbmSN|mj`ziipixMLUp5< zLV_L9vLukTUVADPe!0{_R)l&Sc#?TQ56ZzH82ymgcift-7Ga;wh>3RcboXJ7=E}av z?NIf)_x?bVbicvVx9+U0M6grUJ1(pNe4Tn%MOo(4t(8Hz><|T#*WN4BYAifypw^dG z*qP(_bi{(!z2wCQUW2bKJ6!9E2URKdO4ad0U(F4P`U8K=+=eP!V6PTCf-0clU-Cq- z8on|tRzV3}49lAmi{Mo^*gjG}ASDvUjw^v-@-76+(=X`y&RG;tS+M+&3aAsblgr~% z_^K8926c9)@s`Op$o7EO;ZpH$?Wy(9%{@(|S0lPszwSkIltAW}u}P!@M00UU3uj4m z6F(%U^l3zlvax;J?0)-mo=mOrH<5PE zbDN%6*bG$@X9WBLDUoTDO-9sD#mnX$i5z*>9gkbEm_ir}p-l6Xo@~e9*A;sbEL(SY zJf3UUU3aWJSV{#;N^~b|W~A_+ot%FDuvH;*WJ#AaikMk}-GJ*&9A-Q&lTmE2vH&zE zfJK$Wm^0mwM*3R&BtMmaUY^Fx@&^`iCGtk=p4HY#v#QH$?!Nzh{0H#ZW!(`I$E4jj z6X(w&$BXfZFeQ$GsCqn@wy$0rk_+vq-U3ypzyrw%C|^(+>n*Qg5o^HOtY3t z?Y~5@$hmW&aYhcf87sL_nvioF2BRaBsprGo^tMg3GeBia}>MgJ?qyo`NmiAs~|q zA{rZBk{ko0R)`hSF(|pGI~_``?Z^N6+WpwfRrx7?T43bF^V1G=e>iu;$Y_LTIZ4#d z3+?Pc6T{2#eaoWgs)a^};mM9`3A|wAHXJt;gI)y$7P9$EKK-NL|K%U?O=V}xPrPW) z#d>r|A&9g@YaxJqppM>x;z6%>VYpoH+k)^fU> z|BH?1k!PCXcl@pY^rq+VHM1tE^)=f7+Cy>4Uo*zB;q=31*xF~|THVeRx1(ue?nj)>x9(@Y|k%w1}J(xJ#!~>$ud%xF4}vbY#)+`fZMq74#+gRVWZO(`?3L zWa%QB{ttKlMj{B#LTS|x8>-u35s`gg#?+9q-JUwiJYfd;l+nThP+=rWZxMQKDY+*A z{SaiQ4Yg!eD|fxR?ujQ~Drwx3WBVq~Q32BKboLN*mn2Nd-vQq6?E-RPCUHd-rM)rMFjw{(?OH~#G95YAi zeS;WfICG@gTvw>tvLpLyIKdZJreKaZNk)QCF#)=R+`$+DwS;?11JWRS>4${pu>K5r z#Ud3oKLB^(YY*QfysU;~VtLwg zGg;ZmkRZ|P^irPA#&h=}T5X3Hb#-BF+X6j&q6KfuCNo|^gBc&%u@LGJF?)C(NhxF? zw<`s&R4j-b%IJqRWE6)|6`IqaX}3ZNky6%PoQmTh!Mf|$rbll7zwcuSm1mXc*9Ci3 zzi7*6NA6m41on_om&uA`wPu>VG6GGy{elw)!y3hVf%eT&62k-4vZ{t^oRZ&}x!0HD z^sS;M)2r()IdtM~is#uS;;E~6NONHO4flcOn2Y1*qfkO)O}W61(7tv`C0wmOh?_1R zM3AI5NZQD#_8E6&vP$+tk}#xkta3KR(kbRn(Q6bu$_`{q<@46DPk9=gk%o#Km}|5R zEs~2O**mKno_;Z3B`g%VVci+Vv~` z$LtQAU0o}-)f1w2&vCfigc=lGfg%tET=*)^?vuwbPZ5n*_E;I^=6i1Ci!Oe;RN|Ht zyiHh>gK}qM4Mg3=Bu*8}rnv%u#pFz!N(!q#6?>%xZ*WJ+x};De>MPtH7dbQyI5nlC zTHwxbOeAD`PLElHorexdQm`1PITM$?By*JePlXPts z>XSPzI2JE0s7IR&UcKuK0}1s2_Rc*NiFiysnP!sXqB4VsQ<-$8HX{F(1uw!&3bST^ zk}*Z;^|)y6`oewpt-}+Rie^AXL(BxxpiFWAnMEA&fSAC87J9*6zg8QOYg51qTk!E@ zgdrObHE7=z4p{PBf)3%NY0k{H3&~@FI?N6VG6Jg8SHf~z8HS|EawDkZzZOX)6IGaa zdF0(sIGE-5l|SL9HB1@Y>!KOPw}LgyurEA}P<(vn-m>m!5N|!sd1g#e?dD%+d%9gL)WtR;3nrLRr#?aix05XrmAc4T-xkgZA02B3Ef1}as%{v?s5L;F}T|6SEq6WsXP0taDy)Chb2aF z57?utAEZi$r4Wkkw)Ktl)6xoJuYa&d4y zD@mPM{%GflQ+ro2(>KvdNe#mN70?v ze6sfd0-3Tj!W(kIT+Gxtz1VW%`O@!8SA z7Oo%+A3!Z+Jz%I;!sc%joUPjkGs?^mEg@N`enhE1--b@0Co&BXIBJ+IS)rbM=kCj1|$;Ul4`LEC+r%l30%*y>G_|T>1M#rodje+Of2K^eDD)FC!xvFL(b2; zJ{>>reV;f03$L(Pqg62P)Lqqa!7!d$8lAb?=^q{^?@ka5XCZXN-Ut{le~R3!7%P%& zMYx=-OToJ9WK`8xM5YZ46_&G96b>d0ENnppuK2UDtY2nwrHpGRYYCmWQU%5usqVpn zOX{l{WBq_WYt{^;Gmopd2rbo%Kt6JD3f}#b_&g{RdDmGFnZI5Z4p^1`GAR;MhXe=c zMv8IMkc}_*eQ23;$>gde^r%Ma67s>o4y=x|6UUMPv@kv;UhqeXipYnU!nvxQ{=n-G zKai$t7k*k*ZJSE&Nx0OFZGf)>K{Xr)Ul0xrAfZ1}M=#^ZP+MoT`!-~{Wd#UU4STT9 zobZDJX}O`28=k%u9yQxu{``wi+B)Y<+^cdQep;X34wxsd>F(PI;)-}~q>-ANiEA2i zg@BG%rtr?2`0!GzZe?8TgK1njwbI|&xWF&2h zsc^Fii9rRy{PMRR{djl)0HWm#T9xCD%2eI zDgohsUjCqbi>e%WWz@XI+^&SzoMn$&$;PJvkgCcEy%?y`_PB)BKk35Pe;bcmYD(Xy z65@tBTlY(K5k>~3*%RDQ7;Mj-RBOtWDM*PKh~=rED1xMT&Bn51_$`(puq_WG-HIfA zGDB&1D{>KO)^Bxj-qYzGiE)Lvajhw&A_F`@cHn+oa#y`#>?hB|5-PvMPpc{VkV+LFg@}R z?vJpMqnr&}O>*zf?P(@3zSTu{+nIyk7Tfb3EU8sLKAA)}w~14ZoxEa!n)HBhF4r(v z@+p~X<};+qKy9mn2*hu|>e+(xlnL!E3{Yh694}}gVA2;~)Qs1BbE{0?=j^rCMSW_o zEb104N{5V!je}oNgQ$vXifqU_@du*TvTL3a%N9GOEjTm_ zn@Hgle#vUnZZ{X9XCV9JFQg)Y@T=9A?|k}!LuX?_m9o;4%5(s1V<{C)VYuIMxL zTvL*QxQA>hep-RovIQaLYIXeP zBc6FA#lkA-R<-)L(#>8;4Comb!_^_J0_&!zN`Y| z#=WqP%~%K601c0lQJ09ptH_XpH(zM|lB@|5xje|gKt40QPCRJ!e>2*Dj=!*9`__Mk)wJ$} zn^kI^EpE27^hNkSu)zd863px71q^cE3pg)rn8|jiS2aRWImaxm;h`RC@7O`-YBBA; zfp@IJca=paYNJsaOIg;S2)2P*rk3A%-M+bo1_L0sRTA8j*IxjaPhSK1KKk{Iu%Gm-nIw z83HR}7ioDjt>R*sc}yxx4~uvTsKbK$Y}>gH%A)%mm^xL@<|b zlLVJA{Lh!~evzRaWatX2!G}92SJ%R1s_HvF^Y}kgFu%r6t1A4P3Wj{nd`wX8z)4yz zntt3;_L9-(+JWRXTsj&jZ{yVV1bC$kRz)2L_SuH@17re`zYu9+Gq%R5_h0|bf04ru zI3}@mpfcHV^6F~f~$wG=#m zQ)@NA{_F8thI4)6?0&_pmz{{GuROj)Y`3e}SY9z7;oATroa&sB`X$g5k4KoYS!>s7 ztM%Fx1a}EO-X#&M?|OI_6fH@q1YdDD4{1GTa#P!fQvSiHCbJ^}+CxF2Cet-0HlJC` zi8DTY#{xV@DGvG1Y>PBd@zK*98EU3}A#y-#@v298Km?sejF6LNcQ-*l>fv|-P@<)Ic zJC?z-s7ZIlx#w})|ML_|tz@?J#P?Kcq}b=fJaNB)X=N2oYN8+su(sa2uC@l}O)!Hz z1)}3i`0S!MZ;)#R`N+dHXgC9z<;hKR%OWnRfn#lwZ&&y69*hax^IoEqo`AeTAGpnC zAO!C&wLa@XdBHaEg#jVM$45Y=wGMbJ_<8zz{7FU;-8t{`hyD-NQg(>Rgq;()*M!Ip zNij(w2XL%j_)SJY@lGDjr7AY23#GGL!(RMRMze(0Bz{1|f^^Fo_(VG`N==>$B#W#f zR#qb*qI0ENfA!;DR)wLeOfRukHpyzQ$?L87UfAWx`|0y*s#K9~VwPClO&3nODH8(r zphaRLNzIBC{NQZ33Mep>hl2b`*9yy^W$I4gndv(6jAvf61dmn97T6H0194f;fx?hU zH`|P*S-F8zSbL|^$wRh4bO!6nI#?s{gLi@{G4@eOCVlXhv}y#8IlCGSPz255KV{%t z3blL0EkG_QxsB&g11I3x@$bpgKFGkgY%0yfPt`WDe@Dggn2yJC!1F2GPLZ!3gXYi{ z|Enl1Jtg9#Ff(R!T}5`Mom?IwmwM)9^lE8eo9u=y=qDNIZlr z0ob`{(zTAUutO<_k_E34c-gL}Z**badDhE&kDxGlU|A~+{e=qi3AjAJi7;fixzRTy zdH;0-V=Sjf;mZ`Wa5v+_Qcmd(O({92Bn{lwg!*Ln11C)RO zd$2+zS~skT3ZiG@@>;uG8;Z+QK%|%B4qlcaHprhIdyIMqPp&>pHO?w!43eiRkfK9W zs)Ky5`c$0J7IpYaRx1v35G%o>gKWey=NLz3Dl$17$NF*2#q_%y=;RZWnI4EJ|s~ zQ8?p3)GF^6foenz!Lo!I%+`|9_^IVys6R7^-Ut!aIjcX@LLtxb>t85O65s6~w*-!D znPC^5sGI z0G!frD?vn;Zq7R4A3*L=nIn-Y7MxpTocn+9>m3*30V}`5PphS{$w$o9cW@HEn~MS5 zc4_9Kz03t6sv8Vb4n8l4Qyai27sXwX{820D)VHWq3--Z|b3M52q_=#FS;o>aACKr( z+DohbB))Z?^xt9Q$auHpONFILG-nE~$nI+|R;KlEopLaGcp2@W$Se@Buw)jYYe07% z4k)PPx7!2&H^oZ#XuV|$GF)bN-SFkt2}{N(s#QZCRhe<`baVot>j*9V9IK~PU!nu0 zC99s0fjbEa=H33zmVO&&%LFEhBF(lm6-1f`pln~WyaI{T;9}FaNcV2!^ISfs&3V~7 zSw>uW*`D&*d`L3S3ow|NRM_yk!Qu!WPAn!5CKsjvJ8r^vW-i6S zeksLQaz6NGJ7kpJt>fZ*J8ml0kw{jEEd^#ksDVu!xM9DA6 zU&Q>l8%uu@#!)U?0iGB$FhmxH&b{bI|GbgX_#=K=HrwXxNYS1;*eg)0T}Ws|jSK^V z^$q+QwUhw3^(paV%)>16=rP=q+6-^V$^udnQ(?ehk)*PPI%a`1NzwRzL}oBj;x0oU?4*d$)uI2J z_x{hFlugMYSeuVbwgs{o$7t&@X@zykkS#^Y)Oc;kE=<9;kSzsf@vM{desG^C-|Pz! zS*f}8asY9_VyT7Cf|dlgN)cE*U`M=@@iLNAnIQ?0V~4?HWAiXc;<(fBKmtnzdl$`a z^_UPlt-AjuQZQ9g2EX}fdr^R&fB*~NCgWI=pK(DVHnM#q_3u4i+!8AicWy+4^Xnle z-InOn#utX$vP2(=FDu%xx-7ek*8D{shHKpIk9_S$PW>pGH@x}jDlqb3ojTvg9sPT8 z&xJe>KA3{EGeU##D;aBK%7&Ib7L>D1pytOnwi{s3!FHhKt%Kqj_k=pkc8onp+k zqN;cH3vjMUqg`B!Z~y)aze{mFjGtDh^f!A^nV5i{l~pxq^cGo{tdbNK27;63ty8Nr z2hsO}b9=}o3(cxWjKWq)w^-P=OiTsuCK~IDpZ@Oe&6l9#$P!(#bFhh;du%6N(A+S* zrT`3VCyn#M6o3H%lkmpjeav(y-uL$}lZPXt8JNF1k5)=|p!;(06D?~;J+IwZk%EeV0;|0$w|#qN^Cg-ZlPkPZ_Im}wP%CBDzrbm zFa5f|u=VS1ym~);ODX<%fi8`eS*SQ!gV_v)nzg6n_e1jg+Ek0y{skX3gJ;90QpVY0 zx(sRw1&g(dmrH+W`ft<&L!iPrL;_2KThUZ*rUTtEaY&t0Dua!(NZ~)!cp{i8)Xus5 z?z#VwYd(m@R1PY!4mQkmFUaq0_{N1$aSry$3&Qnb!3GZ}y`Rf$LPw~^b_y3=&63ZfbM#zT1>>#tS z5C^(n;`_gfi$l0rYd)r_DS>IhvSecZoC+Knz%>mSxHAu~D`?#{FW&HuA^!76@K@#SWh+ z1h`EWI2G^jp>z0a{bqJZ$LXGCIgdYZ@T((u?y^JQHrtHb195pF#9lZ|g&D)q2D*#D zUQCH}BE36HiVS7{tG^ffNeWS4G866`Tehr@=vKp*3>qTviyXfz3Vz3T$}zqmUuH`Q zWwu<+E(mv_$%DkqnF9qvi_KX%HOFbbyg@F@I^~>u%kvPx*HN^ zl=s|ZH*8KcDPpj)zC1Jmg(9O;3_ZjeLrmOJDI+worp@=pfWql2%`kX|Z% zoZq!_(U63iTOiKFS7M)XBI#)F0HA=2YUdySc7)x~Wyhy%o>QVS=QUQ5zAjanje2bg z;v%KsZ56r;l>AESkiiAY4koAxS`dU5Ck|fl|;ZU+*bHUtqpfxOze%3Vi8RFW|QI`u|vid zNi!39ZDDJSl&XoLkNmss4H@ZoQpZ4yA;AUFU4fd5G9G?9LPZ z{H@cmnz90!&C687NDXxCd_9LeP26-*aHnQVREJm^Ok4`HtcgKzjADLtFBL#9KT#M` zS|E!IEb&HBKzI7P&p%`uSA2Sj$2wP6%nbEn92GSzc?2qdrQwW6OON;7q^W*s%ntOgSCC2A=v;8a6r?C$bxS~# zVV#UQBw0U&R*fEfG_OfcBcxJ@%XF-}8sSQ$anQ?wFbqh|WbR$=y6>FX-MDq-*b;TW zD4B_+WVJBpr{pM2Yy)1J!cm%T96yNf?aI_vZM$)&0pmQrGvZfhF+((jTiFP;$ce!c z0+FfLqQywTOhO`A?z+V+X^54->&5?d;ybywOWlVJWF|)fDXjxAD#U>Vy%=g)1EH}F zR&;6&I&>dP$d(HzW^w4S zMMMQ$+dzt}0i%RjR&(e= zf^0P!(4>~CYCvi0a%SFZSBg3in}3woyBNjJ1;)_C9FU%t?03l zx^%Kj>0;JZXF>5BQQV^P8%ANvaJ?62)lS8VuE$MvUFKPpIgR|fMtMGSqZc#te4AuV zCEysGdeks7i=&7-O^x}k>agMAR?Cf64dNjP%?zXcN8 zGzDe3j1mMANFiUiIx_6=8*m824Jj4SK*oq6DuzG?F)bFG_DuQ_YNyXjT?&{FUspGPkaTUn)L$G zf9(b{UB_la!y?Abd8RwYOze2|bz`sQnx9Kznb8UDrUxCp*`LCcCcHAfb{*h~z2XPtZ$rdbo6 z@n?!MMTp_ETnkRW^VrWmLWvw+B9ZaEEs=NNi@QLNX|^<>0p(Dg^9lO~kS%9gW?Lx0 zU>FU#m!s?~>65ifW&d;?$x&GK;pUI_rA$grTHJie-j>P7@WtJD?=%W@vOrFv0mj|P z=;t0UvnhIsr15amcCw6uOz6jQ8O36Dz)@V{?o9h6{0A7r1GvXGMC&P?hHX;(AiX-^~ZZONU6p~yJ z8xY!_8QlcBleC7QE|#^)@}DI1HF`H3+Y_XM;u?Y$?#8~MdD(_X|U@4mo!sEx|egPx<}8wh-xnIn^%q)Q5bq&w&-yq(mk zlNTd1Jn-yKhK69>kkD~^pxzMRlY9+QZYIF#yH9+h40)}TsNie&whC?v0V?7HV#WVK zBw9M7HP~5YMQDuI9w~$jaatX#ZcE|I^`C4}i?Jc{Qhfb0e(_(M*g;+?TmKt%{cJnK za9b3v?GY7?Ho-78YQP`EQ!7w@E$-Q)6k;+bWqqpiUg#LeJ}?YA(5qnQ_;E= zR#>#*3~yv4=|z40_aFIpryaxfv;MJ_0(h&gpA^8d{(4YE3&L9QJ5kJVR+c9fFP?R-$ozGdaG+o< zP&7T^fD}xo@wb%+7hEJbn8!1#tN-%#^hwms6MzFj=9dsYg2JgH{qiT?UXK4k3G?? z0~FT+PY$UEmfHOkNDJGPK|o`$5nKR#`vFgBP=~3pzYy4TCia=(vB^TPc1HKPhG$mJ zZ2rnm^j)-q(knTAZ?jG6mQC4V>3tqwxy-#5-H{~PVGjknVrhx3Npm=C88Su)V?U(0 z!@IWX-hULD;)Oqg?o#&IWual8?0MnEpnj6_=b^P)+#t%F(>^&ITD0C2;v&6|*E+QEY`XWK=y91POn(QCSmZ%Q`4EOX=b>l%gKAa_DowJ8AXI5Ir zm*5}9H@a9(`%LdF!Hgws)SIu(4OMdl2&1{WirPe181ka)>l*;1VbP~zrgq?iJsf`* zW4bi)WI1Sa{Qe5}Tyij>T{^qoEt+nldQ9{1)jHI&ag(tL^&kuV?i9yJSC*Ng(=YtQ zH@=RiEiH_>PUXY0v*kG4tPFiV2iN*ges~Hqba>?gpr)9Wz5@5qI9+#u1yG9ilqq+! zBkswv?_F75FTpMQFw3BAr@6O8BUPYpm>cP=GSlbUYK@n!JiETJbHo4Q;VQq!Pb;MS zvSdf&}vrz>zHoB^w()Fy$lOga;Ok}L}4_v%Kzz>Fv(E;= zXIZ6FeTWjTI&X|9on^aG&}VhJRFm4g!~m&Mo=m6-1v z$U_VSWfa*xh7$=WL0SeoHDRNwi0`l}ApJZC$0sdv!A;yaXW&5!t_&=GF55(VMR4!J z7cU8P zArns?>`J!5p?Ah$gs!Rcb+D4cR)yI{6N-)&0us8!)O)}F6F1KO8Xm0dl(5Y=slM!w z%PY`E9&>LQqT=P^JfMCUlEJ~LNa1t%?7Td12lmS`FYSe1CYojKq;3M^>XT@+l1}IX z$=q4miX4J&OrM+%P2y$)kjsWwEOd+qoyvj>^=bmdvq*$7zH89Vw?6QSk7Es$CzNQ= zE)^JaTo<7FdAP4$U9>SBY{O_{Tz_9{;`dX)d<+1+!ZiX{*Ny;m2rh#T=fX5~wGal| zLsLRnZY&KaTFlNeFkAwXls2;vFA@2?OC&gV-Ez%Wp2n@TUx^^Trh*_JI+H5}$1yS* z1J~$^Jl6+3>O;b}Eft#BXRNVltnzw%d>NwCF($0F?b%w|jks~(MItDfRsOLSH<NmB0Ayp#pWwNKqRgO+N)of}G}_28BDRu>oZZ zjT)Rmn__sCis3DC-&LsAYSJaUG6*#c@ETf@5!#%+=QDp0g0j#|^Ol%@qID?Zg{ArG zRAo8bkGp46?*+xt28&!HZolQgXAs+#mREf@X#`p?agO_P%)5!fY}^^F+a)R;YqQGX zRu#k5_~;^gPa5)&lro$WAuyu5VNq>aFE@0n&t1TBdl(O|tj`0#*f6p&ELMV2@X&6R zSZ>38ui=kl^g^<@SAFj4A2A(NcG~IYA0`80fg=cuq5-k6aSeapjsf`(6%!j7w1miD zOEG1TS8BWC6jz+>A7eQfzFKWDvljNKFboW-+o>UWBXG1cFmtP%>`Buu@2lLLHr!<|Rt1H6tN_F=d3$|K+-i z*e6sru6DCcL1d7%gDn0Tz72rSN!z?EYeAcQ;>6|d= z08dsfc6xf~2qh_S`iY})&m&1rvDqmslG3#3=`v*Qfw?PP7&(hA&%gWVjhrr2Dy`op zb?aP7{KG1%Yw?{$FJu*;a7L~V0yjk00^*ClnFUsy=Uj~im39|8tYqIK@8`=GJ)^gS zfAFoDK}l6(+1A={=+Zjl*Vi+ZP>OMWm!#FPioZvmsnWU(-|2Rk1WcCK(~`$PI-w6m z9>=zyP*f>kQXfZTEjx`TWun+Gg`ThgAm({siy=q1QqyjI)*DHTmR5(`;7z)B%os&! zS$}mFMsD?GJzx@Z>ou|wa;=?>_5>Bj2XO0dx@_U~B$)$BO5$lPH_;_nMWdq{hNEte zb^jGjoxE?7#oaRGCBwNIPq}T!w}y%$<7OW-gD5w4G0mOvy-S!fC>!g)*@kP@QTJ2n2?|2OlW~PP|jI1zC z;*R50un*ZjDMmRfdBlscbZedwbNp@aN-#juM1dyxTdS{fA+Eo6-bcTS^;BK}g=-B> z|CDe+*U)&?`dA_$lQhQAc+Hwv+UZ_-+g<%HCRhc27O!Ez@ z1?YK{1&P74%4h5dh1t@H3x$?~OLeMFj0ldx7ByF#ZGD7(%5Wo+qdZ+=_n-Qm=Z;fi zWx@RYDlu|m9dGe=+0k5eIg=GBo-Bq`nFve6@RSEYQm~TVtNOwd3zU5_VOSb zQi4d!4YjW;)!_oU?TIfsg>blX2Yy;r=z(On7uUy7v<{nhcC%SHhW=DN={QF!`Np@<>erZ87 z2kYw^C}LulZEOlLEWA)dJvA@1v!G47AhHyTWWqp%10&6gf%g$0i$Z5CZ=@F_;{cua zL?z+P;`o@D4>2(suNAyMZLK?Kf77%ep1FvejyN#?OXtPFK-wR;CS3aHpLhQ!1y^#g z(Uv39)|g#K=m}7g*xU6SDJcgq&Tu^KZTH%Ry0A=nQp?5R$XM{u=gD;lX7Xr^Lsnb-7 zn~SFqj)Vt?gi}MEy&K-V&e9lYa#uQj1KEM7>XP%~T%kqH=Ax|F_50m{h7fQnKb} z=$c6ucXaOYBR|zGv=KL6i1-tRA%YtZoUB$kr5(gQ7l>n5n%GInw`Ao6Y4sK)zz+H9 zZ`*$2rx`$&)jMuER##8#+evEc(P!x5**LK{<7*w4lfn~g;vykM5yx~0LziByA{j%# zQPc^eliyggc-RnPyukzpL$T@O->qDV=O}&qCnj6a1^%*8uP%t9$0P9>Kz;nOHrUQg ztVf@xi+&?Mhfq;@waihd%CfK~GYZ<)#xqx4{eABOR`8fAi44<>I_c*y#{^S}ye*I# z!$JwM72dH>!r%V+pFC*fbzFVPOx`Ug>*~qw&Tit^@#37Rr{ULNXHdb`?wBc;!29vZ zg~d8dq6w||O$zMeOci~nLor%PIK4H@=5dAl077Aj=n`^(2H?{^P)Rs9V;ur5&UN>r zZ@6hS9<@?3L~4r-gyGHsb+-nmzs(wKU=~-X$H}J9g~mVlZ-@{U}@lDD2OOAi6U0iSjGf}(uIn&jB>%>vv@Ic%^F7q*AQ*P zx|jA$H(vT^eIJ(cR7z?Zw#-m9*PLU%ytJwoHdVxWm>-P1-8seVjX_9^xjco{LhxxPm*Av~vQUJIc4w#Dd>_ zU8WJ1ZKGM8G$N0xd_DyEIG_+-DKjKS9R)dLUPJJbVp8rl2bb6{5F-mKO#3GgkEt;|UQ?oLwhOe_=;c?79uROb_V z1KvrfIOI5m&T?8pA__rqL8&HuCR@+-Y5MOkJGqJllpQs&#Rgrlt5BwXiW730o_y1VNItLEui?m7Ui<5+H(7b1if|P^o+bC4@%PZz zgFKT^=IuipV0k#}PS%^TeA*sT(3H7t?jWk>zC^_H-oF=e% zoWtggGRv$MuAYaIDpvqz zo^bwXb5#ve1CDGfV>?+{qY}9WpYBRsU=ndCuPv3OfF#Zx6yi3W3+Nsm9-9b0Yd+8X zH<$oGWKCwV(w`s)!$ho1S%2^8J&SpHd8Lt^XPiBRZRl5^9$d zG4NV6`Qm6gl!yG)($cqd?mp`oxJ_!$%|^tH@aYg91QJ ze^NeWh{fKLKf_;Hot@Z!lasH$a@1W5U(D728b7Vp!rGZRb?AaMusCC}X-LMRfU^Pg zKZ-Lc+S)Q!*)W8UE|g59t=o|Z0IK#iON4?+b4;r_{gd2>28IAaOn3JV^s$~peUO;s z%wkBk-xs>;J1^YLH&$vEvo7V%)U-@iY_)6gja{qcCCFAND80}?G!Q_t1}MCGQs0#s z1_}B+8-%1O{E&n+SoXjW=eMEj48^~`)FU7I((8WCrJhi-^R0`I%@i0s|Co_y;rr5L`3I~?wfp^fxE4^t>HJUj+k+{ z4=yR=@nxqborJ1jUzt^g+zO{LBm2Io%F@?GR>$GB?ry+L+rM97^Ym5cLxO;|k&=UTFitJnk0NDi(Zb^-x5U zu(epanAv!R8UVsw@nm5%lUlN&e@2SZQ zXMkVf-uetq`o+#RGq&=G>wiZbDjQR><%VR&JWP1ZhmK7??*CL=6Zq1+5vQQ=Kzg2( zS3#vDhXi&5Ix-t3TxMe_qo2o`9^K|qh1&6r@6=Y} z=}OU`RYuda&xgFnF|`Rb3?p^Nzsx5>@l- zuSBKu+~aWYUi58=EolzbHV)QDF~6(7-j18!=Orqhg}CWL8N^$X#<3y_Ba-qxWN3+; zWF`i@bzjhqQzriR2rj6k(SM5_-o94}?8$vTrYrm`9%7mItHvUO?r?mp^;|LEt;gr{ zs8uMqXeUwB?8QsXVq^!>6i6B*L;D=ffvJk#SOhaadO$~-i8ApYx7@shcC%8lb*zf@ z09;)%z6x_ca^ry7=jJdYM2zEXMD9qPhBEL_Z9i zd0qg!05v=oXTcB9joLicUR8TnJtX zDwS&5GVJH>K(ZyR=RWiB(c3>#>nMc*V<@extsen* z+16GviTo?RxH}315=oy)h^e$J7*GsL3Pug9pgQHL7!YOd*fUA0CcbVh?NH)MJY61o z;TKS12p$lKiCHx{u37Nk0D+0jjNiK~cYSyAMI=zr5G!CFTz zQnTn*M>MtO<0P@mHi) zmqEA)lj9cKVT|ifa$B;+AT1%e1Kf*QmV%*Nm8^m&!ZKg-%BMg5!B@~-m1S$KK9GKY zHbPRMu4MzTb!kdEp$wWHIqw^rg;(0qkTZ4p@5P6qAzIv!#dGFT)J#}zG2e0m$x-kF zZOBiH0t{r98wN(x3F^SCep@G4rr9>OvC#8Dk0)?3vr_nPm(O)yymsk(@StS}pIrF_ z-9v=@UBhU?83yRbc%GnriG$(Qc>xu3xX_Mttd;A{_-r>kPJx4R=R*z?E9C%#Vs<25 zfYqR&*aRkZq0$hkGC@YJn^k3Yr4=DqqcLLW3?E)Pc;@_5@ko`DGxV-JPUXPjkB&5Q zO+J3Ns>sK2$5hzo41n;IG!te$ikq6DjJrP1Jj9M#b?$ zjvosgbEJV&0D>AlhoR=ms~7#_)rW9X&Dqn5UHK9f7N=$*k$g#g6}tq^1KXFKK2XI) z+*B_D0?EZTlxN>Js@%TFn=>&YU>_Qu4f>3S^@(t18px`9sHBJxA~xP3;vZ|L_F+-n zg_O5IPKHj9IAbd4PNMd_T7omWvP~Abas0U+k7s+`x8Cuy-hKVwP>Q?p(_)RUe5p#2 zP@sd=W|J;Jx=ks9fKWWBWE--wf@ZVo3WLn;WL$9;k-|fp+KQMHj845KzTO+Y`uvl3 z;Csv1g)3jC>s3>HF~YcIjrv9$u~2BBC5*21ZWtcMthN5OX01)``vKJ$=Ajocci=mN z+=nbzA0JEdm<(10#oAGB%eM{J>{w-%Hxg?SQ3)8eG``TQzW=(fKg5L|R;%0p-r znGRmmu3x^T!{*ogyirZLe%*<`qeZmXyJ< z_|!;~$I;bC`w>B&g481@)3N?`j#rr6?<^I~J8_pKOr$6X(UeEFTV-$hw$>QHKpNx0 z7>{XZ+4zYP{wd$$KrGhhA517Nq4Lm(7}XiNDi_S$Gn&u-5(RT+iLP9%f}yT-s_$%a zzq3^!k_ym-p~CJAp;*9U=oFM|cRr6+qi}^U+$)T=>ue@M8s7bjc;+Za5CNjVd~#*?A))19|vVA7Zsk4YTE0 zF5gc0v|mGIwhnjec8H!lt~{Psw%~n39t1WK1n56P3z82(>?rYaU|Zu{q?+HCdFT7y zJn?OOaaojerDdu+%vJ8!uj?hz(BpIACMCI~y=7yUE23TN>+MIcw*Du&4O?R4(F|>4n?LO$>@0>`1om#S`Y}j^(3&!?) zwF-=F!d||kajch4Jf(NbPR zRm8uATu?|iODhtDan&#MCm^yk4GuyBh)3>@7ie&J`Xj&l<;7S_S%u=2J5_`oR=EAU zRfHte=8>FX%D`Q>YM$(`ShcUH0c*aDSvLAQsmp>qVBIwdnfK8YZFIJA5spNIk`^ZA zIk`;b2tB-%T?~M{VKowXZ!W&m{`cXRyoKT`>1n+3HWeR3uTIq6PwxL|6&$DLxpCrS zLDkss8dVSK$ng4U>I4s91Nxb~ZjW+h6Yyl#2rmN*R|S=qf~`5n661!Jl@T*V!ds%& zxH`Qo(q=M{oB*<2`dtoDMf$149x{XvStMcUq~V`FvexN z4ax?oEV8V1L^&=n&E?yF5fxPqh zu+r>0x-^lcbU~2UMAs%R)%xsGJEE}U0-LZ_r1m^TB$h`Zs!4@~>T-G{#o`I3Ff&NA zunW!Y1FNWwoN*_lyH1#8A+&t;)1G$hvq+9t_AOC@-KqpES9|QUe9OmomTHihCF&5LYfQbD-$fH@ z{6Z^!BY+l+pWPZ_F*cL7)I~A(O|PDH8%6QF5_R~qssmY)6{v?mnHn0iv`pD|1MAl> zwrjKuEMabEJDj6Jxth0*@_KsN%$|vD*ESLY(474VNS}%rL{O;>+`z1$4&o4V#}PG% z`;gB>4;zdJehWEKpFoce_l|+lDDIvcPkYM=DJn;!* zt5ntca9hv0dUQQdh2xNdI+#m_3^cb8YiNlZUa_XIODyPttyPbt1!`({MM~s)%*5RP zf|p;)vhB*f_-R?_*2g79S+3<`I-1Kj6@4vwCs-|}v$@*YQB7Uu8hm!1ATFWb0Ivd~ z>yQXb1Z5;6>rvrw6}F2MC5;0WRjO8)>GG8>{`mJ#WQA?zh&?UH)dK(nK!#m8|?iPvw&soAX^Vtp>zy%AMi~T3BzNddSDz> zCWVMz)__Z-Ev4N@!$K*DjH(P)`+;gu8Z+P9(s`wIBEBi`w;=E}U8eN3v6q}PfkA+J zg>{&b6ZeijSDxwX=1xAJa$>%tb(^4hYvB4X0sW8BhwUJeY1340B$pP{V|6B`l`#9r={-JZ3KG=qUM5zrY?OF1bP+{V`E7{nv{GS zZX=A@G%y63Kf;ZK?Bq?Uo`;nDDtMGGWMstxv=j!Qyw8fosozjup)zP5<+fi?*c_QM5$Rv8j=h=2dq=zQv^bex9}k z#C}wpu3F8~XPxva-6*NT6N?Ys&H@Gnm+BkHpZea&UZtD68+LyD+5dnCFUzrPwTU2v z!+UM+!{jupn_h-*StiXkF#W!bqB(^y8FKB&5ocr3G3iz}c1-2ZZ! zCF#knrzEA29&@nNXq8L76ZG;!u*IW5!)tk=4KF{FkWlf1auOfPmzr$?!xcL+lzaYR17i?(sK&dGq`R4%h)Z8kNWNIn<$vO@Y8C2 zp09#orAN;Q?%aj&d$^8}ZMboXL!c@y4&h>rF&WyvhIz3a0WH&Ab1pvbIaPl;5tEmT zSt*B!l%Znp1}X0qb;+Y!%?izg;%VFNi*L21-G{SWBkN4pl63_FDZaUX4h|xC>XO<6nI6y~`-KU*f0L zn9NhTF%VZMQ^lTZL}G)1xYBqvOl)kl(_rr+Bd%Y{SA@6{oa;13yWRS=1HQ zl+`U}e~_D&Q8?~PiUGo%Pri23MOm z=lz-yED5)rfU1*Aa_*dF@lZGi$D7sAr+>OYuKMu$_le0U>6+PUQ&?y+Fei8o0`Bpa z8Yrf8;K4wHBBz5Y_VyZRo^YjV$2f(e?!+L4s0i6qtqH@^2VX78W9B;b49CnGnqG9oMXl@wCyax_2%{|EwP(&}U z)nJ@(t)2bx5tYE_cxzuReVy!GW$rVhko^;f7eoV$19a>rP4iiBA%O49bs|#O^HI&BER?5tRDqRLZf4%fno6E6M~w^D^sZL1c(Guh_(&C&i1 z^(sc3$Mh}QW=wa%uW_#Pa2vz7CJ($qg*O+UwEDO{@+m4sQ=w#cQmvH3T$B?FpcNED z2ky(*^}?UMnfs`6f5|eg(PbQfOOL$;@4&ls4b;7P!r6QKmp$3&7-o*r-loE(3`T^` zWJMtwc3NaZh`!w3tzM8f48O(T#)~n0-IXVAUwa*%q;hbH5&4|1`#@ZNtfOit4|u4S+r$Ndj`Ff@L8XFME$E+k zw0@UlmT$y@TCIT{j7B)x(}YhRE)M)8937J1w>$B3@*t~3KAqxI$i)h2bsk!>g~~}c z5UOKJVc^%ITmI%}eCVy)ACJ3KO6JsT{TF@nBxPndMtN#EdFYYeprWOxNw3s!YA&v{ z;Rz0!tvljFxNTQd<7xiH6BII#Km#nX+Hjx}Pa!^I9Y_w4oWU~~7L1oyU?2kV*XA2T zSkzW7By-qW?uPg8Qd)Vy(Ul`9rIITAt-Dl8q%M$1>}->Y%j$ByIZnFbnNwa;1Js58 z%sf>lw#=mHa^?NQGg#8!4WiDX@p}L=DKRD~E>jsH1@IRF@LVL*y62yCH%0PyB?iVe&b z{Giz1%r|uh8K659Nu!K6=0!ga;G=_%iwT=A^aAIv~#PzBXqg)}oKQ&bgJfeUj!RCaeh*rWpBpijb3+Ex2 zQ}#W`mu!`-im5Sq$E}sW*z*tj_78;zE}1U0^~d^RJ64c((C2i;pTde~%YXyH5?s_C zB_lyy`>Wy>fyFFVt%Zu)4syz{8>s{|<5&-+H8)70h66iN3Q+k%=iA_pH7d!Bga(wr zEru<29Cgw)|BS~k8+Neurz$U&gr9?9k=5B~Zz@!rtgWM*vo_QmYPQv$a?lr5UT?t- zEl=bmPfLElW6Q`2iH-Cg4u~xaQWc4dfd;`rF0>)MTIir}==*2M zi0+pl5fqN;h9@HoONIos_ckJPElj3B5?o<9LFRs~u0)VHX>s^mC4)txKy<;QrTt~@ z88t|*1amJ~{$mc^DP_xTU|SccAvEpo?Vrl_rmU6zf5D{>BG!H{l6k9vPZgr>8}90X}h6-RY@SEw_Rnf_Mw3>kXZ&;#9=5D$a_fD`y6QoYI0Z7S z>rwcS9sto8D{j3I%90{Q$V* zd*;YdWLv)Q$6_Qsl#yBMMAt|7-p>A=6m zOV$s(p8_ix9I^Ew-MG}g4kwhKxI(q>X54xSZ5tpj>`msy zgT%0ZnULh4@CPCrIz#~&xeB_q5a&yKfZlvkf7#!#N+D+x@o=Vjh->}LFj8~1yY2Re z|MWUav5fzDSfxmhicW~pdUY9!=wjv($)C|C&P;67a5f*#L2D-haq)cwAI9+N?9pw` z03Co$!j(-4Nsu3=b?ViL+(Fj6eqfQ*Tl!U&AW<^(l8N8Tq#Q;pQr$U9QNlxkC*EvK z{5yW1qt9okUU~7Jn{(TNDkaAA=b$nLRV#a*(78@7w0%P7IBEtjgkb+uU>xHjxjGVF& zb({4KZK>J!RDQ3=O)`fn0h$xy`po7H7>`&}fSMaXe2--;Ojc0{{uhouX(kisC2cnlzS!FV#!!Kn{}weI*u1 zV}Md1O@RsRqU8swQ+Ua&zlc->B2!p4Y_81oW1}HQpZEZGuljop=bSqbcNYyA`99O) za7o-y{}A|L@3zF3zWc>}sz-3mI_+7XpSg~r+^0m8GgOo$t-Jd+)<^nS4$P)3O9MK|bkzRjAkC!wV5)V|2HrF)A@Lm${8gR=t>5u%SLU@-7qp50w8mQLTwqf z)z1s^z*)D=I{7y;#I0oJ=C-9OIc91)b58K&!Ir7HfwzQ{3c2u^ zn6IWY&S9iRNMeqX-YAAp2piQD1^GwuGt^Ien+!y`XrQYeOX~K=M0%-nm9O%C1&`A- z3=?bSo38SPcaOdlt0>EXY_qZxA_d8q&Kwx+Z$|B&CcOKH!Cmv$ZK&J9D|NfE@u^Fh zI=XdfBw$EKfMsqPkOxdAmW@3n*lG~Vf?)Ns@l1whMbYREIT|9l(9AR;{t^qvKTseX z0lAAWLC{O4JfRnZV6O#Njm_vpK0TToZ?_fA2&=9!pwp>_fKiQ zSTmT0XfG{GbLxnb$u(yY*W$6I67 zvzR5d0$Gtwx0gWct5y#slnWS}Jn9a9%dk^a?}RxQ`3Gbb!>v2q8tJH^!VtR3tgL?X zzAsaH^GjUb+f{nRPo1okJ>)#q8N#QOs;1vJZc@p62TGwFzBlc!xMxxwU)4x&Nu?QX z8cZF>5{I`qI;qnqj>pCoyT-1Uj6c=tGgV%vH#`p`Hcw!lOY;6ZE_&Wi{{JMoHR&Nj zDE1-Jpl2f?2%n(jY(!kESK6@Whgiezt@v=zsE#7zz+_}+T|G^dVyOM^5Y<_)k6PwX zssIwS+DI@2X(1L+-;wTB(KFqy;TRF$>_8FNAvW!lGMop)ZrKG{5>wWxZiXAlTKVn3yTbI>A`7J{z8y_`oo?w*;G;{ik#!l`-5x0|f>n{LBh)}ux>(`& zv-yu+w&HN!Q)VVDP(P@jhsO|nl2=6M-yXPCoT-DfR+YPb<44}Jh~g?am~h+sR9qd) zo*uGYh4le^UpJBwOip?Ie{tfP7U7B42*9LKrR#+N4$|B3tq`{a422TdEQz6x1;R-Y z1IG?+kuBj%7;sP>FUVJrFk_4N&d zwRQFJwkDw;@_v=h4t#J4x17H#DMJ(Uo>k$5X;T=F9UL!QAV>r=ahHsYQ3v4s3#*|D zvyRooNgXBQs`#q-fFY36PJGtBbMUmK%99Ofn_UNA)vPY8L)-&Vg2EOY_7rf0bw9$4 zp?X_I2Zww{#l-%!L6iPDJg^Y-0(Zs;P(B~b8Njb?s3^%|@I{tK{ z1zbb$uZc{e94$~c;cPnOp*J%%Q_5FaDJ%^U2xYwMJ_q%+|=}{s>f&X;Vv0sDUbNd z4H{U4>Cjj09FfMnbTh~!=xHl3q5zun}x168UWnfi<}w?w{7xQNEdt`@izK?|vQMSK&!EtxLRFm&iO+r`l0` zsc%ySVb!r#UTEbwgA?%<$e3skBHw0$T`3FXl^gj*E>tNKa#NyC*d1^$f=R?=!f$4L zNdlb`EIRcoiXmvgHe|q6R2EuhLHZ;!^>m$?_K}lc$$+cuWQlE7YTGrb?G|(4>E^`Cx^b*c< zmrH-i#Q5SbN*c6;1bpO#B%KyuQYhlP5!ijyvcY5obwx z?KZ1TCJgLA>8Q){^D4_7xT_c*YmURaR*aju9XMuS8gy$jKPUe$T02}OvVF|pi;FA3 zJqju&wguYOOim(R=>J35ZpKgpVP@w z6bds4KBi!t7ur#`@2H3vOUPc4s9QOWC@4r?2_h1==LtxQcCo1BEybIq!0hJtbzU`YyK%Qb*HiS9yxqv*yGRh0>261V2*PUz*i*tkwrZ6_6phIOkE_zkq$o)pHczR+ z&h-(m&E>T7yeEE8Sj`9U+^x3jCn_hx=5CY+`b@=KOao|Xz+@hbN*nsi6{^0~9#S!F z#67!MMo7zL+9CTUc9Q~=77Prx7Js1j7|tK1Ij~zv#f+hgvNdoTiNA}5Uo`$RaxtYl z$f`5BgC6U6L|gZvHdJ*7ZVBrV*hLUqj$d6E?D=ypNA(B=D4^@nENWt7_#`r54h3_Q zEV>eR53rOIy7p({CyZx|jVBDFnRsF-7toPkdFCr9fJ#Z#;r3~&8Kf#6%k)(jjvazS zW4?|1~rkaosO zN%)$xG91E6Qy3>`(MTJh()@SwM`A==HCF!aleY@#H*HVAv;81d4c4?jma0n^!0**w zydAf5(%ktuSziV^#2cqI_|iSam{}U?P9%ro6S}=}?pk7sy!(qtW$!m&0U{R`c z2X$)o61tOUX2iXTfi4I}H(+7p$c*d1@fn$t@IyRstMz$?3TJ;@0v9@5nAkdmdfD12 zjurqd_!sLIO);LlP6e|PH}lPJ7zRclGn4v;E$`%5&`K6k5QP;IziR|<=pU$FcwjTE zm)^MMh-2_=mB*J@jc4l8I+1>BS>PME!00zH;AP9n-v(ZB!mE)Zhy(|amM+dAh*$pN z{Sv^4HGtc8Q*E6y`ik8I+`s0m!~#4WL+}FGN`g){ zq$PD+aVr0M$b~Z6uB6#u``;#WWYGYozFnMhv}EQi7?2ZN{^9^pU-oZw*=#nDRAi>u zKR&Q zro3Ch#IDDtgcm?S5pxueeE!WN&&TtZjmq0@<0Yvrdttb2ixgjpZ&|^DX0~21Uz9*d zD$dj>D@u-fqTdcUCNuUPsP4Evt5lE4aSQpZr@0H6hy|^Y( zV#yTW?dPYxB2AZbMlh)tN4e*0KMU(>tL;J?K<2O^wJmG}Selwl5ybcdJNhU@&tXF} z+GD*KYew|=a#aq^`3r8g2Bh#nt_}cw|FPpFAU-dE95j=O~@)0 z3&pmqpF^~U_dKA0ZhIYo=6DUqQIGtU_irUmtnTD2_?EhK`Crc5>a zz`UX-Iheig*a>77c zk7^Vi!8ui^$>x}bw{9uKW;tFA;%uW7 zyG2&CY$7W`bJ4!-<>Sg6u%McD0FYg#djRU?%M=ZuHq8@xI&NeLo2i??LL+e)MG6-s zFmbtrOl-vTX^l#bjGR5r&D88n%tL_QENE!%~A(m_o~sXRpHH zgYVCK&Kf=aKPb8G61^K%$sLBvojP~Ng=hKyn{aEEAWAH#MmQdpEk-=-J=d`W+@kzn z*9lS`ggc!2NCXILHshO7INeGzrDe_^3*XmuIC{2wCF2oyNv|?x>I@Z;Z*6QAXd9l9g#U{?I9eW zK-`gwZSJP$4$Z>Dmo-6eA4$5m9D}LBu~g3nvo zq}}R+t5K9($N1~^bk9;^jPelQD!Zs+@z!;gW9&L1n(XZ4WeCE&uCIUtLQbgVQ8HxRqlNY zAJq#%cy$pYajX&WmFafzE@>Lnh7({5uNr|XZ3^nZyCUk!RNeI zL)n5{Yaq+*yN&5B=N*{Tl$~#0JISqGR^7ebI%)O_$9DLS zRDA!6?_R(e=t>2sA`qkGi=%0b(Q}ZTmFI^+&fJSG5CF=JD;EEbW=qvU(hi|$L?pnTc6EifGl2Z(~+pKk(A9QHpOrt#q3o&Y3 z-@rVfTHgTpsrs6>S_O`<{v`HWcy5RQQ2=Bn8(W$bDIi!Q8Idvi=BCWDr#y-KdyR7i z{;4q7!__+3T;3npa@at?btQcgB4^#Vpsj?)Oy7kl&fc*hqsk@QyPin9b#e(N_@eIV z{c(BmIA}+=SOkzb!=kYo01}6Xw-dY^@g&v8PvfIV0GgnL>!pR(eQaa`m63_sJhahD z4aO_^Z%xoEa0kVRZUY5uCW<#>fDzN6zaUaBGU~$HRJ;z!|D5%2bgw3>%e(&j3~E4W zhUE^Gl@NU>`9SN!o(bQ9)23w81cGQL+Vm`2O6b4?e~t|xr=%`BNNn-8+x#)>n* zLz5=z*YZJz$KtmGqxE`ktsi_Oc4xh>wh`4l{bOxyO{=Hfg}cDA$cR)Ajt!;4nq>;2 zxJx~rFN&oVfbLY%5oN|Q>upX$|A#<6V-f_usUpJ{F{e(E5}L4K9=l}>Ph?Dj{SQJ2 zF$Y>&BwDUlT#~0>Gv|?~Vl|~Dk$35KWen7rqa94+p0dAc-0N}UrBb!#rdWI5v$rnR z3cgd-M-~qW%bGGrj6GBu0~W$YI*9=pFex%q@wpr(?t9Ud$50Ne)Njq|*tBUfEVDY5 z7=Fr0DuaK-O@XawCUjXkT_L42<<&(StFrJqYp$5caPtiDBlLU3az;Brs5T9urjBS)`&t`}NTNU?X*HL)9%yNUF^5DzW=&D10^Fk>vENP_Q z{-{c*L(J1t?8Fa-$UQRZ5f2{i-|pX)f`hDx@?mqc$A|ev>W|aaq|1JZY>$lC3|bA2 z5gNk@=9)`)3NW|W@;eDRTof~Y^tQJ%wNN=}Pi1-6z6l8Q@F*e35w(^XZ$Kb`;|k?U zZH!mi00K|BP8H^Ad>DHQzRH4KEEQCW6@=!Gt;DdT>s(?65mX^)PkHo(2Q&~DJ32im zP)&61Cc$mZ=)mAuT`Ha=|JDeXY+udj{>k|ZAf+)%#m?0P#{zTtTeqYf_X0_zgtc)=sRWH7G=XdbDWv95k>ogS-Jyl0$f|;Xw>N{1T zF2{YvX)6@bku_#63qS}qRw^(PYF4x)0gey6##xPW?6jF425@8{P=S$%P@)~^o_=3$ zkxUvp{=eSdJV36pN*^v2A)+X&fNaGkI0%D^ijIuwbSESsdqO}(JC*KAy3sV`$x0% z?ON`+XL-(ZmiO%ak3WJcQ*tEJCOcsJskppwa4-r1Rs8=-bghr{40MkihsQNM@_*ms z+#rRU@p|T7`t8FbI<=w$Vvqp$Q%RhXn+UthYz>wn^9XX+%5!?Rwk$#wGfQ|}UMV8t zQAJq(=y5DDgZfCK7GcW+y{q^YLp%-4QSGq^!N;9`?$H$U3 zc4jHh6+Hb8vcu;lRn5uEcA#$yJC}v+vyyWh?Zq4UYA$rMhwwI z*4Tn(mY1bL3Dd^3Zv@O{k%4muVN?7Nl*l=*wsAVok2vb`7g}k;}_mR+0!35FjKg zVR5O!I*ccd_d_lukW)587^iYCAQLwOv)2{p-25_*npX}k(X@HVUZrnw#vu9@>%(Jx z{jtHA_A0H5#KLy12?-wfGnL>*yj($m2SzF!qM)w!78{BGa}}t20Ps4V*XuHB0J>@f zB{~S?WFf7P3o9KJsyy8hER_&cWqbXS-%>DpmI%grT&KX19b}c^i}1;dqs2tb3~En= zoFyGOOg5$hOJ=wWRhV$|F1kuZX+Ae6kmT#Yp0CB9GMR?rC>1B!EuH|8r#qtuuXuTf zl(zOMkwmwu2+RSGhqW>(qFddiWWnJ3-_K9(8B zVqM%D6&iEcib3IKbW|yeXrOK(T|_&$X5^{TC@Cl+bdP%D0(orfCm#JSzGGP*=cX0O z=d^Vx(LwW7I3K|0E{&R!D6I{Fz+ps2E5FaRCTs^Z85s?h>HC{`c}Fglv|ZQ zus6{lAFDuE^n=IIG|2fVcjzvsX^XCU>Q^WyHdZtuN9#l+yWIi(Kro8=?Ks#}E#M%l1<)A4sx8GUYoH@U?Moc0p(dnW&M%Rg85A3#Iw7r@#)aG_Ru}hKlVt=c+wkiQA|!ZD|yp zwIY%{>UhG(7+BikvfIWth40iS>$x{&kOdaaqa|AoW<)%7d)zQ@=jr!QYGrBgM3P#YvAIi)y$Xx1RYz1o^L5Gg)hJQz z;o1Z9zXdmx%$IP=ZCH#7ngc*E14kQx6o>?x-E;mBBtT>mG_lVS0cqcRynpu1AViQ2 z29(ym_H)1Fx}H+u*^YWLDi9tQ&asqI9~=rgfj|>2n;2F_TPyaVHaGR|qWheP&c*;0 z)VcT05)0dKl>`{VaDXI|4L2o_z|SiJC*`T7h07!oBF+q*JHIDj0ZhCXtYckJ@M12! zz2`i3v=mNem$J%I(%)sd6?C|gg>fK{{p#@82_?Zu81-is}e>Dk( zI&l2bHHP0|BoQ756F`fBnW0WqW2;m(_zV1i6ZVp)3kqOc>qyD7S&10&QA0tT(-Y+4i8-*Le^yZ zqJaQtgxwz6)~DygkTNwJb-7%+>bC#j#*VVSgH3PCA_4g=98ZaT;LB>GX^Y>{c==Bkq!=vGVrF!>ruYoaikH^ zfnVw{@}h`FAF1!V81Mc4mitek7@u7tMmxKNS@sl(@iM&iVplKm9~v7>C%p!0Z5-}$ z67vip1dHy>i@ivJ{}LY%j8Nf8lK3r9|K3^3FyvBM``))c|7pY;C5?QW-Z|yU^)-C* zLY(7=BijKZJ*m+Q#u_Bn!Y_cnY=~Yi0(f{kFAKN~ybv5vKlB4>g=Ysw5ay|8R@Z`R z2`_K?1WAeNNJ$f!@>~}J8!*17KH~kNzxT&%Zm`!%B3#+f4>c@cH z8hOGaan-yWKwK+Sq2;6`rUU%O871PFn0_)on5U7c(n#dB8z!Jw77T-2Ra#cC3N+M7 zRhLOJLj%nsHZyd84>(g9hW9!y#I8{aReQ+cf(hfP&1!XVy{=IW=^prX|rdh zXey4$V+eCHnVghZP;g+Ds)OC|KbERc2-F2N)x}of;w}0=oj8dfLd&34F&& z$+5bdHmd^t9mI46zQMAjDFQd;HuN|}&v2yWeZDp7$%GbHm?mfGxQY%szlgiWC zfJ7!0pgi`(?{>a5e?9e~E9l;T#I2 zJ*WFL=n&&oHex1eTaiw6#7q#4NF&?n3pt1v@*yWqFFXAZ4cP&s455mOdaUw)OC=X4 z#F$L>zVW0_?njxNSRxZU)JJ7<9t66yUR#gtr?G%d%6@QP-977ITEnaRn%m6bZiYQ) zW>*ZY{=77e&{Q{sp@EsGC}I&Ekkt25nIc9O@j72f?T(w|E4uuZPHgwVKqxxV`4}HTx2f@)Lfy26NT^$#0nRs6Jea{%A;74Hha<#{V7%d z5LaSH{@#z}BHaGAIvWgqe#!Zx>g(|YL$|5!_SIB1n0_jt5hDtUK-jGn`&(-X9L&q1d zd_Cp(WBfE$hCZL<*p4H<8$8*oM2?^sG|_hk+6AD>h=E!yXCxmUIc}DVSbYtS5S(tR zx^G;#<;BbBl}gT**kmJYd*Sj-ya@0Ki|~ef-OR`nw|ZuRs|X!Z(7PJUts6WzbbXA= zBQk4dmVAZvsma(?C>ozLoHE(5;T~qx$n;i&H$&ntTvvjU;kU9D4sly*>86oxO~-G( z>b|x3&Sl30Z~CHY!Bog;3?JF)y}=oABrqk=qCQovAG7|Xye2qt%}U$_GZTenu?)>& z7vO3J0ORR064Y<{!t3TgF7>O!OG4JodefZsY0Dh3YsUNWhMEYPertIO&H?Sto*AGx zqD?08c-_!((_$@QdP@Jr1W>Co8GsMzTsXT2LPeC=3k-1evN zX3<~cQzZZ_C{9Rn9avQhOhF0CQo_`rp;x(cEdD|ht;{9BXc&llkimlAQ4XB&s1Ty~ zAmR~ZdZm(ScghMVBt%7kgLMVNwZ875b)%!TrZ#%J z@?3%!BRZ$0ML;9i8KdP~b-D}L-|Z|i?~Z8%I4dI=S@gAjF&Qy*X@OA;Z!K>cfEoXX z`V~h!vf%3?xbTPLgTwezr6Ra9xfyOu#j4Hq2w)z9*t4=4zwTZuzit8M5nV0^bSy+o z+oKha4m@=5syfBug>XJ#Sy&{EOhWrJRU}k|KA{vYxW(T{oR>y9M>uxejake=Uq0t7 zww{*K^50bvu-H8tPl-gx(D@A3!->8UcH!=jAE9QVWBKcgu`XM zKe%|F=QE3~Tz zDqXjk%_<_<2gaKCa4))@gw#`?;iKN>45fL?nkK+Z#8EU({~B~r2MPeUDBCcKhY%cT z;qBBZdm0sb>%!XkwgtP9O)6XBx9LBU3eBzc57l?wMQ|)$Iov-mGFV%K;Q=7%(G%BW zkf7GoPAeDFPQ1w?_y*fl>B=DBJ0Xp%Lx~+cGua9t-EF>F3Gf821g1uJfdgyNRE7pu?ahrX2-#nvu9qKamaP?qupeUY;~%S;6a-Qa#!urd-%}z|AvmSY!%(6`~E)C zyAB_pCEeLDTq?<^*YV_=Njkv|@tpVOnuoHwJgqXF0;N4pntw%-0JE%HhT)>~)mK1? zw&g@$lb)fJfuNC^Y?&9kaKFhn2wp5%;k(Jkb%__})?hEyrGpb`PK+L`cLb9s{XN}1 zsC;9h?*DdlaYLd+^PHgpOe$3_3w611r@RJ{+2lQZbpZ={YOcmB-W~VLgfjPpaC;7~ z>CANLZH9qz4@i}D1)F~Af1cMx4_~rlbJGK=U{fNSFW@t?5jQ!SLF_~yx-xRDB*5F3;5hjQt);Y=9!W`mR*8!ZcN*fFINrzs_aR@khf#5ps= z5E>z21Cbn|R7;6wM7RItW2b$axB6hot^P9eMD z3e@oG&cslK`FqrnS|*=A!nwvH?ej_%7mC5gOd{H8j5J=6sE9E!gz@n>&}=1N}$0Fg0+lC5~C%;`(ue9?a;o|HUi;2J6(jcevS{d313 zA;`XDr_rWI^sZT1oC`2GQSGc@1a`FM=?xjSHN1eBC>L7LfREv|OQZ?2h$waQxRN5o z4NO_Q16Y99d?#6S$$e2JL?BFOqyZhrn9F{T1+wb{G6WW*B)xE{1|)QoQ#U!J^YqYd zX8OK=uF`*%_IUkn3T1U0K2zMDtvQB@$HxCWw)+>hYQ3X=4+$w4hUBYhL> z?kG?Ph0qci6Ot)oF1!*2Clr)sLSaSr+QoSPr$70hcT=vo=?YbD+8m3h#tE!oW3n9h?a_T6r!9|B<^B|FzyuqKUJcaOkELNY4#&F9~2s;#lp`((#$bJiCO@ zX`I@rO`c34+3*FuEYzh=-S73YAHY|yJc6G_u<%!v6C24@P9r!a)MMts_^k?xzimNM z>+r%3YjO7EB)M8mZB$0kHaeoEemFzMX%?2?Q8k%T4W|JlQxFNC3X@zjR($W_1Gopj ztVMj%4q_IdunrB@RXvI!P`~&hUg*|y7+S&nH{&zs=mslmdJhs;ZdA4zG=wc3ZuM}O zWB#ZrsQXW2)T!pLU@5gVvnrl;4QndNNZ^$zT=(apIR_yI6H9M$GN{$}!H4!`C7@E$ zw=`)-Ig>I4(g2TCt!v&WHXa*OH+$7*=DO zPHiQGPDl>h(KnK<*6zuIn6>(a+nwezu5xD|vwc9?bV{Z*CZDNBMwL4QrQhKiN^Ya5 zs=A#~9Sq9REnm)4rOOdQ1zqzq!navHD24H?R>lmoh5hg$aWcclyE#ORapY!1 zMpdGhbz^1m2D}*FTB}j1d?+p%`XnMz+(zgwrbrr0XDJmJ0HyHo9<#hfPygO47UPST zErp!iUj@eM_!;%VF+i!ML)f9|dc?Bdfc(C@*+YAspy7h3nZh0mywt2T58~KKiak*h zvU3=(Mj>D_X<-K5z46C!eGW$x(?P!|;t@N9e3<{(FSXVo$&rib&Z~aegYR4UD}EXR z+T;N#pqJGz5^(svIfY>mnOBD4-Rq+xew0ntryVXkY4DDLaX_ppXPa*{6$r zGRxJI0_1=BWL$)O=lpTvR9ari2_uuX(}~sNHm-Pd+uMe>)qeEs;pbZ75k}-WhwQNm zKyCsdIP*;&l_O3wD+TsdQrdwX7`a5uT9N_3#IT)zZXu1|e#t#wmMN_lK}wAwsY7*) zB`FAKVz{~t+lphYBZD@l>sh>MaSrt}cV#H7wGDO$s$+r6rLvx zAT8huRnDA;M2Uc$lzcqUxBgw`QMF@PTJa1a?tRF_;g?Z#C7b*v7pds>;eGb^^r1~- zta?^`CHpj7#aJ=Y?7ueFyzUHNNFQ2k;kK&q9I<15ra&; zTkk5(Dk??sEM}cRifXFAk(St_h)09tOF(yE;l3gHS}0wpCHUm9(1HFLD{(8OQe3Q3 z+z*%MPhfp72lsd3bw!T2)IE;Q;ZfAy>MhOLv)-Qi`jyiSWzrN%Z%y$6QZug;NW#x< zJ7P&_tE*|DY05;*$_>;GT99bo6akf|WBCr&Dup|#!QinlAP7`-=tJ69mI4ZdcPY;P z#fHDorYa=^(UVK2To*YI9Z9Z#Q>#W=#sOhPM~@GG$*mR(0PvEK<9t8U&cmfAzrwql zSaKFmyJ*!CsLChlqMVGw()Qz2)}SkizODE>m*??MdGc}WRjeFV5^9&KJc&irw(HoK z#*Hj)*=+Yz%dU6hY^LVcO*#J<-yLWuoTdZo zblFg(m1fa$BWDvOZvw0G&xpN8w3QRkqecUr< z5SNN6^q;6f_$^=h`n?u^9G_qL27VfE`PHfqPsOE$S<`P7|NsAIL9#2tJiNY3oPljj z$Wf-=l0LHtq3F$%xo`0@QdZG^AmT8;lfLb*K5H)Cxl(fYu_6GA#& z+Uxz~1+Tbj6*Qn9&NT0{h-m^KBD6AwpgwlmofqT#mW}sMj;o+VuSSFhz@d~AX_X%WDYN4BuVwx|cp+OOmPeUff@Vr3g@zVPEfZSZMJA_Z>pf)45HG=`-Slhf! zW4S&;r;!NK_7>_%m2@$!_{Rr+d=-?5Vr~fSLSzJ4n@mMlJ_{S zq<{Vy!1Zb12gId;?VX4GcAo6Pxf?gsD7W=0H;$+*o>;kVv{3Uv77QwOkayftkLq&1 zn*y+C3RH+~@l}Jd#Ai$K>8y=gk(x+D5f1VJobx+c^w}rPBDY+2tn8#M8*J|#y#pWC zsl#NRSLUgq=a?)$s1wzk$E}1c@^S-Y^v#CR63oyOkJ(e?k3Rr^0x1opo4c-j=&Mho z6rNRL582|oHXQ=vX7Mh3A|7tRwGuWc-JHHHQXPYm>Qmr9%_XR#2;{%SQ+=}q0=A&r z+#iu-%^j>uHYr7A`iJ-IfFvrrm59UkvC)g7(*SKaz16PTdFd=rMrXuqUg+-Sg%(21 zMR=`sX?Q*9^^T2x~K5&kp$ag7mGoDm^_{3-s)>z5k#$^GTF*l#~*5Q zUQ}Ni<@t;*RCEdKs<@j&(_k9AlP`0Uj(stGns<_;i_Vf+)_Xb7C80^|Jrk7gK zpUd&;1%Tz&SgGO@h?0~%8IRm7c>>s=h5*`&&r54lN={@5ZUkYYco%mLKa9_vBPf@-Tbg4-$tuGt%E=4j4adB|7y7~RA`LYX2i@?Q{*aE!kI|DZ5K?O) zK2unF@62Yy`kfPZS>5}sYri7YAW!^kL@V!7jbk?yW&zrAJcWm~Srn6u$)q?1++(1u zX4PLL4DvUcOjtq3`zr*|`F%Wi@^LTj!h4n-(Kfj$bHy^afTGqYP`qdQ5{~2oidwwT zf;)LXK2wXKYVx)g+8ek;`Q;zsU1D$=PckL;HsO)wLtdT{{RfP(Nfj;Bv{9We&aj7*mLaB)Cw-;YP|8S zxw~xJjk9_(FP#h{nQa!8<6*^DwWTe2*iipTXW&ztsb#}o#}Hzr745kJg`iWdwJ=`7 zAZ?Je%+l>g^ie;N=Oy8-SPo$B?2?=Qwi9+P#jTX>yPkZnN^UP)UNV9cx2rQo29XQ9 ze`YWrV!D7sNM!3eO2e)7zVS4qg+>xptte}CaqBrTLWYS?vJ@S-&*QP(w_@L7j4iCN zQ1`-;OG9d{kWsZ)EHoqfna8-iE`8*%+vG&elGA)9KcMp3P2?5L87!UG$A)koB3SF5 zkyePQ58$QlbYKu5B=sz$%qvK^WfK}|BC=67X4LRIDSdW&##u%w5H_PRC3D~$_RE-@ z#QbTA1c1ph5*CqDN8s&m{`GDf@pUU)dDduxSEfk6v^K|Bj*GUWa%F$Zy zV144m_4r<`2RFt|`VgTN_UAa`N&`WB&5-+^~KiMh)^ zR4P_vp|&QG^iA7&!QPNYS?mAg2d7#j+wsBkYAbn6s#=b1ig5~(?!fB&9_xLe-o`ie zC}g%7lTHspFWF&!Qj#^7MW3L%AW^!UC6bt47=S(dRY&%`lyWMwsSl}~SS#ZyD)3{S zgLQNg#GC}p3;P5n;DUOvA*B_q;VRcIa&CfAa^#X?lF80i3`H{Fp`AjEAu((z^b2PaWxNF&78kr(2kc|`|d4lKjwnI;Zw2tP2SbNJ? zpK&?`Q8G(E`AHQ7J0)K*1f8K{Cw2-vFD-{Jt40XPd+(=Sln$v zN}~@v7ua0s!&Kkkt#s+(>so^4o+l$cfTPX}k&sJ)D$Sjfk1X4V=6J%1HzVm?diNgj z)K~Ky@yaPBYGe!T_NDZ2rV5O`TztR`*r<$D0|5ut*NXVA;(G@Vr2`HKJ7!tp43m6dLX`pbdG28u%8X0-Uh~&)!R)OWiaPmjtR>qCwZpkPTm)Xu|^nYc4 zeDBh}uN#x;EvrqCv!4yAI4oj;dR%_pjUJZ47Lr!hp}M?1L-}F5OWv7GedK;4B0aB2 z!;*()^)_y_$>aNfaj$$&eJx6Ns4YnauruEQkm@+{jDRB)9?@=HK#PWs`$zhT(%|-G z6%c`=32150$apY?blE1MG5)><5q%Udb;A*_-GJj**%x7n53`|Iod7lm+dMnAg!Sa`e2Dtr9LD_(=|S+)gh@~cxQoPWhv12u1*DOJ=y=+a@KSyz|mIvN^=bbFB?EHbLzWuxJZ6u$3j^TN;abD!0XJ1HH# z_`0f7n+3NCpEieWMCK5XqdA|I1?}W+eDZIBG)qw>5F&64h++ZYM6zIU%$T&XY9!Nw zs^z(=r1~DpIkD)S*vDSZDP$xtR19A)dp9ggSkfL zyOp3%jan@G--Pe;bie}%mPM0fq+yUp)EyN8{=_I*uHkCanH%b(J;>6q+!cWiVGzfv z^0gvy(-i5BjIfn6xY<+CsOUP2Sg1UTJOI~4d?*oxN4Zmb-}4W<6FQZ(@qKgZq_-6x zc_uUgg8`cH3kj;rv(+Ilz%{Ft`F9U6O^Z>xLpTbSDC|u8-Vzpoo0A$3!Xz8^XlneG ze{_^-9WuCZ*3NqGYXw*GAnis!b(aczM!~Y z1l&bKk6NUvUIj$R$@Vsev&k4QOI(;51JR^%pm*&+q(YKu@DdM{43U3?7LKs5l-Fjz z!-J5l(RFFj>+ksJZMd7V1B51jtfFLwhh9*)fn6tXS$tkw2UbFYGCVL?TisHI@@2dl ziX$K?^P+ATk*WxsGQvnByJ=Qxi}lzCPlcDO#o8-ir*<3>uCS2@o0$jK+K8oqSv))f zSQ1e1N)SCwTNcoQ+`^*6@NgM^_o9+ZvhO*M|AHw)gtQ~blwRDOb4!7Cs+dV^o1vu$U&_|6)7-hA4p#2xYagFNK=4^R6I^e z2!c<~geY(Aa$9@t^QNCgxs|NXpZw`mYv3*T;GkSwheRg?{`hZ#NfMj0(wwKRyzjzD z3Y=G*=%C8o;2J`A(j(C+$Lxj0yeE^McwIaU!@MrXvu}RxL(KR~+tMCXIkG`CDr3MM|=N>pb zY6Pz5LZfi3SyCQSxcJ(qSMkM4yIF02VOyopP|l5kgmkQqVN|(cot$?ty3Dp(I@v&B z+J7q*9GFW6+~IveE9-1<2Cvk7HD21Qv(HL!L)b5ipgUghmW_iH(hB5B->l z3+m0(jq6O4Cnu8Id7pWSVqE(DTi^60e015~*-6`iNZ!Qm7+v)BV3r8S?S9cjk8#50 z7jQ7P`eSyKlj1t)M+SO8DR-^TVpJ7{GIaS7zwV3h0tr@Vh2dNh499AA8AEE#5d|NT zm`&JFs>xW9Q-WmDUPTy6Af%+`(s>8``(ncKpW~-dZGNpjW(tJ33ZE7!z9BM%cOug|CO*jov(%OTHiabB6>#dTkYwjN6J4slU{8>Y zr;fG)vM=E6s$z^`{}DQ$u+2_*HTAR!@*(xqy|~hrtw~*%Or9tmCRr7_&6p_b@Sm3G z_zNQlf)()MQ}j7kzw*~4PJYu zuoLhN{lsDH=*k~=5PyKYMHKGt0*euY)Q&sMyn+u?S|5jcRw$JdEF=ibL<)|@{i|)S zVkC2=xp(603s>T+mo5^pg<~QvjFj?;F2pIr?ojDqCiM5+*stG8!xbSk+$kW36A{JJ zAF~-F?En%(r+I?`itq{=WZVF;o)hSn@8^d{877O{aKo~kUpN9Z4ri>UC;OmO)R8ID zw2#$p{M5DKBD|&lial6YtGuKnud`iby#A{5>f_MpB_nCM4UzYR{2I%6$NO6F(AVLW zj5+9yiB*(jvYiWY=)o=;HMU%jG}Tp$gwCP0GaC4axs7O<$slK5T6jwk4VWg$%>B{?X>#+FPGIUf(cYA+^+DSXq-y z^~EWX5^ZQ)DiG(JAkcSaTL-f4S-3i7)PTOD^0F+AIce<3YI;$?ig@pG*}nftyRr4P z!v2Yd0KfTJDe^4?b66kVwPJY;UfNr)4WGzi28{0D0QK71W~aiwu7Y|q-ea**)UHaB zkwsGAtIZL@NaCsz*5SXbYm~)svA%}13z_UmC>izyf$dD5L>PrUn%lWNrmy+HKDXfe zlrh_z_fdIB+hc7A%zs0l7JX9xdg#h1Io_s1;JqpWDU*25tR>Kw98N# zR-%sIS6e?&Z|)c&yX_nB%9+jq6UHU=Rd(7Q9Q2pn9a`JbDz-NyROcz1?Yx5`!raHk z6}%bu(y=^1s@tQW<}PsfX{5+$%|cTtUTzLwJ9nJ1efo=^Bs+jhBKziNCp!XV4UK6- zHN<4c^}mZ6=|$}qQ4nJHg~|mqfZQ}-442U3|H4a3H7MLPJFQj|A1b85D}s+8e;BW# z&FSBQjr3kibn!t~F|I}+iI*Zid8pDfUVNFW+AS~p$%-p+2W33><^z+|I)+iD9>!90 zOfZMS(b7PB^FntIFEnFmkEx|G1Z1lWQe2HDlDH$Mp^_A!0=V(u8o?_POcNSWcf;=} zD-`omvOF)<>jJb(xhm%R1QtmzZA_#wLG~vq%Qw8_Mf@H^Fqgjm#`7MnX^5&CJti%O91y68B!o%YgO)`puiI(zTEQl}jubIgqC`aQy&;gCN6^ z=cL!TFz(vx+!N+d7$wJXZazVU!Iu3ttUY!iT#dI|D6PV{O-(QRZLR-&M{ohiB>Iq- zkd-mqN28bk+>xr7e0mqHBl=&t@%;0--R zEhPyo16dn@LaY$Cq-g4wU0=@r=Hu}?oD%UglSrZ%Yb4H2pztc_*kJ0Q&1@pa(!Sh@&X<-v158WOLjtupzN)lls8L5_--V}~GPVbVSSdM!Z}TfulH`xtw9w79?BjULIphZ$awSm|*atBU zgoDLA634?q6+0jm@Or6r7B3fM_prp>Rr+MW8d z=loU1K@KlbyKLoT+gjIMTr|oqOEZfuMtQSEsgWoUW?0CsnC!%M%ZNui7NF ziC)#$4dj#tZk2dgOJGc{Of_V)9o)OSCUtU5-Pn!2K!|Vgewyb)Og!Nfts977+LDy_ znX)uORW-H@Y?JJT5#`NcL{8nVz4z<8aeG%;33~G!m6!C2N-rp!#VEY1qeS9tZ4$-W zXkKUnXCM6jehZA4kysz9pQ4|{> zlm5&ReM*dUAk*+;LX#|}?h&|h8cUZw3(j=n3A*VaLL#w8UCr$ToENfXNl_xlPIb0} zX8h?{Yj9I#d+|5-s36#khIvoOnQRhw-&8iOZR zXbj+^FmW+D;0DYz59ca$13nI516XrR-E%HV4i8qAeOo{PR%7yCHT24hBkV{-N(he~ zGq~BJBz*ph;7-~tQMO@0j0K;}p&=eyuUs(gu6-Ua(uwMo*()Aom9bK?ka+VzGSoJr zw&!eAfqep>x||e9gf>f8%~PvBY1Hh5KV66LpAapakKin)r6A|n4dFE>zg?#-b-7?B zD$!y-CT0L@`vGrJ)DPxNJzrpK*RXr1?|~)%-UL1n!TNqDriaxO<=xWdjwgdI>oX)k3;t*jBSd z59%7IqfWf{DS!Ld4t&MRlS{n*WhxogpXTexGFBgjSm^S7lDQY1^Z(y{6^ERmYV;Po z67?s2SiwOlLQrs!(21B0Z)l7U0fA|(hq%ynb(-Z$@e zB)(AP_xNdK#NVS5AeqpHHV+A+j%{bq0XJMIuHZz84FkNz$_?gNb+DQ7=&wp#Z7og5?Cx0c;Z0}YOH`gw^3*TadnPe32aw3EfCaSL5Q}-;SewCS#Ac%W zA>De*8}Vw>T-88rHH%x6~H;fPlgk1<&YkHWE`*z@p~yAFqzMJ+JYtN+wfHcDNrqs)&-K})IjXC>QzZ-lH zzEIgdugy2B4EDz5xjf3KI=enP%nTSV0?|v&NaBB05+BB^m%Foxt&3Ui znz{@{7g7}V)~YR`b~Y zmOtP7D86##9{e;$=37-(Or*}h!fW(ES3CP4t85{-%!%kVwlc`ICZu)fo+>Q{$c1uV z9Jofg38vfuIRgUc51-38XQGY>H48#pdVc(#&VK8AMyZgMN{N%TF-3ZlCGFZ=b?6K9 zZkRCub49v>XC=cD>I600K)0Us_DC?rP2 zK=5Y4K}}lyo|+5&DQ7GZ3qtQ~c0B&y$9wG+Op-%!a+2Ws%1<`#MiG_lC*6Ffiip9Z zO{4QJr0ejO9a6`MJSCW8k8e>ux0opP1>=$&qVR}4zb}#jHje4Bh=i#^R*yKPq`>Yj_axen;E@vf50XTKWC8-UDUk_3Ob!k_ z>=&x%=ukJARTpLOCBu}Of^t-mX|_?Hw!u$>y#?plLzjP>%}tdPO7!YJ6-k>L5)PeI z$Mq3>YFLmZgwmtKbuc;L8!r$U|KpWXyKO$+0$&*tE z_#_c!k(Bl_}*yW z9T^*HYIELU*7mdmpSaAAWRMeM)i zqK2+UeRqEM_%BmB+{V!0c(&}O(%A!-yRh%B7Do+}$r&BlfVEawiqbRC+__$d)zu8& zju)#6`7i`}l{g}5vSDp0&B;PG)(U9VD&3UA{tgLwP=YK>IW&UqC@K)1hUhX6Zw8!@ z%$ts!{DK!AN~x2G>6 zMhqW~{4&!6&daR@8HY+p#$uTW-FPzPbkRIK=f>}zK+%*O;k{*#B%1l7(9sSg?qIkU ztQ$^zL=~?c!o_a#!C<+Dd9jHc`>>%D%F%LAK>hFmgmR`Bniu4O*zU*WR+o-vNJ+~H z-UmjX6m#6h6Q)>)NX^f5+ae<8|J#S97Bb=ml8r8~2j6whC_CrN=ESySM|ihs5cRNa zDkd6nR Zc+2x|aT=(N<*UhT;7xjav}TfpFmId^lY+s;7!Iw_vk6!lst(fi0!85a z;Ssr16Y|N_6HlXm2!JdI6BpsmpFR77HHz@e5_7Z`d}Y9Ra`rsgu9uzPcr0Ey+&_SM zyEP1OxN_opY$mKVwF1QDNosYDr}mzMxw%Mxm*#4k(mM{vOQ zA$uF9a&VC(q1F!e_kiZjSZ%V=cqp}OHqEtg_Tk+Ri09k0L<_Aue+sxo7urP-+EOtm zpg%bIdfmOLwTb%hIbz;vT^7KLVd%pG~@lRQPm;CDoZGK>9GJ{w!8Hj0#Ow1 zQ1dS-lBHYGb$b@>w-3DT7?xeixU?;Y>;1H`%5a!fYbe6`(SeoaMU3H|zgxG2-God{ zn4JU!)ZKyc3gYCb^hG`!M3V%ql%pz8C}1fkomd_7NB-D_yM1OGMO5Z3j!_YjZfwh_ z?qOfmhy7{1p~NulsLgPSvBu&lVCk;d0*K)IG?zle$-xbxkQ4#KkqY=FToU_fP$++E z?LC6UX|Mxv2J}oBN(#oeAo#GZRrnPb*zs?u4w5>qd3GWsQxdXOc1i=uO(B~wLZd@Azv=&RGp;bWegkLU_P~SB$Gep^m2NpvZ-DL&;TGrp z?izJzQ1x}I!4`Le#cr<4>aaiSU0j9NI!hIgGo_S{!8CsG`Ln^u;$nu-7-O&?i*rE< z$Eo`_Jd#x?q5|xJHOp4L?}QYpWNjJw?ef}r*ku=Tv3A)3XvPPV2KvV_C^(9hD@`u;Km0{1sErg<)-o!g%kyJ>=G^_@MK=gU8X(!fr;+pq zS%P$^#Y52UY?uRAwSXRpS#Eb4E{+|Kt^FJeNM$W&TVAH(*c+F-(1!u3@_e*j)Gu8s ztXlTUB{?CDmzszYhg+`%0fyDV_37)^P9P{e1_%e6%{SDL_ZBD2rZ9t1(m<+ckyAJD zlZ?QDd_AFnkHD|xPu0z)m`&gZSE3WX&P@F2z>Db;Dm-|l(Pd0mkueOl_l$_c-=eB? zGu~MPCIg7Hdf=PG*>UIbnW!iS^C{LQu+#2>jsEPy5Pkw~Rwk5{s50StkDfs=eJJ8o zEsLt7KbT`~KEdqj#Q8xJuf-_oPUSb#keJdE*Svdw_Sic=K{1w$Fm35nF)~zX_r=no z{^C{%?Y$V|uba`hO)5Q-7}hl-2A8p3sfH)Sl%rD%Fe$8Pr18oOBTLdcuV4tm0dkeK z?%btI92~|e(I^I&XMg6%x6Y*;{;5QrtjnEpn2E~h1iBc2$=v$brNn~iL^m2!n(A;r z+y(+jT5Fh%SfiydNuJGkh%0oIAJ37!!2)PC&EySfB{3LP$z4y{GbmLRl+e?;kG4t& zb1rO4Lj#76Z3vl$Uz#SG$|4AA4}s-J`Y%_Z>(?E5tW*xmL^n67P+N+tx#*k+^VCH_ zovr}OyqEj*5gpy8i}9$XQV{g0FT-=-V6ssraH%Ol$^ezp-fn&AqvSb3ddUov50gkp z^aF_pP~5)fn|A&TN>EC#E>O`iH&}?Bq&S`g%Y@cX^b~rt(Fukf3afCuFqolc8U_#l zklNs8ysd_OwlHNCs&qRs9VQy5RQ+Pr!2$#Zz6>1UJ_(}0sEK5f4hjJ;fU9jh2oC{R za%Gk|>bcj9$*x!%-!XR)d*#ad*0(HI=`aM~yt(@5cpJ`XJNyon4I^SsSP6e-=}-tI zh#cEco1A(gnC;|sv)_ctf~%Gmkzg&%z#X8o2aoG^ojs$RE#nl18v&C5#l>~kg8TO4 zDTbvWqORg1rotM5C%U2gh$pL{K1V^x(&*Hv;rGTCe9y}o>drY20k@3sl|}?in(6(# zT^mYB)3tI?N&u}`uaC#lll1C9zwmL%f?Z?}UiR&OWAjrfb!~m?`{OcTD0<_7MdyQc zLbYq%>R|Ja!sRt~nWw$j|AqpQ{mQ;)(zHn-TA{FxnW%D9`DBy zFWsv~n=AJmu~>EEYP`Ht#?WMyfjusJtZrQb5Upb4_p6aD(|9n}Huwy;!3BX)co&3f zLM{FpzeH!6%Q(U;fC)q%{~M6aRp*x7HXidjeDMlfIvSz*>s57#rIunhUSD-yeSHy2 zjq%qw+8n=b#){Ufq*yY{DiT5E_*oiR<I2`<#rvE>(BYCc+Ul#MR7kCopZov z!)&n8X+zoTVX%t3%q@H)QvH{uhQ zqql3^^B`;@(uZ!X)X7I!q9pCB*=On;>U_&8qc?R&uh2jeBx0TgZFFfk1_ zGMr6PX^*AC3Ah!h0PBnmM5z3Ym4a1IiW6qqoe_mS!8cuLGQhx{euh~#b=KA8mX{qf z%12kWd~8d0YVlkIN9=>Dt;F|?0SJm~4KH+~$i)lIi0d~hE>iD{SfS@Ci<0~)^RO15 zVOng#(L%GPNqSq-OU0WauxBqy%s`N6a+`xb!7<~9Q7D_L(McP;oWM{TjD&e|I}gqc zG0%ne*oIC2_9Y7KKKwKWq;0BWq#kj69gl>lfsd^Z4#kinsYhm@a?~mucyrs^j(9`` zcP3svFKvI2FN>SPfoXCY1R}G=YSz;@XvNB#H7;Z~&iKq9O|NS!{oWpa(}zZ;;Umg= zD7Sn_?~SZ{Ct5w~{kyXA9Ew530Y`z0S-jR&Q$2XZ6);L$Aea7kNiVcAMT&Lv;X& zWc7Ma=IB9*Ib!z^i3rJ_{4c!0$y9&QyemKbSA0~ZqeS(uOI~6Do*CL=#y~XnaT9_+ zPf79Y8t|)JYvz&m>0MrrPo9YofP~5>4%lYxORCc0Dtt)f&vXSDtpNC0F%x5fcub;l zloZm7yh|h+iiO~eID&$X0}s4xrDWaeA*2<;;*bn}D(8t$&8Qj^;K^sa?UYRv;9eyH zyfGPmmtoRGsxZ;cu+!~t#n3&l0F0%Ybo{PV2Px*cX#J2on5ABVVb?!J!;D9VgoKUcz(|)c5W(Noss(*~S6gv1+VZApP4edAJ(W3^vYWnuY(C z5$i(uCr=|)L2us9ouPaGfPXHy${AnomQ0BZZ=-eD!Dg(iv}@z=k*BNdK8*KN*JGMs zCX{+8v_U8l*4m38LWbA!lLughv_#mF?mo(IT3s2Z1=Kw$!ln;us6qsR8PQfDCKyi( zY#TQmxVtR#W}Tx^O!upP5focDayt$Ja!JwmDMu9>y(QbzHAaYL$Of76=#)dDhkDvx z59~jRmzP3$JL`&2zfHRmj~vrydyTxM_aDTgQNV%kZVjw>Y?9__b=w>5q;o>`9yg^p zmEIDshOI_E|Lbkz=Ldfp&38&29*~HYm3wZI5l26e|;LOhLzJw z0V9eJ(_Ne;Qk^UuU0u`|*8 zD1ONeC&!yJF#0-R;w4ZIt)k%t?rKH2kvm(9gTyev9af?I522HJex3stiDFR;)7JT!~S^=JGvI*|WS;gJaL7@cU~FPT)prH?_i)+0)wL%S(f{K(I#+&19li>U`X ztz+Ic<%fx+a#{sA2Q&XL5I7c(C2FI#$U?*eLE0jr`gD4$OMCi;`g>!_j=a*SUg{pxOHJ6;QC)ib%kXODu37cXQWopmwnUgo zPL@)IErd!$WRTG7w|4U8XWjH3d_v`J{4_k(txrxSVZ#7Vd?V&j7Csl^^Oh?@q9-F7 z5Vwaq9heezl>`LXN9(76_&Naj6ESU3dNO5MAIhZ%J$l|z)YFpFthU;CLz@QKj(WX5 zqEF+~@@C9P>V-8&b|4u;kmYDWiaKL4|3aj(&46*!@cKG`B*`DuGaju0G2TC&LarKu zP!-5Yso0Fh8$=;#SAdO2pZVL@P+ZgTk46QsmVT}83}bW#mDdf<6|gXlV?Xd)4A*RE zMx*V39FE_1kua2J9_bllq=ZxchsFYEv;zl8T9h=E#v_Qz+9$GzqjT356g5kZ<-_R( z;^u^{*STyFmhf&_p-ibZEAS{V&UzR@N*k_v@F@?S!$h^hEya!UJ6H{f2&G+zryccn z)j9SZb|K)&(mKub^Xg~hpm<_B<_>Bp_;(4ngf(2kBjU)z0P;bL8S)eimpK4;&N{VO zxhNi+{;DtWpyslyZ|fl{ial|8?g;vRXXC(g*QA5+%Qg5VTA>GVvQ#9*dYlvBbrpQjg=`7b4t!qVUb%NLiNK!WAj3X zrP(xFm!H5J7uoe6dEY(9<1Wgot6ObYfYvv6WDQPXT2im~y3C%7-=d8ND<}a-aHI7T z0ozuC5pSwGc+|I5g4A50hmv*BRe&zaCPuS%RAon^@UxtBw3RAopvFojtIf9>YkF)( zJ0}-_PkGt6~0JSZ+D9Mi68TI z)X!CP|Ax2A3woZIf?M$~oGD4n>;T2-f`yQPZ?%CFU+ODJOe66xAyAcrDKJj`Yx}Vm zrYfBfEU;OBx(np^pM3UI$%;$P_u86u;kR{n*ipYuzDcyoQyv3fhF~>?$vsZk&T_S5 z&6JtnL=!kV8USxV=z{(o$Ci43Yb|eh|EiTd((!37k9(_+U-l6^u~MAVp$bBJr7e9t zN1v>6Sc*5Ci6CduSB)p#5{w5^GCa{_ru!{T2w;A;sYM-ddI^$azoSzx`ouZ^#XBlF zo@%S@;ATOv&1aV$ZPVCf*_Oth9?6M?ZO1V*RplEQU8HH&%s}V$vuJHk-6tzVJb1CL zQDaHDVKPgja43=1N<8Z}E;F$$T=^KQmtAN(u6@Z(Cs1h5D)AH6hRbN(-bst2M^qm! z!8BcmvLRp-}x`x^)YxzIf%7n*>8M_-|mplh0ssKvX& z0@h@&@{1_=OW7X}QezTP8XMVWu||I1-E3#$(LYq1 zScjK_=OAT>_6lmcX$GFSXO!>^E6uBF-Y@cMxGS-m1TR>$!r~Z64b3Q-`-K$wJHP9D zZ~nrqH{&amZCu@IP10?z*&O{Ny>|`_E)G|KyJzN$z?E%H!f!Jme!?5 z2|NU!ndmC1m{=O@+T!ui23FF(kIc!6fc&QWMt<9IPcJ6 zxU|VzSk%5l)oM`)z9usslao*0@FELNk{l-%)n3EbNgc|yW6_-#&EnWd<)tMM!8)O7 z5;#wBJrF_D#G0rayt*nBgU7lu<%{&0i{tqTpLA4N~8wYzvT8Nm^rB6Wim` z*zxrLc^(fnt8lYIV`Z*M|Krfn(KZe&re&=jE#CoMX^_rF$uUozMS@P!)%V~4P`RZUjmb1?rJ z*jgA4O|N0`pZNHtXq(2S9;SST5>lbB6naenCpLk-mNd8 zV9E%dthsx}D2T`!B?Erd0}I;@F+PF|-9vJr1&w(lUJI|`&sTziR(TNza!vQYU`AFW zoFi5*PKyAHsIN7q2ws!vVV24&35+-n8G#5wM(+aH`=TRX(#beda%R=m&!}b)=Xb(M z;nCyF($QK$06lu4yO$SQ5CGAQ?n6%}+@SR)YyC-j=Op1(G6*-076z&9 zy4%4skAkUFBH@4OQ9XZ%yne?=X5H`ue3{C<_-PCn*78n@izE-$=MC4ZOGYRQ*8&;{ zNglb@Ju25)kOS-dbBtgqJov;*N@PXxBiLkpoQk$ACi1yz$s?ZZ-b;V+E4+DS-x5c7 zy*}9~yf4;YJF_v2#6mea0RR!ZNZ8JFQgsH7C}($rk-I7RQmo-tY#|c$FzI5+$YI2v z)UqDcPM64vJ8F0Hkgf{bbQ+(u^{yYluieM#CkzyVyh45}MjNcAS>WFkB^s*E%G0!89G}I)F1%vaJew26>Jl^qW-NKWnj3xz`>^;WHdzz>6^A zz^@`OI8?WO+oUZB$x#jAmId`nuB*}qPA!DI^^Njo)U=ml#mDx){0@A>vXeEo-jW$z z`=-!5(tZY?N(Lk)R)vHeK><*+;X&h8BucQMVIj}94)~!EPufk;_}z=p+tc66ISC8L zti|I0#2HHhYh**-Z>WkJ_3N2jLIF2#pD1mPu2g-mnE&2?rrZ{mDAku#Zhr^U{35e1O7@%76#G;O^tNv*2}3S^|Zpaum` z>nt27_X8;Rfg~IP9BSg|W|td>s+Jp-S5%eUy`_){U*^2$QjSEzM%89DaS-;Bct@%l zo_9-!Fxw>4jtf^`1Rwm?L4;9L3}X zQz(&AICz%4(n7@S#fv-jfbRaDarmPQOmHKS-Bw~rf(91dnj@PHRNG=KI^-u7%76Hc zPTTRtZ!NKxub`W;%Vh{CLZ1%B-x*&jy-QW>a7~ zZ^h>#ml6R0J;qJ}JbWBv>8&Hu4iHJG%L2+IiZ4WsbyzHMmMSGA8p^a}l=xzgiJGsP zC=Pmb)`8M$^)S9xqx#tSMkFBGvSrb|$GLdJ&<))duh__msPLE0ym{W7st56G^_Aq_ zU>2Z03pgTzj+;y01-C!>7x?(fD@x4eN9q^ae!n;2^8`P)>ug z-svE&QNp#IZG)bgykh78k}3j8XbvhH(3I;;>Y*1A#kdF8Od~JdgZPtFMU%B!WZwrJ zu<-3~qwGpf@Z0)-rbu>-G}-o~c%U>D8>RPnp-U?Ojmb_!T-uovibA>I2iLV9UH0kOU-9%d)bj`qqM_r{*!2x3erf>Llo*;j>MSjjs1>Y0+E=aAhqp*1Ir8nX4c0`m z_jO;p{o52t87=&963OWxe@9~iPI{Y0>fOjV)?%2e74**_(2*D2r6WnX%G?E@aXwApt67@HHLa_sH+PZ|v;psjo$5na*&t7WLHVbMn=P{_a~8z>o3M2x4rQ zZFgKc9rBF(r{~4dz{A++H?(eav^LR-1Xkk3T^Z8M9*q?nNxejba!cT? z6c>^Ae;^O{$9u%{UM}U3mzB7OKkDOsHt!CUb}vYO_#RM!izc}DG0Muk+coQ;HCT5t zID#nJ%H3Xr7aPz|?m-%L0Jo!uy8yhh>6-qGiM(l+=uah`=MD zC-pOk;NYqh?(+RyaMi23zIPeEdf9;J)<^#yf+M|P%x7jU8fb_rpd%8VHQRG{iomNK zjKG3DC@czXg7g`9M&@GdUk&V-?R(3gLUc?9jzKU&^nn`MevuF=t1QBgx$y4oxbB;L z?q$c7Z~c=Bk2%uRtzB~WJBd%xBnSSBYqr=!sIde8ER-0Nx**cvM$_#D4V57|!Nuli z3dIa@)9#6ULA`fsW(lUt>h@><>2;i+EA2zKLmQb?P*#YZoJMy1M~-4Oe%-xRe%%82 zBlojJ_AZzyd6tcBN_M_&1~@1w8M*+8Hij{?I=MQBHL^RBfVn}X99T=iGD}sB1N2sZ z*Jl^Ur88H2LAs@WhOgM@j{mHx({^!?b811a;O%%*TG-H znHcs_kSB~fwi@^?-oF1^zRJv`l(PKG6y4%=_&g1}Ji)@fMM2FKeZsz#Z7XOs8R6VJ zWcNFV7}ez_fK~b#d=AG!OmhB3MFAOXpKIWbXvFq(cRI8mooMuckJshdrX$PxXpcC1teQnY;{qC2xay0ZG;cS= z|1#LS&CYA&Lc!T1qDNhYTdy*0>d;8N5l#pR}gx5A8Zn~QopOx`q8EAG+)Y(3HYoP2$E!HR7{CQ!>VVHUPMZ9opq{s z^Nz%l>4&>d#P+!SCF1u5X;PP%i@OfZo;L54k5hUjJJGi7qte?8m*>{bMXS;5<5nYE zb$3KaJw7tjy?(HUJrMnUwN@bYZFsR%LNrQA-s}O~c41n4(h?N^3E!nnF>od*fl2|6 z=G3pgS2P3*AZf(o~np*vdD>7`eRSZNyZP};p5_u=yP-{5MLmMQf-WuKR!-Hl%!Y(igoepPGJ~0{Cx8xW+5&N+Gg>+=A&b;V4fa+2 zn~P#{uLYwED2lEU^*BncY#)lEjxsK2km{__+W8p9a!X^e5)<=s4F?s-wH6{jJ=HQh z++2I^9I*ycj_lj*LGm&QV!n(Jj>mD3t+op9$qhO0~B1opVA@}$!ja4(g%^?;ok?YsyIA&IWBJg$YW2?y8fV~qB~7_I=b7NdhDz@$nzKT$C9}NT(|=HeNJ05 z<2F9{GL~bTEuEMW#kc{VIWt@@zy-D5(T@=u;vJG|00*Yr#7vQZN-1}YrV=Ph{R_}Q z_Ainm3y{ec6(a-Td!*UYu#&W~XB=`699?8qAgyX3>Q(p*hL@cTz$6akR@ss(HqoaAsKPRV76 z!r{b}w=0-o#64pi@8A84KmHA+^4t=CZTmO4d95vHV7fFuiZ@)8sef3F2OtN7T9dG8 z6mQ#4{W66+Q`^Y`AIeaiTyfG8J_WzgMMe6)Q7KdNvys*OOm4f%)tO_2?3Q3wS zhjRnQFx|TJg2#tW#7&g#fZXTro7w)q+F1Q zwvsaPa3l@kp2Ueu9_o39M5Vw&>WjGg)7|X&eK)WVwsKI3n|;Mp-3#e->4wFV@@S*+ z*LV%nT_Ym|zPdU~mV~DR!0U6B5?|zr%YSKNANZ{x^Fb?%pLv9hiyF;|pfqzw?f~*5j z!#-0d8)J1oURTG=tU+y1#AjP@*b@pybOKGSGRR};lSunS#kYEy&PIEmBS2`11BY)@H#rb zf9k_BJ4%Q?Ivg53oY;C!0LCMSZJfzdmW3@LMd}Y#@vKs((&@EUR?qW7H#k3DXd#O}51%J7)YG%f z@6#V*C#_6uWl=PQf{}Xml?#&uZcb!l4nA^bgILx?KFo~;Zpss5B9cJ{eB}}shKD3ofH^XUAoP3;gj%AuFBwN zk(I`+dt;w$X>g#eL$qNei%C8iMIbh2{E0F$ZUOiI;-0PSkS|5$wjzub*)#fwaOy11 zf7M}eF@Zu%jXDZ1=aBgDyIhTPf%MQkIBq_IK3@5=h+YXfh zwla68x7m4|kvA>Yn500ho>!d($+*nrxRf?rb;S*WFYm;6ZnTfHGd1DV6gb_I?Y;wg zsfF#n?lVruXLj1wfYi-E!Yua{raHzhMO3lL3}NB?ZdQEv(-TYi%**)cSLxkM(KG)t zKDEQAgcIwT(R}Gt7(sGS{0zr3LAUW6dGy-cO^3*oK71Roq-|NSlp*&6%y9E(Y`c$a zXuxYt>Q9`)^N|!%RxZYSU)j0m7TiyTt-p;*agK_S1SGr$x@LBD9`u{_by)9*b?W^< zl&vuREKEz1nWt#RAYyRKJ6(vgm?Zd`dSTYkOXO^}n+5}eaEU_R`g4gp-8uWGJ3H`+ zm6Be!l(0rfzY$e#o=4}m8->yd*5~7S+uT_!J}>6$-3tCqddN(HiokMSUu*6=~1zl zyoTK+cBKW6%Fdv$t}J8%|1d)UA1o_K;`v5xA~fctJ(qhoJV%J~-NBHbsE0E{ScrJgD>02rR2(a&gP8XY+g_l}Vx%W)#;E;D{!--Y$~U3|9`J1&-*x^+;>21<6o ziwbBy<{1n0N+@*PSN{--%7j=!c=>IrgGQgc>zC+?+^U6bg?kw&9+y86gzM6n{o;@P zsEY4aDH+w@)~j05erdcJAE-@H8RtizlXZ9mlQYLBVpPHX9+0w%gALoWUItSjU*o~s zhX75nbd*V??Go5==8fMXfm&fM+Zc3g@gM;!)-uzh{7~si0=PvvOzK?`NOM_QD=_k)*NUJ=GpGIM3hrUCY+-*7D)0Z{b zF??g^1s7ZDg%(`TI9}U<_`{Sht8psLY4?bZJIXbrCQL}ee?)X(u&l>8)~$N7;zjw)0ei&*ZIwK;dcGsH>&KU7VL*uruga)duRT@c;);0x?(FV+aVR-re6@ zIqT*7UGd1j?)QzW?{siLGhRS>5dm6DC=?Mgr1p)ClgKdJRBMw45B#lo{-|&u4H3CW zftGF`fE@P=N$4tnhZpYSwGRnTgk)ZJor#nyc|U$x9X)0j^zq zf?%_G3Bpa13m6_`2Eoi}8SQTv58(NH)pT49sB zoZ?+3`_myAV9m@1!{nl=q$BNLfXTw-3l;(D6lQAW#(IjqmHN2pn5=ys-vNC zS@_i0rq6?Eqbu0M$JADB!1pXoa^9^XB0;GlssozmYv)O!XeFZF{L*<*YvmQN~w8|fi1W^xas_@A=luP zCNF$s`iJl}N~?QYk{T_<@CS}^#PM6}C(>GKs?o|(R(Dp7jE=7xZfTg6qu^1^7M9Th zyCZ~$!q3b`#2}i@$XYUtOzVZJRf&Y}3@djgTgql0_{8dQX6sr|nVk5L`YGK!gcSan zyp^~cYjMrdkM^0E#Lj-|%Khk0GTZ1(4 zU=&0-+~D~H`8HgWmuFe6U(U8Yh38>~fPANQR;c%NgqZ#+kbvvj*;_V${N0q?9woZA zeF`P_R(vKnHlPu>26H&}n8hX_j$Bt1FU#r@q^DYeb~j}WD}kQiXW^oylRC3L!CmH& zcL_X|AKi7&2Pg(ES8asH*~ZY1-~L?+~x`f)Wva zIC*Z0u!ePnNS)EA;1dpvU_A7_);(rdTJT#R$BVTaIv#A*2SMRN!VEMw%PY}>f;lmSepZfI@ag%qMNVvqv5H0H34Ny1=%z4S~?iPb@aTjKr82D8y(#5Ytal& z+;;J@I7#Hf-`I;)3a$uuZM=G`C_>4`(QTj5``Q~{VG&lr4fd}^{Tu&EtLMnuuGLG} zU@ezgPzA0kk*PRCZC>HPHwFq(6Ui08?*!^CiFh!s<|)*4yla*onH?|&s%J{Rkw>M( zCYorRZ*<{QE_mP$GU}zV{j(|@?n6hhHM%wr!T%4g8>n+Z5_qvzknQL3(k>Yz#ZfGt zDnQ$#149b)1tv_7uLkto%EsSO3v2-may0C; zBI=n^dU1(e`1lE@y%M)kIibX_T$jwmC~Pob=cO%=G!tX6yL)+|1y$OC*Pbb{32r!l z$R3wq2zdqxZD!#pG)Vl2L0yjj$p7Ot5&PBAC``Z$;f3&5f_E|}PE6F0rz24dW>WOi zMYZF)o4)ZqimI&l;U*Oo$qtBW01U&@@!DvdY(oc(5!h}3*8y3f+=`lAg%_VGBN>8O z)R=-?_E@FGu@sVXLO+C(F56CDv`8SI5MPyv#Z?IMmK~E$vSrUEOWw7K0&;`1c41YY z{)W3b*;3kMYm1SmL|E^@X9mhPQ9*3frl7AJ_R7pF$WtZfJpoCF1ZlF7EKP3_VTlW* z7e;@OvSR|k-PSdrxiBtW`N+C&P#9&JV~dd4(t!QiD~ozVckLF|{GnM6fv(1@J2Ixz zgASiJun*BPTY#8B>f=QHLifoq45`!{GjZW2vUneya!ts2`XDjn?KMYLD`W+82r_ek zPWR7Kr|>NV9_6LjMfY8BENfh4$1`lR?Z;%r?655?yyMD-k-$3a0zox)pc`k5wX}4J z!EL_OQmckX5Q7!eDB#b%R9KyM+?sdFh3%@4r(8_%n8uo?*1XmiV^}$EWlpd$VRkLL zaI*S?Y50z%4Is9Wmt`Ik%v?EbGeBP*=Z%xxl=Vpz3^~tuos`X!PSK>1?PR>x4_IBTCkj3C>OX=Cu!902~F$2 z5*>;%FfmH>Z2F(T4M~z?(o~qN2pWkJ-agm0%rUzMaz%xIww0#By4htUs;o@p&duxF zneZN7vhP!>xSP@x-WK^%wU*X~xPPj;tcDhGm*0`Nux6xh7>Cc-dI#$hC$0yH&VQx|%8$xaZ_PJ-I z6_IViOBd+wP|Z+SSXa%1j#*}%*^*}%BpfZflO7v}EYDIj7(&}p?V9qVPs3>mfYJ~o zC+2mRh_{adU^|UXk+?Z-eBt45I+Eg;S7MI$BnLh<8bx-!KK@ zN(sI2P^KD+t{G~zRg0i+xzE)- z0Ru_A8=JnIp&gpsvIKWjp+Fl6w(qMf*~hT7HVn>mm&{}g$Gf1%11aQiYi)q<$9qZv z!fqi@QR;9ZT&QcY)S4J=WGm$5ZxDBBa-+g30yoK|H>J%;fVrLvU`;@_tNBB)$iADjU3vmun`K!5O7l z5zL`$;G^B`n?F`G7_35I>u945{SosUGXyVzQ5{rrTx7p Date: Mon, 27 May 2024 14:38:09 +0200 Subject: [PATCH 047/211] Add more tests --- .../0_stateless/03166_from_readable_size.sql | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/tests/queries/0_stateless/03166_from_readable_size.sql b/tests/queries/0_stateless/03166_from_readable_size.sql index 9e4cd7829da..72904746bd4 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.sql +++ b/tests/queries/0_stateless/03166_from_readable_size.sql @@ -27,5 +27,26 @@ SELECT fromReadableSize('3.00 KiB'); -- 3072 -- Resulting bytes are rounded up SELECT fromReadableSize('1.0001 KiB'); -- 1025 --- Leading & infix whitespace is ignored -SELECT fromReadableSize(' 1 KiB'); \ No newline at end of file +-- Infix whitespace is ignored +SELECT fromReadableSize('1 KiB'); +SELECT fromReadableSize('1KiB'); + + +-- ERRORS +-- No arguments +SELECT fromReadableSize() -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } +-- Too many arguments +SELECT fromReadableSize('1 B', '2 B') -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } +-- Wrong Type +SELECT fromReadableSize(12) -- { serverError ILLEGAL_TYPE_OF_ARGUMENT } +-- Invalid input - overall garbage +SELECT fromReadableSize("oh no") -- { serverError BAD_ARGUMENTS } +-- Invalid input - unknown unit +SELECT fromReadableSize("12.3 rb") -- { serverError BAD_ARGUMENTS } +-- Invalid input - Leading whitespace +SELECT fromReadableSize(' 1 B') -- { serverError BAD_ARGUMENTS } +-- Invalid input - Trailing characters +SELECT fromReadableSize('1 B leftovers') -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize(' 1 B') -- { serverError BAD_ARGUMENTS } +-- Invalid input - Result too big to fit in output typez +SELECT fromReadableSize('1000000 EiB') -- { serverError BAD_ARGUMENTS } \ No newline at end of file From 24d9b6804ec6be63f562b2932dd2e784eb4d6128 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 14:42:32 +0200 Subject: [PATCH 048/211] Make scale literals long to avoid truncation --- src/Functions/fromReadableSize.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index 9405558cb9d..7b028dcf48c 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -29,22 +29,22 @@ namespace const std::unordered_map size_unit_to_bytes = { - {"b", 1}, + {"b", 1L}, // ISO/IEC 80000-13 binary units - {"kib", 1024}, - {"mib", 1024 * 1024}, - {"gib", 1024 * 1024 * 1024}, - {"tib", 1024 * 1024 * 1024 * 1024}, - {"pib", 1024 * 1024 * 1024 * 1024 * 1024}, - {"eib", 1024 * 1024 * 1024 * 1024 * 1024 * 1024}, + {"kib", 1024L}, + {"mib", 1024L * 1024L}, + {"gib", 1024L * 1024L * 1024L}, + {"tib", 1024L * 1024L * 1024L * 1024L}, + {"pib", 1024L * 1024L * 1024L * 1024L * 1024L}, + {"eib", 1024L * 1024L * 1024L * 1024L * 1024L * 1024L}, // SI units - {"kb", 1000}, - {"mb", 1000 * 1000}, - {"gb", 1000 * 1000 * 1000}, - {"tb", 1000 * 1000 * 1000 * 1000}, - {"pb", 1000 * 1000 * 1000 * 1000 * 1000}, - {"eb", 1000 * 1000 * 1000 * 1000 * 1000 * 1000}, + {"kb", 1000L}, + {"mb", 1000L * 1000L}, + {"gb", 1000L * 1000L * 1000L}, + {"tb", 1000L * 1000L * 1000L * 1000L}, + {"pb", 1000L * 1000L * 1000L * 1000L * 1000L}, + {"eb", 1000L * 1000L * 1000L * 1000L * 1000L * 1000L}, }; class FunctionFromReadableSize : public IFunction From 4d63bc24a5ee2081e8d8a731f66661080cba14cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mar=C3=ADn?= Date: Mon, 27 May 2024 15:00:03 +0200 Subject: [PATCH 049/211] Disable 01701_parallel_parsing_infinite_segmentation on debug and sanitizer builds --- .../0_stateless/01701_parallel_parsing_infinite_segmentation.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/queries/0_stateless/01701_parallel_parsing_infinite_segmentation.sh b/tests/queries/0_stateless/01701_parallel_parsing_infinite_segmentation.sh index 0fe04fb95fd..9284348dd62 100755 --- a/tests/queries/0_stateless/01701_parallel_parsing_infinite_segmentation.sh +++ b/tests/queries/0_stateless/01701_parallel_parsing_infinite_segmentation.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# Tags: no-debug, no-asan, no-tsan, no-msan CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # shellcheck source=../shell_config.sh From 6e4fe264f8471637f93b2d1210480647cde1bdd2 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 27 May 2024 13:00:31 +0000 Subject: [PATCH 050/211] Split QueryAnalysisPass. --- .../QueryAnalysisPass.cpp => QueryAnalysis/QueryAnalyzer.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Analyzer/{Passes/QueryAnalysisPass.cpp => QueryAnalysis/QueryAnalyzer.h} (100%) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/QueryAnalysis/QueryAnalyzer.h similarity index 100% rename from src/Analyzer/Passes/QueryAnalysisPass.cpp rename to src/Analyzer/QueryAnalysis/QueryAnalyzer.h From e680e9ce5230a756f72614835bda8507b4ffe78e Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 27 May 2024 13:02:28 +0000 Subject: [PATCH 051/211] Split QueryAnalysisPass. --- .../IdentifierResolveScope.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Analyzer/{Passes/QueryAnalysisPass.cpp => QueryAnalysis/IdentifierResolveScope.h} (100%) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/QueryAnalysis/IdentifierResolveScope.h similarity index 100% rename from src/Analyzer/Passes/QueryAnalysisPass.cpp rename to src/Analyzer/QueryAnalysis/IdentifierResolveScope.h From bf3762db2079e1a9413cea44dbcf2391a53550cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mar=C3=ADn?= Date: Mon, 27 May 2024 15:04:41 +0200 Subject: [PATCH 052/211] Add max time limit to 00840_long_concurrent_select_and_drop_deadlock --- ...ong_concurrent_select_and_drop_deadlock.sh | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/tests/queries/0_stateless/00840_long_concurrent_select_and_drop_deadlock.sh b/tests/queries/0_stateless/00840_long_concurrent_select_and_drop_deadlock.sh index cbe37de6651..238cdcea547 100755 --- a/tests/queries/0_stateless/00840_long_concurrent_select_and_drop_deadlock.sh +++ b/tests/queries/0_stateless/00840_long_concurrent_select_and_drop_deadlock.sh @@ -19,15 +19,39 @@ trap cleanup EXIT $CLICKHOUSE_CLIENT -q "create view view_00840 as select count(*),database,table from system.columns group by database,table" -for _ in {1..100}; do - $CLICKHOUSE_CLIENT -nm -q " - drop table if exists view_00840; - create view view_00840 as select count(*),database,table from system.columns group by database,table; - " -done & -for _ in {1..250}; do - $CLICKHOUSE_CLIENT -q "select * from view_00840 order by table" >/dev/null 2>&1 || true -done & + +function thread_drop_create() +{ + local TIMELIMIT=$((SECONDS+$1)) + local it=0 + while [ $SECONDS -lt "$TIMELIMIT" ] && [ $it -lt 100 ]; + do + it=$((it+1)) + $CLICKHOUSE_CLIENT -nm -q " + drop table if exists view_00840; + create view view_00840 as select count(*),database,table from system.columns group by database,table; + " + done +} + +function thread_select() +{ + local TIMELIMIT=$((SECONDS+$1)) + local it=0 + while [ $SECONDS -lt "$TIMELIMIT" ] && [ $it -lt 250 ]; + do + it=$((it+1)) + $CLICKHOUSE_CLIENT -q "select * from view_00840 order by table" >/dev/null 2>&1 || true + done +} + + +export -f thread_drop_create +export -f thread_select + +TIMEOUT=60 +thread_drop_create $TIMEOUT & +thread_select $TIMEOUT & wait trap '' EXIT From 0db331249d61a1b69660f4a08737ceb3792024ea Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 15:07:31 +0200 Subject: [PATCH 053/211] Change return type to Float64 --- src/Functions/fromReadableSize.cpp | 42 +++++++++++++----------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index 7b028dcf48c..89132509de2 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -27,24 +27,24 @@ namespace ErrorCodes namespace { -const std::unordered_map size_unit_to_bytes = +const std::unordered_map size_unit_to_bytes = { - {"b", 1L}, + {"b", 1.0}, // ISO/IEC 80000-13 binary units - {"kib", 1024L}, - {"mib", 1024L * 1024L}, - {"gib", 1024L * 1024L * 1024L}, - {"tib", 1024L * 1024L * 1024L * 1024L}, - {"pib", 1024L * 1024L * 1024L * 1024L * 1024L}, - {"eib", 1024L * 1024L * 1024L * 1024L * 1024L * 1024L}, + {"kib", 1024.0}, + {"mib", 1024.0 * 1024.0}, + {"gib", 1024.0 * 1024.0 * 1024.0}, + {"tib", 1024.0 * 1024.0 * 1024.0 * 1024.0}, + {"pib", 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0}, + {"eib", 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0}, // SI units - {"kb", 1000L}, - {"mb", 1000L * 1000L}, - {"gb", 1000L * 1000L * 1000L}, - {"tb", 1000L * 1000L * 1000L * 1000L}, - {"pb", 1000L * 1000L * 1000L * 1000L * 1000L}, - {"eb", 1000L * 1000L * 1000L * 1000L * 1000L * 1000L}, + {"kb", 1000.0}, + {"mb", 1000.0 * 1000.0}, + {"gb", 1000.0 * 1000.0 * 1000.0}, + {"tb", 1000.0 * 1000.0 * 1000.0 * 1000.0}, + {"pb", 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0}, + {"eb", 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0}, }; class FunctionFromReadableSize : public IFunction @@ -66,14 +66,14 @@ public: }; validateFunctionArgumentTypes(*this, arguments, args); - return std::make_shared(); + return std::make_shared(); } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { - auto col_to = ColumnUInt64::create(); + auto col_to = ColumnFloat64::create(); auto & res_data = col_to->getData(); for (size_t i = 0; i < input_rows_count; ++i) @@ -100,14 +100,8 @@ public: if (iter == size_unit_to_bytes.end()) throw_bad_arguments("Unknown readable size unit", unit); - Float64 raw_num_bytes = base * iter->second; - if (raw_num_bytes > std::numeric_limits::max()) - throw_bad_arguments("Result is too big for output type (UInt64)", raw_num_bytes); - // As the input might be an arbitrary decimal number we might end up with a non-integer amount of bytes when parsing binary (eg MiB) units. - // This doesn't make sense so we round up to indicate the byte size that can fit the passed size. - UInt64 result = static_cast(std::ceil(raw_num_bytes)); - - res_data.emplace_back(result); + Float64 num_bytes = base * iter->second; + res_data.emplace_back(num_bytes); } return col_to; From 7dcfb55021d132f24ec5d304db14d51e4972a6b9 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 15:09:30 +0200 Subject: [PATCH 054/211] Update documentation to reflect new type --- docs/en/sql-reference/functions/other-functions.md | 3 +-- src/Functions/fromReadableSize.cpp | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/en/sql-reference/functions/other-functions.md b/docs/en/sql-reference/functions/other-functions.md index 2984cca81c7..db3454c20b1 100644 --- a/docs/en/sql-reference/functions/other-functions.md +++ b/docs/en/sql-reference/functions/other-functions.md @@ -797,7 +797,6 @@ Result: ## fromReadableSize Given a string containing the readable representation of a byte size, this function returns the corresponding number of bytes. - - As the conversion might lead to decimal bytes the result will be rounded up to the next integer to represent the minimum number of bytes that can fit the passed size. - Accepts up to the Exabyte (EB/EiB) **Arguments** @@ -806,7 +805,7 @@ Given a string containing the readable representation of a byte size, this funct **Returned value** -- Number of bytes represented by the readable size [UInt64](../data-types/int-uint.md). +- Number of bytes represented by the readable size [Float64](../data-types/float.md). Example: diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index 89132509de2..de3fde27105 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -128,17 +128,12 @@ Given a string containing the readable representation of a byte size, this funct [example:basic_binary] [example:basic_decimal] -If the resulting number of bytes has a non-zero decimal part, the result is rounded up to indicate the number of bytes necessary to accommodate the provided size. -[example:round] - Accepts readable sizes up to the Exabyte (EB/EiB). -It always returns an UInt64 value. )", .examples{ {"basic_binary", "SELECT fromReadableSize('1 KiB')", "1024"}, {"basic_decimal", "SELECT fromReadableSize('1.523 KB')", "1523"}, - {"round", "SELECT fromReadableSize('1.0001 KiB')", "1025"}, }, .categories{"OtherFunctions"} } From 293c8ce3f49d6b67defec191f860df7c4a36f4e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mar=C3=ADn?= Date: Mon, 27 May 2024 15:13:56 +0200 Subject: [PATCH 055/211] Limit timeout for 01293_optimize_final_force --- .../01293_optimize_final_force.reference | 100 ------------------ .../0_stateless/01293_optimize_final_force.sh | 44 +++++--- 2 files changed, 27 insertions(+), 117 deletions(-) diff --git a/tests/queries/0_stateless/01293_optimize_final_force.reference b/tests/queries/0_stateless/01293_optimize_final_force.reference index b0b9422adf0..e69de29bb2d 100644 --- a/tests/queries/0_stateless/01293_optimize_final_force.reference +++ b/tests/queries/0_stateless/01293_optimize_final_force.reference @@ -1,100 +0,0 @@ -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 -55 0 diff --git a/tests/queries/0_stateless/01293_optimize_final_force.sh b/tests/queries/0_stateless/01293_optimize_final_force.sh index 9b9ed6272a1..d3d3d3e1ac5 100755 --- a/tests/queries/0_stateless/01293_optimize_final_force.sh +++ b/tests/queries/0_stateless/01293_optimize_final_force.sh @@ -6,23 +6,33 @@ CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # shellcheck source=../shell_config.sh . "$CURDIR"/../shell_config.sh -for _ in {1..100}; do $CLICKHOUSE_CLIENT --multiquery --query " -DROP TABLE IF EXISTS mt; -CREATE TABLE mt (x UInt8, k UInt8 DEFAULT 0) ENGINE = SummingMergeTree ORDER BY k; +it=0 +TIMELIMIT=31 +while [ $SECONDS -lt "$TIMELIMIT" ] && [ $it -lt 100 ]; +do + it=$((it+1)) + $CLICKHOUSE_CLIENT --multiquery --query " + DROP TABLE IF EXISTS mt; + CREATE TABLE mt (x UInt8, k UInt8 DEFAULT 0) ENGINE = SummingMergeTree ORDER BY k; -INSERT INTO mt (x) VALUES (1); -INSERT INTO mt (x) VALUES (2); -INSERT INTO mt (x) VALUES (3); -INSERT INTO mt (x) VALUES (4); -INSERT INTO mt (x) VALUES (5); -INSERT INTO mt (x) VALUES (6); -INSERT INTO mt (x) VALUES (7); -INSERT INTO mt (x) VALUES (8); -INSERT INTO mt (x) VALUES (9); -INSERT INTO mt (x) VALUES (10); + INSERT INTO mt (x) VALUES (1); + INSERT INTO mt (x) VALUES (2); + INSERT INTO mt (x) VALUES (3); + INSERT INTO mt (x) VALUES (4); + INSERT INTO mt (x) VALUES (5); + INSERT INTO mt (x) VALUES (6); + INSERT INTO mt (x) VALUES (7); + INSERT INTO mt (x) VALUES (8); + INSERT INTO mt (x) VALUES (9); + INSERT INTO mt (x) VALUES (10); -OPTIMIZE TABLE mt FINAL; -SELECT * FROM mt; + OPTIMIZE TABLE mt FINAL; + "; -DROP TABLE mt; -"; done + RES=$($CLICKHOUSE_CLIENT --query "SELECT * FROM mt;") + if [ "$RES" != "55 0" ]; then + echo "FAIL. Got: $RES" + fi + + $CLICKHOUSE_CLIENT --query "DROP TABLE mt;" +done From b5daa653ee2c1afba391691d3d9006422bf319c9 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 15:22:44 +0200 Subject: [PATCH 056/211] At even more tests --- .../03166_from_readable_size.reference | 7 +++- .../0_stateless/03166_from_readable_size.sql | 33 ++++++++++++------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/tests/queries/0_stateless/03166_from_readable_size.reference b/tests/queries/0_stateless/03166_from_readable_size.reference index 0579e74baff..97ac1921006 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.reference +++ b/tests/queries/0_stateless/03166_from_readable_size.reference @@ -16,5 +16,10 @@ 1.00 MB 1024 3072 -1025 +-1024 1024 +1024 +1024 +1024 +1024 +\N diff --git a/tests/queries/0_stateless/03166_from_readable_size.sql b/tests/queries/0_stateless/03166_from_readable_size.sql index 72904746bd4..0a485d6cf51 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.sql +++ b/tests/queries/0_stateless/03166_from_readable_size.sql @@ -24,29 +24,38 @@ SELECT formatReadableDecimalSize(fromReadableSize('1 mb')); SELECT fromReadableSize('1.00 KiB'); -- 1024 SELECT fromReadableSize('3.00 KiB'); -- 3072 --- Resulting bytes are rounded up -SELECT fromReadableSize('1.0001 KiB'); -- 1025 +-- Should be able to parse negative numbers +SELECT fromReadableSize('-1.00 KiB'); -- 1024 -- Infix whitespace is ignored SELECT fromReadableSize('1 KiB'); SELECT fromReadableSize('1KiB'); +-- Can parse LowCardinality +SELECT fromReadableSize(toLowCardinality('1 KiB')); + +-- Can parse nullable fields +SELECT fromReadableSize(toNullable('1 KiB')); + +-- Can parse non-const columns fields +SELECT fromReadableSize(materialize('1 KiB')); + +-- Output is NULL if NULL arg is passed +SELECT fromReadableSize(NULL); -- ERRORS -- No arguments -SELECT fromReadableSize() -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } +SELECT fromReadableSize(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } -- Too many arguments -SELECT fromReadableSize('1 B', '2 B') -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } +SELECT fromReadableSize('1 B', '2 B'); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } -- Wrong Type -SELECT fromReadableSize(12) -- { serverError ILLEGAL_TYPE_OF_ARGUMENT } +SELECT fromReadableSize(12); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT } -- Invalid input - overall garbage -SELECT fromReadableSize("oh no") -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('oh no'); -- { serverError BAD_ARGUMENTS } -- Invalid input - unknown unit -SELECT fromReadableSize("12.3 rb") -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('12.3 rb'); -- { serverError BAD_ARGUMENTS } -- Invalid input - Leading whitespace -SELECT fromReadableSize(' 1 B') -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize(' 1 B'); -- { serverError BAD_ARGUMENTS } -- Invalid input - Trailing characters -SELECT fromReadableSize('1 B leftovers') -- { serverError BAD_ARGUMENTS } -SELECT fromReadableSize(' 1 B') -- { serverError BAD_ARGUMENTS } --- Invalid input - Result too big to fit in output typez -SELECT fromReadableSize('1000000 EiB') -- { serverError BAD_ARGUMENTS } \ No newline at end of file +SELECT fromReadableSize('1 B leftovers'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize(' 1 B'); -- { serverError BAD_ARGUMENTS } From c3a68397b48dc7ac62f844f2cbc42e93802254dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mar=C3=ADn?= Date: Mon, 27 May 2024 15:23:15 +0200 Subject: [PATCH 057/211] Set max time limit for parallel ddl tests --- tests/queries/0_stateless/00719_parallel_ddl_db.sh | 6 +++++- tests/queries/0_stateless/00719_parallel_ddl_table.sh | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/queries/0_stateless/00719_parallel_ddl_db.sh b/tests/queries/0_stateless/00719_parallel_ddl_db.sh index 004590c21df..b7dea25c182 100755 --- a/tests/queries/0_stateless/00719_parallel_ddl_db.sh +++ b/tests/queries/0_stateless/00719_parallel_ddl_db.sh @@ -11,7 +11,11 @@ ${CLICKHOUSE_CLIENT} --query "DROP DATABASE IF EXISTS parallel_ddl" function query() { - for _ in {1..50}; do + local it=0 + TIMELIMIT=30 + while [ $SECONDS -lt "$TIMELIMIT" ] && [ $it -lt 50 ]; + do + it=$((it+1)) ${CLICKHOUSE_CLIENT} --query "CREATE DATABASE IF NOT EXISTS parallel_ddl" ${CLICKHOUSE_CLIENT} --query "DROP DATABASE IF EXISTS parallel_ddl" done diff --git a/tests/queries/0_stateless/00719_parallel_ddl_table.sh b/tests/queries/0_stateless/00719_parallel_ddl_table.sh index 57a7e228341..fefe12ae656 100755 --- a/tests/queries/0_stateless/00719_parallel_ddl_table.sh +++ b/tests/queries/0_stateless/00719_parallel_ddl_table.sh @@ -10,7 +10,11 @@ ${CLICKHOUSE_CLIENT} --query "DROP TABLE IF EXISTS parallel_ddl" function query() { - for _ in {1..50}; do + local it=0 + TIMELIMIT=30 + while [ $SECONDS -lt "$TIMELIMIT" ] && [ $it -lt 50 ]; + do + it=$((it+1)) ${CLICKHOUSE_CLIENT} --query "CREATE TABLE IF NOT EXISTS parallel_ddl(a Int) ENGINE = Memory" ${CLICKHOUSE_CLIENT} --query "DROP TABLE IF EXISTS parallel_ddl" done From fa53b2f25b4b88733923d0f38cc4b1a7da635fcf Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 27 May 2024 13:58:17 +0000 Subject: [PATCH 058/211] Split QueryAnalysisPass. --- .../QueryAnalysisPass.cpp => QueryAnalysis/IdentifierLookup.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Analyzer/{Passes/QueryAnalysisPass.cpp => QueryAnalysis/IdentifierLookup.h} (100%) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/QueryAnalysis/IdentifierLookup.h similarity index 100% rename from src/Analyzer/Passes/QueryAnalysisPass.cpp rename to src/Analyzer/QueryAnalysis/IdentifierLookup.h From dc65301b5dde8db5a737a949967947d40dec95f0 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 16:53:16 +0200 Subject: [PATCH 059/211] Add tests --- .../03166_from_readable_size.reference | 8 -------- .../0_stateless/03166_from_readable_size.sql | 19 ++++--------------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/tests/queries/0_stateless/03166_from_readable_size.reference b/tests/queries/0_stateless/03166_from_readable_size.reference index 97ac1921006..c79f29c2851 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.reference +++ b/tests/queries/0_stateless/03166_from_readable_size.reference @@ -5,15 +5,7 @@ 1.00 TiB 1.00 PiB 1.00 EiB -1.00 B -1.00 KB -1.00 MB -1.00 GB -1.00 TB -1.00 PB -1.00 EB 1.00 MiB -1.00 MB 1024 3072 -1024 diff --git a/tests/queries/0_stateless/03166_from_readable_size.sql b/tests/queries/0_stateless/03166_from_readable_size.sql index 0a485d6cf51..f16dd9825e1 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.sql +++ b/tests/queries/0_stateless/03166_from_readable_size.sql @@ -7,18 +7,8 @@ SELECT formatReadableSize(fromReadableSize('1 TiB')); SELECT formatReadableSize(fromReadableSize('1 PiB')); SELECT formatReadableSize(fromReadableSize('1 EiB')); --- Should be the inverse of formatReadableDecimalSize -SELECT formatReadableDecimalSize(fromReadableSize('1 B')); -SELECT formatReadableDecimalSize(fromReadableSize('1 KB')); -SELECT formatReadableDecimalSize(fromReadableSize('1 MB')); -SELECT formatReadableDecimalSize(fromReadableSize('1 GB')); -SELECT formatReadableDecimalSize(fromReadableSize('1 TB')); -SELECT formatReadableDecimalSize(fromReadableSize('1 PB')); -SELECT formatReadableDecimalSize(fromReadableSize('1 EB')); - -- Is case-insensitive SELECT formatReadableSize(fromReadableSize('1 mIb')); -SELECT formatReadableDecimalSize(fromReadableSize('1 mb')); -- Should be able to parse decimals SELECT fromReadableSize('1.00 KiB'); -- 1024 @@ -51,11 +41,10 @@ SELECT fromReadableSize('1 B', '2 B'); -- { serverError NUMBER_OF_ARGUMENTS_DOES -- Wrong Type SELECT fromReadableSize(12); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT } -- Invalid input - overall garbage -SELECT fromReadableSize('oh no'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('oh no'); -- { serverError CANNOT_PARSE_NUMBER } -- Invalid input - unknown unit -SELECT fromReadableSize('12.3 rb'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('12.3 rb'); -- { serverError CANNOT_PARSE_TEXT } -- Invalid input - Leading whitespace -SELECT fromReadableSize(' 1 B'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize(' 1 B'); -- { serverError CANNOT_PARSE_INPUT_ASSERTION_FAILED } -- Invalid input - Trailing characters -SELECT fromReadableSize('1 B leftovers'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableSize(' 1 B'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('1 B leftovers'); -- { serverError UNEXPECTED_DATA_AFTER_PARSED_VALUE } From 53b1379d5f8f4accac952772469e093b0342539d Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 16:54:07 +0200 Subject: [PATCH 060/211] Keep only Impl --- src/Functions/fromReadableSize.cpp | 105 +++++------------------------ 1 file changed, 16 insertions(+), 89 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index de3fde27105..441c861d582 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -1,119 +1,46 @@ #include -#include -#include -#include - -#include -#include #include -#include -#include -#include -#include -#include -#include +#include namespace DB { - namespace ErrorCodes { - extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION; - extern const int TOO_MANY_ARGUMENTS_FOR_FUNCTION; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int BAD_ARGUMENTS; + extern const int CANNOT_PARSE_TEXT; } namespace { -const std::unordered_map size_unit_to_bytes = +// ISO/IEC 80000-13 binary units +const std::unordered_map scale_factors = { {"b", 1.0}, - // ISO/IEC 80000-13 binary units {"kib", 1024.0}, {"mib", 1024.0 * 1024.0}, {"gib", 1024.0 * 1024.0 * 1024.0}, {"tib", 1024.0 * 1024.0 * 1024.0 * 1024.0}, {"pib", 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0}, {"eib", 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0}, - - // SI units - {"kb", 1000.0}, - {"mb", 1000.0 * 1000.0}, - {"gb", 1000.0 * 1000.0 * 1000.0}, - {"tb", 1000.0 * 1000.0 * 1000.0 * 1000.0}, - {"pb", 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0}, - {"eb", 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0}, }; -class FunctionFromReadableSize : public IFunction +struct Impl { -public: static constexpr auto name = "fromReadableSize"; - static FunctionPtr create(ContextPtr) { return std::make_shared(); } - String getName() const override { return name; } - bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } - bool useDefaultImplementationForConstants() const override { return true; } - size_t getNumberOfArguments() const override { return 1; } - - DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override + static Float64 getScaleFactorForUnit(const String & unit) // Assumes the unit is already in lowercase { - FunctionArgumentDescriptors args + auto iter = scale_factors.find(unit); + if (iter == scale_factors.end()) { - {"readable_size", static_cast(&isString), nullptr, "String"}, - }; - validateFunctionArgumentTypes(*this, arguments, args); - - return std::make_shared(); - } - - - - ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override - { - auto col_to = ColumnFloat64::create(); - auto & res_data = col_to->getData(); - - for (size_t i = 0; i < input_rows_count; ++i) - { - std::string_view str = arguments[0].column->getDataAt(i).toView(); - ReadBufferFromString buf(str); - // tryReadFloatText does seem to not raise any error when there is leading whitespace so we cehck for it explicitly - skipWhitespaceIfAny(buf); - if (buf.getPosition() > 0) - throw_bad_arguments("Leading whitespace is not allowed", str); - - Float64 base = 0; - if (!tryReadFloatText(base, buf)) - throw_bad_arguments("Unable to parse readable size numeric component", str); - - skipWhitespaceIfAny(buf); - - String unit; - readStringUntilWhitespace(unit, buf); - if (!buf.eof()) - throw_bad_arguments("Found trailing characters after readable size string", str); - boost::algorithm::to_lower(unit); - auto iter = size_unit_to_bytes.find(unit); - if (iter == size_unit_to_bytes.end()) - throw_bad_arguments("Unknown readable size unit", unit); - - Float64 num_bytes = base * iter->second; - res_data.emplace_back(num_bytes); + throw Exception( + ErrorCodes::CANNOT_PARSE_TEXT, + "Invalid expression for function {} - Unknown readable size unit (\"{}\")", + name, + unit + ); } - - return col_to; - } - - -private: - - template - void throw_bad_arguments(const String & msg, Arg arg) const - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {} - {} (\"{}\")", getName(), msg, arg); + return iter->second; } }; @@ -121,7 +48,7 @@ private: REGISTER_FUNCTION(FromReadableSize) { - factory.registerFunction(FunctionDocumentation + factory.registerFunction>(FunctionDocumentation { .description=R"( Given a string containing the readable representation of a byte size, this function returns the corresponding number of bytes: From 41dbd5e6f878c5b7fe65dd28c39bac0f7fa276f3 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 16:54:29 +0200 Subject: [PATCH 061/211] Extract common behaviour to fromReadable & parametrize --- src/Functions/fromReadable.h | 93 ++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/Functions/fromReadable.h diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h new file mode 100644 index 00000000000..308a7684db4 --- /dev/null +++ b/src/Functions/fromReadable.h @@ -0,0 +1,93 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION; + extern const int TOO_MANY_ARGUMENTS_FOR_FUNCTION; + extern const int ILLEGAL_TYPE_OF_ARGUMENT; + extern const int BAD_ARGUMENTS; + extern const int UNEXPECTED_DATA_AFTER_PARSED_VALUE; + extern const int CANNOT_PARSE_INPUT_ASSERTION_FAILED; +} + +template +class FunctionFromReadable : public IFunction +{ +public: + static constexpr auto name = Impl::name; + + static FunctionPtr create(ContextPtr) { return std::make_shared>(); } + + String getName() const override { return name; } + bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } + bool useDefaultImplementationForConstants() const override { return true; } + size_t getNumberOfArguments() const override { return 1; } + + DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override + { + FunctionArgumentDescriptors args + { + {"readable_size", static_cast(&isString), nullptr, "String"}, + }; + validateFunctionArgumentTypes(*this, arguments, args); + + return std::make_shared(); + } + + + ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override + { + auto col_to = ColumnFloat64::create(); + auto & res_data = col_to->getData(); + + for (size_t i = 0; i < input_rows_count; ++i) + { + std::string_view str = arguments[0].column->getDataAt(i).toView(); + ReadBufferFromString buf(str); + // tryReadFloatText does seem to not raise any error when there is leading whitespace so we check it explicitly + skipWhitespaceIfAny(buf); + if (buf.getPosition() > 0) + throw_exception(ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED, "Leading whitespace is not allowed", str); + + Float64 base = 0; + if (!tryReadFloatTextPrecise(base, buf)) // If we use the default (fast) tryReadFloatText this returns True on garbage input + throw_exception(ErrorCodes::CANNOT_PARSE_NUMBER, "Unable to parse readable size numeric component", str); + + skipWhitespaceIfAny(buf); + + String unit; + readStringUntilWhitespace(unit, buf); + if (!buf.eof()) + throw_exception(ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, "Found trailing characters after readable size string", str); + boost::algorithm::to_lower(unit); + Float64 scale_factor = Impl::getScaleFactorForUnit(unit); + Float64 num_bytes = base * scale_factor; + + res_data.emplace_back(num_bytes); + } + + return col_to; + } + + +private: + + template + void throw_exception(const int code, const String & msg, Arg arg) const + { + throw Exception(code, "Invalid expression for function {} - {} (\"{}\")", getName(), msg, arg); + } +}; +} From 392819d01fcab6bee96ef6285848cd20973c51de Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 27 May 2024 14:54:51 +0000 Subject: [PATCH 062/211] Split QueryAnalysisPass. --- .../IdentifierResolveScope.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Analyzer/{Passes/QueryAnalysisPass.cpp => QueryAnalysis/IdentifierResolveScope.cpp} (100%) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp similarity index 100% rename from src/Analyzer/Passes/QueryAnalysisPass.cpp rename to src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp From c1de6a2756a329cf6329d1b25c91f067d6e01dfd Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 16:55:00 +0200 Subject: [PATCH 063/211] Extract fromreadabledecimalsize to its own function --- src/Functions/fromReadableDecimalSize.cpp | 70 +++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/Functions/fromReadableDecimalSize.cpp diff --git a/src/Functions/fromReadableDecimalSize.cpp b/src/Functions/fromReadableDecimalSize.cpp new file mode 100644 index 00000000000..3665db35c31 --- /dev/null +++ b/src/Functions/fromReadableDecimalSize.cpp @@ -0,0 +1,70 @@ +#include +#include +#include + +namespace DB +{ +namespace ErrorCodes +{ + extern const int CANNOT_PARSE_TEXT; +} + +namespace +{ + +// ISO/IEC 80000-13 binary units +const std::unordered_map scale_factors = +{ + {"b", 1.0}, + {"kb", 1000.0}, + {"mb", 1000.0 * 1000.0}, + {"gb", 1000.0 * 1000.0 * 1000.0}, + {"tb", 1000.0 * 1000.0 * 1000.0 * 1000.0}, + {"pb", 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0}, + {"eb", 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0}, +}; + +struct Impl +{ + static constexpr auto name = "fromReadableDecimalSize"; + + static Float64 getScaleFactorForUnit(const String & unit) // Assumes the unit is already in lowercase + { + auto iter = scale_factors.find(unit); + if (iter == scale_factors.end()) + { + throw Exception( + ErrorCodes::CANNOT_PARSE_TEXT, + "Invalid expression for function {} - Unknown readable size unit (\"{}\")", + name, + unit + ); + } + return iter->second; + } + +}; +} + +REGISTER_FUNCTION(FromReadableDecimalSize) +{ + factory.registerFunction>(FunctionDocumentation + { + .description=R"( +Given a string containing the readable representation of a byte size, this function returns the corresponding number of bytes: +[example:basic_binary] +[example:basic_decimal] + +Accepts readable sizes up to the Exabyte (EB/EiB). + +)", + .examples{ + {"basic_binary", "SELECT fromReadableSize('1 KiB')", "1024"}, + {"basic_decimal", "SELECT fromReadableSize('1.523 KB')", "1523"}, + }, + .categories{"OtherFunctions"} + } + ); +} + +} From c2dd92793a5074be433c3f525b6244bec6108057 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 16:56:26 +0200 Subject: [PATCH 064/211] Add tests for fromReadableDecimalSize --- ...03167_from_readable_decimal_size.reference | 17 +++++++ .../03167_from_readable_decimal_size.sql | 50 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 tests/queries/0_stateless/03167_from_readable_decimal_size.reference create mode 100644 tests/queries/0_stateless/03167_from_readable_decimal_size.sql diff --git a/tests/queries/0_stateless/03167_from_readable_decimal_size.reference b/tests/queries/0_stateless/03167_from_readable_decimal_size.reference new file mode 100644 index 00000000000..c360a43ae02 --- /dev/null +++ b/tests/queries/0_stateless/03167_from_readable_decimal_size.reference @@ -0,0 +1,17 @@ +1.00 B +1.00 KB +1.00 MB +1.00 GB +1.00 TB +1.00 PB +1.00 EB +1.00 MB +1000 +3000 +-1000 +1000 +1000 +1000 +1000 +1000 +\N diff --git a/tests/queries/0_stateless/03167_from_readable_decimal_size.sql b/tests/queries/0_stateless/03167_from_readable_decimal_size.sql new file mode 100644 index 00000000000..dbbcd835d71 --- /dev/null +++ b/tests/queries/0_stateless/03167_from_readable_decimal_size.sql @@ -0,0 +1,50 @@ +-- Should be the inverse of formatReadableDecimalSize +SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 B')); +SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 KB')); +SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 MB')); +SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 GB')); +SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 TB')); +SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 PB')); +SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 EB')); + +-- Is case-insensitive +SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 mb')); + +-- Should be able to parse decimals +SELECT fromReadableDecimalSize('1.00 KB'); -- 1024 +SELECT fromReadableDecimalSize('3.00 KB'); -- 3072 + +-- Should be able to parse negative numbers +SELECT fromReadableDecimalSize('-1.00 KB'); -- 1024 + +-- Infix whitespace is ignored +SELECT fromReadableDecimalSize('1 KB'); +SELECT fromReadableDecimalSize('1KB'); + +-- Can parse LowCardinality +SELECT fromReadableDecimalSize(toLowCardinality('1 KB')); + +-- Can parse nullable fields +SELECT fromReadableDecimalSize(toNullable('1 KB')); + +-- Can parse non-const columns fields +SELECT fromReadableDecimalSize(materialize('1 KB')); + +-- Output is NULL if NULL arg is passed +SELECT fromReadableDecimalSize(NULL); + +-- ERRORS +-- No arguments +SELECT fromReadableDecimalSize(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } +-- Too many arguments +SELECT fromReadableDecimalSize('1 B', '2 B'); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } +-- Wrong Type +SELECT fromReadableDecimalSize(12); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT } +-- Invalid input - overall garbage +SELECT fromReadableDecimalSize('oh no'); -- { serverError CANNOT_PARSE_NUMBER } +-- Invalid input - unknown unit +SELECT fromReadableDecimalSize('12.3 rb'); -- { serverError CANNOT_PARSE_TEXT } +-- Invalid input - Leading whitespace +SELECT fromReadableDecimalSize(' 1 B'); -- { serverError CANNOT_PARSE_INPUT_ASSERTION_FAILED } +-- Invalid input - Trailing characters +SELECT fromReadableDecimalSize('1 B leftovers'); -- { serverError UNEXPECTED_DATA_AFTER_PARSED_VALUE } From c5d5c32ee12acb217a9f5b05f948168da35d9565 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 16:57:54 +0200 Subject: [PATCH 065/211] Remove unnecessary extern error codes --- src/Functions/fromReadable.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 308a7684db4..74c4a8958df 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -14,10 +14,6 @@ namespace DB namespace ErrorCodes { - extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION; - extern const int TOO_MANY_ARGUMENTS_FOR_FUNCTION; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int BAD_ARGUMENTS; extern const int UNEXPECTED_DATA_AFTER_PARSED_VALUE; extern const int CANNOT_PARSE_INPUT_ASSERTION_FAILED; } From 9f72635c4ef98abbd5c5653bc96758b2482428c1 Mon Sep 17 00:00:00 2001 From: Blargian Date: Mon, 27 May 2024 16:58:58 +0200 Subject: [PATCH 066/211] Add missing toStartOfMillisecond, toStartOfMicrosecond --- .../functions/date-time-functions.md | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/docs/en/sql-reference/functions/date-time-functions.md b/docs/en/sql-reference/functions/date-time-functions.md index 843f22e5a6f..5661a91816a 100644 --- a/docs/en/sql-reference/functions/date-time-functions.md +++ b/docs/en/sql-reference/functions/date-time-functions.md @@ -1293,6 +1293,116 @@ Result: - [Timezone](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) server configuration parameter. +## toStartOfMillisecond + +Rounds down a date with time to the start of the milliseconds. + +**Syntax** + +``` sql +toStartOfMillisecond(value, [timezone]) +``` + +**Arguments** + +- `value` — Date and time. [DateTime64](../../sql-reference/data-types/datetime64.md). +- `timezone` — [Timezone](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) for the returned value (optional). If not specified, the function uses the timezone of the `value` parameter. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- Input value with sub-milliseconds. [DateTime64](../../sql-reference/data-types/datetime64.md). + +**Examples** + +Query without timezone: + +``` sql +WITH toDateTime64('2020-01-01 10:20:30.999999', 3) AS dt64 +SELECT toStartOfMillisecond(dt64); +``` + +Result: + +``` text +┌─toStartOfMillisecond(dt64)─┐ +│ 2020-01-01 10:20:30.999 │ +└────────────────────────────┘ +``` + +Query with timezone: + +``` sql +WITH toDateTime64('2020-01-01 10:20:30.999999', 3) AS dt64 +SELECT toStartOfMilliSecond(dt64, 'Asia/Istanbul'); +``` + +Result: + +``` text +┌─toStartOfMillisecond(dt64, 'Asia/Istanbul')─┐ +│ 2020-01-01 12:20:30.999 │ +└─────────────────────────────────────────────┘ +``` + +**See also** + +- [Timezone](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) server configuration parameter. + +## toStartOfMicrosecond + +Rounds down a date with time to the start of the milliseconds. + +**Syntax** + +``` sql +toStartOfMicrosecond(value, [timezone]) +``` + +**Arguments** + +- `value` — Date and time. [DateTime64](../../sql-reference/data-types/datetime64.md). +- `timezone` — [Timezone](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) for the returned value (optional). If not specified, the function uses the timezone of the `value` parameter. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- Input value with sub-microseconds. [DateTime64](../../sql-reference/data-types/datetime64.md). + +**Examples** + +Query without timezone: + +``` sql +WITH toDateTime64('2020-01-01 10:20:30.999999', 3) AS dt64 +SELECT toStartOfMicrosecond(dt64); +``` + +Result: + +``` text +┌─toStartOfMicrosecond(dt64)─┐ +│ 2020-01-01 10:20:30.999000 │ +└────────────────────────────┘ +``` + +Query with timezone: + +``` sql +WITH toDateTime64('2020-01-01 10:20:30.999999', 3) AS dt64 +SELECT toStartOfMicrosecond(dt64, 'Asia/Istanbul'); +``` + +Result: + +``` text +┌─toStartOfMicrosecond(dt64, 'Asia/Istanbul')─┐ +│ 2020-01-01 12:20:30.999000 │ +└─────────────────────────────────────────────┘ +``` + +**See also** + +- [Timezone](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) server configuration parameter. + ## toStartOfFiveMinutes Rounds down a date with time to the start of the five-minute interval. From 52691c829f7ea52105c16494938e096ba36bac12 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 27 May 2024 15:00:07 +0000 Subject: [PATCH 067/211] Split QueryAnalysisPass. --- .../QueryAnalysisPass.cpp => QueryAnalysis/ScopeAliases.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Analyzer/{Passes/QueryAnalysisPass.cpp => QueryAnalysis/ScopeAliases.h} (100%) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/QueryAnalysis/ScopeAliases.h similarity index 100% rename from src/Analyzer/Passes/QueryAnalysisPass.cpp rename to src/Analyzer/QueryAnalysis/ScopeAliases.h From be8edfb27f7e79f6ff427f81ae7316367d25afe2 Mon Sep 17 00:00:00 2001 From: alesapin Date: Mon, 27 May 2024 17:09:45 +0200 Subject: [PATCH 068/211] Don't propagate user settings for merges and mutations in object storages --- .../ObjectStorages/S3/S3ObjectStorage.cpp | 5 ++- src/Interpreters/ClientInfo.h | 10 +++++ src/Interpreters/Context.cpp | 11 +++++ src/Interpreters/Context.h | 6 +++ .../MergeTree/MergeFromLogEntryTask.cpp | 1 + .../MergeTree/MergePlainMergeTreeTask.cpp | 1 + .../MergeTree/MutateFromLogEntryTask.cpp | 1 + .../MergeTree/MutatePlainMergeTreeTask.cpp | 1 + tests/config/config.d/storage_conf.xml | 14 +++++++ ..._settings_for_queries_and_merges.reference | 3 ++ ...164_s3_settings_for_queries_and_merges.sql | 40 +++++++++++++++++++ 11 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 tests/queries/0_stateless/03164_s3_settings_for_queries_and_merges.reference create mode 100644 tests/queries/0_stateless/03164_s3_settings_for_queries_and_merges.sql diff --git a/src/Disks/ObjectStorages/S3/S3ObjectStorage.cpp b/src/Disks/ObjectStorages/S3/S3ObjectStorage.cpp index 823e272cf01..875a32e33b3 100644 --- a/src/Disks/ObjectStorages/S3/S3ObjectStorage.cpp +++ b/src/Disks/ObjectStorages/S3/S3ObjectStorage.cpp @@ -259,7 +259,10 @@ std::unique_ptr S3ObjectStorage::writeObject( /// NOLIN throw Exception(ErrorCodes::BAD_ARGUMENTS, "S3 doesn't support append to files"); S3Settings::RequestSettings request_settings = s3_settings.get()->request_settings; - if (auto query_context = CurrentThread::getQueryContext()) + /// NOTE: For background operations settings are not propagated from session or query. They are taken from + /// default user's .xml config. It's obscure and unclear behavior. For them it's always better + /// to rely on settings from disk. + if (auto query_context = CurrentThread::getQueryContext(); query_context && !query_context->isBackgroundOperationContext()) { request_settings.updateFromSettingsIfChanged(query_context->getSettingsRef()); } diff --git a/src/Interpreters/ClientInfo.h b/src/Interpreters/ClientInfo.h index c2ed9f7ffa4..3054667e264 100644 --- a/src/Interpreters/ClientInfo.h +++ b/src/Interpreters/ClientInfo.h @@ -130,6 +130,16 @@ public: UInt64 count_participating_replicas{0}; UInt64 number_of_current_replica{0}; + enum class BackgroundOperationType : uint8_t + { + NOT_A_BACKGROUND_OPERATION = 0, + MERGE = 1, + MUTATION = 2, + }; + + /// It's ClientInfo and context created for background operation (not real query) + BackgroundOperationType background_operation_type{BackgroundOperationType::NOT_A_BACKGROUND_OPERATION}; + bool empty() const { return query_kind == QueryKind::NO_QUERY; } /** Serialization and deserialization. diff --git a/src/Interpreters/Context.cpp b/src/Interpreters/Context.cpp index e1d82a8f604..5c9ae4716b9 100644 --- a/src/Interpreters/Context.cpp +++ b/src/Interpreters/Context.cpp @@ -2386,6 +2386,17 @@ void Context::setCurrentQueryId(const String & query_id) client_info.initial_query_id = client_info.current_query_id; } +void Context::setBackgroundOperationTypeForContext(ClientInfo::BackgroundOperationType background_operation) +{ + chassert(background_operation != ClientInfo::BackgroundOperationType::NOT_A_BACKGROUND_OPERATION); + client_info.background_operation_type = background_operation; +} + +bool Context::isBackgroundOperationContext() const +{ + return client_info.background_operation_type != ClientInfo::BackgroundOperationType::NOT_A_BACKGROUND_OPERATION; +} + void Context::killCurrentQuery() const { if (auto elem = getProcessListElement()) diff --git a/src/Interpreters/Context.h b/src/Interpreters/Context.h index 814534f7035..87a7baa0469 100644 --- a/src/Interpreters/Context.h +++ b/src/Interpreters/Context.h @@ -760,6 +760,12 @@ public: void setCurrentDatabaseNameInGlobalContext(const String & name); void setCurrentQueryId(const String & query_id); + /// FIXME: for background operations (like Merge and Mutation) we also use the same Context object and even setup + /// query_id for it (table_uuid::result_part_name). We can distinguish queries from background operation in some way like + /// bool is_background = query_id.contains("::"), but it's much worse than just enum check with more clear purpose + void setBackgroundOperationTypeForContext(ClientInfo::BackgroundOperationType setBackgroundOperationTypeForContextbackground_operation); + bool isBackgroundOperationContext() const; + void killCurrentQuery() const; bool isCurrentQueryKilled() const; diff --git a/src/Storages/MergeTree/MergeFromLogEntryTask.cpp b/src/Storages/MergeTree/MergeFromLogEntryTask.cpp index e8d55f75b08..2db0c0af3d7 100644 --- a/src/Storages/MergeTree/MergeFromLogEntryTask.cpp +++ b/src/Storages/MergeTree/MergeFromLogEntryTask.cpp @@ -312,6 +312,7 @@ ReplicatedMergeMutateTaskBase::PrepareResult MergeFromLogEntryTask::prepare() task_context = Context::createCopy(storage.getContext()); task_context->makeQueryContext(); task_context->setCurrentQueryId(getQueryId()); + task_context->setBackgroundOperationTypeForContext(ClientInfo::BackgroundOperationType::MERGE); /// Add merge to list merge_mutate_entry = storage.getContext()->getMergeList().insert( diff --git a/src/Storages/MergeTree/MergePlainMergeTreeTask.cpp b/src/Storages/MergeTree/MergePlainMergeTreeTask.cpp index 866a63911c3..a7070c80df9 100644 --- a/src/Storages/MergeTree/MergePlainMergeTreeTask.cpp +++ b/src/Storages/MergeTree/MergePlainMergeTreeTask.cpp @@ -168,6 +168,7 @@ ContextMutablePtr MergePlainMergeTreeTask::createTaskContext() const context->makeQueryContext(); auto queryId = getQueryId(); context->setCurrentQueryId(queryId); + context->setBackgroundOperationTypeForContext(ClientInfo::BackgroundOperationType::MERGE); return context; } diff --git a/src/Storages/MergeTree/MutateFromLogEntryTask.cpp b/src/Storages/MergeTree/MutateFromLogEntryTask.cpp index 3415b08cebb..8d40658bb2c 100644 --- a/src/Storages/MergeTree/MutateFromLogEntryTask.cpp +++ b/src/Storages/MergeTree/MutateFromLogEntryTask.cpp @@ -206,6 +206,7 @@ ReplicatedMergeMutateTaskBase::PrepareResult MutateFromLogEntryTask::prepare() task_context = Context::createCopy(storage.getContext()); task_context->makeQueryContext(); task_context->setCurrentQueryId(getQueryId()); + task_context->setBackgroundOperationTypeForContext(ClientInfo::BackgroundOperationType::MUTATION); merge_mutate_entry = storage.getContext()->getMergeList().insert( storage.getStorageID(), diff --git a/src/Storages/MergeTree/MutatePlainMergeTreeTask.cpp b/src/Storages/MergeTree/MutatePlainMergeTreeTask.cpp index 0b19aebe36d..2fd02708421 100644 --- a/src/Storages/MergeTree/MutatePlainMergeTreeTask.cpp +++ b/src/Storages/MergeTree/MutatePlainMergeTreeTask.cpp @@ -139,6 +139,7 @@ ContextMutablePtr MutatePlainMergeTreeTask::createTaskContext() const context->makeQueryContext(); auto queryId = getQueryId(); context->setCurrentQueryId(queryId); + context->setBackgroundOperationTypeForContext(ClientInfo::BackgroundOperationType::MUTATION); return context; } diff --git a/tests/config/config.d/storage_conf.xml b/tests/config/config.d/storage_conf.xml index 0e6cd4b0e03..7a9b579c00a 100644 --- a/tests/config/config.d/storage_conf.xml +++ b/tests/config/config.d/storage_conf.xml @@ -92,6 +92,13 @@ 22548578304 100 + + s3 + http://localhost:11111/test/special/ + clickhouse + clickhouse + 0 + @@ -107,6 +114,13 @@ + + +

      + s3_no_cache +
      + +
      diff --git a/tests/queries/0_stateless/03164_s3_settings_for_queries_and_merges.reference b/tests/queries/0_stateless/03164_s3_settings_for_queries_and_merges.reference new file mode 100644 index 00000000000..a2aef9837d3 --- /dev/null +++ b/tests/queries/0_stateless/03164_s3_settings_for_queries_and_merges.reference @@ -0,0 +1,3 @@ +655360 +18 0 +2 1 diff --git a/tests/queries/0_stateless/03164_s3_settings_for_queries_and_merges.sql b/tests/queries/0_stateless/03164_s3_settings_for_queries_and_merges.sql new file mode 100644 index 00000000000..652b27b8a67 --- /dev/null +++ b/tests/queries/0_stateless/03164_s3_settings_for_queries_and_merges.sql @@ -0,0 +1,40 @@ +-- Tags: no-random-settings, no-fasttest + +SET allow_prefetched_read_pool_for_remote_filesystem=0; +SET allow_prefetched_read_pool_for_local_filesystem=0; +SET max_threads = 1; +SET remote_read_min_bytes_for_seek = 100000; +-- Will affect INSERT, but not merge +SET s3_check_objects_after_upload=1; + +DROP TABLE IF EXISTS t_compact_bytes_s3; +CREATE TABLE t_compact_bytes_s3(c1 UInt32, c2 UInt32, c3 UInt32, c4 UInt32, c5 UInt32) +ENGINE = MergeTree ORDER BY c1 +SETTINGS index_granularity = 512, min_bytes_for_wide_part = '10G', storage_policy = 's3_no_cache'; + +INSERT INTO t_compact_bytes_s3 SELECT number, number, number, number, number FROM numbers(512 * 32 * 40); + +SYSTEM DROP MARK CACHE; +OPTIMIZE TABLE t_compact_bytes_s3 FINAL; + +SYSTEM DROP MARK CACHE; +SELECT count() FROM t_compact_bytes_s3 WHERE NOT ignore(c2, c4); +SYSTEM FLUSH LOGS; + +SELECT + ProfileEvents['S3ReadRequestsCount'], + ProfileEvents['ReadBufferFromS3Bytes'] < ProfileEvents['ReadCompressedBytes'] * 1.1 +FROM system.query_log +WHERE event_date >= yesterday() AND type = 'QueryFinish' + AND current_database = currentDatabase() + AND query ilike '%INSERT INTO t_compact_bytes_s3 SELECT number, number, number%'; + +SELECT + ProfileEvents['S3ReadRequestsCount'], + ProfileEvents['ReadBufferFromS3Bytes'] < ProfileEvents['ReadCompressedBytes'] * 1.1 +FROM system.query_log +WHERE event_date >= yesterday() AND type = 'QueryFinish' + AND current_database = currentDatabase() + AND query ilike '%OPTIMIZE TABLE t_compact_bytes_s3 FINAL%'; + +DROP TABLE IF EXISTS t_compact_bytes_s3; From 985e327553c0e8ebcb9413cdbaab465b467c278d Mon Sep 17 00:00:00 2001 From: Blargian Date: Mon, 27 May 2024 17:10:32 +0200 Subject: [PATCH 069/211] Add missing toStartOfNanosecond --- .../functions/date-time-functions.md | 86 +++++++++++++++---- 1 file changed, 69 insertions(+), 17 deletions(-) diff --git a/docs/en/sql-reference/functions/date-time-functions.md b/docs/en/sql-reference/functions/date-time-functions.md index 5661a91816a..03bbd6c2083 100644 --- a/docs/en/sql-reference/functions/date-time-functions.md +++ b/docs/en/sql-reference/functions/date-time-functions.md @@ -1317,23 +1317,24 @@ toStartOfMillisecond(value, [timezone]) Query without timezone: ``` sql -WITH toDateTime64('2020-01-01 10:20:30.999999', 3) AS dt64 +WITH toDateTime64('2020-01-01 10:20:30.999999999', 9) AS dt64 SELECT toStartOfMillisecond(dt64); ``` Result: ``` text -┌─toStartOfMillisecond(dt64)─┐ -│ 2020-01-01 10:20:30.999 │ -└────────────────────────────┘ +┌────toStartOfMillisecond(dt64)─┐ +│ 2020-01-01 10:20:30.999000000 │ +└───────────────────────────────┘ ``` Query with timezone: ``` sql -WITH toDateTime64('2020-01-01 10:20:30.999999', 3) AS dt64 -SELECT toStartOfMilliSecond(dt64, 'Asia/Istanbul'); +┌─toStartOfMillisecond(dt64, 'Asia/Istanbul')─┐ +│ 2020-01-01 12:20:30.999000000 │ +└─────────────────────────────────────────────┘ ``` Result: @@ -1344,13 +1345,9 @@ Result: └─────────────────────────────────────────────┘ ``` -**See also** - -- [Timezone](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) server configuration parameter. - ## toStartOfMicrosecond -Rounds down a date with time to the start of the milliseconds. +Rounds down a date with time to the start of the microseconds. **Syntax** @@ -1372,22 +1369,22 @@ toStartOfMicrosecond(value, [timezone]) Query without timezone: ``` sql -WITH toDateTime64('2020-01-01 10:20:30.999999', 3) AS dt64 +WITH toDateTime64('2020-01-01 10:20:30.999999999', 9) AS dt64 SELECT toStartOfMicrosecond(dt64); ``` Result: ``` text -┌─toStartOfMicrosecond(dt64)─┐ -│ 2020-01-01 10:20:30.999000 │ -└────────────────────────────┘ +┌────toStartOfMicrosecond(dt64)─┐ +│ 2020-01-01 10:20:30.999999000 │ +└───────────────────────────────┘ ``` Query with timezone: ``` sql -WITH toDateTime64('2020-01-01 10:20:30.999999', 3) AS dt64 +WITH toDateTime64('2020-01-01 10:20:30.999999999', 9) AS dt64 SELECT toStartOfMicrosecond(dt64, 'Asia/Istanbul'); ``` @@ -1395,7 +1392,7 @@ Result: ``` text ┌─toStartOfMicrosecond(dt64, 'Asia/Istanbul')─┐ -│ 2020-01-01 12:20:30.999000 │ +│ 2020-01-01 12:20:30.999999000 │ └─────────────────────────────────────────────┘ ``` @@ -1403,6 +1400,61 @@ Result: - [Timezone](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) server configuration parameter. +## toStartOfNanosecond + +Rounds down a date with time to the start of the nanoseconds. + +**Syntax** + +``` sql +toStartOfNanosecond(value, [timezone]) +``` + +**Arguments** + +- `value` — Date and time. [DateTime64](../../sql-reference/data-types/datetime64.md). +- `timezone` — [Timezone](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) for the returned value (optional). If not specified, the function uses the timezone of the `value` parameter. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- Input value with nanoseconds. [DateTime64](../../sql-reference/data-types/datetime64.md). + +**Examples** + +Query without timezone: + +``` sql +WITH toDateTime64('2020-01-01 10:20:30.999999999', 9) AS dt64 +SELECT toStartOfNanosecond(dt64); +``` + +Result: + +``` text +┌─────toStartOfNanosecond(dt64)─┐ +│ 2020-01-01 10:20:30.999999999 │ +└───────────────────────────────┘ +``` + +Query with timezone: + +``` sql +WITH toDateTime64('2020-01-01 10:20:30.999999999', 9) AS dt64 +SELECT toStartOfNanosecond(dt64, 'Asia/Istanbul'); +``` + +Result: + +``` text +┌─toStartOfNanosecond(dt64, 'Asia/Istanbul')─┐ +│ 2020-01-01 12:20:30.999999999 │ +└────────────────────────────────────────────┘ +``` + +**See also** + +- [Timezone](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) server configuration parameter. + ## toStartOfFiveMinutes Rounds down a date with time to the start of the five-minute interval. From 1948280fddf1ff9fd88eec9ca939f6a565d231f4 Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Mon, 27 May 2024 17:12:10 +0200 Subject: [PATCH 070/211] enable setting replace_long_file_name_to_hash by default --- src/Storages/MergeTree/MergeTreeSettings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Storages/MergeTree/MergeTreeSettings.h b/src/Storages/MergeTree/MergeTreeSettings.h index a00508fd1c1..2aa4934b683 100644 --- a/src/Storages/MergeTree/MergeTreeSettings.h +++ b/src/Storages/MergeTree/MergeTreeSettings.h @@ -35,7 +35,7 @@ struct Settings; M(UInt64, min_bytes_for_wide_part, 10485760, "Minimal uncompressed size in bytes to create part in wide format instead of compact", 0) \ M(UInt64, min_rows_for_wide_part, 0, "Minimal number of rows to create part in wide format instead of compact", 0) \ M(Float, ratio_of_defaults_for_sparse_serialization, 0.9375f, "Minimal ratio of number of default values to number of all values in column to store it in sparse serializations. If >= 1, columns will be always written in full serialization.", 0) \ - M(Bool, replace_long_file_name_to_hash, false, "If the file name for column is too long (more than 'max_file_name_length' bytes) replace it to SipHash128", 0) \ + M(Bool, replace_long_file_name_to_hash, true, "If the file name for column is too long (more than 'max_file_name_length' bytes) replace it to SipHash128", 0) \ M(UInt64, max_file_name_length, 127, "The maximal length of the file name to keep it as is without hashing", 0) \ M(UInt64, min_bytes_for_full_part_storage, 0, "Only available in ClickHouse Cloud", 0) \ M(UInt64, min_rows_for_full_part_storage, 0, "Only available in ClickHouse Cloud", 0) \ From 822a4d651399c7ceb18a6360d8f62482225273d2 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 27 May 2024 15:18:07 +0000 Subject: [PATCH 071/211] Split QueryAnalysisPass. --- .../QueryAnalysisPass.cpp => QueryAnalysis/TableExpressionData.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Analyzer/{Passes/QueryAnalysisPass.cpp => QueryAnalysis/TableExpressionData.h} (100%) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/QueryAnalysis/TableExpressionData.h similarity index 100% rename from src/Analyzer/Passes/QueryAnalysisPass.cpp rename to src/Analyzer/QueryAnalysis/TableExpressionData.h From b4189f65db8181f64817a3e7d1694883399096e9 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 27 May 2024 15:23:46 +0000 Subject: [PATCH 072/211] Split QueryAnalysisPass. --- .../QueryAnalysisPass.cpp => QueryAnalysis/ExpressionsStack.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Analyzer/{Passes/QueryAnalysisPass.cpp => QueryAnalysis/ExpressionsStack.h} (100%) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/QueryAnalysis/ExpressionsStack.h similarity index 100% rename from src/Analyzer/Passes/QueryAnalysisPass.cpp rename to src/Analyzer/QueryAnalysis/ExpressionsStack.h From e78ed2c54baae7bc42f2fc39e20f24d61acca631 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 27 May 2024 15:40:32 +0000 Subject: [PATCH 073/211] Split QueryAnalysisPass. --- .../QueryExpressionsAliasVisitor.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Analyzer/{Passes/QueryAnalysisPass.cpp => QueryAnalysis/QueryExpressionsAliasVisitor.h} (100%) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/QueryAnalysis/QueryExpressionsAliasVisitor.h similarity index 100% rename from src/Analyzer/Passes/QueryAnalysisPass.cpp rename to src/Analyzer/QueryAnalysis/QueryExpressionsAliasVisitor.h From 631421075ac39c40ecce3867922b1015c8159697 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 27 May 2024 15:41:49 +0000 Subject: [PATCH 074/211] Split QueryAnalysisPass. --- .../TableExpressionsAliasVisitor.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Analyzer/{Passes/QueryAnalysisPass.cpp => QueryAnalysis/TableExpressionsAliasVisitor.h} (100%) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/QueryAnalysis/TableExpressionsAliasVisitor.h similarity index 100% rename from src/Analyzer/Passes/QueryAnalysisPass.cpp rename to src/Analyzer/QueryAnalysis/TableExpressionsAliasVisitor.h From 3f9d330180feefbfa510ac49b22534a1f754d7c2 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Mon, 27 May 2024 18:39:18 +0200 Subject: [PATCH 075/211] Support different error handlings --- src/Functions/fromReadable.h | 95 ++++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 74c4a8958df..86d64dfa04b 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -1,12 +1,15 @@ #include #include +#include #include #include #include #include #include #include +#include "Common/Exception.h" +#include "DataTypes/DataTypeNullable.h" #include namespace DB @@ -18,13 +21,20 @@ namespace ErrorCodes extern const int CANNOT_PARSE_INPUT_ASSERTION_FAILED; } -template +enum class ErrorHandling : uint8_t +{ + Exception, + Zero, + Null +}; + +template class FunctionFromReadable : public IFunction { public: static constexpr auto name = Impl::name; - static FunctionPtr create(ContextPtr) { return std::make_shared>(); } + static FunctionPtr create(ContextPtr) { return std::make_shared>(); } String getName() const override { return name; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } @@ -38,52 +48,77 @@ public: {"readable_size", static_cast(&isString), nullptr, "String"}, }; validateFunctionArgumentTypes(*this, arguments, args); - - return std::make_shared(); + DataTypePtr return_type = std::make_shared(); + if (error_handling == ErrorHandling::Null) { + return std::make_shared(return_type); + } else { + return return_type; + } + } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { - auto col_to = ColumnFloat64::create(); - auto & res_data = col_to->getData(); + auto col_res = ColumnFloat64::create(); + auto & res_data = col_res->getData(); + + ColumnUInt8::MutablePtr col_null_map; + if constexpr (error_handling == ErrorHandling::Null) + col_null_map = ColumnUInt8::create(input_rows_count, 0); for (size_t i = 0; i < input_rows_count; ++i) { std::string_view str = arguments[0].column->getDataAt(i).toView(); - ReadBufferFromString buf(str); - // tryReadFloatText does seem to not raise any error when there is leading whitespace so we check it explicitly - skipWhitespaceIfAny(buf); - if (buf.getPosition() > 0) - throw_exception(ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED, "Leading whitespace is not allowed", str); - - Float64 base = 0; - if (!tryReadFloatTextPrecise(base, buf)) // If we use the default (fast) tryReadFloatText this returns True on garbage input - throw_exception(ErrorCodes::CANNOT_PARSE_NUMBER, "Unable to parse readable size numeric component", str); - - skipWhitespaceIfAny(buf); - - String unit; - readStringUntilWhitespace(unit, buf); - if (!buf.eof()) - throw_exception(ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, "Found trailing characters after readable size string", str); - boost::algorithm::to_lower(unit); - Float64 scale_factor = Impl::getScaleFactorForUnit(unit); - Float64 num_bytes = base * scale_factor; - - res_data.emplace_back(num_bytes); + try + { + auto num_bytes = parseReadableFormat(str); + res_data.emplace_back(num_bytes); + } + catch (...) + { + if constexpr (error_handling == ErrorHandling::Exception) + throw; + res_data[i] = 0; + if constexpr (error_handling == ErrorHandling::Null) + col_null_map->getData()[i] = 1; + } } - - return col_to; + if constexpr (error_handling == ErrorHandling::Null) + return ColumnNullable::create(std::move(col_res), std::move(col_null_map)); + else + return col_res; } private: template - void throw_exception(const int code, const String & msg, Arg arg) const + void throwException(const int code, const String & msg, Arg arg) const { throw Exception(code, "Invalid expression for function {} - {} (\"{}\")", getName(), msg, arg); } + + Float64 parseReadableFormat(const std::string_view & str) const + { + ReadBufferFromString buf(str); + // tryReadFloatText does seem to not raise any error when there is leading whitespace so we check it explicitly + skipWhitespaceIfAny(buf); + if (buf.getPosition() > 0) + throwException(ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED, "Leading whitespace is not allowed", str); + + Float64 base = 0; + if (!tryReadFloatTextPrecise(base, buf)) // If we use the default (fast) tryReadFloatText this returns True on garbage input + throwException(ErrorCodes::CANNOT_PARSE_NUMBER, "Unable to parse readable size numeric component", str); + skipWhitespaceIfAny(buf); + + String unit; + readStringUntilWhitespace(unit, buf); + if (!buf.eof()) + throwException(ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, "Found trailing characters after readable size string", str); + boost::algorithm::to_lower(unit); + Float64 scale_factor = Impl::getScaleFactorForUnit(unit); + return base * scale_factor; + } }; } From 48ca5d48b134a8ba0d427c5088f42d2787d155ef Mon Sep 17 00:00:00 2001 From: Jiebin Sun Date: Mon, 27 May 2024 22:27:58 +0800 Subject: [PATCH 076/211] Reduce the redundant `isDefault()` of `ColumnSparse::filter` to improve performance Add two methods in the Interator of ColumnSparse. Replace the `++offset_it` with `offset_it.increaseCurrentRow()` and `offset_it.increaseCurrentOffset()`, to remove the redundant `isDefault()` in `++` of `Interator` and reuse the following `isDefault()`. Test the patch with Q10 of ClickBench on 80x2 vCPUs and the QPS has got 9.6% performance gain. Signed-off-by: Jiebin Sun --- src/Columns/ColumnSparse.cpp | 5 ++++- src/Columns/ColumnSparse.h | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Columns/ColumnSparse.cpp b/src/Columns/ColumnSparse.cpp index 3a63d2bffc5..8f5639a2ff3 100644 --- a/src/Columns/ColumnSparse.cpp +++ b/src/Columns/ColumnSparse.cpp @@ -323,7 +323,9 @@ ColumnPtr ColumnSparse::filter(const Filter & filt, ssize_t) const size_t res_offset = 0; auto offset_it = begin(); - for (size_t i = 0; i < _size; ++i, ++offset_it) + /// Replace the `++offset_it` with `offset_it.increaseCurrentRow()` and `offset_it.increaseCurrentOffset()`, + /// to remove the redundant `isDefault()` in `++` of `Interator` and reuse the following `isDefault()`. + for (size_t i = 0; i < _size; ++i, offset_it.increaseCurrentRow()) { if (!offset_it.isDefault()) { @@ -338,6 +340,7 @@ ColumnPtr ColumnSparse::filter(const Filter & filt, ssize_t) const { values_filter.push_back(0); } + offset_it.increaseCurrentOffset(); } else { diff --git a/src/Columns/ColumnSparse.h b/src/Columns/ColumnSparse.h index c1bd614102c..e5e554b4c40 100644 --- a/src/Columns/ColumnSparse.h +++ b/src/Columns/ColumnSparse.h @@ -186,6 +186,8 @@ public: size_t ALWAYS_INLINE getValueIndex() const { return isDefault() ? 0 : current_offset + 1; } size_t ALWAYS_INLINE getCurrentRow() const { return current_row; } size_t ALWAYS_INLINE getCurrentOffset() const { return current_offset; } + size_t ALWAYS_INLINE increaseCurrentRow() { return ++current_row; } + size_t ALWAYS_INLINE increaseCurrentOffset() { return ++current_offset; } bool operator==(const Iterator & other) const { From f5a80dfcf575b6f3debe745707de0ae5e1d803d1 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 07:55:20 +0200 Subject: [PATCH 077/211] Add support for orZero and orNull to both flavours of fromReadable --- src/Functions/fromReadable.h | 29 +++++++++----- src/Functions/fromReadableDecimalSize.cpp | 45 ++++++++++++---------- src/Functions/fromReadableSize.cpp | 46 +++++++++++++---------- 3 files changed, 71 insertions(+), 49 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 86d64dfa04b..c4348df4149 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -19,6 +19,7 @@ namespace ErrorCodes { extern const int UNEXPECTED_DATA_AFTER_PARSED_VALUE; extern const int CANNOT_PARSE_INPUT_ASSERTION_FAILED; + extern const int CANNOT_PARSE_TEXT; } enum class ErrorHandling : uint8_t @@ -28,13 +29,12 @@ enum class ErrorHandling : uint8_t Null }; -template +template class FunctionFromReadable : public IFunction { public: - static constexpr auto name = Impl::name; - - static FunctionPtr create(ContextPtr) { return std::make_shared>(); } + static constexpr auto name = Name::name; + static FunctionPtr create(ContextPtr) { return std::make_shared>(); } String getName() const override { return name; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } @@ -60,20 +60,21 @@ public: ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { - auto col_res = ColumnFloat64::create(); - auto & res_data = col_res->getData(); + auto col_res = ColumnFloat64::create(input_rows_count); ColumnUInt8::MutablePtr col_null_map; if constexpr (error_handling == ErrorHandling::Null) col_null_map = ColumnUInt8::create(input_rows_count, 0); + auto & res_data = col_res->getData(); + for (size_t i = 0; i < input_rows_count; ++i) { std::string_view str = arguments[0].column->getDataAt(i).toView(); try { auto num_bytes = parseReadableFormat(str); - res_data.emplace_back(num_bytes); + res_data[i] = num_bytes; } catch (...) { @@ -117,8 +118,18 @@ private: if (!buf.eof()) throwException(ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, "Found trailing characters after readable size string", str); boost::algorithm::to_lower(unit); - Float64 scale_factor = Impl::getScaleFactorForUnit(unit); - return base * scale_factor; + std::unordered_map scale_factors = Impl::getScaleFactors(); + auto iter = scale_factors.find(unit); + if (iter == scale_factors.end()) + { + throw Exception( + ErrorCodes::CANNOT_PARSE_TEXT, + "Invalid expression for function {} - Unknown readable size unit (\"{}\")", + getName(), + unit + ); + } + return base * iter->second; } }; } diff --git a/src/Functions/fromReadableDecimalSize.cpp b/src/Functions/fromReadableDecimalSize.cpp index 3665db35c31..0662fb76148 100644 --- a/src/Functions/fromReadableDecimalSize.cpp +++ b/src/Functions/fromReadableDecimalSize.cpp @@ -4,10 +4,6 @@ namespace DB { -namespace ErrorCodes -{ - extern const int CANNOT_PARSE_TEXT; -} namespace { @@ -26,29 +22,36 @@ const std::unordered_map scale_factors = struct Impl { - static constexpr auto name = "fromReadableDecimalSize"; - - static Float64 getScaleFactorForUnit(const String & unit) // Assumes the unit is already in lowercase + static const std::unordered_map & getScaleFactors() { - auto iter = scale_factors.find(unit); - if (iter == scale_factors.end()) - { - throw Exception( - ErrorCodes::CANNOT_PARSE_TEXT, - "Invalid expression for function {} - Unknown readable size unit (\"{}\")", - name, - unit - ); - } - return iter->second; + return scale_factors; } - }; + +struct NameFromReadableDecimalSize +{ + static constexpr auto name = "fromReadableDecimalSize"; +}; + +struct NameFromReadableDecimalSizeOrNull +{ + static constexpr auto name = "fromReadableDecimalSizeOrNull"; +}; + +struct NameFromReadableDecimalSizeOrZero +{ + static constexpr auto name = "fromReadableDecimalSizeOrZero"; +}; + +using FunctionFromReadableDecimalSize = FunctionFromReadable; +using FunctionFromReadableDecimalSizeOrNull = FunctionFromReadable; +using FunctionFromReadableDecimalSizeOrZero = FunctionFromReadable; + } REGISTER_FUNCTION(FromReadableDecimalSize) { - factory.registerFunction>(FunctionDocumentation + factory.registerFunction(FunctionDocumentation { .description=R"( Given a string containing the readable representation of a byte size, this function returns the corresponding number of bytes: @@ -65,6 +68,8 @@ Accepts readable sizes up to the Exabyte (EB/EiB). .categories{"OtherFunctions"} } ); + factory.registerFunction(); + factory.registerFunction(); } } diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index 441c861d582..b3061f2c9d4 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -4,10 +4,6 @@ namespace DB { -namespace ErrorCodes -{ - extern const int CANNOT_PARSE_TEXT; -} namespace { @@ -26,29 +22,38 @@ const std::unordered_map scale_factors = struct Impl { - static constexpr auto name = "fromReadableSize"; - - static Float64 getScaleFactorForUnit(const String & unit) // Assumes the unit is already in lowercase + static const std::unordered_map & getScaleFactors() { - auto iter = scale_factors.find(unit); - if (iter == scale_factors.end()) - { - throw Exception( - ErrorCodes::CANNOT_PARSE_TEXT, - "Invalid expression for function {} - Unknown readable size unit (\"{}\")", - name, - unit - ); - } - return iter->second; + return scale_factors; } }; + + +struct NameFromReadableSize +{ + static constexpr auto name = "fromReadableSize"; +}; + +struct NameFromReadableSizeOrNull +{ + static constexpr auto name = "fromReadableSizeOrNull"; +}; + +struct NameFromReadableSizeOrZero +{ + static constexpr auto name = "fromReadableSizeOrZero"; +}; + +using FunctionFromReadableSize = FunctionFromReadable; +using FunctionFromReadableSizeOrNull = FunctionFromReadable; +using FunctionFromReadableSizeOrZero = FunctionFromReadable; + } REGISTER_FUNCTION(FromReadableSize) { - factory.registerFunction>(FunctionDocumentation + factory.registerFunction(FunctionDocumentation { .description=R"( Given a string containing the readable representation of a byte size, this function returns the corresponding number of bytes: @@ -65,6 +70,7 @@ Accepts readable sizes up to the Exabyte (EB/EiB). .categories{"OtherFunctions"} } ); + factory.registerFunction(); + factory.registerFunction(); } - } From 8608d457ad7b257cd29fa8c3323d99e898904103 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 08:01:58 +0200 Subject: [PATCH 078/211] Add check to ensure column passed to function implementation is of type String --- src/Functions/fromReadable.h | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index c4348df4149..5c49d75d183 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -3,13 +3,14 @@ #include #include +#include +#include +#include #include #include #include #include #include -#include "Common/Exception.h" -#include "DataTypes/DataTypeNullable.h" #include namespace DB @@ -20,6 +21,7 @@ namespace ErrorCodes extern const int UNEXPECTED_DATA_AFTER_PARSED_VALUE; extern const int CANNOT_PARSE_INPUT_ASSERTION_FAILED; extern const int CANNOT_PARSE_TEXT; + extern const int ILLEGAL_COLUMN; } enum class ErrorHandling : uint8_t @@ -60,6 +62,15 @@ public: ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { + + const auto * col_str = checkAndGetColumn(arguments[0].column.get()); + if (!col_str) + throw Exception( + ErrorCodes::ILLEGAL_COLUMN, + "Illegal column {} of first ('str') argument of function {}. Must be string.", + arguments[0].column->getName(), + getName()); + auto col_res = ColumnFloat64::create(input_rows_count); ColumnUInt8::MutablePtr col_null_map; @@ -70,7 +81,7 @@ public: for (size_t i = 0; i < input_rows_count; ++i) { - std::string_view str = arguments[0].column->getDataAt(i).toView(); + std::string_view str = col_str->getDataAt(i).toView(); try { auto num_bytes = parseReadableFormat(str); From 28464d385de9b3c86e50d8a5a561ed81741d833d Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 08:10:00 +0200 Subject: [PATCH 079/211] Add tests for the orNull and orZero flavours of fromReadableSize --- .../03166_from_readable_size.reference | 22 ++++++++++++++++ .../0_stateless/03166_from_readable_size.sql | 25 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/tests/queries/0_stateless/03166_from_readable_size.reference b/tests/queries/0_stateless/03166_from_readable_size.reference index c79f29c2851..57897e1c450 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.reference +++ b/tests/queries/0_stateless/03166_from_readable_size.reference @@ -15,3 +15,25 @@ 1024 1024 \N +1 B 1 +1 KiB 1024 +1 MiB 1048576 +1 GiB 1073741824 +1 TiB 1099511627776 +1 PiB 1125899906842624 +1 EiB 1152921504606847000 +invalid \N +1 Joe \N + 1 GiB \N +1 TiB with fries \N +1 B 1 +1 KiB 1024 +1 MiB 1048576 +1 GiB 1073741824 +1 TiB 1099511627776 +1 PiB 1125899906842624 +1 EiB 1152921504606847000 +invalid 0 +1 Joe 0 + 1 GiB 0 +1 TiB with fries 0 diff --git a/tests/queries/0_stateless/03166_from_readable_size.sql b/tests/queries/0_stateless/03166_from_readable_size.sql index f16dd9825e1..a099aaa6e9c 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.sql +++ b/tests/queries/0_stateless/03166_from_readable_size.sql @@ -48,3 +48,28 @@ SELECT fromReadableSize('12.3 rb'); -- { serverError CANNOT_PARSE_TEXT } SELECT fromReadableSize(' 1 B'); -- { serverError CANNOT_PARSE_INPUT_ASSERTION_FAILED } -- Invalid input - Trailing characters SELECT fromReadableSize('1 B leftovers'); -- { serverError UNEXPECTED_DATA_AFTER_PARSED_VALUE } + + +-- OR NULL +-- Works as the regular version when inputs are correct +SELECT + arrayJoin(['1 B', '1 KiB', '1 MiB', '1 GiB', '1 TiB', '1 PiB', '1 EiB']) AS readable_sizes, + fromReadableSizeOrNull(readable_sizes) AS filesize; + +-- Returns NULL on invalid values +SELECT + arrayJoin(['invalid', '1 Joe', ' 1 GiB', '1 TiB with fries']) AS readable_sizes, + fromReadableSizeOrNull(readable_sizes) AS filesize; + + +-- OR ZERO +-- Works as the regular version when inputs are correct +SELECT + arrayJoin(['1 B', '1 KiB', '1 MiB', '1 GiB', '1 TiB', '1 PiB', '1 EiB']) AS readable_sizes, + fromReadableSizeOrZero(readable_sizes) AS filesize; + +-- Returns NULL on invalid values +SELECT + arrayJoin(['invalid', '1 Joe', ' 1 GiB', '1 TiB with fries']) AS readable_sizes, + fromReadableSizeOrZero(readable_sizes) AS filesize; + From 5aa38b6dd8615c693470df17ad0adb145cb450df Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 08:13:45 +0200 Subject: [PATCH 080/211] Add orZero and orNull flavours to fromReadableDecimal tests --- ...03167_from_readable_decimal_size.reference | 24 +++++++++++++++++ .../03167_from_readable_decimal_size.sql | 27 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/tests/queries/0_stateless/03167_from_readable_decimal_size.reference b/tests/queries/0_stateless/03167_from_readable_decimal_size.reference index c360a43ae02..fa8b76e7783 100644 --- a/tests/queries/0_stateless/03167_from_readable_decimal_size.reference +++ b/tests/queries/0_stateless/03167_from_readable_decimal_size.reference @@ -15,3 +15,27 @@ 1000 1000 \N +1 B 1 +1 KB 1000 +1 MB 1000000 +1 GB 1000000000 +1 TB 1000000000000 +1 PB 1000000000000000 +1 EB 1000000000000000000 +invalid \N +1 Joe \N +1 KiB \N + 1 GB \N +1 TB with fries \N +1 B 1 +1 KB 1000 +1 MB 1000000 +1 GB 1000000000 +1 TB 1000000000000 +1 PB 1000000000000000 +1 EB 1000000000000000000 +invalid 0 +1 Joe 0 +1 KiB 0 + 1 GiB 0 +1 TiB with fries 0 diff --git a/tests/queries/0_stateless/03167_from_readable_decimal_size.sql b/tests/queries/0_stateless/03167_from_readable_decimal_size.sql index dbbcd835d71..091f8c020d5 100644 --- a/tests/queries/0_stateless/03167_from_readable_decimal_size.sql +++ b/tests/queries/0_stateless/03167_from_readable_decimal_size.sql @@ -48,3 +48,30 @@ SELECT fromReadableDecimalSize('12.3 rb'); -- { serverError CANNOT_PARSE_TEXT } SELECT fromReadableDecimalSize(' 1 B'); -- { serverError CANNOT_PARSE_INPUT_ASSERTION_FAILED } -- Invalid input - Trailing characters SELECT fromReadableDecimalSize('1 B leftovers'); -- { serverError UNEXPECTED_DATA_AFTER_PARSED_VALUE } +-- Invalid input - Binary size unit is not accepted +SELECT fromReadableDecimalSize('1 KiB'); -- { serverError CANNOT_PARSE_TEXT } + + +-- OR NULL +-- Works as the regular version when inputs are correct +SELECT + arrayJoin(['1 B', '1 KB', '1 MB', '1 GB', '1 TB', '1 PB', '1 EB']) AS readable_sizes, + fromReadableDecimalSizeOrNull(readable_sizes) AS filesize; + +-- Returns NULL on invalid values +SELECT + arrayJoin(['invalid', '1 Joe', '1 KiB', ' 1 GB', '1 TB with fries']) AS readable_sizes, + fromReadableDecimalSizeOrNull(readable_sizes) AS filesize; + + +-- OR ZERO +-- Works as the regular version when inputs are correct +SELECT + arrayJoin(['1 B', '1 KB', '1 MB', '1 GB', '1 TB', '1 PB', '1 EB']) AS readable_sizes, + fromReadableDecimalSizeOrZero(readable_sizes) AS filesize; + +-- Returns NULL on invalid values +SELECT + arrayJoin(['invalid', '1 Joe', '1 KiB', ' 1 GiB', '1 TiB with fries']) AS readable_sizes, + fromReadableDecimalSizeOrZero(readable_sizes) AS filesize; + From 8d684cef3b504d80e970b5e029bb60791c46cc07 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 08:16:42 +0200 Subject: [PATCH 081/211] Sync new tests from formatreadabledecimal --- .../queries/0_stateless/03166_from_readable_size.reference | 2 ++ tests/queries/0_stateless/03166_from_readable_size.sql | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/queries/0_stateless/03166_from_readable_size.reference b/tests/queries/0_stateless/03166_from_readable_size.reference index 57897e1c450..8603bf49273 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.reference +++ b/tests/queries/0_stateless/03166_from_readable_size.reference @@ -24,6 +24,7 @@ 1 EiB 1152921504606847000 invalid \N 1 Joe \N +1KB \N 1 GiB \N 1 TiB with fries \N 1 B 1 @@ -35,5 +36,6 @@ invalid \N 1 EiB 1152921504606847000 invalid 0 1 Joe 0 +1KB 0 1 GiB 0 1 TiB with fries 0 diff --git a/tests/queries/0_stateless/03166_from_readable_size.sql b/tests/queries/0_stateless/03166_from_readable_size.sql index a099aaa6e9c..2be570f7d7a 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.sql +++ b/tests/queries/0_stateless/03166_from_readable_size.sql @@ -48,6 +48,8 @@ SELECT fromReadableSize('12.3 rb'); -- { serverError CANNOT_PARSE_TEXT } SELECT fromReadableSize(' 1 B'); -- { serverError CANNOT_PARSE_INPUT_ASSERTION_FAILED } -- Invalid input - Trailing characters SELECT fromReadableSize('1 B leftovers'); -- { serverError UNEXPECTED_DATA_AFTER_PARSED_VALUE } +-- Invalid input - Decimal size unit is not accepted +SELECT fromReadableSize('1 KB'); -- { serverError CANNOT_PARSE_TEXT } -- OR NULL @@ -58,7 +60,7 @@ SELECT -- Returns NULL on invalid values SELECT - arrayJoin(['invalid', '1 Joe', ' 1 GiB', '1 TiB with fries']) AS readable_sizes, + arrayJoin(['invalid', '1 Joe', '1KB', ' 1 GiB', '1 TiB with fries']) AS readable_sizes, fromReadableSizeOrNull(readable_sizes) AS filesize; @@ -70,6 +72,6 @@ SELECT -- Returns NULL on invalid values SELECT - arrayJoin(['invalid', '1 Joe', ' 1 GiB', '1 TiB with fries']) AS readable_sizes, + arrayJoin(['invalid', '1 Joe', '1KB', ' 1 GiB', '1 TiB with fries']) AS readable_sizes, fromReadableSizeOrZero(readable_sizes) AS filesize; From e973155d81f20116c4cb373e47030f739691f32d Mon Sep 17 00:00:00 2001 From: Shaun Struwig <41984034+Blargian@users.noreply.github.com> Date: Tue, 28 May 2024 08:39:50 +0200 Subject: [PATCH 082/211] Update aspell-dict.txt --- utils/check-style/aspell-ignore/en/aspell-dict.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/check-style/aspell-ignore/en/aspell-dict.txt b/utils/check-style/aspell-ignore/en/aspell-dict.txt index 9d5ae17b156..f849d12b0e3 100644 --- a/utils/check-style/aspell-ignore/en/aspell-dict.txt +++ b/utils/check-style/aspell-ignore/en/aspell-dict.txt @@ -2652,6 +2652,9 @@ toStartOfSecond toStartOfTenMinutes toStartOfWeek toStartOfYear +toStartOfMicrosecond +toStartOfMillisecond +toStartOfNanosecond toString toStringCutToZero toTime From 304dc52b3ac339579c8b6d45dfb41d5de8bc6f70 Mon Sep 17 00:00:00 2001 From: Blargian Date: Tue, 28 May 2024 09:02:21 +0200 Subject: [PATCH 083/211] Add missing topLevelDomainRFC --- .../sql-reference/functions/url-functions.md | 55 +++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/docs/en/sql-reference/functions/url-functions.md b/docs/en/sql-reference/functions/url-functions.md index a0b0170721c..1af87db3bf8 100644 --- a/docs/en/sql-reference/functions/url-functions.md +++ b/docs/en/sql-reference/functions/url-functions.md @@ -79,8 +79,9 @@ topLevelDomain(url) **Arguments** -- `url` — URL. Type: [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). +:::note The URL can be specified with or without a scheme. Examples: ``` text @@ -88,26 +89,70 @@ svn+ssh://some.svn-hosting.com:80/repo/trunk some.svn-hosting.com:80/repo/trunk https://clickhouse.com/time/ ``` +::: **Returned values** -- Domain name. If ClickHouse can parse the input string as a URL. -- Empty string. If ClickHouse cannot parse the input string as a URL. - -Type: `String`. +- Domain name if ClickHouse can parse the input string as a URL. Otherwise, an empty string. [String](../../sql-reference/data-types/string.md). **Example** +Query: + ``` sql SELECT topLevelDomain('svn+ssh://www.some.svn-hosting.com:80/repo/trunk'); ``` +Result: + ``` text ┌─topLevelDomain('svn+ssh://www.some.svn-hosting.com:80/repo/trunk')─┐ │ com │ └────────────────────────────────────────────────────────────────────┘ ``` +### topLevelDomainRFC + +Extracts the the top-level domain from a URL. It is similar to [topLevelDomain](#topleveldomain), but conforms to RFC 3986. + +``` sql +topLevelDomainRFC(url) +``` + +**Arguments** + +- `url` — URL. [String](../../sql-reference/data-types/string.md). + +:::note +The URL can be specified with or without a scheme. Examples: + +``` text +svn+ssh://some.svn-hosting.com:80/repo/trunk +some.svn-hosting.com:80/repo/trunk +https://clickhouse.com/time/ +``` +::: + +**Returned values** + +- Domain name if ClickHouse can parse the input string as a URL. Otherwise, an empty string. [String](../../sql-reference/data-types/string.md). + +**Example** + +Query: + +``` sql +SELECT topLevelDomainRFC('svn+ssh://www.some.svn-hosting.com:80/repo/trunk'); +``` + +Result: + +``` text +┌─topLevelDomainRFC('svn+ssh://www.some.svn-hosting.com:80/repo/trunk')─┐ +│ com │ +└───────────────────────────────────────────────────────────────────────┘ +``` + ### firstSignificantSubdomain Returns the “first significant subdomain”. The first significant subdomain is a second-level domain if it is ‘com’, ‘net’, ‘org’, or ‘co’. Otherwise, it is a third-level domain. For example, `firstSignificantSubdomain (‘https://news.clickhouse.com/’) = ‘clickhouse’, firstSignificantSubdomain (‘https://news.clickhouse.com.tr/’) = ‘clickhouse’`. The list of “insignificant” second-level domains and other implementation details may change in the future. From ad647786a1d06b6514adb3c8013b40809f79440e Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 09:26:07 +0200 Subject: [PATCH 084/211] Move scale factor pull out of the parsing loop --- src/Functions/fromReadable.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 5c49d75d183..1d32db0bf36 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -70,6 +70,8 @@ public: "Illegal column {} of first ('str') argument of function {}. Must be string.", arguments[0].column->getName(), getName()); + + std::unordered_map scale_factors = Impl::getScaleFactors(); auto col_res = ColumnFloat64::create(input_rows_count); @@ -84,7 +86,7 @@ public: std::string_view str = col_str->getDataAt(i).toView(); try { - auto num_bytes = parseReadableFormat(str); + auto num_bytes = parseReadableFormat(scale_factors, str); res_data[i] = num_bytes; } catch (...) @@ -111,7 +113,7 @@ private: throw Exception(code, "Invalid expression for function {} - {} (\"{}\")", getName(), msg, arg); } - Float64 parseReadableFormat(const std::string_view & str) const + Float64 parseReadableFormat(const std::unordered_map & scale_factors, const std::string_view & str) const { ReadBufferFromString buf(str); // tryReadFloatText does seem to not raise any error when there is leading whitespace so we check it explicitly @@ -129,7 +131,6 @@ private: if (!buf.eof()) throwException(ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, "Found trailing characters after readable size string", str); boost::algorithm::to_lower(unit); - std::unordered_map scale_factors = Impl::getScaleFactors(); auto iter = scale_factors.find(unit); if (iter == scale_factors.end()) { From b05501f82ca34d779d6a76846e8b5e07240c7457 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 09:28:26 +0200 Subject: [PATCH 085/211] Explicit else in exception handling --- src/Functions/fromReadable.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 1d32db0bf36..d073c33273a 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -91,11 +91,13 @@ public: } catch (...) { - if constexpr (error_handling == ErrorHandling::Exception) - throw; - res_data[i] = 0; - if constexpr (error_handling == ErrorHandling::Null) - col_null_map->getData()[i] = 1; + if constexpr (error_handling == ErrorHandling::Exception) { throw; } + else + { + res_data[i] = 0; + if constexpr (error_handling == ErrorHandling::Null) + col_null_map->getData()[i] = 1; + } } } if constexpr (error_handling == ErrorHandling::Null) From 64532f8484a50f99cfdbcc21b2956cc648aa2d84 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 09:32:41 +0200 Subject: [PATCH 086/211] Inline throw exceptions --- src/Functions/fromReadable.h | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index d073c33273a..d2d647ca17d 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -109,29 +109,45 @@ public: private: - template - void throwException(const int code, const String & msg, Arg arg) const - { - throw Exception(code, "Invalid expression for function {} - {} (\"{}\")", getName(), msg, arg); - } - Float64 parseReadableFormat(const std::unordered_map & scale_factors, const std::string_view & str) const { ReadBufferFromString buf(str); // tryReadFloatText does seem to not raise any error when there is leading whitespace so we check it explicitly skipWhitespaceIfAny(buf); if (buf.getPosition() > 0) - throwException(ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED, "Leading whitespace is not allowed", str); + { + throw Exception( + ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED, + "Invalid expression for function {} - Leading whitespace is not allowed (\"{}\")", + getName(), + str + ); + } Float64 base = 0; if (!tryReadFloatTextPrecise(base, buf)) // If we use the default (fast) tryReadFloatText this returns True on garbage input - throwException(ErrorCodes::CANNOT_PARSE_NUMBER, "Unable to parse readable size numeric component", str); + { + throw Exception( + ErrorCodes::CANNOT_PARSE_NUMBER, + "Invalid expression for function {} - Unable to parse readable size numeric component (\"{}\")", + getName(), + str + ); + } + skipWhitespaceIfAny(buf); String unit; readStringUntilWhitespace(unit, buf); if (!buf.eof()) - throwException(ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, "Found trailing characters after readable size string", str); + { + throw Exception( + ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, + "Invalid expression for function {} - Found trailing characters after readable size string (\"{}\")", + getName(), + str + ); + } boost::algorithm::to_lower(unit); auto iter = scale_factors.find(unit); if (iter == scale_factors.end()) From ac8186d02fde9cabb1e9122563430c9f5727bc13 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 09:33:47 +0200 Subject: [PATCH 087/211] Add missing brackets --- src/Functions/fromReadable.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index d2d647ca17d..0c79223d31e 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -65,11 +65,14 @@ public: const auto * col_str = checkAndGetColumn(arguments[0].column.get()); if (!col_str) + { throw Exception( ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of first ('str') argument of function {}. Must be string.", arguments[0].column->getName(), - getName()); + getName() + ); + } std::unordered_map scale_factors = Impl::getScaleFactors(); From ef42050ce05622fb61a7179864cdbc79efe1569d Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 09:48:34 +0200 Subject: [PATCH 088/211] Make fromReadableSize return UInt64 again --- src/Functions/fromReadable.h | 31 +++++++++++++++++++---- src/Functions/fromReadableDecimalSize.cpp | 18 ++++++------- src/Functions/fromReadableSize.cpp | 18 ++++++------- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 0c79223d31e..e8a9b94e21c 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -50,7 +50,7 @@ public: {"readable_size", static_cast(&isString), nullptr, "String"}, }; validateFunctionArgumentTypes(*this, arguments, args); - DataTypePtr return_type = std::make_shared(); + DataTypePtr return_type = std::make_shared(); if (error_handling == ErrorHandling::Null) { return std::make_shared(return_type); } else { @@ -74,9 +74,9 @@ public: ); } - std::unordered_map scale_factors = Impl::getScaleFactors(); + std::unordered_map scale_factors = Impl::getScaleFactors(); - auto col_res = ColumnFloat64::create(input_rows_count); + auto col_res = ColumnUInt64::create(input_rows_count); ColumnUInt8::MutablePtr col_null_map; if constexpr (error_handling == ErrorHandling::Null) @@ -112,7 +112,7 @@ public: private: - Float64 parseReadableFormat(const std::unordered_map & scale_factors, const std::string_view & str) const + UInt64 parseReadableFormat(const std::unordered_map & scale_factors, const std::string_view & str) const { ReadBufferFromString buf(str); // tryReadFloatText does seem to not raise any error when there is leading whitespace so we check it explicitly @@ -137,6 +137,15 @@ private: str ); } + else if (base < 0) + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {} - Negative sizes are not allowed (\"{}\")", + getName(), + base + ); + } skipWhitespaceIfAny(buf); @@ -162,7 +171,19 @@ private: unit ); } - return base * iter->second; + Float64 num_bytes_with_decimals = base * iter->second; + if (num_bytes_with_decimals > std::numeric_limits::max()) + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {} - Result is too big for output type (\"{}\")", + getName(), + num_bytes_with_decimals + ); + } + // As the input might be an arbitrary decimal number we might end up with a non-integer amount of bytes when parsing binary (eg MiB) units. + // This doesn't make sense so we round up to indicate the byte size that can fit the passed size. + return static_cast(std::ceil(num_bytes_with_decimals)); } }; } diff --git a/src/Functions/fromReadableDecimalSize.cpp b/src/Functions/fromReadableDecimalSize.cpp index 0662fb76148..5093e31685d 100644 --- a/src/Functions/fromReadableDecimalSize.cpp +++ b/src/Functions/fromReadableDecimalSize.cpp @@ -9,20 +9,20 @@ namespace { // ISO/IEC 80000-13 binary units -const std::unordered_map scale_factors = +const std::unordered_map scale_factors = { - {"b", 1.0}, - {"kb", 1000.0}, - {"mb", 1000.0 * 1000.0}, - {"gb", 1000.0 * 1000.0 * 1000.0}, - {"tb", 1000.0 * 1000.0 * 1000.0 * 1000.0}, - {"pb", 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0}, - {"eb", 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0}, + {"b", 1L}, + {"kb", 1000L}, + {"mb", 1000L * 1000L}, + {"gb", 1000L * 1000L * 1000L}, + {"tb", 1000L * 1000L * 1000L * 1000L}, + {"pb", 1000L * 1000L * 1000L * 1000L * 1000L}, + {"eb", 1000L * 1000L * 1000L * 1000L * 1000L * 1000L}, }; struct Impl { - static const std::unordered_map & getScaleFactors() + static const std::unordered_map & getScaleFactors() { return scale_factors; } diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index b3061f2c9d4..841417e0e87 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -9,20 +9,20 @@ namespace { // ISO/IEC 80000-13 binary units -const std::unordered_map scale_factors = +const std::unordered_map scale_factors = { - {"b", 1.0}, - {"kib", 1024.0}, - {"mib", 1024.0 * 1024.0}, - {"gib", 1024.0 * 1024.0 * 1024.0}, - {"tib", 1024.0 * 1024.0 * 1024.0 * 1024.0}, - {"pib", 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0}, - {"eib", 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0}, + {"b", 1L}, + {"kib", 1024L}, + {"mib", 1024L * 1024L}, + {"gib", 1024L * 1024L * 1024L}, + {"tib", 1024L * 1024L * 1024L * 1024L}, + {"pib", 1024L * 1024L * 1024L * 1024L * 1024L}, + {"eib", 1024L * 1024L * 1024L * 1024L * 1024L * 1024L}, }; struct Impl { - static const std::unordered_map & getScaleFactors() + static const std::unordered_map & getScaleFactors() { return scale_factors; } From 35ce67a76eff608c9af87680788e754f0f49a85c Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 09:54:52 +0200 Subject: [PATCH 089/211] Add tests for new UInt64 logic --- .../queries/0_stateless/03166_from_readable_size.reference | 5 ++--- tests/queries/0_stateless/03166_from_readable_size.sql | 7 ++++--- .../0_stateless/03167_from_readable_decimal_size.reference | 1 - .../0_stateless/03167_from_readable_decimal_size.sql | 7 ++++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/queries/0_stateless/03166_from_readable_size.reference b/tests/queries/0_stateless/03166_from_readable_size.reference index 8603bf49273..ad6d0f23a30 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.reference +++ b/tests/queries/0_stateless/03166_from_readable_size.reference @@ -8,7 +8,6 @@ 1.00 MiB 1024 3072 --1024 1024 1024 1024 @@ -21,7 +20,7 @@ 1 GiB 1073741824 1 TiB 1099511627776 1 PiB 1125899906842624 -1 EiB 1152921504606847000 +1 EiB 1152921504606846976 invalid \N 1 Joe \N 1KB \N @@ -33,7 +32,7 @@ invalid \N 1 GiB 1073741824 1 TiB 1099511627776 1 PiB 1125899906842624 -1 EiB 1152921504606847000 +1 EiB 1152921504606846976 invalid 0 1 Joe 0 1KB 0 diff --git a/tests/queries/0_stateless/03166_from_readable_size.sql b/tests/queries/0_stateless/03166_from_readable_size.sql index 2be570f7d7a..41a042bb1d5 100644 --- a/tests/queries/0_stateless/03166_from_readable_size.sql +++ b/tests/queries/0_stateless/03166_from_readable_size.sql @@ -14,9 +14,6 @@ SELECT formatReadableSize(fromReadableSize('1 mIb')); SELECT fromReadableSize('1.00 KiB'); -- 1024 SELECT fromReadableSize('3.00 KiB'); -- 3072 --- Should be able to parse negative numbers -SELECT fromReadableSize('-1.00 KiB'); -- 1024 - -- Infix whitespace is ignored SELECT fromReadableSize('1 KiB'); SELECT fromReadableSize('1KiB'); @@ -50,6 +47,10 @@ SELECT fromReadableSize(' 1 B'); -- { serverError CANNOT_PARSE_INPUT_ASSERTION_F SELECT fromReadableSize('1 B leftovers'); -- { serverError UNEXPECTED_DATA_AFTER_PARSED_VALUE } -- Invalid input - Decimal size unit is not accepted SELECT fromReadableSize('1 KB'); -- { serverError CANNOT_PARSE_TEXT } +-- Invalid input - Negative sizes are not allowed +SELECT fromReadableSize('-1 KiB'); -- { serverError BAD_ARGUMENTS } +-- Invalid input - Input too large to fit in UInt64 +SELECT fromReadableSize('1000 EiB'); -- { serverError BAD_ARGUMENTS } -- OR NULL diff --git a/tests/queries/0_stateless/03167_from_readable_decimal_size.reference b/tests/queries/0_stateless/03167_from_readable_decimal_size.reference index fa8b76e7783..dec92c16499 100644 --- a/tests/queries/0_stateless/03167_from_readable_decimal_size.reference +++ b/tests/queries/0_stateless/03167_from_readable_decimal_size.reference @@ -8,7 +8,6 @@ 1.00 MB 1000 3000 --1000 1000 1000 1000 diff --git a/tests/queries/0_stateless/03167_from_readable_decimal_size.sql b/tests/queries/0_stateless/03167_from_readable_decimal_size.sql index 091f8c020d5..7252547e628 100644 --- a/tests/queries/0_stateless/03167_from_readable_decimal_size.sql +++ b/tests/queries/0_stateless/03167_from_readable_decimal_size.sql @@ -14,9 +14,6 @@ SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 mb')); SELECT fromReadableDecimalSize('1.00 KB'); -- 1024 SELECT fromReadableDecimalSize('3.00 KB'); -- 3072 --- Should be able to parse negative numbers -SELECT fromReadableDecimalSize('-1.00 KB'); -- 1024 - -- Infix whitespace is ignored SELECT fromReadableDecimalSize('1 KB'); SELECT fromReadableDecimalSize('1KB'); @@ -50,6 +47,10 @@ SELECT fromReadableDecimalSize(' 1 B'); -- { serverError CANNOT_PARSE_INPUT_ASSE SELECT fromReadableDecimalSize('1 B leftovers'); -- { serverError UNEXPECTED_DATA_AFTER_PARSED_VALUE } -- Invalid input - Binary size unit is not accepted SELECT fromReadableDecimalSize('1 KiB'); -- { serverError CANNOT_PARSE_TEXT } +-- Invalid input - Negative sizes are not allowed +SELECT fromReadableDecimalSize('-1 KB'); -- { serverError BAD_ARGUMENTS } +-- Invalid input - Input too large to fit in UInt64 +SELECT fromReadableDecimalSize('1000 EB'); -- { serverError BAD_ARGUMENTS } -- OR NULL From 5bfdebde86e89f251234cb67a3156ee1e1b30457 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 09:57:44 +0200 Subject: [PATCH 090/211] Rename test files --- ...m_readable_size.reference => 03166_fromReadableSize.reference} | 0 .../{03166_from_readable_size.sql => 03166_fromReadableSize.sql} | 0 ...mal_size.reference => 03167_fromReadableDecimalSize.reference} | 0 ...eadable_decimal_size.sql => 03167_fromReadableDecimalSize.sql} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename tests/queries/0_stateless/{03166_from_readable_size.reference => 03166_fromReadableSize.reference} (100%) rename tests/queries/0_stateless/{03166_from_readable_size.sql => 03166_fromReadableSize.sql} (100%) rename tests/queries/0_stateless/{03167_from_readable_decimal_size.reference => 03167_fromReadableDecimalSize.reference} (100%) rename tests/queries/0_stateless/{03167_from_readable_decimal_size.sql => 03167_fromReadableDecimalSize.sql} (100%) diff --git a/tests/queries/0_stateless/03166_from_readable_size.reference b/tests/queries/0_stateless/03166_fromReadableSize.reference similarity index 100% rename from tests/queries/0_stateless/03166_from_readable_size.reference rename to tests/queries/0_stateless/03166_fromReadableSize.reference diff --git a/tests/queries/0_stateless/03166_from_readable_size.sql b/tests/queries/0_stateless/03166_fromReadableSize.sql similarity index 100% rename from tests/queries/0_stateless/03166_from_readable_size.sql rename to tests/queries/0_stateless/03166_fromReadableSize.sql diff --git a/tests/queries/0_stateless/03167_from_readable_decimal_size.reference b/tests/queries/0_stateless/03167_fromReadableDecimalSize.reference similarity index 100% rename from tests/queries/0_stateless/03167_from_readable_decimal_size.reference rename to tests/queries/0_stateless/03167_fromReadableDecimalSize.reference diff --git a/tests/queries/0_stateless/03167_from_readable_decimal_size.sql b/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql similarity index 100% rename from tests/queries/0_stateless/03167_from_readable_decimal_size.sql rename to tests/queries/0_stateless/03167_fromReadableDecimalSize.sql From 512afefd6f30cf675dca1e7493403a4df9716887 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 09:59:09 +0200 Subject: [PATCH 091/211] Add comments to indicate that test files should be kept in sync --- tests/queries/0_stateless/03166_fromReadableSize.sql | 2 ++ tests/queries/0_stateless/03167_fromReadableDecimalSize.sql | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/queries/0_stateless/03166_fromReadableSize.sql b/tests/queries/0_stateless/03166_fromReadableSize.sql index 41a042bb1d5..f99561e89b5 100644 --- a/tests/queries/0_stateless/03166_fromReadableSize.sql +++ b/tests/queries/0_stateless/03166_fromReadableSize.sql @@ -1,3 +1,5 @@ +-- Should be kept in sync with 03167_fromReadableDecimalSize.sql + -- Should be the inverse of formatReadableSize SELECT formatReadableSize(fromReadableSize('1 B')); SELECT formatReadableSize(fromReadableSize('1 KiB')); diff --git a/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql b/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql index 7252547e628..861347c6ab8 100644 --- a/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql +++ b/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql @@ -1,3 +1,5 @@ +-- Should be kept in sync with 03166_fromReadableSize.sql + -- Should be the inverse of formatReadableDecimalSize SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 B')); SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 KB')); From ed1d933e53e7cd64925ede0df8e57c9897f29398 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 10:00:12 +0200 Subject: [PATCH 092/211] Update dict ignore --- utils/check-style/aspell-ignore/en/aspell-dict.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/check-style/aspell-ignore/en/aspell-dict.txt b/utils/check-style/aspell-ignore/en/aspell-dict.txt index 39b314d003d..7f54d509da1 100644 --- a/utils/check-style/aspell-ignore/en/aspell-dict.txt +++ b/utils/check-style/aspell-ignore/en/aspell-dict.txt @@ -1603,6 +1603,11 @@ fromDaysSinceYearZero fromModifiedJulianDay fromModifiedJulianDayOrNull fromReadableSize +fromReadableSizeOrNull +fromReadableSizeOrZero +fromReadableDecimalSize +fromReadableDecimalSizeOrNull +fromReadableDecimalSizeOrZero fromUTCTimestamp fromUnixTimestamp fromUnixTimestampInJodaSyntax From 581982739f9847a1e292192e8013ec09c43cd239 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 10:00:32 +0200 Subject: [PATCH 093/211] Remove unnecessary quoting in exception message --- src/Functions/fromReadable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index e8a9b94e21c..e17fe2d63c9 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -141,7 +141,7 @@ private: { throw Exception( ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {} - Negative sizes are not allowed (\"{}\")", + "Invalid expression for function {} - Negative sizes are not allowed ({})", getName(), base ); From ebacc95df30315719b77a708571ed6ab391f07b6 Mon Sep 17 00:00:00 2001 From: Blargian Date: Tue, 28 May 2024 10:35:00 +0200 Subject: [PATCH 094/211] Add missing UTCTimestamp function --- .../functions/date-time-functions.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/en/sql-reference/functions/date-time-functions.md b/docs/en/sql-reference/functions/date-time-functions.md index 6ad26f452ad..08eadc15e78 100644 --- a/docs/en/sql-reference/functions/date-time-functions.md +++ b/docs/en/sql-reference/functions/date-time-functions.md @@ -3953,6 +3953,43 @@ Result: │ 2023-03-16 18:00:00.000 │ └─────────────────────────────────────────────────────────────────────────┘ ``` + +## UTCTimestamp + +Returns the current date and time at the moment of query analysis. The function is a constant expression. + +:::note +This function gives the same result that `now('UTC')` would. It was added only for MySQL support and `now` is the preferred usage. +::: + +**Syntax** + +```sql +UTCTimestamp() +``` + +Alias: `UTC_timestamp`. + +**Returned value** + +- Returns the current date and time at the moment of query analysis. [DateTime](../data-types/datetime.md). + +**Example** + +Query: + +```sql +SELECT UTCTimestamp(); +``` + +Result: + +```response +┌──────UTCTimestamp()─┐ +│ 2024-05-28 08:32:09 │ +└─────────────────────┘ +``` + ## timeDiff Returns the difference between two dates or dates with time values. The difference is calculated in units of seconds. It is same as `dateDiff` and was added only for MySQL support. `dateDiff` is preferred. From 98e6f115d52d080596e52a5130bdc1340c6df059 Mon Sep 17 00:00:00 2001 From: Blargian Date: Tue, 28 May 2024 10:39:17 +0200 Subject: [PATCH 095/211] Add link to now function --- docs/en/sql-reference/functions/date-time-functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/sql-reference/functions/date-time-functions.md b/docs/en/sql-reference/functions/date-time-functions.md index 08eadc15e78..9eee41f4acc 100644 --- a/docs/en/sql-reference/functions/date-time-functions.md +++ b/docs/en/sql-reference/functions/date-time-functions.md @@ -3959,7 +3959,7 @@ Result: Returns the current date and time at the moment of query analysis. The function is a constant expression. :::note -This function gives the same result that `now('UTC')` would. It was added only for MySQL support and `now` is the preferred usage. +This function gives the same result that `now('UTC')` would. It was added only for MySQL support and [`now`](#now-now) is the preferred usage. ::: **Syntax** From 437be2058f499446883fd7966403532e524eae4e Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 28 May 2024 09:42:50 +0000 Subject: [PATCH 096/211] Split QueryAnalysisPass. --- .../QueryAnalysisPass.cpp => QueryAnalysis/QueryAnalyzer.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Analyzer/{Passes/QueryAnalysisPass.cpp => QueryAnalysis/QueryAnalyzer.cpp} (100%) diff --git a/src/Analyzer/Passes/QueryAnalysisPass.cpp b/src/Analyzer/QueryAnalysis/QueryAnalyzer.cpp similarity index 100% rename from src/Analyzer/Passes/QueryAnalysisPass.cpp rename to src/Analyzer/QueryAnalysis/QueryAnalyzer.cpp From 53aeae303797138047a9bbb623904f4a54f4dbef Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 11:52:02 +0200 Subject: [PATCH 097/211] Add cosmetic newline --- src/Functions/fromReadable.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index e17fe2d63c9..45a371f74d5 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -115,6 +115,7 @@ private: UInt64 parseReadableFormat(const std::unordered_map & scale_factors, const std::string_view & str) const { ReadBufferFromString buf(str); + // tryReadFloatText does seem to not raise any error when there is leading whitespace so we check it explicitly skipWhitespaceIfAny(buf); if (buf.getPosition() > 0) From e714b4c86ab65ea556450d99bb03217182c7faf0 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 28 May 2024 10:12:27 +0000 Subject: [PATCH 098/211] Splitting QueryAnalysisPass (Part 1) --- src/Analyzer/QueryAnalysis/ExpressionsStack.h | 8357 +--------------- src/Analyzer/QueryAnalysis/IdentifierLookup.h | 8294 +--------------- .../QueryAnalysis/IdentifierResolveScope.cpp | 8320 +--------------- .../QueryAnalysis/IdentifierResolveScope.h | 8280 +--------------- .../QueryAnalysis/QueryAnalysisPass.cpp | 22 + src/Analyzer/QueryAnalysis/QueryAnalyzer.cpp | 1617 +--- src/Analyzer/QueryAnalysis/QueryAnalyzer.h | 8155 +--------------- .../QueryExpressionsAliasVisitor.h | 8366 +--------------- src/Analyzer/QueryAnalysis/ScopeAliases.h | 8392 +--------------- .../QueryAnalysis/TableExpressionData.h | 8400 +--------------- .../TableExpressionsAliasVisitor.h | 8414 +---------------- src/CMakeLists.txt | 1 + 12 files changed, 218 insertions(+), 76400 deletions(-) create mode 100644 src/Analyzer/QueryAnalysis/QueryAnalysisPass.cpp diff --git a/src/Analyzer/QueryAnalysis/ExpressionsStack.h b/src/Analyzer/QueryAnalysis/ExpressionsStack.h index 3fca66e6eb8..82a27aa8b83 100644 --- a/src/Analyzer/QueryAnalysis/ExpressionsStack.h +++ b/src/Analyzer/QueryAnalysis/ExpressionsStack.h @@ -1,477 +1,12 @@ -#include +#pragma once -#include - -#include -#include -#include - -#include -#include #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - #include - -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ProfileEvents -{ - extern const Event ScalarSubqueriesGlobalCacheHit; - extern const Event ScalarSubqueriesLocalCacheHit; - extern const Event ScalarSubqueriesCacheMiss; -} namespace DB { -namespace ErrorCodes -{ - extern const int UNSUPPORTED_METHOD; - extern const int UNKNOWN_IDENTIFIER; - extern const int UNKNOWN_FUNCTION; - extern const int LOGICAL_ERROR; - extern const int CYCLIC_ALIASES; - extern const int INCORRECT_RESULT_OF_SCALAR_SUBQUERY; - extern const int BAD_ARGUMENTS; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int MULTIPLE_EXPRESSIONS_FOR_ALIAS; - extern const int TYPE_MISMATCH; - extern const int AMBIGUOUS_IDENTIFIER; - extern const int INVALID_WITH_FILL_EXPRESSION; - extern const int INVALID_LIMIT_EXPRESSION; - extern const int EMPTY_LIST_OF_COLUMNS_QUERIED; - extern const int TOO_DEEP_SUBQUERIES; - extern const int UNKNOWN_AGGREGATE_FUNCTION; - extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION; - extern const int TOO_MANY_ARGUMENTS_FOR_FUNCTION; - extern const int ILLEGAL_FINAL; - extern const int SAMPLING_NOT_SUPPORTED; - extern const int NO_COMMON_TYPE; - extern const int NOT_IMPLEMENTED; - extern const int ALIAS_REQUIRED; - extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; - extern const int UNKNOWN_TABLE; - extern const int ILLEGAL_COLUMN; - extern const int NUMBER_OF_COLUMNS_DOESNT_MATCH; - extern const int FUNCTION_CANNOT_HAVE_PARAMETERS; - extern const int SYNTAX_ERROR; - extern const int UNEXPECTED_EXPRESSION; - extern const int INVALID_IDENTIFIER; -} - -/** Query analyzer implementation overview. Please check documentation in QueryAnalysisPass.h first. - * And additional documentation for each method, where special cases are described in detail. - * - * Each node in query must be resolved. For each query tree node resolved state is specific. - * - * For constant node no resolve process exists, it is resolved during construction. - * - * For table node no resolve process exists, it is resolved during construction. - * - * For function node to be resolved parameters and arguments must be resolved, function node must be initialized with concrete aggregate or - * non aggregate function and with result type. - * - * For lambda node there can be 2 different cases. - * 1. Standalone: WITH (x -> x + 1) AS lambda SELECT lambda(1); Such lambdas are inlined in query tree during query analysis pass. - * 2. Function arguments: WITH (x -> x + 1) AS lambda SELECT arrayMap(lambda, [1, 2, 3]); For such lambda resolution must - * set concrete lambda arguments (initially they are identifier nodes) and resolve lambda expression body. - * - * For query node resolve process must resolve all its inner nodes. - * - * For matcher node resolve process must replace it with matched nodes. - * - * For identifier node resolve process must replace it with concrete non identifier node. This part is most complex because - * for identifier resolution scopes and identifier lookup context play important part. - * - * ClickHouse SQL support lexical scoping for identifier resolution. Scope can be defined by query node or by expression node. - * Expression nodes that can define scope are lambdas and table ALIAS columns. - * - * Identifier lookup context can be expression, function, table. - * - * Examples: WITH (x -> x + 1) as func SELECT func() FROM func; During function `func` resolution identifier lookup is performed - * in function context. - * - * If there are no information of identifier context rules are following: - * 1. Try to resolve identifier in expression context. - * 2. Try to resolve identifier in function context, if it is allowed. Example: SELECT func(arguments); Here func identifier cannot be resolved in function context - * because query projection does not support that. - * 3. Try to resolve identifier in table context, if it is allowed. Example: SELECT table; Here table identifier cannot be resolved in function context - * because query projection does not support that. - * - * TODO: This does not supported properly before, because matchers could not be resolved from aliases. - * - * Identifiers are resolved with following rules: - * Resolution starts with current scope. - * 1. Try to resolve identifier from expression scope arguments. Lambda expression arguments are greatest priority. - * 2. Try to resolve identifier from aliases. - * 3. Try to resolve identifier from join tree if scope is query, or if there are registered table columns in scope. - * Steps 2 and 3 can be changed using prefer_column_name_to_alias setting. - * 4. If it is table lookup, try to resolve identifier from CTE. - * If identifier could not be resolved in current scope, resolution must be continued in parent scopes. - * 5. Try to resolve identifier from parent scopes. - * - * Additional rules about aliases and scopes. - * 1. Parent scope cannot refer alias from child scope. - * 2. Child scope can refer to alias in parent scope. - * - * Example: SELECT arrayMap(x -> x + 1 AS a, [1,2,3]), a; Identifier a is unknown in parent scope. - * Example: SELECT a FROM (SELECT 1 as a); Here we do not refer to alias a from child query scope. But we query it projection result, similar to tables. - * Example: WITH 1 as a SELECT (SELECT a) as b; Here in child scope identifier a is resolved using alias from parent scope. - * - * Additional rules about identifier binding. - * Bind for identifier to entity means that identifier first part match some node during analysis. - * If other parts of identifier cannot be resolved in that node, exception must be thrown. - * - * Example: - * CREATE TABLE test_table (id UInt64, compound_value Tuple(value UInt64)) ENGINE=TinyLog; - * SELECT compound_value.value, 1 AS compound_value FROM test_table; - * Identifier first part compound_value bound to entity with alias compound_value, but nested identifier part cannot be resolved from entity, - * lookup should not be continued, and exception must be thrown because if lookup continues that way identifier can be resolved from join tree. - * - * TODO: This was not supported properly before analyzer because nested identifier could not be resolved from alias. - * - * More complex example: - * CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; - * WITH cast(('Value'), 'Tuple (value UInt64') AS value SELECT (SELECT value FROM test_table); - * Identifier first part value bound to test_table column value, but nested identifier part cannot be resolved from it, - * lookup should not be continued, and exception must be thrown because if lookup continues identifier can be resolved from parent scope. - * - * TODO: Update exception messages - * TODO: Table identifiers with optional UUID. - * TODO: Lookup functions arrayReduce(sum, [1, 2, 3]); - * TODO: Support function identifier resolve from parent query scope, if lambda in parent scope does not capture any columns. - */ - -namespace -{ - -/// Identifier lookup context -enum class IdentifierLookupContext : uint8_t -{ - EXPRESSION = 0, - FUNCTION, - TABLE_EXPRESSION, -}; - -const char * toString(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "EXPRESSION"; - case IdentifierLookupContext::FUNCTION: return "FUNCTION"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "TABLE_EXPRESSION"; - } -} - -const char * toStringLowercase(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "expression"; - case IdentifierLookupContext::FUNCTION: return "function"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "table expression"; - } -} - -/** Structure that represent identifier lookup during query analysis. - * Lookup can be in query expression, function, table context. - */ -struct IdentifierLookup -{ - Identifier identifier; - IdentifierLookupContext lookup_context; - - bool isExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::EXPRESSION; - } - - bool isFunctionLookup() const - { - return lookup_context == IdentifierLookupContext::FUNCTION; - } - - bool isTableExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::TABLE_EXPRESSION; - } - - String dump() const - { - return identifier.getFullName() + ' ' + toString(lookup_context); - } -}; - -inline bool operator==(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return lhs.identifier.getFullName() == rhs.identifier.getFullName() && lhs.lookup_context == rhs.lookup_context; -} - -[[maybe_unused]] inline bool operator!=(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return !(lhs == rhs); -} - -struct IdentifierLookupHash -{ - size_t operator()(const IdentifierLookup & identifier_lookup) const - { - return std::hash()(identifier_lookup.identifier.getFullName()) ^ static_cast(identifier_lookup.lookup_context); - } -}; - -enum class IdentifierResolvePlace : UInt8 -{ - NONE = 0, - EXPRESSION_ARGUMENTS, - ALIASES, - JOIN_TREE, - /// Valid only for table lookup - CTE, - /// Valid only for table lookup - DATABASE_CATALOG -}; - -const char * toString(IdentifierResolvePlace resolved_identifier_place) -{ - switch (resolved_identifier_place) - { - case IdentifierResolvePlace::NONE: return "NONE"; - case IdentifierResolvePlace::EXPRESSION_ARGUMENTS: return "EXPRESSION_ARGUMENTS"; - case IdentifierResolvePlace::ALIASES: return "ALIASES"; - case IdentifierResolvePlace::JOIN_TREE: return "JOIN_TREE"; - case IdentifierResolvePlace::CTE: return "CTE"; - case IdentifierResolvePlace::DATABASE_CATALOG: return "DATABASE_CATALOG"; - } -} - -struct IdentifierResolveResult -{ - IdentifierResolveResult() = default; - - QueryTreeNodePtr resolved_identifier; - IdentifierResolvePlace resolve_place = IdentifierResolvePlace::NONE; - bool resolved_from_parent_scopes = false; - - [[maybe_unused]] bool isResolved() const - { - return resolve_place != IdentifierResolvePlace::NONE; - } - - [[maybe_unused]] bool isResolvedFromParentScopes() const - { - return resolved_from_parent_scopes; - } - - [[maybe_unused]] bool isResolvedFromExpressionArguments() const - { - return resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - } - - [[maybe_unused]] bool isResolvedFromAliases() const - { - return resolve_place == IdentifierResolvePlace::ALIASES; - } - - [[maybe_unused]] bool isResolvedFromJoinTree() const - { - return resolve_place == IdentifierResolvePlace::JOIN_TREE; - } - - [[maybe_unused]] bool isResolvedFromCTEs() const - { - return resolve_place == IdentifierResolvePlace::CTE; - } - - void dump(WriteBuffer & buffer) const - { - if (!resolved_identifier) - { - buffer << "unresolved"; - return; - } - - buffer << resolved_identifier->formatASTForErrorMessage() << " place " << toString(resolve_place) << " resolved from parent scopes " << resolved_from_parent_scopes; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -struct IdentifierResolveState -{ - IdentifierResolveResult resolve_result; - bool cyclic_identifier_resolve = false; -}; - -struct IdentifierResolveSettings -{ - /// Allow to check join tree during identifier resolution - bool allow_to_check_join_tree = true; - - /// Allow to check CTEs during table identifier resolution - bool allow_to_check_cte = true; - - /// Allow to check parent scopes during identifier resolution - bool allow_to_check_parent_scopes = true; - - /// Allow to check database catalog during table identifier resolution - bool allow_to_check_database_catalog = true; - - /// Allow to resolve subquery during identifier resolution - bool allow_to_resolve_subquery_during_identifier_resolution = true; -}; - -struct StringTransparentHash -{ - using is_transparent = void; - using hash = std::hash; - - [[maybe_unused]] size_t operator()(const char * data) const - { - return hash()(data); - } - - size_t operator()(std::string_view data) const - { - return hash()(data); - } - - size_t operator()(const std::string & data) const - { - return hash()(data); - } -}; - -using ColumnNameToColumnNodeMap = std::unordered_map>; - -struct TableExpressionData -{ - std::string table_expression_name; - std::string table_expression_description; - std::string database_name; - std::string table_name; - bool should_qualify_columns = true; - NamesAndTypes column_names_and_types; - ColumnNameToColumnNodeMap column_name_to_column_node; - std::unordered_set subcolumn_names; /// Subset columns that are subcolumns of other columns - std::unordered_set> column_identifier_first_parts; - - bool hasFullIdentifierName(IdentifierView identifier_view) const - { - return column_name_to_column_node.contains(identifier_view.getFullName()); - } - - bool canBindIdentifier(IdentifierView identifier_view) const - { - return column_identifier_first_parts.contains(identifier_view.at(0)); - } - - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Table expression name " << table_expression_name; - - if (!table_expression_description.empty()) - buffer << " table expression description " << table_expression_description; - - if (!database_name.empty()) - buffer << " database name " << database_name; - - if (!table_name.empty()) - buffer << " table name " << table_name; - - buffer << " should qualify columns " << should_qualify_columns; - buffer << " columns size " << column_name_to_column_node.size() << '\n'; - - for (const auto & [column_name, column_node] : column_name_to_column_node) - buffer << "Column name " << column_name << " column node " << column_node->dumpTree() << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - class ExpressionsStack { public: @@ -586,7894 +121,4 @@ private: std::unordered_map alias_name_to_expressions; }; -struct ScopeAliases -{ - /// Alias name to query expression node - std::unordered_map alias_name_to_expression_node_before_group_by; - std::unordered_map alias_name_to_expression_node_after_group_by; - - std::unordered_map * alias_name_to_expression_node = nullptr; - - /// Alias name to lambda node - std::unordered_map alias_name_to_lambda_node; - - /// Alias name to table expression node - std::unordered_map alias_name_to_table_expression_node; - - /// Expressions like `x as y` where we can't say whether it's a function, expression or table. - std::unordered_map transitive_aliases; - - /// Nodes with duplicated aliases - std::unordered_set nodes_with_duplicated_aliases; - std::vector cloned_nodes_with_duplicated_aliases; - - /// Names which are aliases from ARRAY JOIN. - /// This is needed to properly qualify columns from matchers and avoid name collision. - std::unordered_set array_join_aliases; - - std::unordered_map & getAliasMap(IdentifierLookupContext lookup_context) - { - switch (lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return *alias_name_to_expression_node; - case IdentifierLookupContext::FUNCTION: return alias_name_to_lambda_node; - case IdentifierLookupContext::TABLE_EXPRESSION: return alias_name_to_table_expression_node; - } - } - - enum class FindOption - { - FIRST_NAME, - FULL_NAME, - }; - - const std::string & getKey(const Identifier & identifier, FindOption find_option) - { - switch (find_option) - { - case FindOption::FIRST_NAME: return identifier.front(); - case FindOption::FULL_NAME: return identifier.getFullName(); - } - } - - QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) - { - auto & alias_map = getAliasMap(lookup.lookup_context); - const std::string * key = &getKey(lookup.identifier, find_option); - - auto it = alias_map.find(*key); - - if (it != alias_map.end()) - return &it->second; - - if (lookup.lookup_context == IdentifierLookupContext::TABLE_EXPRESSION) - return {}; - - while (it == alias_map.end()) - { - auto jt = transitive_aliases.find(*key); - if (jt == transitive_aliases.end()) - return {}; - - key = &(getKey(jt->second, find_option)); - it = alias_map.find(*key); - } - - return &it->second; - } - - const QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) const - { - return const_cast(this)->find(lookup, find_option); - } -}; - - -/** Projection names is name of query tree node that is used in projection part of query node. - * Example: SELECT id FROM test_table; - * `id` is projection name of column node - * - * Example: SELECT id AS id_alias FROM test_table; - * `id_alias` is projection name of column node - * - * Calculation of projection names is done during expression nodes resolution. This is done this way - * because after identifier node is resolved we lose information about identifier name. We could - * potentially save this information in query tree node itself, but that would require to clone it in some cases. - * Example: SELECT big_scalar_subquery AS a, a AS b, b AS c; - * All 3 nodes in projection are the same big_scalar_subquery, but they have different projection names. - * If we want to save it in query tree node, we have to clone subquery node that could lead to performance degradation. - * - * Possible solution is to separate query node metadata and query node content. So only node metadata could be cloned - * if we want to change projection name. This solution does not seem to be easy for client of query tree because projection - * name will be part of interface. If we potentially could hide projection names calculation in analyzer without introducing additional - * changes in query tree structure that would be preferable. - * - * Currently each resolve method returns projection names array. Resolve method must compute projection names of node. - * If node is resolved as list node this is case for `untuple` function or `matcher` result projection names array must contain projection names - * for result nodes. - * If node is not resolved as list node, projection names array contain single projection name for node. - * - * Rules for projection names: - * 1. If node has alias. It is node projection name. - * Except scenario where `untuple` function has alias. Example: SELECT untuple(expr) AS alias, alias. - * - * 2. For constant it is constant value string representation. - * - * 3. For identifier: - * If identifier is resolved from JOIN TREE, we want to remove additional identifier qualifications. - * Example: SELECT default.test_table.id FROM test_table. - * Result projection name is `id`. - * - * Example: SELECT t1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In example both test_table_1, test_table_2 have `id` column. - * In such case projection name is `t1.id` because if additional qualification is removed then column projection name `id` will be ambiguous. - * - * Example: SELECT default.test_table_1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In such case projection name is `test_table_1.id` because we remove unnecessary database qualification, but table name qualification cannot be removed - * because otherwise column projection name `id` will be ambiguous. - * - * If identifier is not resolved from JOIN TREE. Identifier name is projection name. - * Except scenario where `untuple` function resolved using identifier. Example: SELECT untuple(expr) AS alias, alias. - * Example: SELECT sum(1, 1) AS value, value. - * In such case both nodes have `value` projection names. - * - * Example: SELECT id AS value, value FROM test_table. - * In such case both nodes have have `value` projection names. - * - * Special case is `untuple` function. If `untuple` function specified with alias, then result nodes will have alias.tuple_column_name projection names. - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value) AS a; - * Result projection names are `value`, `a.id`. - * - * If `untuple` function does not have alias then result nodes will have `tupleElement(untuple_expression_projection_name, 'tuple_column_name') projection names. - * - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value); - * Result projection names are `value`, `tupleElement(value, 'id')`; - * - * 4. For function: - * Projection name consists from function_name(parameters_projection_names)(arguments_projection_names). - * Additionally if function is window function. Window node projection name is used with OVER clause. - * Example: function_name (parameters_names)(argument_projection_names) OVER window_name; - * Example: function_name (parameters_names)(argument_projection_names) OVER (PARTITION BY id ORDER BY id). - * Example: function_name (parameters_names)(argument_projection_names) OVER (window_name ORDER BY id). - * - * 5. For lambda: - * If it is standalone lambda that returns single expression, function projection name is used. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(1). - * Projection name is `lambda(1)`. - * - * If is it standalone lambda that returns list, projection names of list nodes are used. - * Example: WITH (x -> *) AS lambda SELECT lambda(1) FROM test_table; - * If test_table has two columns `id`, `value`. Then result projection names are `id`, `value`. - * - * If lambda is argument of function. - * Then projection name consists from lambda(tuple(lambda_arguments)(lambda_body_projection_name)); - * - * 6. For matcher: - * Matched nodes projection names are used as matcher projection names. - * - * Matched nodes must be qualified if needed. - * Example: SELECT * FROM test_table_1 AS t1, test_table_2 AS t2. - * In example table test_table_1 and test_table_2 both have `id`, `value` columns. - * Matched nodes after unqualified matcher resolve must be qualified to avoid ambiguous projection names. - * Result projection names must be `t1.id`, `t1.value`, `t2.id`, `t2.value`. - * - * There are special cases - * 1. For lambda inside APPLY matcher transformer: - * Example: SELECT * APPLY x -> toString(x) FROM test_table. - * In such case lambda argument projection name `x` will be replaced by matched node projection name. - * If table has two columns `id` and `value`. Then result projection names are `toString(id)`, `toString(value)`; - * - * 2. For unqualified matcher when JOIN tree contains JOIN with USING. - * Example: SELECT * FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING(id); - * Result projection names must be `id`, `t1.value`, `t2.value`. - * - * 7. For subquery: - * For subquery projection name consists of `_subquery_` prefix and implementation specific unique number suffix. - * Example: SELECT (SELECT 1), (SELECT 1 UNION DISTINCT SELECT 1); - * Result projection name can be `_subquery_1`, `subquery_2`; - * - * 8. For table: - * Table node can be used in expression context only as right argument of IN function. In that case identifier is used - * as table node projection name. - * Example: SELECT id IN test_table FROM test_table; - * Result projection name is `in(id, test_table)`. - */ -using ProjectionName = String; -using ProjectionNames = std::vector; -constexpr auto PROJECTION_NAME_PLACEHOLDER = "__projection_name_placeholder"; - -struct IdentifierResolveScope -{ - /// Construct identifier resolve scope using scope node, and parent scope - IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) - : scope_node(std::move(scope_node_)) - , parent_scope(parent_scope_) - { - if (parent_scope) - { - subquery_depth = parent_scope->subquery_depth; - context = parent_scope->context; - projection_mask_map = parent_scope->projection_mask_map; - } - else - projection_mask_map = std::make_shared>(); - - if (auto * union_node = scope_node->as()) - { - context = union_node->getContext(); - } - else if (auto * query_node = scope_node->as()) - { - context = query_node->getContext(); - group_by_use_nulls = context->getSettingsRef().group_by_use_nulls && - (query_node->isGroupByWithGroupingSets() || query_node->isGroupByWithRollup() || query_node->isGroupByWithCube()); - } - - if (context) - join_use_nulls = context->getSettingsRef().join_use_nulls; - else if (parent_scope) - join_use_nulls = parent_scope->join_use_nulls; - - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - QueryTreeNodePtr scope_node; - - IdentifierResolveScope * parent_scope = nullptr; - - ContextPtr context; - - /// Identifier lookup to result - std::unordered_map identifier_lookup_to_resolve_state; - - /// Argument can be expression like constant, column, function or table expression - std::unordered_map expression_argument_name_to_node; - - ScopeAliases aliases; - - /// Table column name to column node. Valid only during table ALIAS columns resolve. - ColumnNameToColumnNodeMap column_name_to_column_node; - - /// CTE name to query node - std::unordered_map cte_name_to_query_node; - - /// Window name to window node - std::unordered_map window_name_to_window_node; - - /// Current scope expression in resolve process stack - ExpressionsStack expressions_in_resolve_process_stack; - - /// Table expressions in resolve process - std::unordered_set table_expressions_in_resolve_process; - - /// Current scope expression - std::unordered_set non_cached_identifier_lookups_during_expression_resolve; - - /// Table expression node to data - std::unordered_map table_expression_node_to_data; - - QueryTreeNodePtrWithHashIgnoreTypesSet nullable_group_by_keys; - /// Here we count the number of nullable GROUP BY keys we met resolving expression. - /// E.g. for a query `SELECT tuple(tuple(number)) FROM numbers(10) GROUP BY (number, tuple(number)) with cube` - /// both `number` and `tuple(number)` would be in nullable_group_by_keys. - /// But when we resolve `tuple(tuple(number))` we should figure out that `tuple(number)` is already a key, - /// and we should not convert `number` to nullable. - size_t found_nullable_group_by_key_in_scope = 0; - - /** It's possible that after a JOIN, a column in the projection has a type different from the column in the source table. - * (For example, after join_use_nulls or USING column casted to supertype) - * However, the column in the projection still refers to the table as its source. - * This map is used to revert these columns back to their original columns in the source table. - */ - QueryTreeNodePtrWithHashMap join_columns_with_changed_types; - - /// Use identifier lookup to result cache - bool use_identifier_lookup_to_result_cache = true; - - /// Apply nullability to aggregation keys - bool group_by_use_nulls = false; - /// Join retutns NULLs instead of default values - bool join_use_nulls = false; - - /// JOINs count - size_t joins_count = 0; - - /// Subquery depth - size_t subquery_depth = 0; - - /** Scope join tree node for expression. - * Valid only during analysis construction for single expression. - */ - QueryTreeNodePtr expression_join_tree_node; - - /// Node hash to mask id map - std::shared_ptr> projection_mask_map; - - struct ResolvedFunctionsCache - { - FunctionOverloadResolverPtr resolver; - FunctionBasePtr function_base; - }; - - std::map functions_cache; - - [[maybe_unused]] const IdentifierResolveScope * getNearestQueryScope() const - { - const IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - IdentifierResolveScope * getNearestQueryScope() - { - IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - const TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - void pushExpressionNode(const QueryTreeNodePtr & node) - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.push(node); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - void popExpressionNode() - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.pop(); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_after_group_by; - } - - /// Dump identifier resolve scope - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Scope node " << scope_node->formatASTForErrorMessage() << '\n'; - buffer << "Identifier lookup to resolve state " << identifier_lookup_to_resolve_state.size() << '\n'; - for (const auto & [identifier, state] : identifier_lookup_to_resolve_state) - { - buffer << "Identifier " << identifier.dump() << " resolve result "; - state.resolve_result.dump(buffer); - buffer << '\n'; - } - - buffer << "Expression argument name to node " << expression_argument_name_to_node.size() << '\n'; - for (const auto & [alias_name, node] : expression_argument_name_to_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to expression node table size " << aliases.alias_name_to_expression_node->size() << '\n'; - for (const auto & [alias_name, node] : *aliases.alias_name_to_expression_node) - buffer << "Alias name " << alias_name << " expression node " << node->dumpTree() << '\n'; - - buffer << "Alias name to function node table size " << aliases.alias_name_to_lambda_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_lambda_node) - buffer << "Alias name " << alias_name << " lambda node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to table expression node table size " << aliases.alias_name_to_table_expression_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_table_expression_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "CTE name to query node table size " << cte_name_to_query_node.size() << '\n'; - for (const auto & [cte_name, node] : cte_name_to_query_node) - buffer << "CTE name " << cte_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "WINDOW name to window node table size " << window_name_to_window_node.size() << '\n'; - for (const auto & [window_name, node] : window_name_to_window_node) - buffer << "CTE name " << window_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Nodes with duplicated aliases size " << aliases.nodes_with_duplicated_aliases.size() << '\n'; - for (const auto & node : aliases.nodes_with_duplicated_aliases) - buffer << "Alias name " << node->getAlias() << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Expression resolve process stack " << '\n'; - expressions_in_resolve_process_stack.dump(buffer); - - buffer << "Table expressions in resolve process size " << table_expressions_in_resolve_process.size() << '\n'; - for (const auto & node : table_expressions_in_resolve_process) - buffer << "Table expression " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Non cached identifier lookups during expression resolve " << non_cached_identifier_lookups_during_expression_resolve.size() << '\n'; - for (const auto & identifier_lookup : non_cached_identifier_lookups_during_expression_resolve) - buffer << "Identifier lookup " << identifier_lookup.dump() << '\n'; - - buffer << "Table expression node to data " << table_expression_node_to_data.size() << '\n'; - for (const auto & [table_expression_node, table_expression_data] : table_expression_node_to_data) - buffer << "Table expression node " << table_expression_node->formatASTForErrorMessage() << " data " << table_expression_data.dump() << '\n'; - - buffer << "Use identifier lookup to result cache " << use_identifier_lookup_to_result_cache << '\n'; - buffer << "Subquery depth " << subquery_depth << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - - -/** Visitor that extracts expression and function aliases from node and initialize scope tables with it. - * Does not go into child lambdas and queries. - * - * Important: - * Identifier nodes with aliases are added both in alias to expression and alias to function map. - * - * These is necessary because identifier with alias can give alias name to any query tree node. - * - * Example: - * WITH (x -> x + 1) AS id, id AS value SELECT value(1); - * In this example id as value is identifier node that has alias, during scope initialization we cannot derive - * that id is actually lambda or expression. - * - * There are no easy solution here, without trying to make full featured expression resolution at this stage. - * Example: - * WITH (x -> x + 1) AS id, id AS id_1, id_1 AS id_2 SELECT id_2(1); - * Example: SELECT a, b AS a, b AS c, 1 AS c; - * - * It is client responsibility after resolving identifier node with alias, make following actions: - * 1. If identifier node was resolved in function scope, remove alias from scope expression map. - * 2. If identifier node was resolved in expression scope, remove alias from scope function map. - * - * That way we separate alias map initialization and expressions resolution. - */ -class QueryExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit QueryExpressionsAliasVisitor(ScopeAliases & aliases_) - : aliases(aliases_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node, false /*is_lambda_node*/); - } - - bool needChildVisit(const QueryTreeNodePtr &, const QueryTreeNodePtr & child) - { - if (auto * lambda_node = child->as()) - { - updateAliasesIfNeeded(child, true /*is_lambda_node*/); - return false; - } - else if (auto * query_tree_node = child->as()) - { - if (query_tree_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - else if (auto * union_node = child->as()) - { - if (union_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - - return true; - } -private: - void addDuplicatingAlias(const QueryTreeNodePtr & node) - { - aliases.nodes_with_duplicated_aliases.emplace(node); - auto cloned_node = node->clone(); - aliases.cloned_nodes_with_duplicated_aliases.emplace_back(cloned_node); - aliases.nodes_with_duplicated_aliases.emplace(cloned_node); - } - - void updateAliasesIfNeeded(const QueryTreeNodePtr & node, bool is_lambda_node) - { - if (!node->hasAlias()) - return; - - // We should not resolve expressions to WindowNode - if (node->getNodeType() == QueryTreeNodeType::WINDOW) - return; - - const auto & alias = node->getAlias(); - - if (is_lambda_node) - { - if (aliases.alias_name_to_expression_node->contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_lambda_node.insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - return; - } - - if (aliases.alias_name_to_lambda_node.contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_expression_node->insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - /// If node is identifier put it into transitive aliases map. - if (const auto * identifier = typeid_cast(node.get())) - aliases.transitive_aliases.insert(std::make_pair(alias, identifier->getIdentifier())); - } - - ScopeAliases & aliases; -}; - -class TableExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit TableExpressionsAliasVisitor(IdentifierResolveScope & scope_) - : scope(scope_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node); - } - - static bool needChildVisit(const QueryTreeNodePtr & node, const QueryTreeNodePtr & child) - { - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::ARRAY_JOIN: - { - const auto & array_join_node = node->as(); - return child.get() == array_join_node.getTableExpression().get(); - } - case QueryTreeNodeType::JOIN: - { - const auto & join_node = node->as(); - return child.get() == join_node.getLeftTableExpression().get() || child.get() == join_node.getRightTableExpression().get(); - } - default: - { - break; - } - } - - return false; - } - -private: - void updateAliasesIfNeeded(const QueryTreeNodePtr & node) - { - if (!node->hasAlias()) - return; - - const auto & node_alias = node->getAlias(); - auto [_, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(node_alias, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple table expressions with same alias {}. In scope {}", - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - IdentifierResolveScope & scope; -}; - -class QueryAnalyzer -{ -public: - explicit QueryAnalyzer(bool only_analyze_) : only_analyze(only_analyze_) {} - - void resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context) - { - IdentifierResolveScope scope(node, nullptr /*parent_scope*/); - - if (!scope.context) - scope.context = context; - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::QUERY: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For query analysis table expression must be empty"); - - resolveQuery(node, scope); - break; - } - case QueryTreeNodeType::UNION: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For union analysis table expression must be empty"); - - resolveUnion(node, scope); - break; - } - case QueryTreeNodeType::IDENTIFIER: - [[fallthrough]]; - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - [[fallthrough]]; - case QueryTreeNodeType::FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::LIST: - { - if (table_expression) - { - scope.expression_join_tree_node = table_expression; - validateTableExpressionModifiers(scope.expression_join_tree_node, scope); - initializeTableExpressionData(scope.expression_join_tree_node, scope); - } - - if (node_type == QueryTreeNodeType::LIST) - resolveExpressionNodeList(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - else - resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - QueryExpressionsAliasVisitor expressions_alias_visitor(scope.aliases); - resolveTableFunction(node, scope, expressions_alias_visitor, false /*nested_table_function*/); - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Node {} with type {} is not supported by query analyzer. " - "Supported nodes are query, union, identifier, constant, column, function, list.", - node->formatASTForErrorMessage(), - node->getNodeTypeName()); - } - } - } - -private: - /// Utility functions - - static bool isExpressionNodeType(QueryTreeNodeType node_type); - - static bool isFunctionExpressionNodeType(QueryTreeNodeType node_type); - - static bool isSubqueryNodeType(QueryTreeNodeType node_type); - - static bool isTableExpressionNodeType(QueryTreeNodeType node_type); - - static DataTypePtr getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node); - - static ProjectionName calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, - const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names); - - static ProjectionName calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name); - - static ProjectionName calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, - const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, - const ProjectionName & fill_to_expression_projection_name, - const ProjectionName & fill_step_expression_projection_name); - - static void collectCompoundExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result); - - static void collectTableExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result); - - static void collectScopeValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static void collectScopeWithParentScopesValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static std::vector collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers); - - static QueryTreeNodePtr wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path); - - QueryTreeNodePtr tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context); - - void evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & query_tree_node, IdentifierResolveScope & scope); - - static void mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope); - - void replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope); - - static void convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope); - - static void validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope); - - static std::pair recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into); - - static void expandGroupByAll(QueryNode & query_tree_node_typed); - - void expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings); - - static std::string - rewriteAggregateFunctionNameIfNeeded(const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context); - - static std::optional getColumnSideFromJoinTree(const QueryTreeNodePtr & resolved_identifier, const JoinNode & join_node) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - return {}; - - if (resolved_identifier->getNodeType() == QueryTreeNodeType::FUNCTION) - { - const auto & resolved_function = resolved_identifier->as(); - - const auto & argument_nodes = resolved_function.getArguments().getNodes(); - - std::optional result; - for (const auto & argument_node : argument_nodes) - { - auto table_side = getColumnSideFromJoinTree(argument_node, join_node); - if (table_side && result && *table_side != *result) - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Ambiguous identifier {}. In scope {}", - resolved_identifier->formatASTForErrorMessage(), - join_node.formatASTForErrorMessage()); - } - result = table_side; - } - return result; - } - - const auto * column_src = resolved_identifier->as().getColumnSource().get(); - - if (join_node.getLeftTableExpression().get() == column_src) - return JoinTableSide::Left; - if (join_node.getRightTableExpression().get() == column_src) - return JoinTableSide::Right; - return {}; - } - - static QueryTreeNodePtr convertJoinedColumnTypeToNullIfNeeded( - const QueryTreeNodePtr & resolved_identifier, - const JoinKind & join_kind, - std::optional resolved_side, - IdentifierResolveScope & scope) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && - JoinCommon::canBecomeNullable(resolved_identifier->getResultType()) && - (isFull(join_kind) || - (isLeft(join_kind) && resolved_side && *resolved_side == JoinTableSide::Right) || - (isRight(join_kind) && resolved_side && *resolved_side == JoinTableSide::Left))) - { - auto nullable_resolved_identifier = resolved_identifier->clone(); - auto & resolved_column = nullable_resolved_identifier->as(); - auto new_result_type = makeNullableOrLowCardinalityNullable(resolved_column.getColumnType()); - resolved_column.setColumnType(new_result_type); - if (resolved_column.hasExpression()) - { - auto & resolved_expression = resolved_column.getExpression(); - if (!resolved_expression->getResultType()->equals(*new_result_type)) - resolved_expression = buildCastFunction(resolved_expression, new_result_type, scope.context, true); - } - if (!nullable_resolved_identifier->isEqual(*resolved_identifier)) - scope.join_columns_with_changed_types[nullable_resolved_identifier] = resolved_identifier; - return nullable_resolved_identifier; - } - return nullptr; - } - - /// Resolve identifier functions - - static QueryTreeNodePtr tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context); - - QueryTreeNodePtr tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found = false); - - QueryTreeNodePtr tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings); - - QueryTreeNodePtr tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings = {}); - - QueryTreeNodePtr tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found = false); - - /// Resolve query tree nodes functions - - void qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static GetColumnsOptions buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context); - - using QueryTreeNodesWithNames = std::vector>; - - QueryTreeNodesWithNames getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope); - - void updateMatchedColumnsFromJoinUsing(QueryTreeNodesWithNames & result_matched_column_nodes_with_names, const QueryTreeNodePtr & source_table_expression, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionNames resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionName resolveWindow(QueryTreeNodePtr & window_node, IdentifierResolveScope & scope); - - ProjectionNames resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope); - - ProjectionNames resolveFunction(QueryTreeNodePtr & function_node, IdentifierResolveScope & scope); - - ProjectionNames resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias = false); - - ProjectionNames resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression); - - ProjectionNames resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope); - - void resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope); - - void resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope); - - void resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope); - - NamesAndTypes resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope); - - void initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope); - - void initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - void resolveTableFunction(QueryTreeNodePtr & table_function_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, bool nested_table_function); - - void resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope); - - void resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope); - - /// Lambdas that are currently in resolve process - std::unordered_set lambdas_in_resolve_process; - - /// CTEs that are currently in resolve process - std::unordered_set ctes_in_resolve_process; - - /// Function name to user defined lambda map - std::unordered_map function_name_to_user_defined_lambda; - - /// Array join expressions counter - size_t array_join_expressions_counter = 1; - - /// Subquery counter - size_t subquery_counter = 1; - - /// Global expression node to projection name map - std::unordered_map node_to_projection_name; - - /// Global resolve expression node to projection names map - std::unordered_map resolved_expressions; - - /// Global resolve expression node to tree size - std::unordered_map node_to_tree_size; - - /// Global scalar subquery to scalar value map - std::unordered_map scalar_subquery_to_scalar_value_local; - std::unordered_map scalar_subquery_to_scalar_value_global; - - const bool only_analyze; -}; - -/// Utility functions implementation - - -bool QueryAnalyzer::isExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::CONSTANT || node_type == QueryTreeNodeType::COLUMN || node_type == QueryTreeNodeType::FUNCTION - || node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isFunctionExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::LAMBDA; -} - -bool QueryAnalyzer::isSubqueryNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isTableExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::TABLE || node_type == QueryTreeNodeType::TABLE_FUNCTION || - isSubqueryNodeType(node_type); -} - -DataTypePtr QueryAnalyzer::getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node) -{ - auto node_type = query_tree_node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - { - return query_tree_node->getResultType(); - } - case QueryTreeNodeType::FUNCTION: - { - auto & function_node = query_tree_node->as(); - if (function_node.isResolved()) - return function_node.getResultType(); - break; - } - default: - { - break; - } - } - - return nullptr; -} - -ProjectionName QueryAnalyzer::calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names) -{ - const auto & function_node_typed = function_node->as(); - const auto & function_node_name = function_node_typed.getFunctionName(); - - bool is_array_function = function_node_name == "array"; - bool is_tuple_function = function_node_name == "tuple"; - - WriteBufferFromOwnString buffer; - - if (!is_array_function && !is_tuple_function) - buffer << function_node_name; - - if (!parameters_projection_names.empty()) - { - buffer << '('; - - size_t function_parameters_projection_names_size = parameters_projection_names.size(); - for (size_t i = 0; i < function_parameters_projection_names_size; ++i) - { - buffer << parameters_projection_names[i]; - - if (i + 1 != function_parameters_projection_names_size) - buffer << ", "; - } - - buffer << ')'; - } - - char open_bracket = '('; - char close_bracket = ')'; - - if (is_array_function) - { - open_bracket = '['; - close_bracket = ']'; - } - - buffer << open_bracket; - - size_t function_arguments_projection_names_size = arguments_projection_names.size(); - for (size_t i = 0; i < function_arguments_projection_names_size; ++i) - { - buffer << arguments_projection_names[i]; - - if (i + 1 != function_arguments_projection_names_size) - buffer << ", "; - } - - buffer << close_bracket; - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name) -{ - const auto & window_node_typed = window_node->as(); - const auto & window_frame = window_node_typed.getWindowFrame(); - - bool parent_window_node_has_partition_by = false; - bool parent_window_node_has_order_by = false; - - if (parent_window_node) - { - const auto & parent_window_node_typed = parent_window_node->as(); - parent_window_node_has_partition_by = parent_window_node_typed.hasPartitionBy(); - parent_window_node_has_order_by = parent_window_node_typed.hasOrderBy(); - } - - WriteBufferFromOwnString buffer; - - if (!parent_window_name.empty()) - buffer << parent_window_name; - - if (!partition_by_projection_names.empty() && !parent_window_node_has_partition_by) - { - if (!parent_window_name.empty()) - buffer << ' '; - - buffer << "PARTITION BY "; - - size_t partition_by_projection_names_size = partition_by_projection_names.size(); - for (size_t i = 0; i < partition_by_projection_names_size; ++i) - { - buffer << partition_by_projection_names[i]; - if (i + 1 != partition_by_projection_names_size) - buffer << ", "; - } - } - - if (!order_by_projection_names.empty() && !parent_window_node_has_order_by) - { - if (!partition_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << "ORDER BY "; - - size_t order_by_projection_names_size = order_by_projection_names.size(); - for (size_t i = 0; i < order_by_projection_names_size; ++i) - { - buffer << order_by_projection_names[i]; - if (i + 1 != order_by_projection_names_size) - buffer << ", "; - } - } - - if (!window_frame.is_default) - { - if (!partition_by_projection_names.empty() || !order_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << window_frame.type << " BETWEEN "; - if (window_frame.begin_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.begin_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_begin_offset_projection_name; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - - buffer << " AND "; - - if (window_frame.end_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.end_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_end_offset_projection_name; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - } - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, const ProjectionName & fill_to_expression_projection_name, const ProjectionName & fill_step_expression_projection_name) -{ - auto & sort_node_typed = sort_column_node->as(); - - WriteBufferFromOwnString sort_column_projection_name_buffer; - sort_column_projection_name_buffer << sort_expression_projection_name; - - auto sort_direction = sort_node_typed.getSortDirection(); - sort_column_projection_name_buffer << (sort_direction == SortDirection::ASCENDING ? " ASC" : " DESC"); - - auto nulls_sort_direction = sort_node_typed.getNullsSortDirection(); - - if (nulls_sort_direction) - sort_column_projection_name_buffer << " NULLS " << (nulls_sort_direction == sort_direction ? "LAST" : "FIRST"); - - if (auto collator = sort_node_typed.getCollator()) - sort_column_projection_name_buffer << " COLLATE " << collator->getLocale(); - - if (sort_node_typed.withFill()) - { - sort_column_projection_name_buffer << " WITH FILL"; - - if (sort_node_typed.hasFillFrom()) - sort_column_projection_name_buffer << " FROM " << fill_from_expression_projection_name; - - if (sort_node_typed.hasFillTo()) - sort_column_projection_name_buffer << " TO " << fill_to_expression_projection_name; - - if (sort_node_typed.hasFillStep()) - sort_column_projection_name_buffer << " STEP " << fill_step_expression_projection_name; - } - - return sort_column_projection_name_buffer.str(); -} - -/// Get valid identifiers for typo correction from compound expression -void QueryAnalyzer::collectCompoundExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result) -{ - IDataType::forEachSubcolumn([&](const auto &, const auto & name, const auto &) - { - Identifier subcolumn_indentifier(name); - size_t new_identifier_size = valid_identifier_prefix.getPartsSize() + subcolumn_indentifier.getPartsSize(); - - if (new_identifier_size == unresolved_identifier.getPartsSize()) - { - auto new_identifier = valid_identifier_prefix; - for (const auto & part : subcolumn_indentifier) - new_identifier.push_back(part); - - valid_identifiers_result.insert(std::move(new_identifier)); - } - }, ISerialization::SubstreamData(compound_expression_type->getDefaultSerialization())); -} - -/// Get valid identifiers for typo correction from table expression -void QueryAnalyzer::collectTableExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result) -{ - for (const auto & [column_name, column_node] : table_expression_data.column_name_to_column_node) - { - Identifier column_identifier(column_name); - if (unresolved_identifier.getPartsSize() == column_identifier.getPartsSize()) - valid_identifiers_result.insert(column_identifier); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier, - valid_identifiers_result); - - if (table_expression->hasAlias()) - { - Identifier column_identifier_with_alias({table_expression->getAlias()}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_alias.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_alias.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_alias); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_alias, - valid_identifiers_result); - } - - if (!table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name({table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name, - valid_identifiers_result); - } - - if (!table_expression_data.database_name.empty() && !table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name_and_database_name({table_expression_data.database_name, table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name_and_database_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name_and_database_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name_and_database_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name_and_database_name, - valid_identifiers_result); - } - } -} - -/// Get valid identifiers for typo correction from scope without looking at parent scopes -void QueryAnalyzer::collectScopeValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - bool identifier_is_short = unresolved_identifier.isShort(); - bool identifier_is_compound = unresolved_identifier.isCompound(); - - if (allow_expression_identifiers) - { - for (const auto & [name, expression] : *scope.aliases.alias_name_to_expression_node) - { - assert(expression); - auto expression_identifier = Identifier(name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - - for (const auto & [table_expression, table_expression_data] : scope.table_expression_node_to_data) - { - collectTableExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - table_expression, - table_expression_data, - valid_identifiers_result); - } - } - - if (identifier_is_short) - { - if (allow_function_identifiers) - { - for (const auto & [name, _] : *scope.aliases.alias_name_to_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - - if (allow_table_expression_identifiers) - { - for (const auto & [name, _] : scope.aliases.alias_name_to_table_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - } - - for (const auto & [argument_name, expression] : scope.expression_argument_name_to_node) - { - assert(expression); - auto expression_node_type = expression->getNodeType(); - - if (allow_expression_identifiers && isExpressionNodeType(expression_node_type)) - { - auto expression_identifier = Identifier(argument_name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - else if (identifier_is_short && allow_function_identifiers && isFunctionExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - else if (allow_table_expression_identifiers && isTableExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - } -} - -void QueryAnalyzer::collectScopeWithParentScopesValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - const IdentifierResolveScope * current_scope = &scope; - - while (current_scope) - { - collectScopeValidIdentifiersForTypoCorrection(unresolved_identifier, - *current_scope, - allow_expression_identifiers, - allow_function_identifiers, - allow_table_expression_identifiers, - valid_identifiers_result); - - current_scope = current_scope->parent_scope; - } -} - -std::vector QueryAnalyzer::collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers) -{ - std::vector prompting_strings; - prompting_strings.reserve(valid_identifiers.size()); - - for (const auto & valid_identifier : valid_identifiers) - prompting_strings.push_back(valid_identifier.getFullName()); - - return NamePrompter<1>::getHints(unresolved_identifier.getFullName(), prompting_strings); -} - -/** Wrap expression node in tuple element function calls for nested paths. - * Example: Expression node: compound_expression. Nested path: nested_path_1.nested_path_2. - * Result: tupleElement(tupleElement(compound_expression, 'nested_path_1'), 'nested_path_2'). - */ -QueryTreeNodePtr QueryAnalyzer::wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path) -{ - size_t nested_path_parts_size = nested_path.getPartsSize(); - for (size_t i = 0; i < nested_path_parts_size; ++i) - { - const auto & nested_path_part = nested_path[i]; - auto tuple_element_function = std::make_shared("tupleElement"); - - auto & tuple_element_function_arguments_nodes = tuple_element_function->getArguments().getNodes(); - tuple_element_function_arguments_nodes.reserve(2); - tuple_element_function_arguments_nodes.push_back(expression_node); - tuple_element_function_arguments_nodes.push_back(std::make_shared(nested_path_part)); - - expression_node = std::move(tuple_element_function); - } - - return expression_node; -} - -/** Try to get lambda node from sql user defined functions if sql user defined function with function name exists. - * Returns lambda node if function exists, nullptr otherwise. - */ -QueryTreeNodePtr QueryAnalyzer::tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context) -{ - auto user_defined_function = UserDefinedSQLFunctionFactory::instance().tryGet(function_name); - if (!user_defined_function) - return {}; - - auto it = function_name_to_user_defined_lambda.find(function_name); - if (it != function_name_to_user_defined_lambda.end()) - return it->second; - - const auto & create_function_query = user_defined_function->as(); - auto result_node = buildQueryTree(create_function_query->function_core, context); - if (result_node->getNodeType() != QueryTreeNodeType::LAMBDA) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "SQL user defined function {} must represent lambda expression. Actual {}", - function_name, - create_function_query->function_core->formatForErrorMessage()); - - function_name_to_user_defined_lambda.emplace(function_name, result_node); - - return result_node; -} - -bool subtreeHasViewSource(const IQueryTreeNode * node, const Context & context) -{ - if (!node) - return false; - - if (const auto * table_node = node->as()) - { - if (table_node->getStorageID().getFullNameNotQuoted() == context.getViewSource()->getStorageID().getFullNameNotQuoted()) - return true; - } - - for (const auto & child : node->getChildren()) - if (subtreeHasViewSource(child.get(), context)) - return true; - - return false; -} - -/// Evaluate scalar subquery and perform constant folding if scalar subquery does not have constant value -void QueryAnalyzer::evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - auto * query_node = node->as(); - auto * union_node = node->as(); - if (!query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node must have query or union type. Actual {} {}", - node->getNodeTypeName(), - node->formatASTForErrorMessage()); - - auto & context = scope.context; - - Block scalar_block; - - auto node_without_alias = node->clone(); - node_without_alias->removeAlias(); - - QueryTreeNodePtrWithHash node_with_hash(node_without_alias); - auto str_hash = DB::toString(node_with_hash.hash); - - bool can_use_global_scalars = !only_analyze && !(context->getViewSource() && subtreeHasViewSource(node_without_alias.get(), *context)); - - auto & scalars_cache = can_use_global_scalars ? scalar_subquery_to_scalar_value_global : scalar_subquery_to_scalar_value_local; - - if (scalars_cache.contains(node_with_hash)) - { - if (can_use_global_scalars) - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - else - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesLocalCacheHit); - - scalar_block = scalars_cache.at(node_with_hash); - } - else if (context->hasQueryContext() && can_use_global_scalars && context->getQueryContext()->hasScalar(str_hash)) - { - scalar_block = context->getQueryContext()->getScalar(str_hash); - scalar_subquery_to_scalar_value_global.emplace(node_with_hash, scalar_block); - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - } - else - { - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesCacheMiss); - auto subquery_context = Context::createCopy(context); - - Settings subquery_settings = context->getSettings(); - subquery_settings.max_result_rows = 1; - subquery_settings.extremes = false; - subquery_context->setSettings(subquery_settings); - /// When execute `INSERT INTO t WITH ... SELECT ...`, it may lead to `Unknown columns` - /// exception with this settings enabled(https://github.com/ClickHouse/ClickHouse/issues/52494). - subquery_context->setSetting("use_structure_from_insertion_table_in_table_functions", false); - - auto options = SelectQueryOptions(QueryProcessingStage::Complete, scope.subquery_depth, true /*is_subquery*/); - options.only_analyze = only_analyze; - auto interpreter = std::make_unique(node->toAST(), subquery_context, subquery_context->getViewSource(), options); - - if (only_analyze) - { - /// If query is only analyzed, then constants are not correct. - scalar_block = interpreter->getSampleBlock(); - for (auto & column : scalar_block) - { - if (column.column->empty()) - { - auto mut_col = column.column->cloneEmpty(); - mut_col->insertDefault(); - column.column = std::move(mut_col); - } - } - } - else - { - auto io = interpreter->execute(); - PullingAsyncPipelineExecutor executor(io.pipeline); - io.pipeline.setProgressCallback(context->getProgressCallback()); - io.pipeline.setProcessListElement(context->getProcessListElement()); - - Block block; - - while (block.rows() == 0 && executor.pull(block)) - { - } - - if (block.rows() == 0) - { - auto types = interpreter->getSampleBlock().getDataTypes(); - if (types.size() != 1) - types = {std::make_shared(types)}; - - auto & type = types[0]; - if (!type->isNullable()) - { - if (!type->canBeInsideNullable()) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, - "Scalar subquery returned empty result of type {} which cannot be Nullable", - type->getName()); - - type = makeNullable(type); - } - - auto scalar_column = type->createColumn(); - scalar_column->insert(Null()); - scalar_block.insert({std::move(scalar_column), type, "null"}); - } - else - { - if (block.rows() != 1) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - Block tmp_block; - while (tmp_block.rows() == 0 && executor.pull(tmp_block)) - { - } - - if (tmp_block.rows() != 0) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - block = materializeBlock(block); - size_t columns = block.columns(); - - if (columns == 1) - { - auto & column = block.getByPosition(0); - /// Here we wrap type to nullable if we can. - /// It is needed cause if subquery return no rows, it's result will be Null. - /// In case of many columns, do not check it cause tuple can't be nullable. - if (!column.type->isNullable() && column.type->canBeInsideNullable()) - { - column.type = makeNullable(column.type); - column.column = makeNullable(column.column); - } - - scalar_block = block; - } - else - { - /** Make unique column names for tuple. - * - * Example: SELECT (SELECT 2 AS x, x) - */ - makeUniqueColumnNamesInBlock(block); - - scalar_block.insert({ - ColumnTuple::create(block.getColumns()), - std::make_shared(block.getDataTypes(), block.getNames()), - "tuple"}); - } - } - } - - scalars_cache.emplace(node_with_hash, scalar_block); - if (can_use_global_scalars && context->hasQueryContext()) - context->getQueryContext()->addScalar(str_hash, scalar_block); - } - - const auto & scalar_column_with_type = scalar_block.safeGetByPosition(0); - const auto & scalar_type = scalar_column_with_type.type; - - Field scalar_value; - scalar_column_with_type.column->get(0, scalar_value); - - const auto * scalar_type_name = scalar_block.safeGetByPosition(0).type->getFamilyName(); - static const std::set useless_literal_types = {"Array", "Tuple", "AggregateFunction", "Function", "Set", "LowCardinality"}; - auto * nearest_query_scope = scope.getNearestQueryScope(); - - /// Always convert to literals when there is no query context - if (!context->getSettingsRef().enable_scalar_subquery_optimization || - !useless_literal_types.contains(scalar_type_name) || - !context->hasQueryContext() || - !nearest_query_scope) - { - auto constant_value = std::make_shared(std::move(scalar_value), scalar_type); - auto constant_node = std::make_shared(constant_value, node); - - if (constant_node->getValue().isNull()) - { - node = buildCastFunction(constant_node, constant_node->getResultType(), context); - node = std::make_shared(std::move(constant_value), node); - } - else - node = std::move(constant_node); - - return; - } - - auto & nearest_query_scope_query_node = nearest_query_scope->scope_node->as(); - auto & mutable_context = nearest_query_scope_query_node.getMutableContext(); - - auto scalar_query_hash_string = DB::toString(node_with_hash.hash) + (only_analyze ? "_analyze" : ""); - - if (mutable_context->hasQueryContext()) - mutable_context->getQueryContext()->addScalar(scalar_query_hash_string, scalar_block); - - mutable_context->addScalar(scalar_query_hash_string, scalar_block); - - std::string get_scalar_function_name = "__getScalar"; - - auto scalar_query_hash_constant_value = std::make_shared(std::move(scalar_query_hash_string), std::make_shared()); - auto scalar_query_hash_constant_node = std::make_shared(std::move(scalar_query_hash_constant_value)); - - auto get_scalar_function_node = std::make_shared(get_scalar_function_name); - get_scalar_function_node->getArguments().getNodes().push_back(std::move(scalar_query_hash_constant_node)); - - auto get_scalar_function = FunctionFactory::instance().get(get_scalar_function_name, mutable_context); - get_scalar_function_node->resolveAsFunction(get_scalar_function->build(get_scalar_function_node->getArgumentColumns())); - - node = std::move(get_scalar_function_node); -} - -void QueryAnalyzer::mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope) -{ - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - - auto & parent_window_node_typed = parent_window_node->as(); - - /** If an existing_window_name is specified it must refer to an earlier - * entry in the WINDOW list; the new window copies its partitioning clause - * from that entry, as well as its ordering clause if any. In this case - * the new window cannot specify its own PARTITION BY clause, and it can - * specify ORDER BY only if the copied window does not have one. The new - * window always uses its own frame clause; the copied window must not - * specify a frame clause. - * https://www.postgresql.org/docs/current/sql-select.html - */ - if (window_node_typed.hasPartitionBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override PARTITION BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (window_node_typed.hasOrderBy() && parent_window_node_typed.hasOrderBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override a non-empty ORDER BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (!parent_window_node_typed.getWindowFrame().is_default) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parent window '{}' is not allowed to define a frame: while processing derived window definition '{}'. In scope {}", - parent_window_name, - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - window_node_typed.getPartitionByNode() = parent_window_node_typed.getPartitionBy().clone(); - - if (parent_window_node_typed.hasOrderBy()) - window_node_typed.getOrderByNode() = parent_window_node_typed.getOrderBy().clone(); -} - -/** Replace nodes in node list with positional arguments. - * - * Example: SELECT id, value FROM test_table GROUP BY 1, 2; - * Example: SELECT id, value FROM test_table ORDER BY 1, 2; - * Example: SELECT id, value FROM test_table LIMIT 5 BY 1, 2; - */ -void QueryAnalyzer::replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope) -{ - const auto & settings = scope.context->getSettingsRef(); - if (!settings.enable_positional_arguments || scope.context->getClientInfo().query_kind != ClientInfo::QueryKind::INITIAL_QUERY) - return; - - auto & node_list_typed = node_list->as(); - - for (auto & node : node_list_typed.getNodes()) - { - auto * node_to_replace = &node; - - if (auto * sort_node = node->as()) - node_to_replace = &sort_node->getExpression(); - - auto * constant_node = (*node_to_replace)->as(); - - if (!constant_node - || (constant_node->getValue().getType() != Field::Types::UInt64 - && constant_node->getValue().getType() != Field::Types::Int64)) - continue; - - UInt64 pos; - if (constant_node->getValue().getType() == Field::Types::UInt64) - { - pos = constant_node->getValue().get(); - } - else // Int64 - { - auto value = constant_node->getValue().get(); - if (value > 0) - pos = value; - else - { - if (value < -static_cast(projection_nodes.size())) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Negative positional argument number {} is out of bounds. Expected in range [-{}, -1]. In scope {}", - value, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - pos = projection_nodes.size() + value + 1; - } - } - - if (!pos || pos > projection_nodes.size()) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Positional argument number {} is out of bounds. Expected in range [1, {}]. In scope {}", - pos, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - - --pos; - *node_to_replace = projection_nodes[pos]->clone(); - if (auto it = resolved_expressions.find(projection_nodes[pos]); it != resolved_expressions.end()) - { - resolved_expressions[*node_to_replace] = it->second; - } - } -} - -void QueryAnalyzer::convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope) -{ - const auto * limit_offset_constant_node = expression_node->as(); - if (!limit_offset_constant_node || !isNativeNumber(removeNullable(limit_offset_constant_node->getResultType()))) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} expression must be constant with numeric type. Actual {}. In scope {}", - expression_description, - expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - Field converted_value = convertFieldToType(limit_offset_constant_node->getValue(), DataTypeUInt64()); - if (converted_value.isNull()) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} numeric constant expression is not representable as UInt64", - expression_description); - - auto constant_value = std::make_shared(std::move(converted_value), std::make_shared()); - auto result_constant_node = std::make_shared(std::move(constant_value)); - result_constant_node->getSourceExpression() = limit_offset_constant_node->getSourceExpression(); - - expression_node = std::move(result_constant_node); -} - -void QueryAnalyzer::validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unexpected table expression. Expected table, table function, query or union node. Table node: {}, scope node: {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (table_node || table_function_node) - { - auto table_expression_modifiers = table_node ? table_node->getTableExpressionModifiers() : table_function_node->getTableExpressionModifiers(); - - if (table_expression_modifiers.has_value()) - { - const auto & storage = table_node ? table_node->getStorage() : table_function_node->getStorage(); - if (table_expression_modifiers->hasFinal() && !storage->supportsFinal()) - throw Exception(ErrorCodes::ILLEGAL_FINAL, - "Storage {} doesn't support FINAL", - storage->getName()); - - if (table_expression_modifiers->hasSampleSizeRatio() && !storage->supportsSampling()) - throw Exception(ErrorCodes::SAMPLING_NOT_SUPPORTED, - "Storage {} doesn't support sampling", - storage->getStorageID().getFullNameNotQuoted()); - } - } -} - -void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - bool table_expression_has_alias = table_expression_node->hasAlias(); - if (table_expression_has_alias) - return; - - if (join_node->as().getKind() == JoinKind::Paste) - return; - - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - if ((query_node && !query_node->getCTEName().empty()) || (union_node && !union_node->getCTEName().empty())) - return; - - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || - table_expression_node_type == QueryTreeNodeType::QUERY || - table_expression_node_type == QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::ALIAS_REQUIRED, - "JOIN {} no alias for subquery or table function {}. " - "In scope {} (set joined_subquery_requires_alias = 0 to disable restriction)", - join_node->formatASTForErrorMessage(), - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); -} - -std::pair QueryAnalyzer::recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into) -{ - checkStackSize(); - - if (node->as()) - { - into.push_back(node); - return {false, 1}; - } - - auto * function = node->as(); - - if (!function) - return {false, 0}; - - if (function->isAggregateFunction()) - return {true, 0}; - - UInt64 pushed_children = 0; - bool has_aggregate = false; - - for (auto & child : function->getArguments().getNodes()) - { - auto [child_has_aggregate, child_pushed_children] = recursivelyCollectMaxOrdinaryExpressions(child, into); - has_aggregate |= child_has_aggregate; - pushed_children += child_pushed_children; - } - - /// The current function is not aggregate function and there is no aggregate function in its arguments, - /// so use the current function to replace its arguments - if (!has_aggregate) - { - for (UInt64 i = 0; i < pushed_children; i++) - into.pop_back(); - - into.push_back(node); - pushed_children = 1; - } - - return {has_aggregate, pushed_children}; -} - -/** Expand GROUP BY ALL by extracting all the SELECT-ed expressions that are not aggregate functions. - * - * For a special case that if there is a function having both aggregate functions and other fields as its arguments, - * the `GROUP BY` keys will contain the maximum non-aggregate fields we can extract from it. - * - * Example: - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY ALL - * will expand as - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY substring(a, 4, 2), substring(a, 1, 2) - */ -void QueryAnalyzer::expandGroupByAll(QueryNode & query_tree_node_typed) -{ - if (!query_tree_node_typed.isGroupByAll()) - return; - - auto & group_by_nodes = query_tree_node_typed.getGroupBy().getNodes(); - auto & projection_list = query_tree_node_typed.getProjection(); - - for (auto & node : projection_list.getNodes()) - recursivelyCollectMaxOrdinaryExpressions(node, group_by_nodes); - query_tree_node_typed.setIsGroupByAll(false); -} - -void QueryAnalyzer::expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings) -{ - if (!settings.enable_order_by_all || !query_tree_node_typed.isOrderByAll()) - return; - - auto * all_node = query_tree_node_typed.getOrderBy().getNodes()[0]->as(); - if (!all_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Select analyze for not sort node."); - - auto & projection_nodes = query_tree_node_typed.getProjection().getNodes(); - auto list_node = std::make_shared(); - list_node->getNodes().reserve(projection_nodes.size()); - - for (auto & node : projection_nodes) - { - /// Detect and reject ambiguous statements: - /// E.g. for a table with columns "all", "a", "b": - /// - SELECT all, a, b ORDER BY all; -- should we sort by all columns in SELECT or by column "all"? - /// - SELECT a, b AS all ORDER BY all; -- like before but "all" as alias - /// - SELECT func(...) AS all ORDER BY all; -- like before but "all" as function - /// - SELECT a, b ORDER BY all; -- tricky in other way: does the user want to sort by columns in SELECT clause or by not SELECTed column "all"? - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - auto projection_names = resolved_expression_it->second; - if (projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected 1 projection names. Actual {}", - projection_names.size()); - if (boost::iequals(projection_names[0], "all")) - throw Exception(ErrorCodes::UNEXPECTED_EXPRESSION, - "Cannot use ORDER BY ALL to sort a column with name 'all', please disable setting `enable_order_by_all` and try again"); - } - - auto sort_node = std::make_shared(node, all_node->getSortDirection(), all_node->getNullsSortDirection()); - list_node->getNodes().push_back(sort_node); - } - - query_tree_node_typed.getOrderByNode() = list_node; - query_tree_node_typed.setIsOrderByAll(false); -} - -std::string QueryAnalyzer::rewriteAggregateFunctionNameIfNeeded( - const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context) -{ - std::string result_aggregate_function_name = aggregate_function_name; - auto aggregate_function_name_lowercase = Poco::toLower(aggregate_function_name); - - const auto & settings = context->getSettingsRef(); - - if (aggregate_function_name_lowercase == "countdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - } - else if (aggregate_function_name_lowercase == "countdistinctif" || aggregate_function_name_lowercase == "countifdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - result_aggregate_function_name += "If"; - } - - /// Replace aggregateFunctionIfDistinct into aggregateFunctionDistinctIf to make execution more optimal - if (result_aggregate_function_name.ends_with("ifdistinct")) - { - size_t prefix_length = result_aggregate_function_name.size() - strlen("ifdistinct"); - result_aggregate_function_name = result_aggregate_function_name.substr(0, prefix_length) + "DistinctIf"; - } - - bool need_add_or_null = settings.aggregate_functions_null_for_empty && !result_aggregate_function_name.ends_with("OrNull"); - if (need_add_or_null) - { - auto properties = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (!properties->returns_default_when_only_null) - result_aggregate_function_name += "OrNull"; - } - - /** Move -OrNull suffix ahead, this should execute after add -OrNull suffix. - * Used to rewrite aggregate functions with -OrNull suffix in some cases. - * Example: sumIfOrNull. - * Result: sumOrNullIf. - */ - if (result_aggregate_function_name.ends_with("OrNull")) - { - auto function_properies = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (function_properies && !function_properies->returns_default_when_only_null) - { - size_t function_name_size = result_aggregate_function_name.size(); - - static constexpr std::array suffixes_to_replace = {"MergeState", "Merge", "State", "If"}; - for (const auto & suffix : suffixes_to_replace) - { - auto suffix_string_value = String(suffix); - auto suffix_to_check = suffix_string_value + "OrNull"; - - if (!result_aggregate_function_name.ends_with(suffix_to_check)) - continue; - - result_aggregate_function_name = result_aggregate_function_name.substr(0, function_name_size - suffix_to_check.size()); - result_aggregate_function_name += "OrNull"; - result_aggregate_function_name += suffix_string_value; - - break; - } - } - } - - return result_aggregate_function_name; -} - -/// Resolve identifier functions implementation - -/// Try resolve table identifier from database catalog -QueryTreeNodePtr QueryAnalyzer::tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context) -{ - size_t parts_size = table_identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected table identifier to contain 1 or 2 parts. Actual '{}'", - table_identifier.getFullName()); - - std::string database_name; - std::string table_name; - - if (table_identifier.isCompound()) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - else - { - table_name = table_identifier[0]; - } - - StorageID storage_id(database_name, table_name); - storage_id = context->resolveStorageID(storage_id); - bool is_temporary_table = storage_id.getDatabaseName() == DatabaseCatalog::TEMPORARY_DATABASE; - - StoragePtr storage; - - if (is_temporary_table) - storage = DatabaseCatalog::instance().getTable(storage_id, context); - else - storage = DatabaseCatalog::instance().tryGetTable(storage_id, context); - - if (!storage) - return {}; - - auto storage_lock = storage->lockForShare(context->getInitialQueryId(), context->getSettingsRef().lock_acquire_timeout); - auto storage_snapshot = storage->getStorageSnapshot(storage->getInMemoryMetadataPtr(), context); - auto result = std::make_shared(std::move(storage), std::move(storage_lock), std::move(storage_snapshot)); - if (is_temporary_table) - result->setTemporaryTableName(table_name); - - return result; -} - -/// Resolve identifier from compound expression -/// If identifier cannot be resolved throw exception or return nullptr if can_be_not_found is true -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found) -{ - Identifier compound_expression_identifier; - for (size_t i = 0; i < identifier_bind_size; ++i) - compound_expression_identifier.push_back(expression_identifier[i]); - - IdentifierView nested_path(expression_identifier); - nested_path.popFirst(identifier_bind_size); - - auto expression_type = compound_expression->getResultType(); - - if (!expression_type->hasSubcolumn(nested_path.getFullName())) - { - if (auto * column = compound_expression->as()) - { - const DataTypePtr & column_type = column->getColumn().getTypeInStorage(); - if (column_type->getTypeId() == TypeIndex::Object) - { - const auto * object_type = checkAndGetDataType(column_type.get()); - if (object_type->getSchemaFormat() == "json" && object_type->hasNullableSubcolumns()) - { - QueryTreeNodePtr constant_node_null = std::make_shared(Field()); - return constant_node_null; - } - } - } - - if (can_be_not_found) - return {}; - - std::unordered_set valid_identifiers; - collectCompoundExpressionValidIdentifiersForTypoCorrection(expression_identifier, - expression_type, - compound_expression_identifier, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(expression_identifier, valid_identifiers); - - String compound_expression_from_error_message; - if (!compound_expression_source.empty()) - { - compound_expression_from_error_message += " from "; - compound_expression_from_error_message += compound_expression_source; - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier {} nested path {} cannot be resolved from type {}{}. In scope {}{}", - expression_identifier, - nested_path, - expression_type->getName(), - compound_expression_from_error_message, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - QueryTreeNodePtr get_subcolumn_function = std::make_shared("getSubcolumn"); - auto & get_subcolumn_function_arguments_nodes = get_subcolumn_function->as()->getArguments().getNodes(); - - get_subcolumn_function_arguments_nodes.reserve(2); - get_subcolumn_function_arguments_nodes.push_back(compound_expression); - get_subcolumn_function_arguments_nodes.push_back(std::make_shared(nested_path.getFullName())); - - resolveFunction(get_subcolumn_function, scope); - return get_subcolumn_function; -} - -/** Resolve identifier from expression arguments. - * - * Expression arguments can be initialized during lambda analysis or they could be provided externally. - * Expression arguments must be already resolved nodes. This is client responsibility to resolve them. - * - * Example: SELECT arrayMap(x -> x + 1, [1,2,3]); - * For lambda x -> x + 1, `x` is lambda expression argument. - * - * Resolve strategy: - * 1. Try to bind identifier to scope argument name to node map. - * 2. If identifier is binded but expression context and node type are incompatible return nullptr. - * - * It is important to support edge cases, where we lookup for table or function node, but argument has same name. - * Example: WITH (x -> x + 1) AS func, (func -> func(1) + func) AS lambda SELECT lambda(1); - * - * 3. If identifier is compound and identifier lookup is in expression context use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - auto it = scope.expression_argument_name_to_node.find(identifier_lookup.identifier.getFullName()); - bool resolve_full_identifier = it != scope.expression_argument_name_to_node.end(); - - if (!resolve_full_identifier) - { - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - it = scope.expression_argument_name_to_node.find(identifier_bind_part); - if (it == scope.expression_argument_name_to_node.end()) - return {}; - } - - auto node_type = it->second->getNodeType(); - if (identifier_lookup.isExpressionLookup() && !isExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isTableExpressionLookup() && !isTableExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isFunctionLookup() && !isFunctionExpressionNodeType(node_type)) - return {}; - - if (!resolve_full_identifier && identifier_lookup.identifier.isCompound() && identifier_lookup.isExpressionLookup()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return it->second; -} - -bool QueryAnalyzer::tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope) -{ - return scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME) != nullptr || scope.aliases.array_join_aliases.contains(identifier_lookup.identifier.front()); -} - -/** Resolve identifier from scope aliases. - * - * Resolve strategy: - * 1. If alias is registered in current expressions that are in resolve process and if top expression is not part of bottom expression with the same alias subtree - * throw cyclic aliases exception. - * Otherwise prevent cache usage for identifier lookup and return nullptr. - * - * This is special scenario where identifier has name the same as alias name in one of its parent expressions including itself. - * In such case we cannot resolve identifier from aliases because of recursion. It is client responsibility to register and deregister alias - * names during expressions resolve. - * - * We must prevent cache usage for lookup because lookup outside of expression is supposed to return other value. - * Example: SELECT (id + 1) AS id, id + 2. Lookup for id inside (id + 1) as id should return id from table, but lookup (id + 2) should return - * (id + 1) AS id. - * - * Below cases should work: - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * SELECT (id + 1) AS id FROM test_table; - * SELECT (1 + (1 + id)) AS id FROM test_table; - * - * Below cases should throw cyclic aliases exception: - * SELECT (id + b) AS id, id as b FROM test_table; - * SELECT (1 + b + 1 + id) AS id, b as c, id as b FROM test_table; - * - * 2. Depending on IdentifierLookupContext get alias name to node map from IdentifierResolveScope. - * 3. Try to bind identifier to alias name in map. If there are no such binding return nullptr. - * 4. If node in map is not resolved, resolve it. It is important in case of compound expressions. - * Example: SELECT value.a, cast('(1)', 'Tuple(a UInt64)') AS value; - * - * Special case if node is identifier node. - * Example: SELECT value, id AS value FROM test_table; - * - * Add node in current scope expressions in resolve process stack. - * Try to resolve identifier. - * If identifier is resolved, depending on lookup context, erase entry from expression or lambda map. Check QueryExpressionsAliasVisitor documentation. - * Pop node from current scope expressions in resolve process stack. - * - * 5. If identifier is compound and identifier lookup is in expression context, use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - auto * it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME); - if (it == nullptr) - return {}; - - QueryTreeNodePtr & alias_node = *it; - - if (!alias_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node with alias {} is not valid. In scope {}", - identifier_bind_part, - scope.scope_node->formatASTForErrorMessage()); - - if (auto root_expression_with_alias = scope.expressions_in_resolve_process_stack.getExpressionWithAlias(identifier_bind_part)) - { - const auto top_expression = scope.expressions_in_resolve_process_stack.getTop(); - - if (!isNodePartOfTree(top_expression.get(), root_expression_with_alias.get())) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - scope.non_cached_identifier_lookups_during_expression_resolve.insert(identifier_lookup); - return {}; - } - - auto node_type = alias_node->getNodeType(); - - /// Resolve expression if necessary - if (node_type == QueryTreeNodeType::IDENTIFIER) - { - scope.pushExpressionNode(alias_node); - - auto & alias_identifier_node = alias_node->as(); - auto identifier = alias_identifier_node.getIdentifier(); - auto lookup_result = tryResolveIdentifier(IdentifierLookup{identifier, identifier_lookup.lookup_context}, scope, identifier_resolve_settings); - if (!lookup_result.resolved_identifier) - { - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(identifier, scope, true, false, false, valid_identifiers); - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {} identifier '{}'. In scope {}{}", - toStringLowercase(identifier_lookup.lookup_context), - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - alias_node = lookup_result.resolved_identifier; - scope.popExpressionNode(); - } - else if (node_type == QueryTreeNodeType::FUNCTION) - { - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - else if (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION) - { - if (identifier_resolve_settings.allow_to_resolve_subquery_during_identifier_resolution) - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, identifier_lookup.isTableExpressionLookup() /*allow_table_expression*/); - } - - if (identifier_lookup.identifier.isCompound() && alias_node) - { - if (identifier_lookup.isExpressionLookup()) - { - return tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - 1 /*identifier_bind_size*/, - alias_node, - {} /* compound_expression_source */, - scope, - identifier_resolve_settings.allow_to_check_join_tree /* can_be_not_found */); - } - else if (identifier_lookup.isFunctionLookup() || identifier_lookup.isTableExpressionLookup()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Compound identifier '{}' cannot be resolved as {}. In scope {}", - identifier_lookup.identifier.getFullName(), - identifier_lookup.isFunctionLookup() ? "function" : "table expression", - scope.scope_node->formatASTForErrorMessage()); - } - } - - return alias_node; -} - -/** Resolve identifier from table columns. - * - * 1. If table column nodes are empty or identifier is not expression lookup return nullptr. - * 2. If identifier full name match table column use column. Save information that we resolve identifier using full name. - * 3. Else if identifier binds to table column, use column. - * 4. Try to resolve column ALIAS expression if it exists. - * 5. If identifier was compound and was not resolved using full name during step 1 use `tryResolveIdentifierFromCompoundExpression`. - * This can be the case with compound ALIAS columns. - * - * Example: - * CREATE TABLE test_table (id UInt64, value Tuple(id UInt64, value String), alias_value ALIAS value.id) ENGINE=TinyLog; - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - if (scope.column_name_to_column_node.empty() || !identifier_lookup.isExpressionLookup()) - return {}; - - const auto & identifier = identifier_lookup.identifier; - auto it = scope.column_name_to_column_node.find(identifier.getFullName()); - bool full_column_name_match = it != scope.column_name_to_column_node.end(); - - if (!full_column_name_match) - { - it = scope.column_name_to_column_node.find(identifier_lookup.identifier[0]); - if (it == scope.column_name_to_column_node.end()) - return {}; - } - - if (it->second->hasExpression()) - resolveExpressionNode(it->second->getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - QueryTreeNodePtr result = it->second; - - if (!full_column_name_match && identifier.isCompound()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return result; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - if (parts_size == 1 && path_start == table_name) - return true; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return true; - else - return false; - } - - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier)) || table_expression_data.canBindIdentifier(IdentifierView(identifier))) - return true; - - if (identifier.getPartsSize() == 1) - return false; - - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return true; - - if (identifier.getPartsSize() == 2) - return false; - - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return true; - - return false; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node_to_ignore, - const IdentifierResolveScope & scope) -{ - bool can_bind_identifier_to_table_expression = false; - - for (const auto & [table_expression_node, _] : scope.table_expression_node_to_data) - { - if (table_expression_node.get() == table_expression_node_to_ignore.get()) - continue; - - can_bind_identifier_to_table_expression = tryBindIdentifierToTableExpression(identifier_lookup, table_expression_node, scope); - if (can_bind_identifier_to_table_expression) - break; - } - - return can_bind_identifier_to_table_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found) -{ - auto identifier_without_column_qualifier = identifier; - identifier_without_column_qualifier.popFirst(identifier_column_qualifier_parts); - - /** Compound identifier cannot be resolved directly from storage if storage is not table. - * - * Example: SELECT test_table.id.value1.value2 FROM test_table; - * In table storage column test_table.id.value1.value2 will exists. - * - * Example: SELECT test_subquery.compound_expression.value FROM (SELECT compound_expression AS value) AS test_subquery; - * Here there is no column with name test_subquery.compound_expression.value, and additional wrap in tuple element is required. - */ - - QueryTreeNodePtr result_expression; - bool match_full_identifier = false; - - const auto & identifier_full_name = identifier_without_column_qualifier.getFullName(); - auto it = table_expression_data.column_name_to_column_node.find(identifier_full_name); - bool can_resolve_directly_from_storage = it != table_expression_data.column_name_to_column_node.end(); - if (can_resolve_directly_from_storage && table_expression_data.subcolumn_names.contains(identifier_full_name)) - { - /** In the case when we have an ARRAY JOIN, we should not resolve subcolumns directly from storage. - * For example, consider the following SQL query: - * SELECT ProfileEvents.Values FROM system.query_log ARRAY JOIN ProfileEvents - * In this case, ProfileEvents.Values should also be array joined, not directly resolved from storage. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - if (nearest_query_scope_query_node && nearest_query_scope_query_node->getJoinTree()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - can_resolve_directly_from_storage = false; - } - - if (can_resolve_directly_from_storage) - { - match_full_identifier = true; - result_expression = it->second; - } - else - { - it = table_expression_data.column_name_to_column_node.find(identifier_without_column_qualifier.at(0)); - if (it != table_expression_data.column_name_to_column_node.end()) - result_expression = it->second; - } - - bool clone_is_needed = true; - - String table_expression_source = table_expression_data.table_expression_description; - if (!table_expression_data.table_expression_name.empty()) - table_expression_source += " with name " + table_expression_data.table_expression_name; - - if (result_expression && !match_full_identifier && identifier_without_column_qualifier.isCompound()) - { - size_t identifier_bind_size = identifier_column_qualifier_parts + 1; - result_expression = tryResolveIdentifierFromCompoundExpression(identifier, - identifier_bind_size, - result_expression, - table_expression_source, - scope, - can_be_not_found); - if (can_be_not_found && !result_expression) - return {}; - clone_is_needed = false; - } - - if (!result_expression) - { - QueryTreeNodes nested_column_nodes; - DataTypes nested_types; - Array nested_names_array; - - for (const auto & [column_name, _] : table_expression_data.column_names_and_types) - { - Identifier column_name_identifier_without_last_part(column_name); - auto column_name_identifier_last_part = column_name_identifier_without_last_part.getParts().back(); - column_name_identifier_without_last_part.popLast(); - - if (identifier_without_column_qualifier.getFullName() != column_name_identifier_without_last_part.getFullName()) - continue; - - auto column_node_it = table_expression_data.column_name_to_column_node.find(column_name); - if (column_node_it == table_expression_data.column_name_to_column_node.end()) - continue; - - const auto & column_node = column_node_it->second; - const auto & column_type = column_node->getColumnType(); - const auto * column_type_array = typeid_cast(column_type.get()); - if (!column_type_array) - continue; - - nested_column_nodes.push_back(column_node); - nested_types.push_back(column_type_array->getNestedType()); - nested_names_array.push_back(Field(std::move(column_name_identifier_last_part))); - } - - if (!nested_types.empty()) - { - auto nested_function_node = std::make_shared("nested"); - auto & nested_function_node_arguments = nested_function_node->getArguments().getNodes(); - - auto nested_function_names_array_type = std::make_shared(std::make_shared()); - auto nested_function_names_constant_node = std::make_shared(std::move(nested_names_array), - std::move(nested_function_names_array_type)); - nested_function_node_arguments.push_back(std::move(nested_function_names_constant_node)); - nested_function_node_arguments.insert(nested_function_node_arguments.end(), - nested_column_nodes.begin(), - nested_column_nodes.end()); - - auto nested_function = FunctionFactory::instance().get(nested_function_node->getFunctionName(), scope.context); - nested_function_node->resolveAsFunction(nested_function->build(nested_function_node->getArgumentColumns())); - - clone_is_needed = false; - result_expression = std::move(nested_function_node); - } - } - - if (!result_expression) - { - if (can_be_not_found) - return {}; - std::unordered_set valid_identifiers; - collectTableExpressionValidIdentifiersForTypoCorrection(identifier, - table_expression_node, - table_expression_data, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Identifier '{}' cannot be resolved from {}. In scope {}{}", - identifier.getFullName(), - table_expression_source, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (clone_is_needed) - result_expression = result_expression->clone(); - - auto qualified_identifier = identifier; - - for (size_t i = 0; i < identifier_column_qualifier_parts; ++i) - { - auto qualified_identifier_with_removed_part = qualified_identifier; - qualified_identifier_with_removed_part.popFirst(); - - if (qualified_identifier_with_removed_part.empty()) - break; - - IdentifierLookup column_identifier_lookup = {qualified_identifier_with_removed_part, IdentifierLookupContext::EXPRESSION}; - if (tryBindIdentifierToAliases(column_identifier_lookup, scope)) - break; - - if (table_expression_data.should_qualify_columns && - tryBindIdentifierToTableExpressions(column_identifier_lookup, table_expression_node, scope)) - break; - - qualified_identifier = std::move(qualified_identifier_with_removed_part); - } - - auto qualified_identifier_full_name = qualified_identifier.getFullName(); - node_to_projection_name.emplace(result_expression, std::move(qualified_identifier_full_name)); - - return result_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (parts_size == 1 && path_start == table_name) - return table_expression_node; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return table_expression_node; - else - return {}; - } - - /** If identifier first part binds to some column start or table has full identifier name. Then we can try to find whole identifier in table. - * 1. Try to bind identifier first part to column in table, if true get full identifier from table or throw exception. - * 2. Try to bind identifier first part to table name or storage alias, if true remove first part and try to get full identifier from table or throw exception. - * Storage alias works for subquery, table function as well. - * 3. Try to bind identifier first parts to database name and table name, if true remove first two parts and try to get full identifier from table or throw exception. - */ - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier))) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/); - - if (table_expression_data.canBindIdentifier(IdentifierView(identifier))) - { - /** This check is insufficient to determine whether and identifier can be resolved from table expression. - * A further check will be performed in `tryResolveIdentifierFromStorage` to see if we have such a subcolumn. - * In cases where the subcolumn cannot be found we want to have `nullptr` instead of exception. - * So, we set `can_be_not_found = true` to have an attempt to resolve the identifier from another table expression. - * Example: `SELECT t.t from (SELECT 1 as t) AS a FULL JOIN (SELECT 1 as t) as t ON a.t = t.t;` - * Initially, we will try to resolve t.t from `a` because `t.` is bound to `1 as t`. However, as it is not a nested column, we will need to resolve it from the second table expression. - */ - auto resolved_identifier = tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/, true /*can_be_not_found*/); - if (resolved_identifier) - return resolved_identifier; - } - - if (identifier.getPartsSize() == 1) - return {}; - - const auto & table_name = table_expression_data.table_name; - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 1 /*identifier_column_qualifier_parts*/); - - if (identifier.getPartsSize() == 2) - return {}; - - const auto & database_name = table_expression_data.database_name; - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 2 /*identifier_column_qualifier_parts*/); - - return {}; -} - -QueryTreeNodePtr checkIsMissedObjectJSONSubcolumn(const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier) -{ - if (left_resolved_identifier && right_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT - && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL" && right_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (left_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (right_resolved_identifier && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & right_resolved_column = right_resolved_identifier->as(); - if (right_resolved_column.getValueStringRepresentation() == "NULL") - return right_resolved_identifier; - } - return {}; -} - -/// Used to replace columns that changed type because of JOIN to their original type -class ReplaceColumnsVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit ReplaceColumnsVisitor(const QueryTreeNodePtrWithHashMap & replacement_map_, const ContextPtr & context_) - : replacement_map(replacement_map_) - , context(context_) - {} - - /// Apply replacement transitively, because column may change it's type twice, one to have a supertype and then because of `joun_use_nulls` - static QueryTreeNodePtr findTransitiveReplacement(QueryTreeNodePtr node, const QueryTreeNodePtrWithHashMap & replacement_map_) - { - auto it = replacement_map_.find(node); - QueryTreeNodePtr result_node = nullptr; - for (; it != replacement_map_.end(); it = replacement_map_.find(result_node)) - { - if (result_node && result_node->isEqual(*it->second)) - { - Strings map_dump; - for (const auto & [k, v]: replacement_map_) - map_dump.push_back(fmt::format("{} -> {} (is_equals: {}, is_same: {})", - k.node->dumpTree(), v->dumpTree(), k.node->isEqual(*v), k.node == v)); - throw Exception(ErrorCodes::LOGICAL_ERROR, "Infinite loop in query tree replacement map: {}", fmt::join(map_dump, "; ")); - } - chassert(it->second); - - result_node = it->second; - } - return result_node; - } - - void visitImpl(QueryTreeNodePtr & node) - { - if (auto replacement_node = findTransitiveReplacement(node, replacement_map)) - node = replacement_node; - - if (auto * function_node = node->as(); function_node && function_node->isResolved()) - rerunFunctionResolve(function_node, context); - } - - /// We want to re-run resolve for function _after_ its arguments are replaced - bool shouldTraverseTopToBottom() const { return false; } - - bool needChildVisit(QueryTreeNodePtr & /* parent */, QueryTreeNodePtr & child) - { - /// Visit only expressions, but not subqueries - return child->getNodeType() == QueryTreeNodeType::IDENTIFIER - || child->getNodeType() == QueryTreeNodeType::LIST - || child->getNodeType() == QueryTreeNodeType::FUNCTION - || child->getNodeType() == QueryTreeNodeType::COLUMN; - } - -private: - const QueryTreeNodePtrWithHashMap & replacement_map; - const ContextPtr & context; -}; - -/// Compare resolved identifiers considering columns that become nullable after JOIN -bool resolvedIdenfiersFromJoinAreEquals( - const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier, - const IdentifierResolveScope & scope) -{ - auto left_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(left_resolved_identifier, scope.join_columns_with_changed_types); - const auto & left_resolved_to_compare = left_original_node ? left_original_node : left_resolved_identifier; - - auto right_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(right_resolved_identifier, scope.join_columns_with_changed_types); - const auto & right_resolved_to_compare = right_original_node ? right_original_node : right_resolved_identifier; - - return left_resolved_to_compare->isEqual(*right_resolved_to_compare, IQueryTreeNode::CompareOptions{.compare_aliases = false}); -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_join_node = table_expression_node->as(); - auto left_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getLeftTableExpression(), scope); - auto right_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getRightTableExpression(), scope); - - if (!identifier_lookup.isExpressionLookup()) - { - if (left_resolved_identifier && right_resolved_identifier) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.dump(), - scope.scope_node->formatASTForErrorMessage()); - - return left_resolved_identifier ? left_resolved_identifier : right_resolved_identifier; - } - - bool join_node_in_resolve_process = scope.table_expressions_in_resolve_process.contains(table_expression_node.get()); - - std::unordered_map join_using_column_name_to_column_node; - - if (!join_node_in_resolve_process && from_join_node.isUsingJoinExpression()) - { - auto & join_using_list = from_join_node.getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & column_node = join_using_node->as(); - join_using_column_name_to_column_node.emplace(column_node.getColumnName(), std::static_pointer_cast(join_using_node)); - } - } - - auto check_nested_column_not_in_using = [&join_using_column_name_to_column_node, &identifier_lookup](const QueryTreeNodePtr & node) - { - /** tldr: When an identifier is resolved into the function `nested` or `getSubcolumn`, and - * some column in its argument is in the USING list and its type has to be updated, we throw an error to avoid overcomplication. - * - * Identifiers can be resolved into functions in case of nested or subcolumns. - * For example `t.t.t` can be resolved into `getSubcolumn(t, 't.t')` function in case of `t` is `Tuple`. - * So, `t` in USING list is resolved from JOIN itself and has supertype of columns from left and right table. - * But `t` in `getSubcolumn` argument is still resolved from table and we need to update its type. - * - * Example: - * - * SELECT t.t FROM ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t UInt32, s1 String), s1 String) as t - * ) AS a FULL JOIN ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t Int32, s2 String), s2 String) as t - * ) AS b USING t; - * - * Result type of `t` is `Tuple(Tuple(Int64, String), String)` (different type and no names for subcolumns), - * so it may be tricky to have a correct type for `t.t` that is resolved into getSubcolumn(t, 't'). - * - * It can be more complicated in case of Nested subcolumns, in that case in query: - * SELECT t FROM ... JOIN ... USING (t.t) - * Here, `t` is resolved into function `nested(['t', 's'], t.t, t.s) so, `t.t` should be from JOIN and `t.s` should be from table. - * - * Updating type accordingly is pretty complicated, so just forbid such cases. - * - * While it still may work for storages that support selecting subcolumns directly without `getSubcolumn` function: - * SELECT t, t.t, toTypeName(t), toTypeName(t.t) FROM t1 AS a FULL JOIN t2 AS b USING t.t; - * We just support it as a best-effort: `t` will have original type from table, but `t.t` will have super-type from JOIN. - * Probably it's good to prohibit such cases as well, but it's not clear how to check it in general case. - */ - if (node->getNodeType() != QueryTreeNodeType::FUNCTION) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {}, expected function node", node->getNodeType()); - - const auto & function_argument_nodes = node->as().getArguments().getNodes(); - for (const auto & argument_node : function_argument_nodes) - { - if (argument_node->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_name = argument_node->as().getColumnName(); - if (join_using_column_name_to_column_node.contains(column_name)) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Cannot select subcolumn for identifier '{}' while joining using column '{}'", - identifier_lookup.identifier, column_name); - } - else if (argument_node->getNodeType() == QueryTreeNodeType::CONSTANT) - { - continue; - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {} for argument node in {}", - argument_node->getNodeType(), node->formatASTForErrorMessage()); - } - } - }; - - std::optional resolved_side; - QueryTreeNodePtr resolved_identifier; - - JoinKind join_kind = from_join_node.getKind(); - - /// If columns from left or right table were missed Object(Nullable('json')) subcolumns, they will be replaced - /// to ConstantNode(NULL), which can't be cast to ColumnNode, so we resolve it here. - if (auto missed_subcolumn_identifier = checkIsMissedObjectJSONSubcolumn(left_resolved_identifier, right_resolved_identifier)) - return missed_subcolumn_identifier; - - if (left_resolved_identifier && right_resolved_identifier) - { - auto using_column_node_it = join_using_column_name_to_column_node.end(); - if (left_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && right_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getColumnName() == right_resolved_column.getColumnName()) - using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - } - else - { - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(left_resolved_identifier); - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(right_resolved_identifier); - } - - if (using_column_node_it != join_using_column_name_to_column_node.end()) - { - JoinTableSide using_column_inner_column_table_side = isRight(join_kind) ? JoinTableSide::Right : JoinTableSide::Left; - auto & using_column_node = using_column_node_it->second->as(); - auto & using_expression_list = using_column_node.getExpression()->as(); - - size_t inner_column_node_index = using_column_inner_column_table_side == JoinTableSide::Left ? 0 : 1; - const auto & inner_column_node = using_expression_list.getNodes().at(inner_column_node_index); - - auto result_column_node = inner_column_node->clone(); - auto & result_column = result_column_node->as(); - result_column.setColumnType(using_column_node.getColumnType()); - - const auto & join_using_left_column = using_expression_list.getNodes().at(0); - if (!result_column_node->isEqual(*join_using_left_column)) - scope.join_columns_with_changed_types[result_column_node] = join_using_left_column; - - resolved_identifier = std::move(result_column_node); - } - else if (resolvedIdenfiersFromJoinAreEquals(left_resolved_identifier, right_resolved_identifier, scope)) - { - const auto & identifier_path_part = identifier_lookup.identifier.front(); - auto * left_resolved_identifier_column = left_resolved_identifier->as(); - auto * right_resolved_identifier_column = right_resolved_identifier->as(); - - if (left_resolved_identifier_column && right_resolved_identifier_column) - { - const auto & left_column_source_alias = left_resolved_identifier_column->getColumnSource()->getAlias(); - const auto & right_column_source_alias = right_resolved_identifier_column->getColumnSource()->getAlias(); - - /** If column from right table was resolved using alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one JOIN system.one AS A ON A.dummy = system.one.dummy; - * - * If alias is specified for left table, and alias is not specified for right table and identifier was resolved - * without using left table alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one AS A JOIN system.one ON A.dummy = system.one.dummy; - * - * Otherwise we prefer column from left table. - */ - bool column_resolved_using_right_alias = identifier_path_part == right_column_source_alias; - bool column_resolved_without_using_left_alias = !left_column_source_alias.empty() - && right_column_source_alias.empty() - && identifier_path_part != left_column_source_alias; - if (column_resolved_using_right_alias || column_resolved_without_using_left_alias) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else if (scope.joins_count == 1 && scope.context->getSettingsRef().single_join_prefer_left_table) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - else - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier '{}'. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - else if (left_resolved_identifier) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(left_resolved_identifier); - } - else - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*left_resolved_column.getColumnType())) - { - auto left_resolved_column_clone = std::static_pointer_cast(left_resolved_column.clone()); - left_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(left_resolved_column_clone); - - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - else if (right_resolved_identifier) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(right_resolved_identifier); - } - else - { - auto & right_resolved_column = right_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(right_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*right_resolved_column.getColumnType())) - { - auto right_resolved_column_clone = std::static_pointer_cast(right_resolved_column.clone()); - right_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(right_resolved_column_clone); - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - - if (join_node_in_resolve_process || !resolved_identifier) - return resolved_identifier; - - if (scope.join_use_nulls) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier); - auto nullable_resolved_identifier = convertJoinedColumnTypeToNullIfNeeded(resolved_identifier, join_kind, resolved_side, scope); - if (nullable_resolved_identifier) - { - resolved_identifier = nullable_resolved_identifier; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(resolved_identifier, projection_name_it->second); - } - } - } - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope) -{ - const auto * resolved_function = resolved_expression->as(); - if (!resolved_function || resolved_function->getFunctionName() != "getSubcolumn") - return {}; - - const auto * array_join_parent_column = array_join_column_inner_expression.get(); - - /** If both resolved and array-joined expressions are subcolumns, try to match them: - * For example, in `SELECT t.map.values FROM (SELECT * FROM tbl) ARRAY JOIN t.map` - * Identifier `t.map.values` is resolved into `getSubcolumn(t, 'map.values')` and t.map is resolved into `getSubcolumn(t, 'map')` - * Since we need to perform array join on `getSubcolumn(t, 'map')`, `t.map.values` should become `getSubcolumn(getSubcolumn(t, 'map'), 'values')` - * - * Note: It doesn't work when subcolumn in ARRAY JOIN is transformed by another expression, for example - * SELECT c.map, c.map.values FROM (SELECT * FROM tbl) ARRAY JOIN mapApply(x -> x, t.map); - */ - String array_join_subcolumn_prefix; - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "getSubcolumn") - { - const auto & argument_nodes = array_join_column_inner_expression_function->getArguments().getNodes(); - if (argument_nodes.size() == 2 && argument_nodes.at(1)->getNodeType() == QueryTreeNodeType::CONSTANT) - { - const auto & constant_node = argument_nodes.at(1)->as(); - const auto & constant_node_value = constant_node.getValue(); - if (constant_node_value.getType() == Field::Types::String) - { - array_join_subcolumn_prefix = constant_node_value.get() + "."; - array_join_parent_column = argument_nodes.at(0).get(); - } - } - } - - const auto & argument_nodes = resolved_function->getArguments().getNodes(); - if (argument_nodes.size() != 2 && !array_join_parent_column->isEqual(*argument_nodes.at(0))) - return {}; - - const auto * second_argument = argument_nodes.at(1)->as(); - if (!second_argument || second_argument->getValue().getType() != Field::Types::String) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected constant string as second argument of getSubcolumn function {}", resolved_function->dumpTree()); - - const auto & resolved_subcolumn_path = second_argument->getValue().get(); - if (!startsWith(resolved_subcolumn_path, array_join_subcolumn_prefix)) - return {}; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(array_join_column_expression_typed.getColumn(), array_join_column_expression_typed.getColumnSource())); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(resolved_subcolumn_path.substr(array_join_subcolumn_prefix.size()))); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - return function_query_node; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & array_join_node = table_expression_node->as(); - const auto & array_join_column_expressions_list = array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions_list.getNodes(); - - QueryTreeNodePtr array_join_resolved_expression; - - /** Special case when qualified or unqualified identifier point to array join expression without alias. - * - * CREATE TABLE test_table (id UInt64, value String, value_array Array(UInt8)) ENGINE=TinyLog; - * SELECT id, value, value_array, test_table.value_array, default.test_table.value_array FROM test_table ARRAY JOIN value_array; - * - * value_array, test_table.value_array, default.test_table.value_array must be resolved into array join expression. - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - if (array_join_column_expression_typed.hasAlias()) - continue; - - auto & array_join_column_inner_expression = array_join_column_expression_typed.getExpressionOrThrow(); - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "nested" && - array_join_column_inner_expression_function->getArguments().getNodes().size() > 1 && - isTuple(array_join_column_expression_typed.getResultType())) - { - const auto & nested_function_arguments = array_join_column_inner_expression_function->getArguments().getNodes(); - size_t nested_function_arguments_size = nested_function_arguments.size(); - - const auto & nested_keys_names_constant_node = nested_function_arguments[0]->as(); - const auto & nested_keys_names = nested_keys_names_constant_node.getValue().get(); - size_t nested_keys_names_size = nested_keys_names.size(); - - if (nested_keys_names_size == nested_function_arguments_size - 1) - { - for (size_t i = 1; i < nested_function_arguments_size; ++i) - { - if (!nested_function_arguments[i]->isEqual(*resolved_expression)) - continue; - - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - - const auto & nested_key_name = nested_keys_names[i - 1].get(); - Identifier nested_identifier = Identifier(nested_key_name); - auto tuple_element_function = wrapExpressionNodeInTupleElement(array_join_column, nested_identifier); - resolveFunction(tuple_element_function, scope); - - array_join_resolved_expression = std::move(tuple_element_function); - break; - } - } - } - - if (array_join_resolved_expression) - break; - - if (array_join_column_inner_expression->isEqual(*resolved_expression)) - { - array_join_resolved_expression = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - break; - } - - /// When we select subcolumn of array joined column it also should be array joined - array_join_resolved_expression = matchArrayJoinSubcolumns(array_join_column_inner_expression, array_join_column_expression_typed, resolved_expression, scope); - if (array_join_resolved_expression) - break; - } - return array_join_resolved_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_array_join_node = table_expression_node->as(); - auto resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_array_join_node.getTableExpression(), scope); - - if (scope.table_expressions_in_resolve_process.contains(table_expression_node.get()) || !identifier_lookup.isExpressionLookup()) - return resolved_identifier; - - const auto & array_join_column_expressions = from_array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions.getNodes(); - - /** Allow JOIN with USING with ARRAY JOIN. - * - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN [1,2,3] AS id INNER JOIN test_table_2 AS t2 USING (id); - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN t1.id AS id INNER JOIN test_table_2 AS t2 USING (id); - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - - IdentifierView identifier_view(identifier_lookup.identifier); - - if (identifier_view.isCompound() && from_array_join_node.hasAlias() && identifier_view.front() == from_array_join_node.getAlias()) - identifier_view.popFirst(); - - const auto & alias_or_name = array_join_column_expression_typed.hasAlias() - ? array_join_column_expression_typed.getAlias() - : array_join_column_expression_typed.getColumnName(); - - if (identifier_view.front() == alias_or_name) - identifier_view.popFirst(); - else if (identifier_view.getFullName() == alias_or_name) - identifier_view.popFirst(identifier_view.getPartsSize()); /// Clear - else - continue; - - if (identifier_view.empty()) - { - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - return array_join_column; - } - - auto compound_expr = tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - identifier_lookup.identifier.getPartsSize() - identifier_view.getPartsSize() /*identifier_bind_size*/, - array_join_column_expression, - {} /* compound_expression_source */, - scope, - true /* can_be_not_found */); - - if (compound_expr) - return compound_expr; - } - - if (!resolved_identifier) - return nullptr; - - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(resolved_identifier, table_expression_node, scope); - if (array_join_resolved_expression) - resolved_identifier = std::move(array_join_resolved_expression); - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope) -{ - auto join_tree_node_type = join_tree_node->getNodeType(); - - switch (join_tree_node_type) - { - case QueryTreeNodeType::JOIN: - return tryResolveIdentifierFromJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::ARRAY_JOIN: - return tryResolveIdentifierFromArrayJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - [[fallthrough]]; - case QueryTreeNodeType::TABLE: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - { - /** Edge case scenario when subquery in FROM node try to resolve identifier from parent scopes, when FROM is not resolved. - * SELECT subquery.b AS value FROM (SELECT value, 1 AS b) AS subquery; - * TODO: This can be supported - */ - if (scope.table_expressions_in_resolve_process.contains(join_tree_node.get())) - return {}; - - return tryResolveIdentifierFromTableExpression(identifier_lookup, join_tree_node, scope); - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Scope FROM section expected table, table function, query, union, join or array join. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } -} - -/** Resolve identifier from scope join tree. - * - * 1. If identifier is in function lookup context return nullptr. - * 2. Try to resolve identifier from table columns. - * 3. If there is no FROM section return nullptr. - * 4. If identifier is in table lookup context, check if it has 1 or 2 parts, otherwise throw exception. - * If identifier has 2 parts try to match it with database_name and table_name. - * If identifier has 1 part try to match it with table_name, then try to match it with table alias. - * 5. If identifier is in expression lookup context, we first need to bind identifier to some table column using identifier first part. - * Start with identifier first part, if it match some column name in table try to get column with full identifier name. - * TODO: Need to check if it is okay to throw exception if compound identifier first part bind to column but column is not valid. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope) -{ - if (identifier_lookup.isFunctionLookup()) - return {}; - - /// Try to resolve identifier from table columns - if (auto resolved_identifier = tryResolveIdentifierFromTableColumns(identifier_lookup, scope)) - return resolved_identifier; - - if (scope.expression_join_tree_node) - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, scope.expression_join_tree_node, scope); - - auto * query_scope_node = scope.scope_node->as(); - if (!query_scope_node || !query_scope_node->getJoinTree()) - return {}; - - const auto & join_tree_node = query_scope_node->getJoinTree(); - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_tree_node, scope); -} - -/** Try resolve identifier in current scope parent scopes. - * - * TODO: If column is matched, throw exception that nested subqueries are not supported. - * - * If initial scope is expression. Then try to resolve identifier in parent scopes until query scope is hit. - * For query scope resolve strategy is same as if initial scope if query. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - bool initial_scope_is_query = scope.scope_node->getNodeType() == QueryTreeNodeType::QUERY; - bool initial_scope_is_expression = !initial_scope_is_query; - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_parent_scopes = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - IdentifierResolveScope * scope_to_check = scope.parent_scope; - - if (initial_scope_is_expression) - { - while (scope_to_check != nullptr) - { - auto resolve_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - if (resolve_result.resolved_identifier) - return resolve_result; - - bool scope_was_query = scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY; - scope_to_check = scope_to_check->parent_scope; - - if (scope_was_query) - break; - } - } - - if (!scope.context->getSettingsRef().enable_global_with_statement) - return {}; - - /** Nested subqueries cannot access outer subqueries table expressions from JOIN tree because - * that can prevent resolution of table expression from CTE. - * - * Example: WITH a AS (SELECT number FROM numbers(1)), b AS (SELECT number FROM a) SELECT * FROM a as l, b as r; - */ - if (identifier_lookup.isTableExpressionLookup()) - identifier_resolve_settings.allow_to_check_join_tree = false; - - while (scope_to_check != nullptr) - { - auto lookup_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - const auto & resolved_identifier = lookup_result.resolved_identifier; - - scope_to_check = scope_to_check->parent_scope; - - if (resolved_identifier) - { - auto * subquery_node = resolved_identifier->as(); - auto * union_node = resolved_identifier->as(); - - bool is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - bool is_table_from_expression_arguments = lookup_result.resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS && - resolved_identifier->getNodeType() == QueryTreeNodeType::TABLE; - bool is_valid_table_expression = is_cte || is_table_from_expression_arguments; - - /** From parent scopes we can resolve table identifiers only as CTE. - * Example: SELECT (SELECT 1 FROM a) FROM test_table AS a; - * - * During child scope table identifier resolve a, table node test_table with alias a from parent scope - * is invalid. - */ - if (identifier_lookup.isTableExpressionLookup() && !is_valid_table_expression) - continue; - - if (is_valid_table_expression || resolved_identifier->as()) - { - return lookup_result; - } - else if (auto * resolved_function = resolved_identifier->as()) - { - /// Special case: scalar subquery was executed and replaced by __getScalar function. - /// Handle it as a constant. - if (resolved_function->getFunctionName() == "__getScalar") - return lookup_result; - } - - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Resolve identifier '{}' from parent scope only supported for constants and CTE. Actual {} node type {}. In scope {}", - identifier_lookup.identifier.getFullName(), - resolved_identifier->formatASTForErrorMessage(), - resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - return {}; -} - -/** Resolve identifier in scope. - * - * If identifier was resolved resolve identified lookup status will be updated. - * - * Steps: - * 1. Register identifier lookup in scope identifier lookup to resolve status table. - * If entry is already registered and is not resolved, that means that we have cyclic aliases for identifier. - * Example: SELECT a AS b, b AS a; - * Try resolve identifier in current scope: - * 3. Try resolve identifier from expression arguments. - * - * If prefer_column_name_to_alias = true. - * 4. Try to resolve identifier from join tree. - * 5. Try to resolve identifier from aliases. - * Otherwise. - * 4. Try to resolve identifier from aliases. - * 5. Try to resolve identifier from join tree. - * - * 6. If it is table identifier lookup try to lookup identifier in current scope CTEs. - * - * 7. If identifier is not resolved in current scope, try to resolve it in parent scopes. - * 8. If identifier is not resolved from parent scopes and it is table identifier lookup try to lookup identifier - * in database catalog. - * - * Same is not done for functions because function resolution is more complex, and in case of aggregate functions requires not only name - * but also argument types, it is responsibility of resolve function method to handle resolution of function name. - * - * 9. If identifier was not resolved, or identifier caching was disabled remove it from identifier lookup to resolve status table. - * - * It is okay for identifier to be not resolved, in case we want first try to lookup identifier in one context, - * then if there is no identifier in this context, try to lookup in another context. - * Example: Try to lookup identifier as expression, if it is not found, lookup as function. - * Example: Try to lookup identifier as expression, if it is not found, lookup as table. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - auto it = scope.identifier_lookup_to_resolve_state.find(identifier_lookup); - if (it != scope.identifier_lookup_to_resolve_state.end()) - { - if (it->second.cyclic_identifier_resolve) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (!it->second.resolve_result.isResolved()) - it->second.cyclic_identifier_resolve = true; - - if (it->second.resolve_result.isResolved() && - scope.use_identifier_lookup_to_result_cache && - !scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) && - (!it->second.resolve_result.isResolvedFromCTEs() || !ctes_in_resolve_process.contains(identifier_lookup.identifier.getFullName()))) - return it->second.resolve_result; - } - else - { - auto [insert_it, _] = scope.identifier_lookup_to_resolve_state.insert({identifier_lookup, IdentifierResolveState()}); - it = insert_it; - } - - /// Resolve identifier from current scope - - IdentifierResolveResult resolve_result; - resolve_result.resolved_identifier = tryResolveIdentifierFromExpressionArguments(identifier_lookup, scope); - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - - if (!resolve_result.resolved_identifier) - { - bool prefer_column_name_to_alias = scope.context->getSettingsRef().prefer_column_name_to_alias; - - if (identifier_lookup.isExpressionLookup()) - { - /* For aliases from ARRAY JOIN we prefer column from join tree: - * SELECT id FROM ( SELECT ... ) AS subquery ARRAY JOIN [0] AS id INNER JOIN second_table USING (id) - * In the example, identifier `id` should be resolved into one from USING (id) column. - */ - - auto * alias_it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FULL_NAME); - if (alias_it && (*alias_it)->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_node = (*alias_it)->as(); - if (column_node.getColumnSource()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - prefer_column_name_to_alias = true; - } - } - - if (unlikely(prefer_column_name_to_alias)) - { - if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - - if (!resolve_result.resolved_identifier) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - } - else - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - { - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - else if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - } - } - - if (!resolve_result.resolved_identifier && identifier_lookup.isTableExpressionLookup()) - { - auto full_name = identifier_lookup.identifier.getFullName(); - auto cte_query_node_it = scope.cte_name_to_query_node.find(full_name); - - /// CTE may reference table expressions with the same name, e.g.: - /// - /// WITH test1 AS (SELECT * FROM test1) SELECT * FROM test1; - /// - /// Since we don't support recursive CTEs, `test1` identifier inside of CTE - /// references to table .test1. - /// This means that the example above is equivalent to the following query: - /// - /// SELECT * FROM test1; - /// - /// To accomplish this behaviour it's not allowed to resolve identifiers to - /// CTE that is being resolved. - if (cte_query_node_it != scope.cte_name_to_query_node.end() - && !ctes_in_resolve_process.contains(full_name)) - { - resolve_result.resolved_identifier = cte_query_node_it->second; - resolve_result.resolve_place = IdentifierResolvePlace::CTE; - } - } - - /// Try to resolve identifier from parent scopes - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_parent_scopes) - { - resolve_result = tryResolveIdentifierInParentScopes(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolved_from_parent_scopes = true; - } - - /// Try to resolve table identifier from database catalog - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_database_catalog && identifier_lookup.isTableExpressionLookup()) - { - resolve_result.resolved_identifier = tryResolveTableIdentifierFromDatabaseCatalog(identifier_lookup.identifier, scope.context); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::DATABASE_CATALOG; - } - - bool was_cyclic_identifier_resolve = it->second.cyclic_identifier_resolve; - if (!was_cyclic_identifier_resolve) - it->second.resolve_result = resolve_result; - it->second.cyclic_identifier_resolve = false; - - /** If identifier was not resolved, or during expression resolution identifier was explicitly added into non cached set, - * or identifier caching was disabled in resolve scope we remove identifier lookup result from identifier lookup to result table. - */ - if (!was_cyclic_identifier_resolve && (!resolve_result.resolved_identifier || - scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) || - !scope.use_identifier_lookup_to_result_cache)) - scope.identifier_lookup_to_resolve_state.erase(it); - - return resolve_result; -} - -/// Resolve query tree nodes functions implementation - -/** Qualify column nodes with projection names. - * - * Example: SELECT * FROM test_table AS t1, test_table AS t2; - */ -void QueryAnalyzer::qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - /// Build additional column qualification parts array - std::vector additional_column_qualification_parts; - - if (table_expression_node->hasAlias()) - additional_column_qualification_parts = {table_expression_node->getAlias()}; - else if (auto * table_node = table_expression_node->as()) - additional_column_qualification_parts = {table_node->getStorageID().getDatabaseName(), table_node->getStorageID().getTableName()}; - - size_t additional_column_qualification_parts_size = additional_column_qualification_parts.size(); - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - /** For each matched column node iterate over additional column qualifications and apply them if column needs to be qualified. - * To check if column needs to be qualified we check if column name can bind to any other table expression in scope or to scope aliases. - */ - std::vector column_qualified_identifier_parts; - - for (const auto & column_node : column_nodes) - { - const auto & column_name = column_node->as().getColumnName(); - column_qualified_identifier_parts = Identifier(column_name).getParts(); - - /// Iterate over additional column qualifications and apply them if needed - for (size_t i = 0; i < additional_column_qualification_parts_size; ++i) - { - auto identifier_to_check = Identifier(column_qualified_identifier_parts); - IdentifierLookup identifier_lookup{identifier_to_check, IdentifierLookupContext::EXPRESSION}; - bool need_to_qualify = table_expression_data.should_qualify_columns; - if (need_to_qualify) - need_to_qualify = tryBindIdentifierToTableExpressions(identifier_lookup, table_expression_node, scope); - - if (tryBindIdentifierToAliases(identifier_lookup, scope)) - need_to_qualify = true; - - if (need_to_qualify) - { - /** Add last qualification part that was not used into column qualified identifier. - * If additional column qualification parts consists from [database_name, table_name]. - * On first iteration if column is needed to be qualified to qualify it with table_name. - * On second iteration if column is needed to be qualified to qualify it with database_name. - */ - size_t part_index_to_use_for_qualification = additional_column_qualification_parts_size - i - 1; - const auto & part_to_use = additional_column_qualification_parts[part_index_to_use_for_qualification]; - column_qualified_identifier_parts.insert(column_qualified_identifier_parts.begin(), part_to_use); - } - else - { - break; - } - } - - auto qualified_node_name = Identifier(column_qualified_identifier_parts).getFullName(); - node_to_projection_name.emplace(column_node, qualified_node_name); - } -} - -/// Build get columns options for matcher -GetColumnsOptions QueryAnalyzer::buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context) -{ - auto & matcher_node_typed = matcher_node->as(); - UInt8 get_columns_options_kind = GetColumnsOptions::AllPhysicalAndAliases; - - if (matcher_node_typed.isAsteriskMatcher()) - { - get_columns_options_kind = GetColumnsOptions::Ordinary; - - const auto & settings = context->getSettingsRef(); - - if (settings.asterisk_include_alias_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Aliases; - - if (settings.asterisk_include_materialized_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Materialized; - } - - return GetColumnsOptions(static_cast(get_columns_options_kind)); -} - -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - /** Use resolved columns from table expression data in nearest query scope if available. - * It is important for ALIAS columns to use column nodes with resolved ALIAS expression. - */ - const TableExpressionData * table_expression_data = nullptr; - const auto * nearest_query_scope = scope.getNearestQueryScope(); - if (nearest_query_scope) - table_expression_data = &nearest_query_scope->getTableExpressionDataOrThrow(table_expression_node); - - QueryTreeNodes matched_column_nodes; - - for (const auto & column : matched_columns) - { - const auto & column_name = column.name; - if (!matcher_node_typed.isMatchingColumn(column_name)) - continue; - - if (table_expression_data) - { - auto column_node_it = table_expression_data->column_name_to_column_node.find(column_name); - if (column_node_it != table_expression_data->column_name_to_column_node.end()) - { - matched_column_nodes.emplace_back(column_node_it->second); - continue; - } - } - - matched_column_nodes.emplace_back(std::make_shared(column, table_expression_node)); - } - - const auto & qualify_matched_column_nodes_scope = nearest_query_scope ? *nearest_query_scope : scope; - qualifyColumnNodesWithProjectionNames(matched_column_nodes, table_expression_node, qualify_matched_column_nodes_scope); - - QueryAnalyzer::QueryTreeNodesWithNames matched_column_nodes_with_names; - matched_column_nodes_with_names.reserve(matched_column_nodes.size()); - - for (auto && matched_column_node : matched_column_nodes) - { - auto column_name = matched_column_node->as().getColumnName(); - matched_column_nodes_with_names.emplace_back(std::move(matched_column_node), std::move(column_name)); - } - - return matched_column_nodes_with_names; -} - -bool hasTableExpressionInJoinTree(const QueryTreeNodePtr & join_tree_node, const QueryTreeNodePtr & table_expression) -{ - QueryTreeNodes nodes_to_process; - nodes_to_process.push_back(join_tree_node); - - while (!nodes_to_process.empty()) - { - auto node_to_process = std::move(nodes_to_process.back()); - nodes_to_process.pop_back(); - if (node_to_process == table_expression) - return true; - - if (node_to_process->getNodeType() == QueryTreeNodeType::JOIN) - { - const auto & join_node = node_to_process->as(); - nodes_to_process.push_back(join_node.getLeftTableExpression()); - nodes_to_process.push_back(join_node.getRightTableExpression()); - } - } - return false; -} - -/// Columns that resolved from matcher can also match columns from JOIN USING. -/// In that case we update type to type of column in USING section. -/// TODO: It's not completely correct for qualified matchers, so t1.* should be resolved to left table column type. -/// But in planner we do not distinguish such cases. -void QueryAnalyzer::updateMatchedColumnsFromJoinUsing( - QueryTreeNodesWithNames & result_matched_column_nodes_with_names, - const QueryTreeNodePtr & source_table_expression, - IdentifierResolveScope & scope) -{ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "There are no table sources. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - const auto & join_tree = nearest_query_scope_query_node->getJoinTree(); - - const auto * join_node = join_tree->as(); - if (join_node && join_node->isUsingJoinExpression()) - { - const auto & join_using_list = join_node->getJoinExpression()->as(); - const auto & join_using_nodes = join_using_list.getNodes(); - - for (auto & [matched_column_node, _] : result_matched_column_nodes_with_names) - { - auto & matched_column_node_typed = matched_column_node->as(); - const auto & matched_column_name = matched_column_node_typed.getColumnName(); - - for (const auto & join_using_node : join_using_nodes) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (matched_column_name != join_using_column_name) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - auto it = node_to_projection_name.find(matched_column_node); - - if (hasTableExpressionInJoinTree(join_node->getLeftTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(0); - else if (hasTableExpressionInJoinTree(join_node->getRightTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(1); - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Cannot find column {} in JOIN USING section {}", - matched_column_node->dumpTree(), join_node->dumpTree()); - - matched_column_node = matched_column_node->clone(); - if (it != node_to_projection_name.end()) - node_to_projection_name.emplace(matched_column_node, it->second); - - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - } - } - } -} - -/** Resolve qualified tree matcher. - * - * First try to match qualified identifier to expression. If qualified identifier matched expression node then - * if expression is compound match it column names using matcher `isMatchingColumn` method, if expression is not compound, throw exception. - * If qualified identifier did not match expression in query tree, try to lookup qualified identifier in table context. - */ -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isQualified()); - - auto expression_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::EXPRESSION}; - auto expression_identifier_resolve_result = tryResolveIdentifier(expression_identifier_lookup, scope); - auto expression_query_tree_node = expression_identifier_resolve_result.resolved_identifier; - - /// Try to resolve unqualified matcher for query expression - - if (expression_query_tree_node) - { - auto result_type = expression_query_tree_node->getResultType(); - - while (true) - { - if (const auto * array_type = typeid_cast(result_type.get())) - result_type = array_type->getNestedType(); - else if (const auto * map_type = typeid_cast(result_type.get())) - result_type = map_type->getNestedType(); - else - break; - } - - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Qualified matcher {} find non compound expression {} with type {}. Expected tuple or array of tuples. In scope {}", - matcher_node->formatASTForErrorMessage(), - expression_query_tree_node->formatASTForErrorMessage(), - expression_query_tree_node->getResultType()->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - auto qualified_matcher_element_identifier = matcher_node_typed.getQualifiedIdentifier(); - for (const auto & element_name : element_names) - { - if (!matcher_node_typed.isMatchingColumn(element_name)) - continue; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back(expression_query_tree_node); - get_subcolumn_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - qualified_matcher_element_identifier.push_back(element_name); - node_to_projection_name.emplace(function_query_node, qualified_matcher_element_identifier.getFullName()); - qualified_matcher_element_identifier.pop_back(); - - matched_expression_nodes_with_column_names.emplace_back(std::move(function_query_node), element_name); - } - - return matched_expression_nodes_with_column_names; - } - - /// Try to resolve qualified matcher for table expression - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_cte = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - auto table_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, identifier_resolve_settings); - auto table_expression_node = table_identifier_resolve_result.resolved_identifier; - - if (!table_expression_node) - { - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Qualified matcher {} does not find table. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - NamesAndTypes matched_columns; - - auto * table_expression_query_node = table_expression_node->as(); - auto * table_expression_union_node = table_expression_node->as(); - auto * table_expression_table_node = table_expression_node->as(); - auto * table_expression_table_function_node = table_expression_node->as(); - - if (table_expression_query_node || table_expression_union_node) - { - matched_columns = table_expression_query_node ? table_expression_query_node->getProjectionColumns() - : table_expression_union_node->computeProjectionColumns(); - } - else if (table_expression_table_node || table_expression_table_function_node) - { - const auto & storage_snapshot = table_expression_table_node ? table_expression_table_node->getStorageSnapshot() - : table_expression_table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - matched_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Invalid table expression node {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto result_matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression_node, - matched_columns, - scope); - - updateMatchedColumnsFromJoinUsing(result_matched_column_nodes_with_names, table_expression_node, scope); - - return result_matched_column_nodes_with_names; -} - -/// Resolve non qualified matcher, using scope join tree node. -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isUnqualified()); - - /** There can be edge case if matcher is inside lambda expression. - * Try to find parent query expression using parent scopes. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unqualified matcher {} cannot be resolved. There are no table sources. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** For unqualifited matcher resolve we build table expressions stack from JOIN tree and then process it. - * For table, table function, query, union table expressions add matched columns into table expressions columns stack. - * For array join continue processing. - * For join node combine last left and right table expressions columns on stack together. It is important that if JOIN has USING - * we must add USING columns before combining left and right table expressions columns. Columns from left and right table - * expressions that have same names as columns in USING clause must be skipped. - */ - - auto table_expressions_stack = buildTableExpressionsStack(nearest_query_scope_query_node->getJoinTree()); - std::vector table_expressions_column_nodes_with_names_stack; - - std::unordered_set table_expression_column_names_to_skip; - - QueryTreeNodesWithNames result; - - if (matcher_node_typed.getMatcherType() == MatcherNodeType::COLUMNS_LIST) - { - auto identifiers = matcher_node_typed.getColumnsIdentifiers(); - result.reserve(identifiers.size()); - - for (const auto & identifier : identifiers) - { - auto resolve_result = tryResolveIdentifier(IdentifierLookup{identifier, IdentifierLookupContext::EXPRESSION}, scope); - if (!resolve_result.isResolved()) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Unknown identifier '{}' inside COLUMNS matcher. In scope {}", - identifier.getFullName(), scope.dump()); - - // TODO: Introduce IdentifierLookupContext::COLUMN and get rid of this check - auto * resolved_column = resolve_result.resolved_identifier->as(); - if (!resolved_column) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier '{}' inside COLUMNS matcher must resolve into a column, but got {}. In scope {}", - identifier.getFullName(), - resolve_result.resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - result.emplace_back(resolve_result.resolved_identifier, resolved_column->getColumnName()); - } - return result; - } - - result.resize(matcher_node_typed.getColumnsIdentifiers().size()); - - for (auto & table_expression : table_expressions_stack) - { - bool table_expression_in_resolve_process = nearest_query_scope->table_expressions_in_resolve_process.contains(table_expression.get()); - - if (auto * array_join_node = table_expression->as()) - { - if (table_expressions_column_nodes_with_names_stack.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 1 table expressions on stack before ARRAY JOIN processing"); - - if (table_expression_in_resolve_process) - continue; - - auto & table_expression_column_nodes_with_names = table_expressions_column_nodes_with_names_stack.back(); - - for (auto & [table_expression_column_node, _] : table_expression_column_nodes_with_names) - { - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(table_expression_column_node, - table_expression, - scope); - if (array_join_resolved_expression) - table_expression_column_node = std::move(array_join_resolved_expression); - } - - continue; - } - - auto * join_node = table_expression->as(); - - if (join_node) - { - size_t table_expressions_column_nodes_with_names_stack_size = table_expressions_column_nodes_with_names_stack.size(); - if (table_expressions_column_nodes_with_names_stack_size < 2) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 2 table expressions on stack before JOIN processing. Actual {}", - table_expressions_column_nodes_with_names_stack_size); - - auto right_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - auto left_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - table_expression_column_names_to_skip.clear(); - - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - /** If there is JOIN with USING we need to match only single USING column and do not use left table expression - * and right table expression column with same name. - * - * Example: SELECT id FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING (id); - */ - if (!table_expression_in_resolve_process && join_node->isUsingJoinExpression()) - { - auto & join_using_list = join_node->getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (!matcher_node_typed.isMatchingColumn(join_using_column_name)) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - /** If column doesn't exists in the table, then do not match column from USING clause. - * Example: SELECT a + 1 AS id, * FROM (SELECT 1 AS a) AS t1 JOIN (SELECT 2 AS id) AS t2 USING (id); - * In this case `id` is not present in the left table expression, - * so asterisk should return `id` from the right table expression. - */ - auto is_column_from_parent_scope = [&scope](const QueryTreeNodePtr & using_node_from_table) - { - const auto & using_column_from_table = using_node_from_table->as(); - auto table_expression_data_it = scope.table_expression_node_to_data.find(using_column_from_table.getColumnSource()); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - { - const auto & table_expression_data = table_expression_data_it->second; - const auto & column_name = using_column_from_table.getColumnName(); - return !table_expression_data.column_name_to_column_node.contains(column_name); - } - return false; - }; - - if (is_column_from_parent_scope(join_using_column_nodes.at(0)) || - is_column_from_parent_scope(join_using_column_nodes.at(1))) - continue; - - QueryTreeNodePtr matched_column_node; - - if (isRight(join_node->getKind())) - matched_column_node = join_using_column_nodes.at(1); - else - matched_column_node = join_using_column_nodes.at(0); - - matched_column_node = matched_column_node->clone(); - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - - table_expression_column_names_to_skip.insert(join_using_column_name); - matched_expression_nodes_with_column_names.emplace_back(std::move(matched_column_node), join_using_column_name); - } - } - - for (auto && left_table_column_with_name : left_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(left_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(left_table_column_with_name)); - } - - for (auto && right_table_column_with_name : right_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(right_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(right_table_column_with_name)); - } - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_expression_nodes_with_column_names)); - continue; - } - - if (table_expression_in_resolve_process) - { - table_expressions_column_nodes_with_names_stack.emplace_back(); - continue; - } - - auto * table_node = table_expression->as(); - auto * table_function_node = table_expression->as(); - auto * query_node = table_expression->as(); - auto * union_node = table_expression->as(); - - NamesAndTypes table_expression_columns; - - if (query_node || union_node) - { - table_expression_columns = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - } - else if (table_node || table_function_node) - { - const auto & storage_snapshot - = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - table_expression_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unqualified matcher {} resolve unexpected table expression. In scope {}", - matcher_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression, - table_expression_columns, - scope); - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_column_nodes_with_names)); - } - - for (auto & table_expression_column_nodes_with_names : table_expressions_column_nodes_with_names_stack) - { - for (auto && table_expression_column_node_with_name : table_expression_column_nodes_with_names) - result.push_back(std::move(table_expression_column_node_with_name)); - } - - return result; -} - - -/** Resolve query tree matcher. Check MatcherNode.h for detailed matcher description. Check ColumnTransformers.h for detailed transformers description. - * - * 1. Populate matched expression nodes resolving qualified or unqualified matcher. - * 2. Apply column transformers to matched expression nodes. For strict column transformers save used column names. - * 3. Validate strict column transformers. - */ -ProjectionNames QueryAnalyzer::resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - QueryTreeNodesWithNames matched_expression_nodes_with_names; - - if (matcher_node_typed.isQualified()) - matched_expression_nodes_with_names = resolveQualifiedMatcher(matcher_node, scope); - else - matched_expression_nodes_with_names = resolveUnqualifiedMatcher(matcher_node, scope); - - if (scope.join_use_nulls) - { - /** If we are resolving matcher came from the result of JOIN and `join_use_nulls` is set, - * we need to convert joined column type to Nullable. - * We are taking the nearest JoinNode to check to which table column belongs, - * because for LEFT/RIGHT join, we convert only the corresponding side. - */ - const auto * nearest_query_scope = scope.getNearestQueryScope(); - const QueryNode * nearest_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - const QueryTreeNodePtr & nearest_scope_join_tree = nearest_scope_query_node ? nearest_scope_query_node->getJoinTree() : nullptr; - const JoinNode * nearest_scope_join_node = nearest_scope_join_tree ? nearest_scope_join_tree->as() : nullptr; - if (nearest_scope_join_node) - { - for (auto & [node, node_name] : matched_expression_nodes_with_names) - { - auto join_identifier_side = getColumnSideFromJoinTree(node, *nearest_scope_join_node); - auto projection_name_it = node_to_projection_name.find(node); - auto nullable_node = convertJoinedColumnTypeToNullIfNeeded(node, nearest_scope_join_node->getKind(), join_identifier_side, scope); - if (nullable_node) - { - node = nullable_node; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(node, projection_name_it->second); - } - } - } - } - } - - if (!scope.expressions_in_resolve_process_stack.hasAggregateFunction()) - { - for (auto & [node, _] : matched_expression_nodes_with_names) - { - auto it = scope.nullable_group_by_keys.find(node); - if (it != scope.nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - } - } - } - - std::unordered_map> strict_transformer_to_used_column_names; - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - auto * except_transformer = transformer->as(); - auto * replace_transformer = transformer->as(); - - if (except_transformer && except_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(except_transformer, std::unordered_set()); - else if (replace_transformer && replace_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(replace_transformer, std::unordered_set()); - } - - ListNodePtr list = std::make_shared(); - ProjectionNames result_projection_names; - ProjectionNames node_projection_names; - - for (auto & [node, column_name] : matched_expression_nodes_with_names) - { - bool apply_transformer_was_used = false; - bool replace_transformer_was_used = false; - bool execute_apply_transformer = false; - bool execute_replace_transformer = false; - - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - else - result_projection_names.push_back(column_name); - - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - if (auto * apply_transformer = transformer->as()) - { - const auto & expression_node = apply_transformer->getExpressionNode(); - apply_transformer_was_used = true; - - if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::LAMBDA) - { - auto lambda_expression_to_resolve = expression_node->clone(); - IdentifierResolveScope lambda_scope(expression_node, &scope /*parent_scope*/); - node_projection_names = resolveLambda(expression_node, lambda_expression_to_resolve, {node}, lambda_scope); - auto & lambda_expression_to_resolve_typed = lambda_expression_to_resolve->as(); - node = lambda_expression_to_resolve_typed.getExpression(); - } - else if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::FUNCTION) - { - auto function_to_resolve_untyped = expression_node->clone(); - auto & function_to_resolve_typed = function_to_resolve_untyped->as(); - function_to_resolve_typed.getArguments().getNodes().push_back(node); - node_projection_names = resolveFunction(function_to_resolve_untyped, scope); - node = function_to_resolve_untyped; - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unsupported apply matcher expression type. Expected lambda or function apply transformer. Actual {}. In scope {}", - transformer->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - execute_apply_transformer = true; - } - else if (auto * except_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - if (except_transformer->isColumnMatching(column_name)) - { - if (except_transformer->isStrict()) - strict_transformer_to_used_column_names[except_transformer].insert(column_name); - - node = {}; - break; - } - } - else if (auto * replace_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - auto replace_expression = replace_transformer->findReplacementExpression(column_name); - if (!replace_expression) - continue; - - replace_transformer_was_used = true; - - if (replace_transformer->isStrict()) - strict_transformer_to_used_column_names[replace_transformer].insert(column_name); - - node = replace_expression->clone(); - node_projection_names = resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** If replace expression resolved as single node, we want to use replace column name as result projection name, instead - * of using replace expression projection name. - * - * Example: SELECT * REPLACE id + 5 AS id FROM test_table; - */ - if (node_projection_names.size() == 1) - node_projection_names[0] = column_name; - - execute_replace_transformer = true; - } - - if (execute_apply_transformer || execute_replace_transformer) - { - if (auto * node_list = node->as()) - { - auto & node_list_nodes = node_list->getNodes(); - size_t node_list_nodes_size = node_list_nodes.size(); - - if (node_list_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "{} transformer {} resolved as list node with size {}. Expected 1. In scope {}", - execute_apply_transformer ? "APPLY" : "REPLACE", - transformer->formatASTForErrorMessage(), - node_list_nodes_size, - scope.scope_node->formatASTForErrorMessage()); - - node = node_list_nodes[0]; - } - - if (node_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Matcher node expected 1 projection name. Actual {}", node_projection_names.size()); - - result_projection_names.back() = std::move(node_projection_names[0]); - node_to_projection_name.emplace(node, result_projection_names.back()); - node_projection_names.clear(); - } - } - - if (node) - list->getNodes().push_back(node); - else - result_projection_names.pop_back(); - } - - for (auto & [strict_transformer, used_column_names] : strict_transformer_to_used_column_names) - { - auto strict_transformer_type = strict_transformer->getTransformerType(); - const Names * strict_transformer_column_names = nullptr; - - switch (strict_transformer_type) - { - case ColumnTransfomerType::EXCEPT: - { - const auto * except_transformer = static_cast(strict_transformer); - const auto & except_names = except_transformer->getExceptColumnNames(); - - if (except_names.size() != used_column_names.size()) - strict_transformer_column_names = &except_transformer->getExceptColumnNames(); - - break; - } - case ColumnTransfomerType::REPLACE: - { - const auto * replace_transformer = static_cast(strict_transformer); - const auto & replacement_names = replace_transformer->getReplacementsNames(); - - if (replacement_names.size() != used_column_names.size()) - strict_transformer_column_names = &replace_transformer->getReplacementsNames(); - - break; - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected strict EXCEPT or REPLACE column transformer. Actual type {}. In scope {}", - toString(strict_transformer_type), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (!strict_transformer_column_names) - continue; - - Names non_matched_column_names; - size_t strict_transformer_column_names_size = strict_transformer_column_names->size(); - for (size_t i = 0; i < strict_transformer_column_names_size; ++i) - { - const auto & column_name = (*strict_transformer_column_names)[i]; - if (used_column_names.find(column_name) == used_column_names.end()) - non_matched_column_names.push_back(column_name); - } - - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Strict {} column transformer {} expects following column(s) : {}. In scope {}", - toString(strict_transformer_type), - strict_transformer->formatASTForErrorMessage(), - fmt::join(non_matched_column_names, ", "), - scope.scope_node->formatASTForErrorMessage()); - } - - auto original_ast = matcher_node->getOriginalAST(); - matcher_node = std::move(list); - if (original_ast) - matcher_node->setOriginalAST(original_ast); - - return result_projection_names; -} - -/** Resolve window function window node. - * - * Node can be identifier or window node. - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - * Example: SELECT count(*) OVER (PARTITION BY id); - * - * If node has parent window name specified, then parent window definition is searched in nearest query scope WINDOW section. - * If node is identifier, than node is replaced with window definition. - * If node is window, that window node is merged with parent window node. - * - * Window node PARTITION BY and ORDER BY parts are resolved. - * If window node has frame begin OFFSET or frame end OFFSET specified, they are resolved, and window node frame constants are updated. - * Window node frame is validated. - */ -ProjectionName QueryAnalyzer::resolveWindow(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - std::string parent_window_name; - auto * identifier_node = node->as(); - - ProjectionName result_projection_name; - QueryTreeNodePtr parent_window_node; - - if (identifier_node) - parent_window_name = identifier_node->getIdentifier().getFullName(); - else if (auto * window_node = node->as()) - parent_window_name = window_node->getParentWindowName(); - - if (!parent_window_name.empty()) - { - auto * nearest_query_scope = scope.getNearestQueryScope(); - - if (!nearest_query_scope) - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Window '{}' does not exist.", parent_window_name); - - auto & scope_window_name_to_window_node = nearest_query_scope->window_name_to_window_node; - - auto window_node_it = scope_window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope_window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - nearest_query_scope->scope_node->formatASTForErrorMessage()); - - parent_window_node = window_node_it->second; - - if (identifier_node) - { - node = parent_window_node->clone(); - result_projection_name = parent_window_name; - } - else - { - mergeWindowWithParentWindow(node, parent_window_node, scope); - } - } - - auto & window_node = node->as(); - window_node.setParentWindowName({}); - - ProjectionNames partition_by_projection_names = resolveExpressionNodeList(window_node.getPartitionByNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - ProjectionNames order_by_projection_names = resolveSortNodeList(window_node.getOrderByNode(), scope); - - ProjectionNames frame_begin_offset_projection_names; - ProjectionNames frame_end_offset_projection_names; - - if (window_node.hasFrameBeginOffset()) - { - frame_begin_offset_projection_names = resolveExpressionNode(window_node.getFrameBeginOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_begin_constant_node = window_node.getFrameBeginOffsetNode()->as(); - if (!window_frame_begin_constant_node || !isNativeNumber(removeNullable(window_frame_begin_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameBeginOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().begin_offset = window_frame_begin_constant_node->getValue(); - if (frame_begin_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_begin_offset_projection_names.size()); - } - - if (window_node.hasFrameEndOffset()) - { - frame_end_offset_projection_names = resolveExpressionNode(window_node.getFrameEndOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_end_constant_node = window_node.getFrameEndOffsetNode()->as(); - if (!window_frame_end_constant_node || !isNativeNumber(removeNullable(window_frame_end_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameEndOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().end_offset = window_frame_end_constant_node->getValue(); - if (frame_end_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_end_offset_projection_names.size()); - } - - window_node.getWindowFrame().checkValid(); - - if (result_projection_name.empty()) - { - result_projection_name = calculateWindowProjectionName(node, - parent_window_node, - parent_window_name, - partition_by_projection_names, - order_by_projection_names, - frame_begin_offset_projection_names.empty() ? "" : frame_begin_offset_projection_names.front(), - frame_end_offset_projection_names.empty() ? "" : frame_end_offset_projection_names.front()); - } - - return result_projection_name; -} - -/** Resolve lambda function. - * This function modified lambda_node during resolve. It is caller responsibility to clone lambda before resolve - * if it is needed for later use. - * - * Lambda body expression result projection names is used as lambda projection names. - * - * Lambda expression can be resolved into list node. It is caller responsibility to handle it properly. - * - * lambda_node - node that must have LambdaNode type. - * lambda_node_to_resolve - lambda node to resolve that must have LambdaNode type. - * arguments - lambda arguments. - * scope - lambda scope. It is client responsibility to create it. - * - * Resolve steps: - * 1. Validate arguments. - * 2. Register lambda node in lambdas in resolve process. This is necessary to prevent recursive lambda resolving. - * 3. Initialize scope with lambda aliases. - * 4. Validate lambda argument names, and scope expressions. - * 5. Resolve lambda body expression. - * 6. Deregister lambda node from lambdas in resolve process. - */ -ProjectionNames QueryAnalyzer::resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope) -{ - auto & lambda_to_resolve = lambda_node_to_resolve->as(); - auto & lambda_arguments_nodes = lambda_to_resolve.getArguments().getNodes(); - size_t lambda_arguments_nodes_size = lambda_arguments_nodes.size(); - - /** Register lambda as being resolved, to prevent recursive lambdas resolution. - * Example: WITH (x -> x + lambda_2(x)) AS lambda_1, (x -> x + lambda_1(x)) AS lambda_2 SELECT 1; - */ - auto it = lambdas_in_resolve_process.find(lambda_node.get()); - if (it != lambdas_in_resolve_process.end()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive lambda {}. In scope {}", - lambda_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - lambdas_in_resolve_process.emplace(lambda_node.get()); - - size_t arguments_size = lambda_arguments.size(); - if (lambda_arguments_nodes_size != arguments_size) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} expect {} arguments. Actual {}. In scope {}", - lambda_to_resolve.formatASTForErrorMessage(), - lambda_arguments_nodes_size, - arguments_size, - scope.scope_node->formatASTForErrorMessage()); - - /// Initialize aliases in lambda scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - visitor.visit(lambda_to_resolve.getExpression()); - - /** Replace lambda arguments with new arguments. - * Additionally validate that there are no aliases with same name as lambda arguments. - * Arguments are registered in current scope expression_argument_name_to_node map. - */ - QueryTreeNodes lambda_new_arguments_nodes; - lambda_new_arguments_nodes.reserve(lambda_arguments_nodes_size); - - for (size_t i = 0; i < lambda_arguments_nodes_size; ++i) - { - auto & lambda_argument_node = lambda_arguments_nodes[i]; - const auto * lambda_argument_identifier = lambda_argument_node->as(); - const auto * lambda_argument_column = lambda_argument_node->as(); - if (!lambda_argument_identifier && !lambda_argument_column) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected IDENTIFIER or COLUMN as lambda argument, got {}", lambda_node->dumpTree()); - const auto & lambda_argument_name = lambda_argument_identifier ? lambda_argument_identifier->getIdentifier().getFullName() - : lambda_argument_column->getColumnName(); - - bool has_expression_node = scope.aliases.alias_name_to_expression_node->contains(lambda_argument_name); - bool has_alias_node = scope.aliases.alias_name_to_lambda_node.contains(lambda_argument_name); - - if (has_expression_node || has_alias_node) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Alias name '{}' inside lambda {} cannot have same name as lambda argument. In scope {}", - lambda_argument_name, - lambda_argument_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - scope.expression_argument_name_to_node.emplace(lambda_argument_name, lambda_arguments[i]); - lambda_new_arguments_nodes.push_back(lambda_arguments[i]); - } - - lambda_to_resolve.getArguments().getNodes() = std::move(lambda_new_arguments_nodes); - - /// Lambda body expression is resolved as standard query expression node. - auto result_projection_names = resolveExpressionNode(lambda_to_resolve.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - lambdas_in_resolve_process.erase(lambda_node.get()); - - return result_projection_names; -} - -namespace -{ -void checkFunctionNodeHasEmptyNullsAction(FunctionNode const & node) -{ - if (node.getNullsAction() != NullsAction::EMPTY) - throw Exception( - ErrorCodes::SYNTAX_ERROR, - "Function with name '{}' cannot use {} NULLS", - node.getFunctionName(), - node.getNullsAction() == NullsAction::IGNORE_NULLS ? "IGNORE" : "RESPECT"); -} -} - -/** Resolve function node in scope. - * During function node resolve, function node can be replaced with another expression (if it match lambda or sql user defined function), - * with constant (if it allow constant folding), or with expression list. It is caller responsibility to handle such cases appropriately. - * - * Steps: - * 1. Resolve function parameters. Validate that each function parameter must be constant node. - * 2. Try to lookup function as lambda in current scope. If it is lambda we can skip `in` and `count` special handling. - * 3. If function is count function, that take unqualified ASTERISK matcher, remove it from its arguments. Example: SELECT count(*) FROM test_table; - * 4. If function is `IN` function, then right part of `IN` function is replaced as subquery. - * 5. Resolve function arguments list, lambda expressions are allowed as function arguments. - * For `IN` function table expressions are allowed as function arguments. - * 6. Initialize argument_columns, argument_types, function_lambda_arguments_indexes arrays from function arguments. - * 7. If function name identifier was not resolved as function in current scope, try to lookup lambda from sql user defined functions factory. - * 8. If function was resolve as lambda from step 2 or 7, then resolve lambda using function arguments and replace function node with lambda result. - * After than function node is resolved. - * 9. If function was not resolved during step 6 as lambda, then try to resolve function as window function or executable user defined function - * or ordinary function or aggregate function. - * - * If function is resolved as window function or executable user defined function or aggregate function, function node is resolved - * no additional special handling is required. - * - * 8. If function was resolved as non aggregate function. Then if some of function arguments are lambda expressions, their result types need to be initialized and - * they must be resolved. - * 9. If function is suitable for constant folding, try to perform constant folding for function node. - */ -ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - FunctionNodePtr function_node_ptr = std::static_pointer_cast(node); - auto function_name = function_node_ptr->getFunctionName(); - - /// Resolve function parameters - - auto parameters_projection_names = resolveExpressionNodeList(function_node_ptr->getParametersNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - /// Convert function parameters into constant parameters array - - Array parameters; - - auto & parameters_nodes = function_node_ptr->getParameters().getNodes(); - parameters.reserve(parameters_nodes.size()); - - for (auto & parameter_node : parameters_nodes) - { - const auto * constant_node = parameter_node->as(); - if (!constant_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parameter for function '{}' expected to have constant value. Actual {}. In scope {}", - function_name, - parameter_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - parameters.push_back(constant_node->getValue()); - } - - //// If function node is not window function try to lookup function node name as lambda identifier. - QueryTreeNodePtr lambda_expression_untyped; - if (!function_node_ptr->isWindowFunction()) - { - auto function_lookup_result = tryResolveIdentifier({Identifier{function_name}, IdentifierLookupContext::FUNCTION}, scope); - lambda_expression_untyped = function_lookup_result.resolved_identifier; - } - - bool is_special_function_in = false; - bool is_special_function_dict_get = false; - bool is_special_function_join_get = false; - bool is_special_function_exists = false; - bool is_special_function_if = false; - - if (!lambda_expression_untyped) - { - is_special_function_in = isNameOfInFunction(function_name); - is_special_function_dict_get = functionIsDictGet(function_name); - is_special_function_join_get = functionIsJoinGet(function_name); - is_special_function_exists = function_name == "exists"; - is_special_function_if = function_name == "if"; - - auto function_name_lowercase = Poco::toLower(function_name); - - /** Special handling for count and countState functions. - * - * Example: SELECT count(*) FROM test_table - * Example: SELECT countState(*) FROM test_table; - */ - if (function_node_ptr->getArguments().getNodes().size() == 1 && - (function_name_lowercase == "count" || function_name_lowercase == "countstate")) - { - auto * matcher_node = function_node_ptr->getArguments().getNodes().front()->as(); - if (matcher_node && matcher_node->isUnqualified()) - function_node_ptr->getArguments().getNodes().clear(); - } - } - - /** Special functions dictGet and its variations and joinGet can be executed when first argument is identifier. - * Example: SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Try to resolve identifier as expression identifier and if it is resolved use it. - * Example: WITH 'dict_name' AS identifier SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Otherwise replace identifier with identifier full name constant. - * Validation that dictionary exists or table exists will be performed during function `getReturnType` method call. - */ - if ((is_special_function_dict_get || is_special_function_join_get) && - !function_node_ptr->getArguments().getNodes().empty() && - function_node_ptr->getArguments().getNodes()[0]->getNodeType() == QueryTreeNodeType::IDENTIFIER) - { - auto & first_argument = function_node_ptr->getArguments().getNodes()[0]; - auto & first_argument_identifier = first_argument->as(); - auto identifier = first_argument_identifier.getIdentifier(); - - IdentifierLookup identifier_lookup{identifier, IdentifierLookupContext::EXPRESSION}; - auto resolve_result = tryResolveIdentifier(identifier_lookup, scope); - - if (resolve_result.isResolved()) - { - first_argument = std::move(resolve_result.resolved_identifier); - } - else - { - size_t parts_size = identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected {} function first argument identifier to contain 1 or 2 parts. Actual '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_special_function_dict_get) - { - scope.context->getExternalDictionariesLoader().assertDictionaryStructureExists(identifier.getFullName(), scope.context); - } - else - { - auto table_node = tryResolveTableIdentifierFromDatabaseCatalog(identifier, scope.context); - if (!table_node) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} first argument expected table identifier '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node_typed = table_node->as(); - if (!std::dynamic_pointer_cast(table_node_typed.getStorage())) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} table '{}' should have engine StorageJoin. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - first_argument = std::make_shared(identifier.getFullName()); - } - } - - if (is_special_function_exists) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /// Rewrite EXISTS (subquery) into 1 IN (SELECT 1 FROM (subquery) LIMIT 1). - auto & exists_subquery_argument = function_node_ptr->getArguments().getNodes().at(0); - - auto constant_data_type = std::make_shared(); - - auto in_subquery = std::make_shared(Context::createCopy(scope.context)); - in_subquery->setIsSubquery(true); - in_subquery->getProjection().getNodes().push_back(std::make_shared(1UL, constant_data_type)); - in_subquery->getJoinTree() = exists_subquery_argument; - in_subquery->getLimit() = std::make_shared(1UL, constant_data_type); - - function_node_ptr = std::make_shared("in"); - function_node_ptr->getArguments().getNodes() = {std::make_shared(1UL, constant_data_type), in_subquery}; - node = function_node_ptr; - function_name = "in"; - is_special_function_in = true; - } - - if (is_special_function_if && !function_node_ptr->getArguments().getNodes().empty()) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /** Handle special case with constant If function, even if some of the arguments are invalid. - * - * SELECT if(hasColumnInTable('system', 'numbers', 'not_existing_column'), not_existing_column, 5) FROM system.numbers; - */ - auto & if_function_arguments = function_node_ptr->getArguments().getNodes(); - auto if_function_condition = if_function_arguments[0]; - resolveExpressionNode(if_function_condition, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto constant_condition = tryExtractConstantFromConditionNode(if_function_condition); - - if (constant_condition.has_value() && if_function_arguments.size() == 3) - { - QueryTreeNodePtr constant_if_result_node; - QueryTreeNodePtr possibly_invalid_argument_node; - - if (*constant_condition) - { - possibly_invalid_argument_node = if_function_arguments[2]; - constant_if_result_node = if_function_arguments[1]; - } - else - { - possibly_invalid_argument_node = if_function_arguments[1]; - constant_if_result_node = if_function_arguments[2]; - } - - bool apply_constant_if_optimization = false; - - try - { - resolveExpressionNode(possibly_invalid_argument_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - } - catch (...) - { - apply_constant_if_optimization = true; - } - - if (apply_constant_if_optimization) - { - auto result_projection_names = resolveExpressionNode(constant_if_result_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - node = std::move(constant_if_result_node); - return result_projection_names; - } - } - } - - /// Resolve function arguments - bool allow_table_expressions = is_special_function_in; - auto arguments_projection_names = resolveExpressionNodeList(function_node_ptr->getArgumentsNode(), - scope, - true /*allow_lambda_expression*/, - allow_table_expressions /*allow_table_expression*/); - - /// Mask arguments if needed - if (!scope.context->getSettingsRef().format_display_secrets_in_show_and_select) - { - if (FunctionSecretArgumentsFinder::Result secret_arguments = FunctionSecretArgumentsFinderTreeNode(*function_node_ptr).getResult(); secret_arguments.count) - { - auto & argument_nodes = function_node_ptr->getArgumentsNode()->as().getNodes(); - - for (size_t n = secret_arguments.start; n < secret_arguments.start + secret_arguments.count; ++n) - { - if (auto * constant = argument_nodes[n]->as()) - { - auto mask = scope.projection_mask_map->insert({constant->getTreeHash(), scope.projection_mask_map->size() + 1}).first->second; - constant->setMaskId(mask); - arguments_projection_names[n] = "[HIDDEN id: " + std::to_string(mask) + "]"; - } - } - } - } - - auto & function_node = *function_node_ptr; - - /// Replace right IN function argument if it is table or table function with subquery that read ordinary columns - if (is_special_function_in) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - if (scope.context->getSettingsRef().transform_null_in) - { - static constexpr std::array, 4> in_function_to_replace_null_in_function_map = - {{ - {"in", "nullIn"}, - {"notIn", "notNullIn"}, - {"globalIn", "globalNullIn"}, - {"globalNotIn", "globalNotNullIn"}, - }}; - - for (const auto & [in_function_name, in_function_name_to_replace] : in_function_to_replace_null_in_function_map) - { - if (function_name == in_function_name) - { - function_name = in_function_name_to_replace; - break; - } - } - } - - auto & function_in_arguments_nodes = function_node.getArguments().getNodes(); - if (function_in_arguments_nodes.size() != 2) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function '{}' expects 2 arguments", function_name); - - auto & in_second_argument = function_in_arguments_nodes[1]; - auto * table_node = in_second_argument->as(); - auto * table_function_node = in_second_argument->as(); - - if (table_node) - { - /// If table is already prepared set, we do not replace it with subquery. - /// If table is not a StorageSet, we'll create plan to build set in the Planner. - } - else if (table_function_node) - { - const auto & storage_snapshot = table_function_node->getStorageSnapshot(); - auto columns_to_select = storage_snapshot->getColumns(GetColumnsOptions(GetColumnsOptions::Ordinary)); - - size_t columns_to_select_size = columns_to_select.size(); - - auto column_nodes_to_select = std::make_shared(); - column_nodes_to_select->getNodes().reserve(columns_to_select_size); - - NamesAndTypes projection_columns; - projection_columns.reserve(columns_to_select_size); - - for (auto & column : columns_to_select) - { - column_nodes_to_select->getNodes().emplace_back(std::make_shared(column, in_second_argument)); - projection_columns.emplace_back(column.name, column.type); - } - - auto in_second_argument_query_node = std::make_shared(Context::createCopy(scope.context)); - in_second_argument_query_node->setIsSubquery(true); - in_second_argument_query_node->getProjectionNode() = std::move(column_nodes_to_select); - in_second_argument_query_node->getJoinTree() = std::move(in_second_argument); - in_second_argument_query_node->resolveProjectionColumns(std::move(projection_columns)); - - in_second_argument = std::move(in_second_argument_query_node); - } - else - { - /// Replace storage with values storage of insertion block - if (StoragePtr storage = scope.context->getViewSource()) - { - QueryTreeNodePtr table_expression; - /// Process possibly nested sub-selects - for (auto * query_node = in_second_argument->as(); query_node; query_node = table_expression->as()) - table_expression = extractLeftTableExpression(query_node->getJoinTree()); - - if (table_expression) - { - if (auto * query_table_node = table_expression->as()) - { - if (query_table_node->getStorageID().getFullNameNotQuoted() == storage->getStorageID().getFullNameNotQuoted()) - { - auto replacement_table_expression = std::make_shared(storage, scope.context); - if (std::optional table_expression_modifiers = query_table_node->getTableExpressionModifiers()) - replacement_table_expression->setTableExpressionModifiers(*table_expression_modifiers); - in_second_argument = in_second_argument->cloneAndReplace(table_expression, std::move(replacement_table_expression)); - } - } - } - } - - resolveExpressionNode(in_second_argument, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - } - } - - /// Initialize function argument columns - - ColumnsWithTypeAndName argument_columns; - DataTypes argument_types; - bool all_arguments_constants = true; - std::vector function_lambda_arguments_indexes; - - auto & function_arguments = function_node.getArguments().getNodes(); - size_t function_arguments_size = function_arguments.size(); - - for (size_t function_argument_index = 0; function_argument_index < function_arguments_size; ++function_argument_index) - { - auto & function_argument = function_arguments[function_argument_index]; - - ColumnWithTypeAndName argument_column; - argument_column.name = arguments_projection_names[function_argument_index]; - - /** If function argument is lambda, save lambda argument index and initialize argument type as DataTypeFunction - * where function argument types are initialized with empty array of lambda arguments size. - */ - if (const auto * lambda_node = function_argument->as()) - { - size_t lambda_arguments_size = lambda_node->getArguments().getNodes().size(); - argument_column.type = std::make_shared(DataTypes(lambda_arguments_size, nullptr), nullptr); - function_lambda_arguments_indexes.push_back(function_argument_index); - } - else if (is_special_function_in && function_argument_index == 1) - { - argument_column.type = std::make_shared(); - } - else - { - argument_column.type = function_argument->getResultType(); - } - - if (!argument_column.type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' argument is not resolved. In scope {}", - function_name, - scope.scope_node->formatASTForErrorMessage()); - - bool argument_is_constant = false; - const auto * constant_node = function_argument->as(); - if (constant_node) - { - argument_column.column = constant_node->getResultType()->createColumnConst(1, constant_node->getValue()); - argument_column.type = constant_node->getResultType(); - argument_is_constant = true; - } - else if (const auto * get_scalar_function_node = function_argument->as(); - get_scalar_function_node && get_scalar_function_node->getFunctionName() == "__getScalar") - { - /// Allow constant folding through getScalar - const auto * get_scalar_const_arg = get_scalar_function_node->getArguments().getNodes().at(0)->as(); - if (get_scalar_const_arg && scope.context->hasQueryContext()) - { - auto query_context = scope.context->getQueryContext(); - auto scalar_string = toString(get_scalar_const_arg->getValue()); - if (query_context->hasScalar(scalar_string)) - { - auto scalar = query_context->getScalar(scalar_string); - argument_column.column = ColumnConst::create(scalar.getByPosition(0).column, 1); - argument_column.type = get_scalar_function_node->getResultType(); - argument_is_constant = true; - } - } - } - - all_arguments_constants &= argument_is_constant; - - argument_types.push_back(argument_column.type); - argument_columns.emplace_back(std::move(argument_column)); - } - - /// Calculate function projection name - ProjectionNames result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - - /** Try to resolve function as - * 1. Lambda function in current scope. Example: WITH (x -> x + 1) AS lambda SELECT lambda(1); - * 2. Lambda function from sql user defined functions. - * 3. Special `untuple` function. - * 4. Special `grouping` function. - * 5. Window function. - * 6. Executable user defined function. - * 7. Ordinary function. - * 8. Aggregate function. - * - * TODO: Provide better error hints. - */ - if (!function_node.isWindowFunction()) - { - if (!lambda_expression_untyped) - lambda_expression_untyped = tryGetLambdaFromSQLUserDefinedFunctions(function_node.getFunctionName(), scope.context); - - /** If function is resolved as lambda. - * Clone lambda before resolve. - * Initialize lambda arguments as function arguments. - * Resolve lambda and then replace function node with resolved lambda expression body. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(value) FROM test_table; - * Result: SELECT value + 1 FROM test_table; - */ - if (lambda_expression_untyped) - { - auto * lambda_expression = lambda_expression_untyped->as(); - if (!lambda_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function identifier '{}' must be resolved as lambda. Actual {}. In scope {}", - function_node.getFunctionName(), - lambda_expression_untyped->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - if (!parameters.empty()) - { - throw Exception( - ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_node.formatASTForErrorMessage()); - } - - auto lambda_expression_clone = lambda_expression_untyped->clone(); - - IdentifierResolveScope lambda_scope(lambda_expression_clone, &scope /*parent_scope*/); - ProjectionNames lambda_projection_names = resolveLambda(lambda_expression_untyped, lambda_expression_clone, function_arguments, lambda_scope); - - auto & resolved_lambda = lambda_expression_clone->as(); - node = resolved_lambda.getExpression(); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(lambda_projection_names); - - return result_projection_names; - } - - if (function_name == "untuple") - { - /// Special handling of `untuple` function - - if (function_arguments.size() != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' must have 1 argument. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - const auto & untuple_argument = function_arguments[0]; - /// Handle this special case first as `getResultType()` might return nullptr - if (untuple_argument->as()) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Function untuple can't have lambda-expressions as arguments"); - - auto result_type = untuple_argument->getResultType(); - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' argument must have compound type. Actual type {}. In scope {}", - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - - auto result_list = std::make_shared(); - result_list->getNodes().reserve(element_names.size()); - - for (const auto & element_name : element_names) - { - auto tuple_element_function = std::make_shared("tupleElement"); - tuple_element_function->getArguments().getNodes().push_back(untuple_argument); - tuple_element_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = tuple_element_function; - resolveFunction(function_query_node, scope); - - result_list->getNodes().push_back(std::move(function_query_node)); - } - - auto untuple_argument_projection_name = arguments_projection_names.at(0); - result_projection_names.clear(); - - for (const auto & element_name : element_names) - { - if (node->hasAlias()) - result_projection_names.push_back(node->getAlias() + '.' + element_name); - else - result_projection_names.push_back(fmt::format("tupleElement({}, '{}')", untuple_argument_projection_name, element_name)); - } - - node = std::move(result_list); - return result_projection_names; - } - else if (function_name == "grouping") - { - /// It is responsibility of planner to perform additional handling of grouping function - if (function_arguments_size == 0) - throw Exception(ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING expects at least one argument"); - else if (function_arguments_size > 64) - throw Exception(ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING can have up to 64 arguments, but {} provided", - function_arguments_size); - checkFunctionNodeHasEmptyNullsAction(function_node); - - bool force_grouping_standard_compatibility = scope.context->getSettingsRef().force_grouping_standard_compatibility; - auto grouping_function = std::make_shared(force_grouping_standard_compatibility); - auto grouping_function_adaptor = std::make_shared(std::move(grouping_function)); - function_node.resolveAsFunction(grouping_function_adaptor->build(argument_columns)); - - return result_projection_names; - } - } - - if (function_node.isWindowFunction()) - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - throw Exception(ErrorCodes::UNKNOWN_AGGREGATE_FUNCTION, "Aggregate function with name '{}' does not exist. In scope {}{}", - function_name, scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(AggregateFunctionFactory::instance().getHints(function_name))); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Window function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsWindowFunction(std::move(aggregate_function)); - - bool window_node_is_identifier = function_node.getWindowNode()->getNodeType() == QueryTreeNodeType::IDENTIFIER; - ProjectionName window_projection_name = resolveWindow(function_node.getWindowNode(), scope); - - if (window_node_is_identifier) - result_projection_names[0] += " OVER " + window_projection_name; - else - result_projection_names[0] += " OVER (" + window_projection_name + ')'; - - return result_projection_names; - } - - FunctionOverloadResolverPtr function = UserDefinedExecutableFunctionFactory::instance().tryGet(function_name, scope.context, parameters); /// NOLINT(readability-static-accessed-through-instance) - bool is_executable_udf = true; - - IdentifierResolveScope::ResolvedFunctionsCache * function_cache = nullptr; - - if (!function) - { - /// This is a hack to allow a query like `select randConstant(), randConstant(), randConstant()`. - /// Function randConstant() would return the same value for the same arguments (in scope). - - auto hash = function_node_ptr->getTreeHash(); - function_cache = &scope.functions_cache[hash]; - if (!function_cache->resolver) - function_cache->resolver = FunctionFactory::instance().tryGet(function_name, scope.context); - - function = function_cache->resolver; - - is_executable_udf = false; - } - - if (function) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - } - else - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - std::vector possible_function_names; - - auto function_names = UserDefinedExecutableFunctionFactory::instance().getRegisteredNames(scope.context); /// NOLINT(readability-static-accessed-through-instance) - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = UserDefinedSQLFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = FunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = AggregateFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - for (auto & [name, lambda_node] : scope.aliases.alias_name_to_lambda_node) - { - if (lambda_node->getNodeType() == QueryTreeNodeType::LAMBDA) - possible_function_names.push_back(name); - } - - auto hints = NamePrompter<2>::getHints(function_name, possible_function_names); - - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Function with name '{}' does not exist. In scope {}{}", - function_name, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Aggregate function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsAggregateFunction(std::move(aggregate_function)); - - return result_projection_names; - } - - /// Executable UDFs may have parameters. They are checked in UserDefinedExecutableFunctionFactory. - if (!parameters.empty() && !is_executable_udf) - { - throw Exception(ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_name); - } - - /** For lambda arguments we need to initialize lambda argument types DataTypeFunction using `getLambdaArgumentTypes` function. - * Then each lambda arguments are initialized with columns, where column source is lambda. - * This information is important for later steps of query processing. - * Example: SELECT arrayMap(x -> x + 1, [1, 2, 3]). - * lambda node x -> x + 1 identifier x is resolved as column where source is lambda node. - */ - bool has_lambda_arguments = !function_lambda_arguments_indexes.empty(); - if (has_lambda_arguments) - { - function->getLambdaArgumentTypes(argument_types); - - ProjectionNames lambda_projection_names; - for (auto & function_lambda_argument_index : function_lambda_arguments_indexes) - { - auto & lambda_argument = function_arguments[function_lambda_argument_index]; - auto lambda_to_resolve = lambda_argument->clone(); - auto & lambda_to_resolve_typed = lambda_to_resolve->as(); - - const auto & lambda_argument_names = lambda_to_resolve_typed.getArgumentNames(); - size_t lambda_arguments_size = lambda_to_resolve_typed.getArguments().getNodes().size(); - - const auto * function_data_type = typeid_cast(argument_types[function_lambda_argument_index].get()); - if (!function_data_type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' expected function data type for lambda argument with index {}. Actual {}. In scope {}", - function_name, - function_lambda_argument_index, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & function_data_type_argument_types = function_data_type->getArgumentTypes(); - size_t function_data_type_arguments_size = function_data_type_argument_types.size(); - if (function_data_type_arguments_size != lambda_arguments_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}" - "' function data type for lambda argument with index {} arguments size mismatch. " - "Actual {}. Expected {}. In scope {}", - function_name, - function_data_type_arguments_size, - lambda_arguments_size, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - QueryTreeNodes lambda_arguments; - lambda_arguments.reserve(lambda_arguments_size); - - for (size_t i = 0; i < lambda_arguments_size; ++i) - { - const auto & argument_type = function_data_type_argument_types[i]; - auto column_name_and_type = NameAndTypePair{lambda_argument_names[i], argument_type}; - lambda_arguments.push_back(std::make_shared(std::move(column_name_and_type), lambda_to_resolve)); - } - - IdentifierResolveScope lambda_scope(lambda_to_resolve, &scope /*parent_scope*/); - lambda_projection_names = resolveLambda(lambda_argument, lambda_to_resolve, lambda_arguments, lambda_scope); - - if (auto * lambda_list_node_result = lambda_to_resolve_typed.getExpression()->as()) - { - size_t lambda_list_node_result_nodes_size = lambda_list_node_result->getNodes().size(); - - if (lambda_list_node_result_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Lambda as function argument resolved as list node with size {}. Expected 1. In scope {}", - lambda_list_node_result_nodes_size, - lambda_to_resolve->formatASTForErrorMessage()); - - lambda_to_resolve_typed.getExpression() = lambda_list_node_result->getNodes().front(); - } - - if (arguments_projection_names.at(function_lambda_argument_index) == PROJECTION_NAME_PLACEHOLDER) - { - size_t lambda_projection_names_size =lambda_projection_names.size(); - if (lambda_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Lambda argument inside function expected to have 1 projection name. Actual {}", - lambda_projection_names_size); - - WriteBufferFromOwnString lambda_argument_projection_name_buffer; - lambda_argument_projection_name_buffer << "lambda("; - lambda_argument_projection_name_buffer << "tuple("; - - size_t lambda_argument_names_size = lambda_argument_names.size(); - - for (size_t i = 0; i < lambda_argument_names_size; ++i) - { - const auto & lambda_argument_name = lambda_argument_names[i]; - lambda_argument_projection_name_buffer << lambda_argument_name; - - if (i + 1 != lambda_argument_names_size) - lambda_argument_projection_name_buffer << ", "; - } - - lambda_argument_projection_name_buffer << "), "; - lambda_argument_projection_name_buffer << lambda_projection_names[0]; - lambda_argument_projection_name_buffer << ")"; - - lambda_projection_names.clear(); - - arguments_projection_names[function_lambda_argument_index] = lambda_argument_projection_name_buffer.str(); - } - - auto lambda_resolved_type = std::make_shared(function_data_type_argument_types, lambda_to_resolve_typed.getExpression()->getResultType()); - lambda_to_resolve_typed.resolve(lambda_resolved_type); - - argument_types[function_lambda_argument_index] = lambda_resolved_type; - argument_columns[function_lambda_argument_index].type = lambda_resolved_type; - function_arguments[function_lambda_argument_index] = std::move(lambda_to_resolve); - } - - /// Recalculate function projection name after lambda resolution - result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - } - - /** Create SET column for special function IN to allow constant folding - * if left and right arguments are constants. - * - * Example: SELECT * FROM test_table LIMIT 1 IN 1; - */ - if (is_special_function_in) - { - const auto * first_argument_constant_node = function_arguments[0]->as(); - const auto * second_argument_constant_node = function_arguments[1]->as(); - - if (first_argument_constant_node && second_argument_constant_node) - { - const auto & first_argument_constant_type = first_argument_constant_node->getResultType(); - const auto & second_argument_constant_literal = second_argument_constant_node->getValue(); - const auto & second_argument_constant_type = second_argument_constant_node->getResultType(); - - const auto & settings = scope.context->getSettingsRef(); - - auto result_block = getSetElementsForConstantValue(first_argument_constant_type, - second_argument_constant_literal, - second_argument_constant_type, - settings.transform_null_in); - - SizeLimits size_limits_for_set = {settings.max_rows_in_set, settings.max_bytes_in_set, settings.set_overflow_mode}; - - auto set = std::make_shared(size_limits_for_set, 0, settings.transform_null_in); - - set->setHeader(result_block.cloneEmpty().getColumnsWithTypeAndName()); - set->insertFromBlock(result_block.getColumnsWithTypeAndName()); - set->finishInsert(); - - auto future_set = std::make_shared(std::move(set)); - - /// Create constant set column for constant folding - - auto column_set = ColumnSet::create(1, std::move(future_set)); - argument_columns[1].column = ColumnConst::create(std::move(column_set), 1); - } - - argument_columns[1].type = std::make_shared(); - } - - std::shared_ptr constant_value; - - try - { - FunctionBasePtr function_base; - if (function_cache) - { - auto & cached_function = function_cache->function_base; - if (!cached_function) - cached_function = function->build(argument_columns); - - function_base = cached_function; - } - else - function_base = function->build(argument_columns); - - /// Do not constant fold get scalar functions - bool disable_constant_folding = function_name == "__getScalar" || function_name == "shardNum" || - function_name == "shardCount" || function_name == "hostName" || function_name == "tcpPort"; - - /** If function is suitable for constant folding try to convert it to constant. - * Example: SELECT plus(1, 1); - * Result: SELECT 2; - */ - if (function_base->isSuitableForConstantFolding() && !disable_constant_folding) - { - auto result_type = function_base->getResultType(); - auto executable_function = function_base->prepare(argument_columns); - - ColumnPtr column; - - if (all_arguments_constants) - { - size_t num_rows = function_arguments.empty() ? 0 : argument_columns.front().column->size(); - column = executable_function->execute(argument_columns, result_type, num_rows, true); - } - else - { - column = function_base->getConstantResultForNonConstArguments(argument_columns, result_type); - } - - if (column && column->getDataType() != result_type->getColumnType()) - throw Exception( - ErrorCodes::LOGICAL_ERROR, - "Unexpected return type from {}. Expected {}. Got {}", - function->getName(), - result_type->getColumnType(), - column->getDataType()); - - /** Do not perform constant folding if there are aggregate or arrayJoin functions inside function. - * Example: SELECT toTypeName(sum(number)) FROM numbers(10); - */ - if (column && isColumnConst(*column) && !typeid_cast(column.get())->getDataColumn().isDummy() && - !hasAggregateFunctionNodes(node) && !hasFunctionNode(node, "arrayJoin") && - /// Sanity check: do not convert large columns to constants - column->byteSize() < 1_MiB) - { - /// Replace function node with result constant node - Field column_constant_value; - column->get(0, column_constant_value); - constant_value = std::make_shared(std::move(column_constant_value), result_type); - } - } - - function_node.resolveAsFunction(std::move(function_base)); - } - catch (Exception & e) - { - e.addMessage("In scope {}", scope.scope_node->formatASTForErrorMessage()); - throw; - } - - if (constant_value) - node = std::make_shared(std::move(constant_value), node); - - return result_projection_names; -} - -/** Resolve expression node. - * Argument node can be replaced with different node, or even with list node in case of matcher resolution. - * Example: SELECT * FROM test_table; - * * - is matcher node, and it can be resolved into ListNode. - * - * Steps: - * 1. If node has alias, replace node with its value in scope alias map. Register alias in expression_aliases_in_resolve_process, to prevent resolving identifier - * which can bind to expression alias name. Check tryResolveIdentifierFromAliases documentation for additional explanation. - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * - * 2. Call specific resolve method depending on node type. - * - * If allow_table_expression = true and node is query node, then it is not evaluated as scalar subquery. - * Although if node is identifier that is resolved into query node that query is evaluated as scalar subquery. - * SELECT id, (SELECT 1) AS c FROM test_table WHERE a IN c; - * SELECT id, FROM test_table WHERE a IN (SELECT 1); - * - * 3. Special case identifier node. - * Try resolve it as expression identifier. - * Then if allow_lambda_expression = true try to resolve it as function. - * Then if allow_table_expression = true try to resolve it as table expression. - * - * 4. If node has alias, update its value in scope alias map. Deregister alias from expression_aliases_in_resolve_process. - */ -ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias) -{ - checkStackSize(); - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - /** There can be edge case, when subquery for IN function is resolved multiple times in different context. - * SELECT id IN (subquery AS value), value FROM test_table; - * When we start to resolve `value` identifier, subquery is already resolved but constant folding is not performed. - */ - auto node_type = node->getNodeType(); - if (!allow_table_expression && (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION)) - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - } - - return resolved_expression_it->second; - } - - String node_alias = node->getAlias(); - ProjectionNames result_projection_names; - - if (node_alias.empty()) - { - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - else - { - result_projection_names.push_back(node_alias); - } - - bool is_duplicated_alias = scope.aliases.nodes_with_duplicated_aliases.contains(node); - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.insert({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - /** Do not use alias table if node has alias same as some other node. - * Example: WITH x -> x + 1 AS lambda SELECT 1 AS lambda; - * During 1 AS lambda resolve if we use alias table we replace node with x -> x + 1 AS lambda. - * - * Do not use alias table if allow_table_expression = true and we resolve query node directly. - * Example: SELECT a FROM test_table WHERE id IN (SELECT 1) AS a; - * To support both (SELECT 1) AS expression in projection and (SELECT 1) as subquery in IN, do not use - * alias table because in alias table subquery could be evaluated as scalar. - */ - bool use_alias_table = !ignore_alias; - if (is_duplicated_alias || (allow_table_expression && isSubqueryNodeType(node->getNodeType()))) - use_alias_table = false; - - if (!node_alias.empty() && use_alias_table) - { - /** Node could be potentially resolved by resolving other nodes. - * SELECT b, a as b FROM test_table; - * - * To resolve b we need to resolve a. - */ - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - node = it->second; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - node = it->second; - } - } - - scope.pushExpressionNode(node); - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & identifier_node = node->as(); - auto unresolved_identifier = identifier_node.getIdentifier(); - auto resolve_identifier_expression_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier_node = resolve_identifier_expression_result.resolved_identifier; - - if (resolved_identifier_node && result_projection_names.empty() && - (resolve_identifier_expression_result.isResolvedFromJoinTree() || resolve_identifier_expression_result.isResolvedFromExpressionArguments())) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier_node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - - if (!resolved_identifier_node && allow_lambda_expression) - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::FUNCTION}, scope).resolved_identifier; - - if (!resolved_identifier_node && allow_table_expression) - { - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::TABLE_EXPRESSION}, scope).resolved_identifier; - - if (resolved_identifier_node) - { - /// If table identifier is resolved as CTE clone it and resolve - auto * subquery_node = resolved_identifier_node->as(); - auto * union_node = resolved_identifier_node->as(); - bool resolved_as_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - - if (resolved_as_cte) - { - resolved_identifier_node = resolved_identifier_node->clone(); - subquery_node = resolved_identifier_node->as(); - union_node = resolved_identifier_node->as(); - - std::string_view cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - if (subquery_node) - subquery_node->setIsCTE(false); - else - union_node->setIsCTE(false); - - IdentifierResolveScope subquery_scope(resolved_identifier_node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - /// CTE is being resolved, it's required to forbid to resolve to it again - /// because recursive CTEs are not supported, e.g.: - /// - /// WITH test1 AS (SELECT i + 1, j + 1 FROM test1) SELECT toInt64(4) i, toInt64(5) j FROM numbers(3) WHERE (i, j) IN test1; - /// - /// In this example argument of function `in` is being resolve here. If CTE `test1` is not forbidden, - /// `test1` is resolved to CTE (not to the table) in `initializeQueryJoinTreeNode` function. - ctes_in_resolve_process.insert(cte_name); - - if (subquery_node) - resolveQuery(resolved_identifier_node, subquery_scope); - else - resolveUnion(resolved_identifier_node, subquery_scope); - - ctes_in_resolve_process.erase(cte_name); - } - } - } - - if (!resolved_identifier_node) - { - std::string message_clarification; - if (allow_lambda_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::FUNCTION); - - if (allow_table_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::TABLE_EXPRESSION); - - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(unresolved_identifier, - scope, - true, - allow_lambda_expression, - allow_table_expression, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(unresolved_identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {}{} identifier '{}' in scope {}{}", - toStringLowercase(IdentifierLookupContext::EXPRESSION), - message_clarification, - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - node = std::move(resolved_identifier_node); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - { - result_projection_names.clear(); - resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - return resolved_expression_it->second; - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier '{}' resolve into list node and list node projection names are not initialized. In scope {}", - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_projection_names.empty()) - result_projection_names.push_back(unresolved_identifier.getFullName()); - - break; - } - case QueryTreeNodeType::MATCHER: - { - result_projection_names = resolveMatcher(node, scope); - break; - } - case QueryTreeNodeType::LIST: - { - /** Edge case if list expression has alias. - * Matchers cannot have aliases, but `untuple` function can. - * Example: SELECT a, untuple(CAST(('hello', 1) AS Tuple(name String, count UInt32))) AS a; - * During resolveFunction `untuple` function is replaced by list of 2 constants 'hello', 1. - */ - result_projection_names = resolveExpressionNodeList(node, scope, allow_lambda_expression, allow_lambda_expression); - break; - } - case QueryTreeNodeType::CONSTANT: - { - if (result_projection_names.empty()) - { - const auto & constant_node = node->as(); - result_projection_names.push_back(constant_node.getValueStringRepresentation()); - } - - /// Already resolved - break; - } - case QueryTreeNodeType::COLUMN: - { - auto & column_node = node->as(); - if (column_node.hasExpression()) - resolveExpressionNode(column_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (result_projection_names.empty()) - result_projection_names.push_back(column_node.getColumnName()); - - break; - } - case QueryTreeNodeType::FUNCTION: - { - auto function_projection_names = resolveFunction(node, scope); - - if (result_projection_names.empty() || node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(function_projection_names); - - break; - } - case QueryTreeNodeType::LAMBDA: - { - if (!allow_lambda_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (result_projection_names.empty()) - result_projection_names.push_back(PROJECTION_NAME_PLACEHOLDER); - - /// Lambda must be resolved by caller - break; - } - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - std::string projection_name = "_subquery_" + std::to_string(subquery_counter); - ++subquery_counter; - - if (node_type == QueryTreeNodeType::QUERY) - resolveQuery(node, subquery_scope); - else - resolveUnion(node, subquery_scope); - - if (!allow_table_expression) - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - - if (result_projection_names.empty()) - result_projection_names.push_back(std::move(projection_name)); - - break; - } - case QueryTreeNodeType::TABLE: - { - if (!allow_table_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Table {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node = node->as(); - result_projection_names.push_back(table_node.getStorageID().getFullNameNotQuoted()); - - break; - } - case QueryTreeNodeType::TRANSFORMER: - [[fallthrough]]; - case QueryTreeNodeType::SORT: - [[fallthrough]]; - case QueryTreeNodeType::INTERPOLATE: - [[fallthrough]]; - case QueryTreeNodeType::WINDOW: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::ARRAY_JOIN: - [[fallthrough]]; - case QueryTreeNodeType::JOIN: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "{} {} is not allowed in expression context. In scope {}", - node->getNodeType(), - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - validateTreeSize(node, scope.context->getSettingsRef().max_expanded_ast_elements, node_to_tree_size); - - /// Lambda can be inside the aggregate function, so we should check parent scopes. - /// Most likely only the root scope can have an arrgegate function, but let's check all just in case. - bool in_aggregate_function_scope = false; - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - in_aggregate_function_scope = in_aggregate_function_scope || scope_ptr->expressions_in_resolve_process_stack.hasAggregateFunction(); - - if (!in_aggregate_function_scope) - { - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - { - auto it = scope_ptr->nullable_group_by_keys.find(node); - if (it != scope_ptr->nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - break; - } - } - } - - /** Update aliases after expression node was resolved. - * Do not update node in alias table if we resolve it for duplicate alias. - */ - if (!node_alias.empty() && use_alias_table && !scope.group_by_use_nulls) - { - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - it->second = node; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - it->second = node; - } - } - - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.erase({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - if (!ignore_alias) - resolved_expressions.emplace(node, result_projection_names); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - return result_projection_names; -} - -/** Resolve expression node list. - * If expression is CTE subquery node it is skipped. - * If expression is resolved in list, it is flattened into initial node list. - * - * Such examples must work: - * Example: CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; SELECT plus(*) FROM test_table; - * Example: SELECT *** FROM system.one; - */ -ProjectionNames QueryAnalyzer::resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression) -{ - auto & node_list_typed = node_list->as(); - size_t node_list_size = node_list_typed.getNodes().size(); - - QueryTreeNodes result_nodes; - result_nodes.reserve(node_list_size); - - ProjectionNames result_projection_names; - - for (auto & node : node_list_typed.getNodes()) - { - auto node_to_resolve = node; - auto expression_node_projection_names = resolveExpressionNode(node_to_resolve, scope, allow_lambda_expression, allow_table_expression); - size_t expected_projection_names_size = 1; - if (auto * expression_list = node_to_resolve->as()) - { - expected_projection_names_size = expression_list->getNodes().size(); - for (auto & expression_list_node : expression_list->getNodes()) - result_nodes.push_back(expression_list_node); - } - else - { - result_nodes.push_back(std::move(node_to_resolve)); - } - - if (expression_node_projection_names.size() != expected_projection_names_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected {} projection names. Actual {}", - expected_projection_names_size, - expression_node_projection_names.size()); - - result_projection_names.insert(result_projection_names.end(), expression_node_projection_names.begin(), expression_node_projection_names.end()); - expression_node_projection_names.clear(); - } - - node_list_typed.getNodes() = std::move(result_nodes); - - return result_projection_names; -} - -/** Resolve sort columns nodes list. - */ -ProjectionNames QueryAnalyzer::resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames result_projection_names; - ProjectionNames sort_expression_projection_names; - ProjectionNames fill_from_expression_projection_names; - ProjectionNames fill_to_expression_projection_names; - ProjectionNames fill_step_expression_projection_names; - - auto & sort_node_list_typed = sort_node_list->as(); - for (auto & node : sort_node_list_typed.getNodes()) - { - auto & sort_node = node->as(); - sort_expression_projection_names = resolveExpressionNode(sort_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (auto * sort_column_list_node = sort_node.getExpression()->as()) - { - size_t sort_column_list_node_size = sort_column_list_node->getNodes().size(); - if (sort_column_list_node_size != 1) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Sort column node expression resolved into list with size {}. Expected 1. In scope {}", - sort_column_list_node_size, - scope.scope_node->formatASTForErrorMessage()); - } - - sort_node.getExpression() = sort_column_list_node->getNodes().front(); - } - - size_t sort_expression_projection_names_size = sort_expression_projection_names.size(); - if (sort_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort expression expected 1 projection name. Actual {}", - sort_expression_projection_names_size); - - if (sort_node.hasFillFrom()) - { - fill_from_expression_projection_names = resolveExpressionNode(sort_node.getFillFrom(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillFrom()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL FROM expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_from_expression_projection_names_size = fill_from_expression_projection_names.size(); - if (fill_from_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL FROM expression expected 1 projection name. Actual {}", - fill_from_expression_projection_names_size); - } - - if (sort_node.hasFillTo()) - { - fill_to_expression_projection_names = resolveExpressionNode(sort_node.getFillTo(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillTo()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL TO expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_to_expression_projection_names_size = fill_to_expression_projection_names.size(); - if (fill_to_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL TO expression expected 1 projection name. Actual {}", - fill_to_expression_projection_names_size); - } - - if (sort_node.hasFillStep()) - { - fill_step_expression_projection_names = resolveExpressionNode(sort_node.getFillStep(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillStep()->as(); - if (!constant_node) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - bool is_number = isColumnedAsNumber(constant_node->getResultType()); - bool is_interval = WhichDataType(constant_node->getResultType()).isInterval(); - if (!is_number && !is_interval) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_step_expression_projection_names_size = fill_step_expression_projection_names.size(); - if (fill_step_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort FILL STEP expression expected 1 projection name. Actual {}", - fill_step_expression_projection_names_size); - } - - auto sort_column_projection_name = calculateSortColumnProjectionName(node, - sort_expression_projection_names[0], - fill_from_expression_projection_names.empty() ? "" : fill_from_expression_projection_names.front(), - fill_to_expression_projection_names.empty() ? "" : fill_to_expression_projection_names.front(), - fill_step_expression_projection_names.empty() ? "" : fill_step_expression_projection_names.front()); - - result_projection_names.push_back(std::move(sort_column_projection_name)); - - sort_expression_projection_names.clear(); - fill_from_expression_projection_names.clear(); - fill_to_expression_projection_names.clear(); - fill_step_expression_projection_names.clear(); - } - - return result_projection_names; -} - -namespace -{ - -void expandTuplesInList(QueryTreeNodes & key_list) -{ - QueryTreeNodes expanded_keys; - expanded_keys.reserve(key_list.size()); - for (auto const & key : key_list) - { - if (auto * function = key->as(); function != nullptr && function->getFunctionName() == "tuple") - { - std::copy(function->getArguments().begin(), function->getArguments().end(), std::back_inserter(expanded_keys)); - } - else - expanded_keys.push_back(key); - } - key_list = std::move(expanded_keys); -} - -} - -/** Resolve GROUP BY clause. - */ -void QueryAnalyzer::resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope) -{ - if (query_node_typed.isGroupByWithGroupingSets()) - { - for (auto & grouping_sets_keys_list_node : query_node_typed.getGroupBy().getNodes()) - { - replaceNodesWithPositionalArguments(grouping_sets_keys_list_node, query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(grouping_sets_keys_list_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = grouping_sets_keys_list_node->as().getNodes(); - expandTuplesInList(group_by_list); - } - - if (scope.group_by_use_nulls) - { - for (const auto & grouping_set : query_node_typed.getGroupBy().getNodes()) - { - for (const auto & group_by_elem : grouping_set->as()->getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } - } - else - { - replaceNodesWithPositionalArguments(query_node_typed.getGroupByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getGroupByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = query_node_typed.getGroupBy().getNodes(); - expandTuplesInList(group_by_list); - - if (scope.group_by_use_nulls) - { - for (const auto & group_by_elem : query_node_typed.getGroupBy().getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } -} - -/** Resolve interpolate columns nodes list. - */ -void QueryAnalyzer::resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope) -{ - auto & interpolate_node_list_typed = interpolate_node_list->as(); - - for (auto & interpolate_node : interpolate_node_list_typed.getNodes()) - { - auto & interpolate_node_typed = interpolate_node->as(); - - auto * column_to_interpolate = interpolate_node_typed.getExpression()->as(); - if (!column_to_interpolate) - throw Exception(ErrorCodes::LOGICAL_ERROR, "INTERPOLATE can work only for indentifiers, but {} is found", - interpolate_node_typed.getExpression()->formatASTForErrorMessage()); - auto column_to_interpolate_name = column_to_interpolate->getIdentifier().getFullName(); - - resolveExpressionNode(interpolate_node_typed.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool is_column_constant = interpolate_node_typed.getExpression()->getNodeType() == QueryTreeNodeType::CONSTANT; - - auto & interpolation_to_resolve = interpolate_node_typed.getInterpolateExpression(); - IdentifierResolveScope interpolate_scope(interpolation_to_resolve, &scope /*parent_scope*/); - - auto fake_column_node = std::make_shared(NameAndTypePair(column_to_interpolate_name, interpolate_node_typed.getExpression()->getResultType()), interpolate_node_typed.getExpression()); - if (is_column_constant) - interpolate_scope.expression_argument_name_to_node.emplace(column_to_interpolate_name, fake_column_node); - - resolveExpressionNode(interpolation_to_resolve, interpolate_scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (is_column_constant) - interpolation_to_resolve = interpolation_to_resolve->cloneAndReplace(fake_column_node, interpolate_node_typed.getExpression()); - } -} - -/** Resolve window nodes list. - */ -void QueryAnalyzer::resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope) -{ - auto & window_node_list_typed = window_node_list->as(); - for (auto & node : window_node_list_typed.getNodes()) - resolveWindow(node, scope); -} - -NamesAndTypes QueryAnalyzer::resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames projection_names = resolveExpressionNodeList(projection_node_list, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto projection_nodes = projection_node_list->as().getNodes(); - size_t projection_nodes_size = projection_nodes.size(); - - NamesAndTypes projection_columns; - projection_columns.reserve(projection_nodes_size); - - for (size_t i = 0; i < projection_nodes_size; ++i) - { - auto projection_node = projection_nodes[i]; - - if (!isExpressionNodeType(projection_node->getNodeType())) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Projection node must be constant, function, column, query or union"); - - projection_columns.emplace_back(projection_names[i], projection_node->getResultType()); - } - - return projection_columns; -} - -/** Initialize query join tree node. - * - * 1. Resolve identifiers. - * 2. Register table, table function, query, union, join, array join nodes in scope table expressions in resolve process. - */ -void QueryAnalyzer::initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope) -{ - std::deque join_tree_node_ptrs_to_process_queue; - join_tree_node_ptrs_to_process_queue.push_back(&join_tree_node); - - while (!join_tree_node_ptrs_to_process_queue.empty()) - { - auto * current_join_tree_node_ptr = join_tree_node_ptrs_to_process_queue.front(); - join_tree_node_ptrs_to_process_queue.pop_front(); - - auto & current_join_tree_node = *current_join_tree_node_ptr; - auto current_join_tree_node_type = current_join_tree_node->getNodeType(); - - switch (current_join_tree_node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & from_table_identifier = current_join_tree_node->as(); - auto table_identifier_lookup = IdentifierLookup{from_table_identifier.getIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - - auto from_table_identifier_alias = from_table_identifier.getAlias(); - - IdentifierResolveSettings resolve_settings; - /// In join tree initialization ignore join tree as identifier lookup source - resolve_settings.allow_to_check_join_tree = false; - /** Disable resolve of subquery during identifier resolution. - * Example: SELECT * FROM (SELECT 1) AS t1, t1; - * During `t1` identifier resolution we resolve it into subquery SELECT 1, but we want to disable - * subquery resolution at this stage, because JOIN TREE of parent query is not resolved. - */ - resolve_settings.allow_to_resolve_subquery_during_identifier_resolution = false; - - scope.pushExpressionNode(current_join_tree_node); - - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, resolve_settings); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - auto resolved_identifier = table_identifier_resolve_result.resolved_identifier; - - if (!resolved_identifier) - throw Exception(ErrorCodes::UNKNOWN_TABLE, - "Unknown table expression identifier '{}' in scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - resolved_identifier = resolved_identifier->clone(); - - /// Update alias name to table expression map - auto table_expression_it = scope.aliases.alias_name_to_table_expression_node.find(from_table_identifier_alias); - if (table_expression_it != scope.aliases.alias_name_to_table_expression_node.end()) - table_expression_it->second = resolved_identifier; - - auto table_expression_modifiers = from_table_identifier.getTableExpressionModifiers(); - - auto * resolved_identifier_query_node = resolved_identifier->as(); - auto * resolved_identifier_union_node = resolved_identifier->as(); - - if (resolved_identifier_query_node || resolved_identifier_union_node) - { - if (table_expression_modifiers.has_value()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Table expression modifiers {} are not supported for subquery {}", - table_expression_modifiers->formatForErrorMessage(), - resolved_identifier->formatASTForErrorMessage()); - } - } - else if (auto * resolved_identifier_table_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else if (auto * resolved_identifier_table_function_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_function_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier in JOIN TREE '{}' resolved into unexpected table expression. In scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto current_join_tree_node_alias = current_join_tree_node->getAlias(); - resolved_identifier->setAlias(current_join_tree_node_alias); - current_join_tree_node = resolved_identifier; - - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::QUERY: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::UNION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - auto & array_join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&array_join.getTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::JOIN: - { - auto & join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&join.getLeftTableExpression()); - join_tree_node_ptrs_to_process_queue.push_back(&join.getRightTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - ++scope.joins_count; - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, UNION, ARRAY JOIN or JOIN. Actual {} {}. In scope {}", - current_join_tree_node->getNodeTypeName(), - current_join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - } -} - -/// Initialize table expression data for table expression node -void QueryAnalyzer::initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto table_expression_data_it = scope.table_expression_node_to_data.find(table_expression_node); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - return; - - TableExpressionData table_expression_data; - - if (table_node) - { - if (!table_node->getTemporaryTableName().empty()) - { - table_expression_data.table_name = table_node->getTemporaryTableName(); - table_expression_data.table_expression_name = table_node->getTemporaryTableName(); - } - else - { - const auto & table_storage_id = table_node->getStorageID(); - table_expression_data.database_name = table_storage_id.database_name; - table_expression_data.table_name = table_storage_id.table_name; - table_expression_data.table_expression_name = table_storage_id.getFullNameNotQuoted(); - } - - table_expression_data.table_expression_description = "table"; - } - else if (query_node || union_node) - { - table_expression_data.table_name = query_node ? query_node->getCTEName() : union_node->getCTEName(); - table_expression_data.table_expression_description = "subquery"; - } - else if (table_function_node) - { - table_expression_data.table_expression_description = "table_function"; - } - - if (table_expression_node->hasAlias()) - table_expression_data.table_expression_name = table_expression_node->getAlias(); - - if (table_node || table_function_node) - { - const auto & storage_snapshot = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - - auto get_column_options = GetColumnsOptions(GetColumnsOptions::All).withExtendedObjects().withVirtuals(); - if (storage_snapshot->storage.supportsSubcolumns()) - get_column_options.withSubcolumns(); - - auto column_names_and_types = storage_snapshot->getColumns(get_column_options); - table_expression_data.column_names_and_types = NamesAndTypes(column_names_and_types.begin(), column_names_and_types.end()); - - const auto & columns_description = storage_snapshot->metadata->getColumns(); - - std::vector> alias_columns_to_resolve; - ColumnNameToColumnNodeMap column_name_to_column_node; - column_name_to_column_node.reserve(column_names_and_types.size()); - - /** For ALIAS columns in table we must additionally analyze ALIAS expressions. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + 5); - * - * To do that we collect alias columns and build table column name to column node map. - * For each alias column we build identifier resolve scope, initialize it with table column name to node map - * and resolve alias column. - */ - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - for (const auto & subcolumn : columns_description.getSubcolumns(column_name_and_type.name)) - table_expression_data.subcolumn_names.insert(subcolumn.name); - const auto & column_default = columns_description.getDefault(column_name_and_type.name); - - if (column_default && column_default->kind == ColumnDefaultKind::Alias) - { - auto alias_expression = buildQueryTree(column_default->expression, scope.context); - auto column_node = std::make_shared(column_name_and_type, std::move(alias_expression), table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - alias_columns_to_resolve.emplace_back(column_name_and_type.name, column_node); - } - else - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - for (auto & [alias_column_to_resolve_name, alias_column_to_resolve] : alias_columns_to_resolve) - { - /** Alias column could be potentially resolved during resolve of other ALIAS column. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + alias_value_2, alias_value_2 ALIAS id + 5) ENGINE=TinyLog; - * - * During resolve of alias_value_1, alias_value_2 column will be resolved. - */ - alias_column_to_resolve = column_name_to_column_node[alias_column_to_resolve_name]; - - IdentifierResolveScope alias_column_resolve_scope(alias_column_to_resolve, nullptr /*parent_scope*/); - alias_column_resolve_scope.column_name_to_column_node = std::move(column_name_to_column_node); - alias_column_resolve_scope.context = scope.context; - - /// Initialize aliases in alias column scope - QueryExpressionsAliasVisitor visitor(alias_column_resolve_scope.aliases); - visitor.visit(alias_column_to_resolve->getExpression()); - - resolveExpressionNode(alias_column_resolve_scope.scope_node, - alias_column_resolve_scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - auto & resolved_expression = alias_column_to_resolve->getExpression(); - if (!resolved_expression->getResultType()->equals(*alias_column_to_resolve->getResultType())) - resolved_expression = buildCastFunction(resolved_expression, alias_column_to_resolve->getResultType(), scope.context, true); - column_name_to_column_node = std::move(alias_column_resolve_scope.column_name_to_column_node); - column_name_to_column_node[alias_column_to_resolve_name] = alias_column_to_resolve; - } - - table_expression_data.column_name_to_column_node = std::move(column_name_to_column_node); - } - else if (query_node || union_node) - { - table_expression_data.column_names_and_types = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - table_expression_data.column_name_to_column_node.reserve(table_expression_data.column_names_and_types.size()); - - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - table_expression_data.column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - table_expression_data.column_identifier_first_parts.reserve(table_expression_data.column_name_to_column_node.size()); - - for (auto & [column_name, _] : table_expression_data.column_name_to_column_node) - { - Identifier column_name_identifier(column_name); - table_expression_data.column_identifier_first_parts.insert(column_name_identifier.at(0)); - } - - if (auto * scope_query_node = scope.scope_node->as()) - { - auto left_table_expression = extractLeftTableExpression(scope_query_node->getJoinTree()); - if (table_expression_node.get() == left_table_expression.get() && - scope.joins_count == 1 && - scope.context->getSettingsRef().single_join_prefer_left_table) - table_expression_data.should_qualify_columns = false; - } - - scope.table_expression_node_to_data.emplace(table_expression_node, std::move(table_expression_data)); -} - -bool findIdentifier(const FunctionNode & function) -{ - for (const auto & argument : function.getArguments()) - { - if (argument->as()) - return true; - if (const auto * f = argument->as(); f && findIdentifier(*f)) - return true; - } - return false; -} - -/// Resolve table function node in scope -void QueryAnalyzer::resolveTableFunction(QueryTreeNodePtr & table_function_node, - IdentifierResolveScope & scope, - QueryExpressionsAliasVisitor & expressions_visitor, - bool nested_table_function) -{ - auto & table_function_node_typed = table_function_node->as(); - - if (!nested_table_function) - expressions_visitor.visit(table_function_node_typed.getArgumentsNode()); - - const auto & table_function_name = table_function_node_typed.getTableFunctionName(); - - auto & scope_context = scope.context; - - TableFunctionPtr table_function_ptr = TableFunctionFactory::instance().tryGet(table_function_name, scope_context); - if (!table_function_ptr) - { - String database_name = scope_context->getCurrentDatabase(); - String table_name; - - auto function_ast = table_function_node->toAST(); - Identifier table_identifier{table_function_name}; - if (table_identifier.getPartsSize() == 1) - { - table_name = table_identifier[0]; - } - else if (table_identifier.getPartsSize() == 2) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - - auto parametrized_view_storage = scope_context->getQueryContext()->buildParametrizedViewStorage(function_ast, database_name, table_name); - if (parametrized_view_storage) - { - auto fake_table_node = std::make_shared(parametrized_view_storage, scope_context); - fake_table_node->setAlias(table_function_node->getAlias()); - table_function_node = fake_table_node; - return; - } - - auto hints = TableFunctionFactory::instance().getHints(table_function_name); - if (!hints.empty()) - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}. Maybe you meant: {}", - table_function_name, - DB::toString(hints)); - else - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}", - table_function_name); - } - - QueryTreeNodes result_table_function_arguments; - - auto skip_analysis_arguments_indexes = table_function_ptr->skipAnalysisForArguments(table_function_node, scope_context); - - auto & table_function_arguments = table_function_node_typed.getArguments().getNodes(); - size_t table_function_arguments_size = table_function_arguments.size(); - - for (size_t table_function_argument_index = 0; table_function_argument_index < table_function_arguments_size; ++table_function_argument_index) - { - auto & table_function_argument = table_function_arguments[table_function_argument_index]; - - auto skip_argument_index_it = std::find(skip_analysis_arguments_indexes.begin(), - skip_analysis_arguments_indexes.end(), - table_function_argument_index); - if (skip_argument_index_it != skip_analysis_arguments_indexes.end()) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - if (auto * identifier_node = table_function_argument->as()) - { - const auto & unresolved_identifier = identifier_node->getIdentifier(); - auto identifier_resolve_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier = std::move(identifier_resolve_result.resolved_identifier); - - if (resolved_identifier && resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - result_table_function_arguments.push_back(std::move(resolved_identifier)); - else - result_table_function_arguments.push_back(table_function_argument); - - continue; - } - else if (auto * table_function_argument_function = table_function_argument->as()) - { - const auto & table_function_argument_function_name = table_function_argument_function->getFunctionName(); - if (TableFunctionFactory::instance().isTableFunctionName(table_function_argument_function_name)) - { - auto table_function_node_to_resolve_typed = std::make_shared(table_function_argument_function_name); - table_function_node_to_resolve_typed->getArgumentsNode() = table_function_argument_function->getArgumentsNode(); - - QueryTreeNodePtr table_function_node_to_resolve = std::move(table_function_node_to_resolve_typed); - resolveTableFunction(table_function_node_to_resolve, scope, expressions_visitor, true /*nested_table_function*/); - - result_table_function_arguments.push_back(std::move(table_function_node_to_resolve)); - continue; - } - } - - /** Table functions arguments can contain expressions with invalid identifiers. - * We cannot skip analysis for such arguments, because some table functions cannot provide - * information if analysis for argument should be skipped until other arguments will be resolved. - * - * Example: SELECT key from remote('127.0.0.{1,2}', view(select number AS key from numbers(2)), cityHash64(key)); - * Example: SELECT id from remote('127.0.0.{1,2}', 'default', 'test_table', cityHash64(id)); - */ - try - { - resolveExpressionNode(table_function_argument, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - catch (const Exception & exception) - { - if (exception.code() == ErrorCodes::UNKNOWN_IDENTIFIER) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - throw; - } - - if (auto * expression_list = table_function_argument->as()) - { - for (auto & expression_list_node : expression_list->getNodes()) - result_table_function_arguments.push_back(expression_list_node); - } - else - { - result_table_function_arguments.push_back(table_function_argument); - } - } - - table_function_node_typed.getArguments().getNodes() = std::move(result_table_function_arguments); - - auto table_function_ast = table_function_node_typed.toAST(); - table_function_ptr->parseArguments(table_function_ast, scope_context); - - - uint64_t use_structure_from_insertion_table_in_table_functions = scope_context->getSettingsRef().use_structure_from_insertion_table_in_table_functions; - if (!nested_table_function && - use_structure_from_insertion_table_in_table_functions && - scope_context->hasInsertionTable() && - table_function_ptr->needStructureHint()) - { - const auto & insertion_table = scope_context->getInsertionTable(); - if (!insertion_table.empty()) - { - const auto & insert_columns = DatabaseCatalog::instance() - .getTable(insertion_table, scope_context) - ->getInMemoryMetadataPtr() - ->getColumns(); - const auto & insert_column_names = scope_context->hasInsertionTableColumnNames() ? *scope_context->getInsertionTableColumnNames() : insert_columns.getOrdinary().getNames(); - DB::ColumnsDescription structure_hint; - - bool use_columns_from_insert_query = true; - - /// Insert table matches columns against SELECT expression by position, so we want to map - /// insert table columns to table function columns through names from SELECT expression. - - auto insert_column_name_it = insert_column_names.begin(); - auto insert_column_names_end = insert_column_names.end(); /// end iterator of the range covered by possible asterisk - auto virtual_column_names = table_function_ptr->getVirtualsToCheckBeforeUsingStructureHint(); - bool asterisk = false; - const auto & expression_list = scope.scope_node->as().getProjection(); - auto expression = expression_list.begin(); - - /// We want to go through SELECT expression list and correspond each expression to column in insert table - /// which type will be used as a hint for the file structure inference. - for (; expression != expression_list.end() && insert_column_name_it != insert_column_names_end; ++expression) - { - if (auto * identifier_node = (*expression)->as()) - { - - if (!virtual_column_names.contains(identifier_node->getIdentifier().getFullName())) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - ColumnDescription column = insert_columns.get(*insert_column_name_it); - column.name = identifier_node->getIdentifier().getFullName(); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else if (auto * matcher_node = (*expression)->as(); matcher_node && matcher_node->getMatcherType() == MatcherNodeType::ASTERISK) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Only one asterisk can be used in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - if (!structure_hint.empty()) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - asterisk = true; - } - else if (auto * function = (*expression)->as()) - { - if (use_structure_from_insertion_table_in_table_functions == 2 && findIdentifier(*function)) - { - use_columns_from_insert_query = false; - break; - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else - { - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - } - - if (use_structure_from_insertion_table_in_table_functions == 2 && !asterisk) - { - /// For input function we should check if input format supports reading subset of columns. - if (table_function_ptr->getName() == "input") - use_columns_from_insert_query = FormatFactory::instance().checkIfFormatSupportsSubsetOfColumns(scope.context->getInsertFormat(), scope.context); - else - use_columns_from_insert_query = table_function_ptr->supportsReadingSubsetOfColumns(scope.context); - } - - if (use_columns_from_insert_query) - { - if (expression == expression_list.end()) - { - /// Append tail of insert structure to the hint - if (asterisk) - { - for (; insert_column_name_it != insert_column_names_end; ++insert_column_name_it) - { - ColumnDescription column = insert_columns.get(*insert_column_name_it); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - } - - if (!structure_hint.empty()) - table_function_ptr->setStructureHint(structure_hint); - - } else if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::NUMBER_OF_COLUMNS_DOESNT_MATCH, "Number of columns in insert table less than required by SELECT expression."); - } - } - } - - auto table_function_storage = scope_context->getQueryContext()->executeTableFunction(table_function_ast, table_function_ptr); - table_function_node_typed.resolve(std::move(table_function_ptr), std::move(table_function_storage), scope_context, std::move(skip_analysis_arguments_indexes)); -} - -/// Resolve array join node in scope -void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & array_join_node_typed = array_join_node->as(); - resolveQueryJoinTreeNode(array_join_node_typed.getTableExpression(), scope, expressions_visitor); - - std::unordered_set array_join_column_names; - - /// Wrap array join expressions into column nodes, where array join expression is inner expression - - auto & array_join_nodes = array_join_node_typed.getJoinExpressions().getNodes(); - size_t array_join_nodes_size = array_join_nodes.size(); - - if (array_join_nodes_size == 0) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, - "ARRAY JOIN requires at least single expression"); - - std::vector array_join_column_expressions; - array_join_column_expressions.reserve(array_join_nodes_size); - - for (auto & array_join_expression : array_join_nodes) - { - auto array_join_expression_alias = array_join_expression->getAlias(); - - for (const auto & elem : array_join_nodes) - { - if (elem->hasAlias()) - scope.aliases.array_join_aliases.insert(elem->getAlias()); - - for (auto & child : elem->getChildren()) - { - if (child) - expressions_visitor.visit(child); - } - } - - std::string identifier_full_name; - - if (auto * identifier_node = array_join_expression->as()) - identifier_full_name = identifier_node->getIdentifier().getFullName(); - - resolveExpressionNode(array_join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/, true /*ignore_alias*/); - - auto process_array_join_expression = [&](QueryTreeNodePtr & expression) - { - auto result_type = expression->getResultType(); - bool is_array_type = isArray(result_type); - bool is_map_type = isMap(result_type); - - if (!is_array_type && !is_map_type) - throw Exception(ErrorCodes::TYPE_MISMATCH, - "ARRAY JOIN {} requires expression {} with Array or Map type. Actual {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - expression->formatASTForErrorMessage(), - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_map_type) - result_type = assert_cast(*result_type).getNestedType(); - - result_type = assert_cast(*result_type).getNestedType(); - - String array_join_column_name; - - if (!array_join_expression_alias.empty()) - { - array_join_column_name = array_join_expression_alias; - } - else if (auto * array_join_expression_inner_column = array_join_expression->as()) - { - array_join_column_name = array_join_expression_inner_column->getColumnName(); - } - else if (!identifier_full_name.empty()) - { - array_join_column_name = identifier_full_name; - } - else - { - array_join_column_name = "__array_join_expression_" + std::to_string(array_join_expressions_counter); - ++array_join_expressions_counter; - } - - if (array_join_column_names.contains(array_join_column_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "ARRAY JOIN {} multiple columns with name {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - array_join_column_name, - scope.scope_node->formatASTForErrorMessage()); - array_join_column_names.emplace(array_join_column_name); - - NameAndTypePair array_join_column(array_join_column_name, result_type); - auto array_join_column_node = std::make_shared(std::move(array_join_column), expression, array_join_node); - array_join_column_node->setAlias(array_join_expression_alias); - array_join_column_expressions.push_back(std::move(array_join_column_node)); - }; - - // Support ARRAY JOIN COLUMNS(...). COLUMNS transformer is resolved to list of columns. - if (auto * columns_list = array_join_expression->as()) - { - for (auto & array_join_subexpression : columns_list->getNodes()) - process_array_join_expression(array_join_subexpression); - } - else - { - process_array_join_expression(array_join_expression); - } - } - - array_join_nodes = std::move(array_join_column_expressions); -} - -void QueryAnalyzer::checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope) -{ - Names column_names; - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - if (join_node->as().getKind() != JoinKind::Paste) - return; - - auto * left_node = left_table_expr->as(); - auto * right_node = right_table_expr->as(); - - if (!left_node && !right_node) - return; - - if (left_node) - for (const auto & name_and_type : left_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - if (right_node) - for (const auto & name_and_type : right_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - - if (column_names.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of projection columns cannot be empty"); - - std::sort(column_names.begin(), column_names.end()); - for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is no any duplicates because it will lead to broken result - if (column_names[i] == column_names[i+1]) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add/change aliases to avoid duplication)" - "While processing '{}'", join_node->formatASTForErrorMessage()); -} - -/// Resolve join node in scope -void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & join_node_typed = join_node->as(); - - resolveQueryJoinTreeNode(join_node_typed.getLeftTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getLeftTableExpression(), scope); - - resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); - - if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) - checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope); - - if (join_node_typed.isOnJoinExpression()) - { - expressions_visitor.visit(join_node_typed.getJoinExpression()); - auto join_expression = join_node_typed.getJoinExpression(); - resolveExpressionNode(join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - join_node_typed.getJoinExpression() = std::move(join_expression); - } - else if (join_node_typed.isUsingJoinExpression()) - { - auto & join_using_list = join_node_typed.getJoinExpression()->as(); - std::unordered_set join_using_identifiers; - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto * identifier_node = join_using_node->as(); - if (!identifier_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} USING clause expected identifier. Actual {}", - join_node_typed.formatASTForErrorMessage(), - join_using_node->formatASTForErrorMessage()); - - const auto & identifier_full_name = identifier_node->getIdentifier().getFullName(); - - if (join_using_identifiers.contains(identifier_full_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} identifier '{}' appears more than once in USING clause", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name); - - join_using_identifiers.insert(identifier_full_name); - - const auto & settings = scope.context->getSettingsRef(); - - /** While resolving JOIN USING identifier, try to resolve identifier from parent subquery projection. - * Example: SELECT a + 1 AS b FROM (SELECT 1 AS a) t1 JOIN (SELECT 2 AS b) USING b - * In this case `b` is not in the left table expression, but it is in the parent subquery projection. - */ - auto try_resolve_identifier_from_query_projection = [this](const String & identifier_full_name_, - const QueryTreeNodePtr & left_table_expression, - const IdentifierResolveScope & scope_) -> QueryTreeNodePtr - { - const QueryNode * query_node = scope_.scope_node ? scope_.scope_node->as() : nullptr; - if (!query_node) - return nullptr; - - const auto & projection_list = query_node->getProjection(); - for (const auto & projection_node : projection_list.getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name_ == projection_node->getAlias()) - { - auto left_subquery = std::make_shared(query_node->getMutableContext()); - left_subquery->getProjection().getNodes().push_back(projection_node->clone()); - left_subquery->getJoinTree() = left_table_expression; - - IdentifierResolveScope left_subquery_scope(left_subquery, nullptr /*parent_scope*/); - resolveQuery(left_subquery, left_subquery_scope); - - const auto & resolved_nodes = left_subquery->getProjection().getNodes(); - if (resolved_nodes.size() == 1) - { - /// Create ColumnNode with expression from parent projection - return std::make_shared( - NameAndTypePair{identifier_full_name_, resolved_nodes.front()->getResultType()}, - resolved_nodes.front(), left_table_expression); - } - } - } - return nullptr; - }; - - QueryTreeNodePtr result_left_table_expression = nullptr; - /** With `analyzer_compatibility_join_using_top_level_identifier` alias in projection has higher priority than column from left table. - * But if aliased expression cannot be resolved from left table, we get UNKNOW_IDENTIFIER error, - * despite the fact that column from USING could be resolved from left table. - * It's compatibility with a default behavior for old analyzer. - */ - if (settings.analyzer_compatibility_join_using_top_level_identifier) - result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - IdentifierLookup identifier_lookup{identifier_node->getIdentifier(), IdentifierLookupContext::EXPRESSION}; - if (!result_left_table_expression) - result_left_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getLeftTableExpression(), scope); - - /** Here we may try to resolve identifier from projection in case it's not resolved from left table expression - * and analyzer_compatibility_join_using_top_level_identifier is disabled. - * For now we do not do this, because not all corner cases are clear. - * But let's at least mention it in error message - */ - /// if (!settings.analyzer_compatibility_join_using_top_level_identifier && !result_left_table_expression) - /// result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - if (!result_left_table_expression) - { - String extra_message; - const QueryNode * query_node = scope.scope_node ? scope.scope_node->as() : nullptr; - if (settings.analyzer_compatibility_join_using_top_level_identifier && query_node) - { - for (const auto & projection_node : query_node->getProjection().getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name == projection_node->getAlias()) - { - extra_message = fmt::format( - ", but alias '{}' is present in SELECT list." - " You may try to SET analyzer_compatibility_join_using_top_level_identifier = 1, to allow to use it in USING clause", - projection_node->formatASTForErrorMessage()); - break; - } - } - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from left table expression{}. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - extra_message, - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_left_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from left table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto result_right_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getRightTableExpression(), scope); - if (!result_right_table_expression) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - if (result_right_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto expression_types = DataTypes{result_left_table_expression->getResultType(), result_right_table_expression->getResultType()}; - DataTypePtr common_type = tryGetLeastSupertype(expression_types); - - if (!common_type) - throw Exception(ErrorCodes::NO_COMMON_TYPE, - "JOIN {} cannot infer common type for {} and {} in USING for identifier '{}'. In scope {}", - join_node_typed.formatASTForErrorMessage(), - result_left_table_expression->getResultType()->getName(), - result_right_table_expression->getResultType()->getName(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - NameAndTypePair join_using_column(identifier_full_name, common_type); - ListNodePtr join_using_expression = std::make_shared(QueryTreeNodes{result_left_table_expression, result_right_table_expression}); - auto join_using_column_node = std::make_shared(std::move(join_using_column), std::move(join_using_expression), join_node); - join_using_node = std::move(join_using_column_node); - } - } -} - -/** Resolve query join tree. - * - * Query join tree must be initialized before calling this function. - */ -void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto from_node_type = join_tree_node->getNodeType(); - - switch (from_node_type) - { - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - resolveExpressionNode(join_tree_node, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - resolveTableFunction(join_tree_node, scope, expressions_visitor, false /*nested_table_function*/); - break; - } - case QueryTreeNodeType::TABLE: - { - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - resolveArrayJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::JOIN: - { - resolveJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::IDENTIFIER: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifiers in FROM section must be already resolved. Node {}, scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, ARRAY JOIN or JOIN. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - auto join_tree_node_type = join_tree_node->getNodeType(); - if (isTableExpressionNodeType(join_tree_node_type)) - { - validateTableExpressionModifiers(join_tree_node, scope); - initializeTableExpressionData(join_tree_node, scope); - - auto & query_node = scope.scope_node->as(); - auto & mutable_context = query_node.getMutableContext(); - - if (!mutable_context->isDistributed()) - { - bool is_distributed = false; - - if (auto * table_node = join_tree_node->as()) - is_distributed = table_node->getStorage()->isRemote(); - else if (auto * table_function_node = join_tree_node->as()) - is_distributed = table_function_node->getStorage()->isRemote(); - - mutable_context->setDistributed(is_distributed); - } - } - - auto add_table_expression_alias_into_scope = [&](const QueryTreeNodePtr & table_expression_node) - { - const auto & alias_name = table_expression_node->getAlias(); - if (alias_name.empty()) - return; - - auto [it, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(alias_name, table_expression_node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Duplicate aliases {} for table expressions in FROM section are not allowed. Try to register {}. Already registered {}.", - alias_name, - table_expression_node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage()); - }; - - add_table_expression_alias_into_scope(join_tree_node); - scope.table_expressions_in_resolve_process.erase(join_tree_node.get()); -} - -/** Resolve query. - * This function modifies query node during resolve. It is caller responsibility to clone query node before resolve - * if it is needed for later use. - * - * query_node - query_tree_node that must have QueryNode type. - * scope - query scope. It is caller responsibility to create it. - * - * Resolve steps: - * 1. Validate subqueries depth, perform GROUP BY validation that does not depend on information about aggregate functions. - * 2. Initialize query scope with aliases. - * 3. Register CTE subqueries from WITH section in scope and remove them from WITH section. - * 4. Resolve JOIN TREE. - * 5. Resolve projection columns. - * 6. Resolve expressions in other query parts. - * 7. Validate nodes with duplicate aliases. - * 8. Validate aggregate functions, GROUPING function, window functions. - * 9. Remove WITH and WINDOW sections from query. - * 10. Remove aliases from expression and lambda nodes. - * 11. Resolve query tree node with projection columns. - */ -void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope) -{ - size_t max_subquery_depth = scope.context->getSettingsRef().max_subquery_depth; - if (max_subquery_depth && scope.subquery_depth > max_subquery_depth) - throw Exception(ErrorCodes::TOO_DEEP_SUBQUERIES, - "Too deep subqueries. Maximum: {}", - max_subquery_depth); - - auto & query_node_typed = query_node->as(); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.insert(query_node_typed.getCTEName()); - - bool is_rollup_or_cube = query_node_typed.isGroupByWithRollup() || query_node_typed.isGroupByWithCube(); - - if (query_node_typed.isGroupByWithGroupingSets() - && query_node_typed.isGroupByWithTotals() - && query_node_typed.getGroupBy().getNodes().size() != 1) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and GROUPING SETS are not supported together"); - - if (query_node_typed.isGroupByWithGroupingSets() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "GROUPING SETS are not supported together with ROLLUP and CUBE"); - - if (query_node_typed.isGroupByWithRollup() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithCube())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "ROLLUP is not supported together with GROUPING SETS and CUBE"); - - if (query_node_typed.isGroupByWithCube() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithRollup())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "CUBE is not supported together with GROUPING SETS and ROLLUP"); - - if (query_node_typed.hasHaving() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of HAVING"); - - if (query_node_typed.hasQualify() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of QUALIFY"); - - /// Initialize aliases in query node scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - - if (query_node_typed.hasWith()) - visitor.visit(query_node_typed.getWithNode()); - - if (!query_node_typed.getProjection().getNodes().empty()) - visitor.visit(query_node_typed.getProjectionNode()); - - if (query_node_typed.getPrewhere()) - visitor.visit(query_node_typed.getPrewhere()); - - if (query_node_typed.getWhere()) - visitor.visit(query_node_typed.getWhere()); - - if (query_node_typed.hasGroupBy()) - visitor.visit(query_node_typed.getGroupByNode()); - - if (query_node_typed.hasHaving()) - visitor.visit(query_node_typed.getHaving()); - - if (query_node_typed.hasWindow()) - visitor.visit(query_node_typed.getWindowNode()); - - if (query_node_typed.hasQualify()) - visitor.visit(query_node_typed.getQualify()); - - if (query_node_typed.hasOrderBy()) - visitor.visit(query_node_typed.getOrderByNode()); - - if (query_node_typed.hasInterpolate()) - visitor.visit(query_node_typed.getInterpolate()); - - if (query_node_typed.hasLimitByLimit()) - visitor.visit(query_node_typed.getLimitByLimit()); - - if (query_node_typed.hasLimitByOffset()) - visitor.visit(query_node_typed.getLimitByOffset()); - - if (query_node_typed.hasLimitBy()) - visitor.visit(query_node_typed.getLimitByNode()); - - if (query_node_typed.hasLimit()) - visitor.visit(query_node_typed.getLimit()); - - if (query_node_typed.hasOffset()) - visitor.visit(query_node_typed.getOffset()); - - /// Register CTE subqueries and remove them from WITH section - - auto & with_nodes = query_node_typed.getWith().getNodes(); - - for (auto & node : with_nodes) - { - auto * subquery_node = node->as(); - auto * union_node = node->as(); - - bool subquery_is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - if (!subquery_is_cte) - continue; - - const auto & cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - auto [_, inserted] = scope.cte_name_to_query_node.emplace(cte_name, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "CTE with name {} already exists. In scope {}", - cte_name, - scope.scope_node->formatASTForErrorMessage()); - } - - /** WITH section can be safely removed, because WITH section only can provide aliases to query expressions - * and CTE for other sections to use. - * - * Example: WITH 1 AS constant, (x -> x + 1) AS lambda, a AS (SELECT * FROM test_table); - */ - query_node_typed.getWith().getNodes().clear(); - - for (auto & window_node : query_node_typed.getWindow().getNodes()) - { - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - if (!parent_window_name.empty()) - { - auto window_node_it = scope.window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope.window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - scope.scope_node->formatASTForErrorMessage()); - - mergeWindowWithParentWindow(window_node, window_node_it->second, scope); - window_node_typed.setParentWindowName({}); - } - - auto [_, inserted] = scope.window_name_to_window_node.emplace(window_node_typed.getAlias(), window_node); - if (!inserted) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' is already defined. In scope {}", - window_node_typed.getAlias(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** Disable identifier cache during JOIN TREE resolve. - * Depending on JOIN expression section, identifier with same name - * can be resolved in different columns. - * - * Example: SELECT id FROM test_table AS t1 INNER JOIN test_table AS t2 ON t1.id = t2.id INNER JOIN test_table AS t3 ON t1.id = t3.id - * In first join expression ON t1.id = t2.id t1.id is resolved into test_table.id column. - * In second join expression ON t1.id = t3.id t1.id must be resolved into test_table.id column after first JOIN. - */ - scope.use_identifier_lookup_to_result_cache = false; - - if (query_node_typed.getJoinTree()) - { - TableExpressionsAliasVisitor table_expressions_visitor(scope); - table_expressions_visitor.visit(query_node_typed.getJoinTree()); - - initializeQueryJoinTreeNode(query_node_typed.getJoinTree(), scope); - scope.aliases.alias_name_to_table_expression_node.clear(); - - resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor); - } - - if (!scope.group_by_use_nulls) - scope.use_identifier_lookup_to_result_cache = true; - - /// Resolve query node sections. - - NamesAndTypes projection_columns; - - if (!scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - if (auto & prewhere_node = query_node_typed.getPrewhere()) - { - resolveExpressionNode(prewhere_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** Expressions in PREWHERE with JOIN should not change their type. - * Example: SELECT * FROM t1 JOIN t2 USING (a) PREWHERE a = 1 - * Column `a` in PREWHERE should be resolved from the left table - * and should not change its type to Nullable or to the supertype of `a` from t1 and t2. - * Here's a more complicated example where the column is somewhere inside an expression: - * SELECT a + 1 as b FROM t1 JOIN t2 USING (id) PREWHERE b = 1 - * The expression `a + 1 as b` in the projection and in PREWHERE should have different `a`. - */ - prewhere_node = prewhere_node->clone(); - ReplaceColumnsVisitor replace_visitor(scope.join_columns_with_changed_types, scope.context); - replace_visitor.visit(prewhere_node); - } - - if (query_node_typed.getWhere()) - resolveExpressionNode(query_node_typed.getWhere(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasGroupBy()) - resolveGroupByNode(query_node_typed, scope); - - if (scope.group_by_use_nulls) - { - resolved_expressions.clear(); - /// Clone is needed cause aliases share subtrees. - /// If not clone, the same (shared) subtree could be resolved again with different (Nullable) type - /// See 03023_group_by_use_nulls_analyzer_crashes - for (auto & [key, node] : scope.aliases.alias_name_to_expression_node_before_group_by) - scope.aliases.alias_name_to_expression_node_after_group_by[key] = node->clone(); - - scope.aliases.alias_name_to_expression_node = &scope.aliases.alias_name_to_expression_node_after_group_by; - } - - if (query_node_typed.hasHaving()) - resolveExpressionNode(query_node_typed.getHaving(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasWindow()) - resolveWindowNodeList(query_node_typed.getWindowNode(), scope); - - if (query_node_typed.hasQualify()) - resolveExpressionNode(query_node_typed.getQualify(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasOrderBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getOrderByNode(), query_node_typed.getProjection().getNodes(), scope); - - const auto & settings = scope.context->getSettingsRef(); - - expandOrderByAll(query_node_typed, settings); - resolveSortNodeList(query_node_typed.getOrderByNode(), scope); - } - - if (query_node_typed.hasInterpolate()) - resolveInterpolateColumnsNodeList(query_node_typed.getInterpolate(), scope); - - if (query_node_typed.hasLimitByLimit()) - { - resolveExpressionNode(query_node_typed.getLimitByLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByLimit(), "LIMIT BY LIMIT", scope); - } - - if (query_node_typed.hasLimitByOffset()) - { - resolveExpressionNode(query_node_typed.getLimitByOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByOffset(), "LIMIT BY OFFSET", scope); - } - - if (query_node_typed.hasLimitBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getLimitByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getLimitByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - - if (query_node_typed.hasLimit()) - { - resolveExpressionNode(query_node_typed.getLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimit(), "LIMIT", scope); - } - - if (query_node_typed.hasOffset()) - { - resolveExpressionNode(query_node_typed.getOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getOffset(), "OFFSET", scope); - } - - if (scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - /** Resolve nodes with duplicate aliases. - * Table expressions cannot have duplicate aliases. - * - * Such nodes during scope aliases collection are placed into duplicated array. - * After scope nodes are resolved, we can compare node with duplicate alias with - * node from scope alias table. - */ - for (const auto & node_with_duplicated_alias : scope.aliases.cloned_nodes_with_duplicated_aliases) - { - auto node = node_with_duplicated_alias; - auto node_alias = node->getAlias(); - - /// Add current alias to non cached set, because in case of cyclic alias identifier should not be substituted from cache. - /// See 02896_cyclic_aliases_crash. - resolveExpressionNode(node, scope, true /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool has_node_in_alias_table = false; - - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - if (!has_node_in_alias_table) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node {} with duplicate alias {} does not exist in alias table. In scope {}", - node->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - - node->removeAlias(); - } - - expandGroupByAll(query_node_typed); - - validateFilters(query_node); - validateAggregates(query_node, { .group_by_use_nulls = scope.group_by_use_nulls }); - - for (const auto & column : projection_columns) - { - if (isNotCreatable(column.type)) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Invalid projection column with type {}. In scope {}", - column.type->getName(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** WINDOW section can be safely removed, because WINDOW section can only provide window definition to window functions. - * - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - */ - query_node_typed.getWindow().getNodes().clear(); - - /// Remove aliases from expression and lambda nodes - - for (auto & [_, node] : *scope.aliases.alias_name_to_expression_node) - node->removeAlias(); - - for (auto & [_, node] : scope.aliases.alias_name_to_lambda_node) - node->removeAlias(); - - query_node_typed.resolveProjectionColumns(std::move(projection_columns)); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.erase(query_node_typed.getCTEName()); -} - -void QueryAnalyzer::resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope) -{ - auto & union_node_typed = union_node->as(); - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.insert(union_node_typed.getCTEName()); - - auto & queries_nodes = union_node_typed.getQueries().getNodes(); - - std::optional recursive_cte_table; - TableNodePtr recursive_cte_table_node; - - if (union_node_typed.isCTE() && union_node_typed.isRecursiveCTE()) - { - auto & non_recursive_query = queries_nodes[0]; - bool non_recursive_query_is_query_node = non_recursive_query->getNodeType() == QueryTreeNodeType::QUERY; - auto & non_recursive_query_mutable_context = non_recursive_query_is_query_node ? non_recursive_query->as().getMutableContext() - : non_recursive_query->as().getMutableContext(); - - IdentifierResolveScope non_recursive_subquery_scope(non_recursive_query, &scope /*parent_scope*/); - non_recursive_subquery_scope.subquery_depth = scope.subquery_depth + 1; - - if (non_recursive_query_is_query_node) - resolveQuery(non_recursive_query, non_recursive_subquery_scope); - else - resolveUnion(non_recursive_query, non_recursive_subquery_scope); - - auto temporary_table_columns = non_recursive_query_is_query_node - ? non_recursive_query->as().getProjectionColumns() - : non_recursive_query->as().computeProjectionColumns(); - - auto temporary_table_holder = std::make_shared( - non_recursive_query_mutable_context, - ColumnsDescription{NamesAndTypesList{temporary_table_columns.begin(), temporary_table_columns.end()}}, - ConstraintsDescription{}, - nullptr /*query*/, - true /*create_for_global_subquery*/); - auto temporary_table_storage = temporary_table_holder->getTable(); - - recursive_cte_table_node = std::make_shared(temporary_table_storage, non_recursive_query_mutable_context); - recursive_cte_table_node->setTemporaryTableName(union_node_typed.getCTEName()); - - recursive_cte_table.emplace(std::move(temporary_table_holder), std::move(temporary_table_storage), std::move(temporary_table_columns)); - } - - size_t queries_nodes_size = queries_nodes.size(); - for (size_t i = recursive_cte_table.has_value(); i < queries_nodes_size; ++i) - { - auto & query_node = queries_nodes[i]; - - IdentifierResolveScope subquery_scope(query_node, &scope /*parent_scope*/); - - if (recursive_cte_table_node) - subquery_scope.expression_argument_name_to_node[union_node_typed.getCTEName()] = recursive_cte_table_node; - - auto query_node_type = query_node->getNodeType(); - - if (query_node_type == QueryTreeNodeType::QUERY) - { - resolveQuery(query_node, subquery_scope); - } - else if (query_node_type == QueryTreeNodeType::UNION) - { - resolveUnion(query_node, subquery_scope); - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "UNION unsupported node {}. In scope {}", - query_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (recursive_cte_table && isStorageUsedInTree(recursive_cte_table->storage, union_node.get())) - { - if (union_node_typed.getUnionMode() != SelectUnionMode::UNION_ALL) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive CTE subquery {} with {} union mode is unsupported, only UNION ALL union mode is supported", - union_node_typed.formatASTForErrorMessage(), - toString(union_node_typed.getUnionMode())); - - union_node_typed.setRecursiveCTETable(std::move(*recursive_cte_table)); - } - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.erase(union_node_typed.getCTEName()); -} - -} - -QueryAnalysisPass::QueryAnalysisPass(QueryTreeNodePtr table_expression_, bool only_analyze_) - : table_expression(std::move(table_expression_)) - , only_analyze(only_analyze_) -{} - -QueryAnalysisPass::QueryAnalysisPass(bool only_analyze_) : only_analyze(only_analyze_) {} - -void QueryAnalysisPass::run(QueryTreeNodePtr & query_tree_node, ContextPtr context) -{ - QueryAnalyzer analyzer(only_analyze); - analyzer.resolve(query_tree_node, table_expression, context); - createUniqueTableAliases(query_tree_node, table_expression, context); -} - } diff --git a/src/Analyzer/QueryAnalysis/IdentifierLookup.h b/src/Analyzer/QueryAnalysis/IdentifierLookup.h index 3fca66e6eb8..8dd70c188e9 100644 --- a/src/Analyzer/QueryAnalysis/IdentifierLookup.h +++ b/src/Analyzer/QueryAnalysis/IdentifierLookup.h @@ -1,221 +1,15 @@ -#include +#pragma once -#include - -#include -#include -#include - -#include #include #include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include -#include - -namespace ProfileEvents -{ - extern const Event ScalarSubqueriesGlobalCacheHit; - extern const Event ScalarSubqueriesLocalCacheHit; - extern const Event ScalarSubqueriesCacheMiss; -} namespace DB { -namespace ErrorCodes -{ - extern const int UNSUPPORTED_METHOD; - extern const int UNKNOWN_IDENTIFIER; - extern const int UNKNOWN_FUNCTION; - extern const int LOGICAL_ERROR; - extern const int CYCLIC_ALIASES; - extern const int INCORRECT_RESULT_OF_SCALAR_SUBQUERY; - extern const int BAD_ARGUMENTS; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int MULTIPLE_EXPRESSIONS_FOR_ALIAS; - extern const int TYPE_MISMATCH; - extern const int AMBIGUOUS_IDENTIFIER; - extern const int INVALID_WITH_FILL_EXPRESSION; - extern const int INVALID_LIMIT_EXPRESSION; - extern const int EMPTY_LIST_OF_COLUMNS_QUERIED; - extern const int TOO_DEEP_SUBQUERIES; - extern const int UNKNOWN_AGGREGATE_FUNCTION; - extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION; - extern const int TOO_MANY_ARGUMENTS_FOR_FUNCTION; - extern const int ILLEGAL_FINAL; - extern const int SAMPLING_NOT_SUPPORTED; - extern const int NO_COMMON_TYPE; - extern const int NOT_IMPLEMENTED; - extern const int ALIAS_REQUIRED; - extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; - extern const int UNKNOWN_TABLE; - extern const int ILLEGAL_COLUMN; - extern const int NUMBER_OF_COLUMNS_DOESNT_MATCH; - extern const int FUNCTION_CANNOT_HAVE_PARAMETERS; - extern const int SYNTAX_ERROR; - extern const int UNEXPECTED_EXPRESSION; - extern const int INVALID_IDENTIFIER; -} - -/** Query analyzer implementation overview. Please check documentation in QueryAnalysisPass.h first. - * And additional documentation for each method, where special cases are described in detail. - * - * Each node in query must be resolved. For each query tree node resolved state is specific. - * - * For constant node no resolve process exists, it is resolved during construction. - * - * For table node no resolve process exists, it is resolved during construction. - * - * For function node to be resolved parameters and arguments must be resolved, function node must be initialized with concrete aggregate or - * non aggregate function and with result type. - * - * For lambda node there can be 2 different cases. - * 1. Standalone: WITH (x -> x + 1) AS lambda SELECT lambda(1); Such lambdas are inlined in query tree during query analysis pass. - * 2. Function arguments: WITH (x -> x + 1) AS lambda SELECT arrayMap(lambda, [1, 2, 3]); For such lambda resolution must - * set concrete lambda arguments (initially they are identifier nodes) and resolve lambda expression body. - * - * For query node resolve process must resolve all its inner nodes. - * - * For matcher node resolve process must replace it with matched nodes. - * - * For identifier node resolve process must replace it with concrete non identifier node. This part is most complex because - * for identifier resolution scopes and identifier lookup context play important part. - * - * ClickHouse SQL support lexical scoping for identifier resolution. Scope can be defined by query node or by expression node. - * Expression nodes that can define scope are lambdas and table ALIAS columns. - * - * Identifier lookup context can be expression, function, table. - * - * Examples: WITH (x -> x + 1) as func SELECT func() FROM func; During function `func` resolution identifier lookup is performed - * in function context. - * - * If there are no information of identifier context rules are following: - * 1. Try to resolve identifier in expression context. - * 2. Try to resolve identifier in function context, if it is allowed. Example: SELECT func(arguments); Here func identifier cannot be resolved in function context - * because query projection does not support that. - * 3. Try to resolve identifier in table context, if it is allowed. Example: SELECT table; Here table identifier cannot be resolved in function context - * because query projection does not support that. - * - * TODO: This does not supported properly before, because matchers could not be resolved from aliases. - * - * Identifiers are resolved with following rules: - * Resolution starts with current scope. - * 1. Try to resolve identifier from expression scope arguments. Lambda expression arguments are greatest priority. - * 2. Try to resolve identifier from aliases. - * 3. Try to resolve identifier from join tree if scope is query, or if there are registered table columns in scope. - * Steps 2 and 3 can be changed using prefer_column_name_to_alias setting. - * 4. If it is table lookup, try to resolve identifier from CTE. - * If identifier could not be resolved in current scope, resolution must be continued in parent scopes. - * 5. Try to resolve identifier from parent scopes. - * - * Additional rules about aliases and scopes. - * 1. Parent scope cannot refer alias from child scope. - * 2. Child scope can refer to alias in parent scope. - * - * Example: SELECT arrayMap(x -> x + 1 AS a, [1,2,3]), a; Identifier a is unknown in parent scope. - * Example: SELECT a FROM (SELECT 1 as a); Here we do not refer to alias a from child query scope. But we query it projection result, similar to tables. - * Example: WITH 1 as a SELECT (SELECT a) as b; Here in child scope identifier a is resolved using alias from parent scope. - * - * Additional rules about identifier binding. - * Bind for identifier to entity means that identifier first part match some node during analysis. - * If other parts of identifier cannot be resolved in that node, exception must be thrown. - * - * Example: - * CREATE TABLE test_table (id UInt64, compound_value Tuple(value UInt64)) ENGINE=TinyLog; - * SELECT compound_value.value, 1 AS compound_value FROM test_table; - * Identifier first part compound_value bound to entity with alias compound_value, but nested identifier part cannot be resolved from entity, - * lookup should not be continued, and exception must be thrown because if lookup continues that way identifier can be resolved from join tree. - * - * TODO: This was not supported properly before analyzer because nested identifier could not be resolved from alias. - * - * More complex example: - * CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; - * WITH cast(('Value'), 'Tuple (value UInt64') AS value SELECT (SELECT value FROM test_table); - * Identifier first part value bound to test_table column value, but nested identifier part cannot be resolved from it, - * lookup should not be continued, and exception must be thrown because if lookup continues identifier can be resolved from parent scope. - * - * TODO: Update exception messages - * TODO: Table identifiers with optional UUID. - * TODO: Lookup functions arrayReduce(sum, [1, 2, 3]); - * TODO: Support function identifier resolve from parent query scope, if lambda in parent scope does not capture any columns. - */ - -namespace -{ - /// Identifier lookup context enum class IdentifierLookupContext : uint8_t { @@ -224,7 +18,7 @@ enum class IdentifierLookupContext : uint8_t TABLE_EXPRESSION, }; -const char * toString(IdentifierLookupContext identifier_lookup_context) +inline const char * toString(IdentifierLookupContext identifier_lookup_context) { switch (identifier_lookup_context) { @@ -234,7 +28,7 @@ const char * toString(IdentifierLookupContext identifier_lookup_context) } } -const char * toStringLowercase(IdentifierLookupContext identifier_lookup_context) +inline const char * toStringLowercase(IdentifierLookupContext identifier_lookup_context) { switch (identifier_lookup_context) { @@ -303,7 +97,7 @@ enum class IdentifierResolvePlace : UInt8 DATABASE_CATALOG }; -const char * toString(IdentifierResolvePlace resolved_identifier_place) +inline const char * toString(IdentifierResolvePlace resolved_identifier_place) { switch (resolved_identifier_place) { @@ -398,8082 +192,4 @@ struct IdentifierResolveSettings bool allow_to_resolve_subquery_during_identifier_resolution = true; }; -struct StringTransparentHash -{ - using is_transparent = void; - using hash = std::hash; - - [[maybe_unused]] size_t operator()(const char * data) const - { - return hash()(data); - } - - size_t operator()(std::string_view data) const - { - return hash()(data); - } - - size_t operator()(const std::string & data) const - { - return hash()(data); - } -}; - -using ColumnNameToColumnNodeMap = std::unordered_map>; - -struct TableExpressionData -{ - std::string table_expression_name; - std::string table_expression_description; - std::string database_name; - std::string table_name; - bool should_qualify_columns = true; - NamesAndTypes column_names_and_types; - ColumnNameToColumnNodeMap column_name_to_column_node; - std::unordered_set subcolumn_names; /// Subset columns that are subcolumns of other columns - std::unordered_set> column_identifier_first_parts; - - bool hasFullIdentifierName(IdentifierView identifier_view) const - { - return column_name_to_column_node.contains(identifier_view.getFullName()); - } - - bool canBindIdentifier(IdentifierView identifier_view) const - { - return column_identifier_first_parts.contains(identifier_view.at(0)); - } - - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Table expression name " << table_expression_name; - - if (!table_expression_description.empty()) - buffer << " table expression description " << table_expression_description; - - if (!database_name.empty()) - buffer << " database name " << database_name; - - if (!table_name.empty()) - buffer << " table name " << table_name; - - buffer << " should qualify columns " << should_qualify_columns; - buffer << " columns size " << column_name_to_column_node.size() << '\n'; - - for (const auto & [column_name, column_node] : column_name_to_column_node) - buffer << "Column name " << column_name << " column node " << column_node->dumpTree() << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -class ExpressionsStack -{ -public: - void push(const QueryTreeNodePtr & node) - { - if (node->hasAlias()) - { - const auto & node_alias = node->getAlias(); - alias_name_to_expressions[node_alias].push_back(node); - } - - if (const auto * function = node->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - ++aggregate_functions_counter; - } - - expressions.emplace_back(node); - } - - void pop() - { - const auto & top_expression = expressions.back(); - const auto & top_expression_alias = top_expression->getAlias(); - - if (!top_expression_alias.empty()) - { - auto it = alias_name_to_expressions.find(top_expression_alias); - auto & alias_expressions = it->second; - alias_expressions.pop_back(); - - if (alias_expressions.empty()) - alias_name_to_expressions.erase(it); - } - - if (const auto * function = top_expression->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - --aggregate_functions_counter; - } - - expressions.pop_back(); - } - - [[maybe_unused]] const QueryTreeNodePtr & getRoot() const - { - return expressions.front(); - } - - const QueryTreeNodePtr & getTop() const - { - return expressions.back(); - } - - [[maybe_unused]] bool hasExpressionWithAlias(const std::string & alias) const - { - return alias_name_to_expressions.contains(alias); - } - - bool hasAggregateFunction() const - { - return aggregate_functions_counter > 0; - } - - QueryTreeNodePtr getExpressionWithAlias(const std::string & alias) const - { - auto expression_it = alias_name_to_expressions.find(alias); - if (expression_it == alias_name_to_expressions.end()) - return {}; - - return expression_it->second.front(); - } - - [[maybe_unused]] size_t size() const - { - return expressions.size(); - } - - bool empty() const - { - return expressions.empty(); - } - - void dump(WriteBuffer & buffer) const - { - buffer << expressions.size() << '\n'; - - for (const auto & expression : expressions) - { - buffer << "Expression "; - buffer << expression->formatASTForErrorMessage(); - - const auto & alias = expression->getAlias(); - if (!alias.empty()) - buffer << " alias " << alias; - - buffer << '\n'; - } - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } - -private: - QueryTreeNodes expressions; - size_t aggregate_functions_counter = 0; - std::unordered_map alias_name_to_expressions; -}; - -struct ScopeAliases -{ - /// Alias name to query expression node - std::unordered_map alias_name_to_expression_node_before_group_by; - std::unordered_map alias_name_to_expression_node_after_group_by; - - std::unordered_map * alias_name_to_expression_node = nullptr; - - /// Alias name to lambda node - std::unordered_map alias_name_to_lambda_node; - - /// Alias name to table expression node - std::unordered_map alias_name_to_table_expression_node; - - /// Expressions like `x as y` where we can't say whether it's a function, expression or table. - std::unordered_map transitive_aliases; - - /// Nodes with duplicated aliases - std::unordered_set nodes_with_duplicated_aliases; - std::vector cloned_nodes_with_duplicated_aliases; - - /// Names which are aliases from ARRAY JOIN. - /// This is needed to properly qualify columns from matchers and avoid name collision. - std::unordered_set array_join_aliases; - - std::unordered_map & getAliasMap(IdentifierLookupContext lookup_context) - { - switch (lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return *alias_name_to_expression_node; - case IdentifierLookupContext::FUNCTION: return alias_name_to_lambda_node; - case IdentifierLookupContext::TABLE_EXPRESSION: return alias_name_to_table_expression_node; - } - } - - enum class FindOption - { - FIRST_NAME, - FULL_NAME, - }; - - const std::string & getKey(const Identifier & identifier, FindOption find_option) - { - switch (find_option) - { - case FindOption::FIRST_NAME: return identifier.front(); - case FindOption::FULL_NAME: return identifier.getFullName(); - } - } - - QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) - { - auto & alias_map = getAliasMap(lookup.lookup_context); - const std::string * key = &getKey(lookup.identifier, find_option); - - auto it = alias_map.find(*key); - - if (it != alias_map.end()) - return &it->second; - - if (lookup.lookup_context == IdentifierLookupContext::TABLE_EXPRESSION) - return {}; - - while (it == alias_map.end()) - { - auto jt = transitive_aliases.find(*key); - if (jt == transitive_aliases.end()) - return {}; - - key = &(getKey(jt->second, find_option)); - it = alias_map.find(*key); - } - - return &it->second; - } - - const QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) const - { - return const_cast(this)->find(lookup, find_option); - } -}; - - -/** Projection names is name of query tree node that is used in projection part of query node. - * Example: SELECT id FROM test_table; - * `id` is projection name of column node - * - * Example: SELECT id AS id_alias FROM test_table; - * `id_alias` is projection name of column node - * - * Calculation of projection names is done during expression nodes resolution. This is done this way - * because after identifier node is resolved we lose information about identifier name. We could - * potentially save this information in query tree node itself, but that would require to clone it in some cases. - * Example: SELECT big_scalar_subquery AS a, a AS b, b AS c; - * All 3 nodes in projection are the same big_scalar_subquery, but they have different projection names. - * If we want to save it in query tree node, we have to clone subquery node that could lead to performance degradation. - * - * Possible solution is to separate query node metadata and query node content. So only node metadata could be cloned - * if we want to change projection name. This solution does not seem to be easy for client of query tree because projection - * name will be part of interface. If we potentially could hide projection names calculation in analyzer without introducing additional - * changes in query tree structure that would be preferable. - * - * Currently each resolve method returns projection names array. Resolve method must compute projection names of node. - * If node is resolved as list node this is case for `untuple` function or `matcher` result projection names array must contain projection names - * for result nodes. - * If node is not resolved as list node, projection names array contain single projection name for node. - * - * Rules for projection names: - * 1. If node has alias. It is node projection name. - * Except scenario where `untuple` function has alias. Example: SELECT untuple(expr) AS alias, alias. - * - * 2. For constant it is constant value string representation. - * - * 3. For identifier: - * If identifier is resolved from JOIN TREE, we want to remove additional identifier qualifications. - * Example: SELECT default.test_table.id FROM test_table. - * Result projection name is `id`. - * - * Example: SELECT t1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In example both test_table_1, test_table_2 have `id` column. - * In such case projection name is `t1.id` because if additional qualification is removed then column projection name `id` will be ambiguous. - * - * Example: SELECT default.test_table_1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In such case projection name is `test_table_1.id` because we remove unnecessary database qualification, but table name qualification cannot be removed - * because otherwise column projection name `id` will be ambiguous. - * - * If identifier is not resolved from JOIN TREE. Identifier name is projection name. - * Except scenario where `untuple` function resolved using identifier. Example: SELECT untuple(expr) AS alias, alias. - * Example: SELECT sum(1, 1) AS value, value. - * In such case both nodes have `value` projection names. - * - * Example: SELECT id AS value, value FROM test_table. - * In such case both nodes have have `value` projection names. - * - * Special case is `untuple` function. If `untuple` function specified with alias, then result nodes will have alias.tuple_column_name projection names. - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value) AS a; - * Result projection names are `value`, `a.id`. - * - * If `untuple` function does not have alias then result nodes will have `tupleElement(untuple_expression_projection_name, 'tuple_column_name') projection names. - * - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value); - * Result projection names are `value`, `tupleElement(value, 'id')`; - * - * 4. For function: - * Projection name consists from function_name(parameters_projection_names)(arguments_projection_names). - * Additionally if function is window function. Window node projection name is used with OVER clause. - * Example: function_name (parameters_names)(argument_projection_names) OVER window_name; - * Example: function_name (parameters_names)(argument_projection_names) OVER (PARTITION BY id ORDER BY id). - * Example: function_name (parameters_names)(argument_projection_names) OVER (window_name ORDER BY id). - * - * 5. For lambda: - * If it is standalone lambda that returns single expression, function projection name is used. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(1). - * Projection name is `lambda(1)`. - * - * If is it standalone lambda that returns list, projection names of list nodes are used. - * Example: WITH (x -> *) AS lambda SELECT lambda(1) FROM test_table; - * If test_table has two columns `id`, `value`. Then result projection names are `id`, `value`. - * - * If lambda is argument of function. - * Then projection name consists from lambda(tuple(lambda_arguments)(lambda_body_projection_name)); - * - * 6. For matcher: - * Matched nodes projection names are used as matcher projection names. - * - * Matched nodes must be qualified if needed. - * Example: SELECT * FROM test_table_1 AS t1, test_table_2 AS t2. - * In example table test_table_1 and test_table_2 both have `id`, `value` columns. - * Matched nodes after unqualified matcher resolve must be qualified to avoid ambiguous projection names. - * Result projection names must be `t1.id`, `t1.value`, `t2.id`, `t2.value`. - * - * There are special cases - * 1. For lambda inside APPLY matcher transformer: - * Example: SELECT * APPLY x -> toString(x) FROM test_table. - * In such case lambda argument projection name `x` will be replaced by matched node projection name. - * If table has two columns `id` and `value`. Then result projection names are `toString(id)`, `toString(value)`; - * - * 2. For unqualified matcher when JOIN tree contains JOIN with USING. - * Example: SELECT * FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING(id); - * Result projection names must be `id`, `t1.value`, `t2.value`. - * - * 7. For subquery: - * For subquery projection name consists of `_subquery_` prefix and implementation specific unique number suffix. - * Example: SELECT (SELECT 1), (SELECT 1 UNION DISTINCT SELECT 1); - * Result projection name can be `_subquery_1`, `subquery_2`; - * - * 8. For table: - * Table node can be used in expression context only as right argument of IN function. In that case identifier is used - * as table node projection name. - * Example: SELECT id IN test_table FROM test_table; - * Result projection name is `in(id, test_table)`. - */ -using ProjectionName = String; -using ProjectionNames = std::vector; -constexpr auto PROJECTION_NAME_PLACEHOLDER = "__projection_name_placeholder"; - -struct IdentifierResolveScope -{ - /// Construct identifier resolve scope using scope node, and parent scope - IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) - : scope_node(std::move(scope_node_)) - , parent_scope(parent_scope_) - { - if (parent_scope) - { - subquery_depth = parent_scope->subquery_depth; - context = parent_scope->context; - projection_mask_map = parent_scope->projection_mask_map; - } - else - projection_mask_map = std::make_shared>(); - - if (auto * union_node = scope_node->as()) - { - context = union_node->getContext(); - } - else if (auto * query_node = scope_node->as()) - { - context = query_node->getContext(); - group_by_use_nulls = context->getSettingsRef().group_by_use_nulls && - (query_node->isGroupByWithGroupingSets() || query_node->isGroupByWithRollup() || query_node->isGroupByWithCube()); - } - - if (context) - join_use_nulls = context->getSettingsRef().join_use_nulls; - else if (parent_scope) - join_use_nulls = parent_scope->join_use_nulls; - - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - QueryTreeNodePtr scope_node; - - IdentifierResolveScope * parent_scope = nullptr; - - ContextPtr context; - - /// Identifier lookup to result - std::unordered_map identifier_lookup_to_resolve_state; - - /// Argument can be expression like constant, column, function or table expression - std::unordered_map expression_argument_name_to_node; - - ScopeAliases aliases; - - /// Table column name to column node. Valid only during table ALIAS columns resolve. - ColumnNameToColumnNodeMap column_name_to_column_node; - - /// CTE name to query node - std::unordered_map cte_name_to_query_node; - - /// Window name to window node - std::unordered_map window_name_to_window_node; - - /// Current scope expression in resolve process stack - ExpressionsStack expressions_in_resolve_process_stack; - - /// Table expressions in resolve process - std::unordered_set table_expressions_in_resolve_process; - - /// Current scope expression - std::unordered_set non_cached_identifier_lookups_during_expression_resolve; - - /// Table expression node to data - std::unordered_map table_expression_node_to_data; - - QueryTreeNodePtrWithHashIgnoreTypesSet nullable_group_by_keys; - /// Here we count the number of nullable GROUP BY keys we met resolving expression. - /// E.g. for a query `SELECT tuple(tuple(number)) FROM numbers(10) GROUP BY (number, tuple(number)) with cube` - /// both `number` and `tuple(number)` would be in nullable_group_by_keys. - /// But when we resolve `tuple(tuple(number))` we should figure out that `tuple(number)` is already a key, - /// and we should not convert `number` to nullable. - size_t found_nullable_group_by_key_in_scope = 0; - - /** It's possible that after a JOIN, a column in the projection has a type different from the column in the source table. - * (For example, after join_use_nulls or USING column casted to supertype) - * However, the column in the projection still refers to the table as its source. - * This map is used to revert these columns back to their original columns in the source table. - */ - QueryTreeNodePtrWithHashMap join_columns_with_changed_types; - - /// Use identifier lookup to result cache - bool use_identifier_lookup_to_result_cache = true; - - /// Apply nullability to aggregation keys - bool group_by_use_nulls = false; - /// Join retutns NULLs instead of default values - bool join_use_nulls = false; - - /// JOINs count - size_t joins_count = 0; - - /// Subquery depth - size_t subquery_depth = 0; - - /** Scope join tree node for expression. - * Valid only during analysis construction for single expression. - */ - QueryTreeNodePtr expression_join_tree_node; - - /// Node hash to mask id map - std::shared_ptr> projection_mask_map; - - struct ResolvedFunctionsCache - { - FunctionOverloadResolverPtr resolver; - FunctionBasePtr function_base; - }; - - std::map functions_cache; - - [[maybe_unused]] const IdentifierResolveScope * getNearestQueryScope() const - { - const IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - IdentifierResolveScope * getNearestQueryScope() - { - IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - const TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - void pushExpressionNode(const QueryTreeNodePtr & node) - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.push(node); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - void popExpressionNode() - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.pop(); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_after_group_by; - } - - /// Dump identifier resolve scope - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Scope node " << scope_node->formatASTForErrorMessage() << '\n'; - buffer << "Identifier lookup to resolve state " << identifier_lookup_to_resolve_state.size() << '\n'; - for (const auto & [identifier, state] : identifier_lookup_to_resolve_state) - { - buffer << "Identifier " << identifier.dump() << " resolve result "; - state.resolve_result.dump(buffer); - buffer << '\n'; - } - - buffer << "Expression argument name to node " << expression_argument_name_to_node.size() << '\n'; - for (const auto & [alias_name, node] : expression_argument_name_to_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to expression node table size " << aliases.alias_name_to_expression_node->size() << '\n'; - for (const auto & [alias_name, node] : *aliases.alias_name_to_expression_node) - buffer << "Alias name " << alias_name << " expression node " << node->dumpTree() << '\n'; - - buffer << "Alias name to function node table size " << aliases.alias_name_to_lambda_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_lambda_node) - buffer << "Alias name " << alias_name << " lambda node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to table expression node table size " << aliases.alias_name_to_table_expression_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_table_expression_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "CTE name to query node table size " << cte_name_to_query_node.size() << '\n'; - for (const auto & [cte_name, node] : cte_name_to_query_node) - buffer << "CTE name " << cte_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "WINDOW name to window node table size " << window_name_to_window_node.size() << '\n'; - for (const auto & [window_name, node] : window_name_to_window_node) - buffer << "CTE name " << window_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Nodes with duplicated aliases size " << aliases.nodes_with_duplicated_aliases.size() << '\n'; - for (const auto & node : aliases.nodes_with_duplicated_aliases) - buffer << "Alias name " << node->getAlias() << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Expression resolve process stack " << '\n'; - expressions_in_resolve_process_stack.dump(buffer); - - buffer << "Table expressions in resolve process size " << table_expressions_in_resolve_process.size() << '\n'; - for (const auto & node : table_expressions_in_resolve_process) - buffer << "Table expression " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Non cached identifier lookups during expression resolve " << non_cached_identifier_lookups_during_expression_resolve.size() << '\n'; - for (const auto & identifier_lookup : non_cached_identifier_lookups_during_expression_resolve) - buffer << "Identifier lookup " << identifier_lookup.dump() << '\n'; - - buffer << "Table expression node to data " << table_expression_node_to_data.size() << '\n'; - for (const auto & [table_expression_node, table_expression_data] : table_expression_node_to_data) - buffer << "Table expression node " << table_expression_node->formatASTForErrorMessage() << " data " << table_expression_data.dump() << '\n'; - - buffer << "Use identifier lookup to result cache " << use_identifier_lookup_to_result_cache << '\n'; - buffer << "Subquery depth " << subquery_depth << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - - -/** Visitor that extracts expression and function aliases from node and initialize scope tables with it. - * Does not go into child lambdas and queries. - * - * Important: - * Identifier nodes with aliases are added both in alias to expression and alias to function map. - * - * These is necessary because identifier with alias can give alias name to any query tree node. - * - * Example: - * WITH (x -> x + 1) AS id, id AS value SELECT value(1); - * In this example id as value is identifier node that has alias, during scope initialization we cannot derive - * that id is actually lambda or expression. - * - * There are no easy solution here, without trying to make full featured expression resolution at this stage. - * Example: - * WITH (x -> x + 1) AS id, id AS id_1, id_1 AS id_2 SELECT id_2(1); - * Example: SELECT a, b AS a, b AS c, 1 AS c; - * - * It is client responsibility after resolving identifier node with alias, make following actions: - * 1. If identifier node was resolved in function scope, remove alias from scope expression map. - * 2. If identifier node was resolved in expression scope, remove alias from scope function map. - * - * That way we separate alias map initialization and expressions resolution. - */ -class QueryExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit QueryExpressionsAliasVisitor(ScopeAliases & aliases_) - : aliases(aliases_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node, false /*is_lambda_node*/); - } - - bool needChildVisit(const QueryTreeNodePtr &, const QueryTreeNodePtr & child) - { - if (auto * lambda_node = child->as()) - { - updateAliasesIfNeeded(child, true /*is_lambda_node*/); - return false; - } - else if (auto * query_tree_node = child->as()) - { - if (query_tree_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - else if (auto * union_node = child->as()) - { - if (union_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - - return true; - } -private: - void addDuplicatingAlias(const QueryTreeNodePtr & node) - { - aliases.nodes_with_duplicated_aliases.emplace(node); - auto cloned_node = node->clone(); - aliases.cloned_nodes_with_duplicated_aliases.emplace_back(cloned_node); - aliases.nodes_with_duplicated_aliases.emplace(cloned_node); - } - - void updateAliasesIfNeeded(const QueryTreeNodePtr & node, bool is_lambda_node) - { - if (!node->hasAlias()) - return; - - // We should not resolve expressions to WindowNode - if (node->getNodeType() == QueryTreeNodeType::WINDOW) - return; - - const auto & alias = node->getAlias(); - - if (is_lambda_node) - { - if (aliases.alias_name_to_expression_node->contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_lambda_node.insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - return; - } - - if (aliases.alias_name_to_lambda_node.contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_expression_node->insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - /// If node is identifier put it into transitive aliases map. - if (const auto * identifier = typeid_cast(node.get())) - aliases.transitive_aliases.insert(std::make_pair(alias, identifier->getIdentifier())); - } - - ScopeAliases & aliases; -}; - -class TableExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit TableExpressionsAliasVisitor(IdentifierResolveScope & scope_) - : scope(scope_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node); - } - - static bool needChildVisit(const QueryTreeNodePtr & node, const QueryTreeNodePtr & child) - { - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::ARRAY_JOIN: - { - const auto & array_join_node = node->as(); - return child.get() == array_join_node.getTableExpression().get(); - } - case QueryTreeNodeType::JOIN: - { - const auto & join_node = node->as(); - return child.get() == join_node.getLeftTableExpression().get() || child.get() == join_node.getRightTableExpression().get(); - } - default: - { - break; - } - } - - return false; - } - -private: - void updateAliasesIfNeeded(const QueryTreeNodePtr & node) - { - if (!node->hasAlias()) - return; - - const auto & node_alias = node->getAlias(); - auto [_, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(node_alias, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple table expressions with same alias {}. In scope {}", - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - IdentifierResolveScope & scope; -}; - -class QueryAnalyzer -{ -public: - explicit QueryAnalyzer(bool only_analyze_) : only_analyze(only_analyze_) {} - - void resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context) - { - IdentifierResolveScope scope(node, nullptr /*parent_scope*/); - - if (!scope.context) - scope.context = context; - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::QUERY: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For query analysis table expression must be empty"); - - resolveQuery(node, scope); - break; - } - case QueryTreeNodeType::UNION: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For union analysis table expression must be empty"); - - resolveUnion(node, scope); - break; - } - case QueryTreeNodeType::IDENTIFIER: - [[fallthrough]]; - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - [[fallthrough]]; - case QueryTreeNodeType::FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::LIST: - { - if (table_expression) - { - scope.expression_join_tree_node = table_expression; - validateTableExpressionModifiers(scope.expression_join_tree_node, scope); - initializeTableExpressionData(scope.expression_join_tree_node, scope); - } - - if (node_type == QueryTreeNodeType::LIST) - resolveExpressionNodeList(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - else - resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - QueryExpressionsAliasVisitor expressions_alias_visitor(scope.aliases); - resolveTableFunction(node, scope, expressions_alias_visitor, false /*nested_table_function*/); - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Node {} with type {} is not supported by query analyzer. " - "Supported nodes are query, union, identifier, constant, column, function, list.", - node->formatASTForErrorMessage(), - node->getNodeTypeName()); - } - } - } - -private: - /// Utility functions - - static bool isExpressionNodeType(QueryTreeNodeType node_type); - - static bool isFunctionExpressionNodeType(QueryTreeNodeType node_type); - - static bool isSubqueryNodeType(QueryTreeNodeType node_type); - - static bool isTableExpressionNodeType(QueryTreeNodeType node_type); - - static DataTypePtr getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node); - - static ProjectionName calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, - const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names); - - static ProjectionName calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name); - - static ProjectionName calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, - const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, - const ProjectionName & fill_to_expression_projection_name, - const ProjectionName & fill_step_expression_projection_name); - - static void collectCompoundExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result); - - static void collectTableExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result); - - static void collectScopeValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static void collectScopeWithParentScopesValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static std::vector collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers); - - static QueryTreeNodePtr wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path); - - QueryTreeNodePtr tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context); - - void evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & query_tree_node, IdentifierResolveScope & scope); - - static void mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope); - - void replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope); - - static void convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope); - - static void validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope); - - static std::pair recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into); - - static void expandGroupByAll(QueryNode & query_tree_node_typed); - - void expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings); - - static std::string - rewriteAggregateFunctionNameIfNeeded(const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context); - - static std::optional getColumnSideFromJoinTree(const QueryTreeNodePtr & resolved_identifier, const JoinNode & join_node) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - return {}; - - if (resolved_identifier->getNodeType() == QueryTreeNodeType::FUNCTION) - { - const auto & resolved_function = resolved_identifier->as(); - - const auto & argument_nodes = resolved_function.getArguments().getNodes(); - - std::optional result; - for (const auto & argument_node : argument_nodes) - { - auto table_side = getColumnSideFromJoinTree(argument_node, join_node); - if (table_side && result && *table_side != *result) - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Ambiguous identifier {}. In scope {}", - resolved_identifier->formatASTForErrorMessage(), - join_node.formatASTForErrorMessage()); - } - result = table_side; - } - return result; - } - - const auto * column_src = resolved_identifier->as().getColumnSource().get(); - - if (join_node.getLeftTableExpression().get() == column_src) - return JoinTableSide::Left; - if (join_node.getRightTableExpression().get() == column_src) - return JoinTableSide::Right; - return {}; - } - - static QueryTreeNodePtr convertJoinedColumnTypeToNullIfNeeded( - const QueryTreeNodePtr & resolved_identifier, - const JoinKind & join_kind, - std::optional resolved_side, - IdentifierResolveScope & scope) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && - JoinCommon::canBecomeNullable(resolved_identifier->getResultType()) && - (isFull(join_kind) || - (isLeft(join_kind) && resolved_side && *resolved_side == JoinTableSide::Right) || - (isRight(join_kind) && resolved_side && *resolved_side == JoinTableSide::Left))) - { - auto nullable_resolved_identifier = resolved_identifier->clone(); - auto & resolved_column = nullable_resolved_identifier->as(); - auto new_result_type = makeNullableOrLowCardinalityNullable(resolved_column.getColumnType()); - resolved_column.setColumnType(new_result_type); - if (resolved_column.hasExpression()) - { - auto & resolved_expression = resolved_column.getExpression(); - if (!resolved_expression->getResultType()->equals(*new_result_type)) - resolved_expression = buildCastFunction(resolved_expression, new_result_type, scope.context, true); - } - if (!nullable_resolved_identifier->isEqual(*resolved_identifier)) - scope.join_columns_with_changed_types[nullable_resolved_identifier] = resolved_identifier; - return nullable_resolved_identifier; - } - return nullptr; - } - - /// Resolve identifier functions - - static QueryTreeNodePtr tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context); - - QueryTreeNodePtr tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found = false); - - QueryTreeNodePtr tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings); - - QueryTreeNodePtr tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings = {}); - - QueryTreeNodePtr tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found = false); - - /// Resolve query tree nodes functions - - void qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static GetColumnsOptions buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context); - - using QueryTreeNodesWithNames = std::vector>; - - QueryTreeNodesWithNames getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope); - - void updateMatchedColumnsFromJoinUsing(QueryTreeNodesWithNames & result_matched_column_nodes_with_names, const QueryTreeNodePtr & source_table_expression, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionNames resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionName resolveWindow(QueryTreeNodePtr & window_node, IdentifierResolveScope & scope); - - ProjectionNames resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope); - - ProjectionNames resolveFunction(QueryTreeNodePtr & function_node, IdentifierResolveScope & scope); - - ProjectionNames resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias = false); - - ProjectionNames resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression); - - ProjectionNames resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope); - - void resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope); - - void resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope); - - void resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope); - - NamesAndTypes resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope); - - void initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope); - - void initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - void resolveTableFunction(QueryTreeNodePtr & table_function_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, bool nested_table_function); - - void resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope); - - void resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope); - - /// Lambdas that are currently in resolve process - std::unordered_set lambdas_in_resolve_process; - - /// CTEs that are currently in resolve process - std::unordered_set ctes_in_resolve_process; - - /// Function name to user defined lambda map - std::unordered_map function_name_to_user_defined_lambda; - - /// Array join expressions counter - size_t array_join_expressions_counter = 1; - - /// Subquery counter - size_t subquery_counter = 1; - - /// Global expression node to projection name map - std::unordered_map node_to_projection_name; - - /// Global resolve expression node to projection names map - std::unordered_map resolved_expressions; - - /// Global resolve expression node to tree size - std::unordered_map node_to_tree_size; - - /// Global scalar subquery to scalar value map - std::unordered_map scalar_subquery_to_scalar_value_local; - std::unordered_map scalar_subquery_to_scalar_value_global; - - const bool only_analyze; -}; - -/// Utility functions implementation - - -bool QueryAnalyzer::isExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::CONSTANT || node_type == QueryTreeNodeType::COLUMN || node_type == QueryTreeNodeType::FUNCTION - || node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isFunctionExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::LAMBDA; -} - -bool QueryAnalyzer::isSubqueryNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isTableExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::TABLE || node_type == QueryTreeNodeType::TABLE_FUNCTION || - isSubqueryNodeType(node_type); -} - -DataTypePtr QueryAnalyzer::getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node) -{ - auto node_type = query_tree_node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - { - return query_tree_node->getResultType(); - } - case QueryTreeNodeType::FUNCTION: - { - auto & function_node = query_tree_node->as(); - if (function_node.isResolved()) - return function_node.getResultType(); - break; - } - default: - { - break; - } - } - - return nullptr; -} - -ProjectionName QueryAnalyzer::calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names) -{ - const auto & function_node_typed = function_node->as(); - const auto & function_node_name = function_node_typed.getFunctionName(); - - bool is_array_function = function_node_name == "array"; - bool is_tuple_function = function_node_name == "tuple"; - - WriteBufferFromOwnString buffer; - - if (!is_array_function && !is_tuple_function) - buffer << function_node_name; - - if (!parameters_projection_names.empty()) - { - buffer << '('; - - size_t function_parameters_projection_names_size = parameters_projection_names.size(); - for (size_t i = 0; i < function_parameters_projection_names_size; ++i) - { - buffer << parameters_projection_names[i]; - - if (i + 1 != function_parameters_projection_names_size) - buffer << ", "; - } - - buffer << ')'; - } - - char open_bracket = '('; - char close_bracket = ')'; - - if (is_array_function) - { - open_bracket = '['; - close_bracket = ']'; - } - - buffer << open_bracket; - - size_t function_arguments_projection_names_size = arguments_projection_names.size(); - for (size_t i = 0; i < function_arguments_projection_names_size; ++i) - { - buffer << arguments_projection_names[i]; - - if (i + 1 != function_arguments_projection_names_size) - buffer << ", "; - } - - buffer << close_bracket; - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name) -{ - const auto & window_node_typed = window_node->as(); - const auto & window_frame = window_node_typed.getWindowFrame(); - - bool parent_window_node_has_partition_by = false; - bool parent_window_node_has_order_by = false; - - if (parent_window_node) - { - const auto & parent_window_node_typed = parent_window_node->as(); - parent_window_node_has_partition_by = parent_window_node_typed.hasPartitionBy(); - parent_window_node_has_order_by = parent_window_node_typed.hasOrderBy(); - } - - WriteBufferFromOwnString buffer; - - if (!parent_window_name.empty()) - buffer << parent_window_name; - - if (!partition_by_projection_names.empty() && !parent_window_node_has_partition_by) - { - if (!parent_window_name.empty()) - buffer << ' '; - - buffer << "PARTITION BY "; - - size_t partition_by_projection_names_size = partition_by_projection_names.size(); - for (size_t i = 0; i < partition_by_projection_names_size; ++i) - { - buffer << partition_by_projection_names[i]; - if (i + 1 != partition_by_projection_names_size) - buffer << ", "; - } - } - - if (!order_by_projection_names.empty() && !parent_window_node_has_order_by) - { - if (!partition_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << "ORDER BY "; - - size_t order_by_projection_names_size = order_by_projection_names.size(); - for (size_t i = 0; i < order_by_projection_names_size; ++i) - { - buffer << order_by_projection_names[i]; - if (i + 1 != order_by_projection_names_size) - buffer << ", "; - } - } - - if (!window_frame.is_default) - { - if (!partition_by_projection_names.empty() || !order_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << window_frame.type << " BETWEEN "; - if (window_frame.begin_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.begin_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_begin_offset_projection_name; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - - buffer << " AND "; - - if (window_frame.end_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.end_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_end_offset_projection_name; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - } - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, const ProjectionName & fill_to_expression_projection_name, const ProjectionName & fill_step_expression_projection_name) -{ - auto & sort_node_typed = sort_column_node->as(); - - WriteBufferFromOwnString sort_column_projection_name_buffer; - sort_column_projection_name_buffer << sort_expression_projection_name; - - auto sort_direction = sort_node_typed.getSortDirection(); - sort_column_projection_name_buffer << (sort_direction == SortDirection::ASCENDING ? " ASC" : " DESC"); - - auto nulls_sort_direction = sort_node_typed.getNullsSortDirection(); - - if (nulls_sort_direction) - sort_column_projection_name_buffer << " NULLS " << (nulls_sort_direction == sort_direction ? "LAST" : "FIRST"); - - if (auto collator = sort_node_typed.getCollator()) - sort_column_projection_name_buffer << " COLLATE " << collator->getLocale(); - - if (sort_node_typed.withFill()) - { - sort_column_projection_name_buffer << " WITH FILL"; - - if (sort_node_typed.hasFillFrom()) - sort_column_projection_name_buffer << " FROM " << fill_from_expression_projection_name; - - if (sort_node_typed.hasFillTo()) - sort_column_projection_name_buffer << " TO " << fill_to_expression_projection_name; - - if (sort_node_typed.hasFillStep()) - sort_column_projection_name_buffer << " STEP " << fill_step_expression_projection_name; - } - - return sort_column_projection_name_buffer.str(); -} - -/// Get valid identifiers for typo correction from compound expression -void QueryAnalyzer::collectCompoundExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result) -{ - IDataType::forEachSubcolumn([&](const auto &, const auto & name, const auto &) - { - Identifier subcolumn_indentifier(name); - size_t new_identifier_size = valid_identifier_prefix.getPartsSize() + subcolumn_indentifier.getPartsSize(); - - if (new_identifier_size == unresolved_identifier.getPartsSize()) - { - auto new_identifier = valid_identifier_prefix; - for (const auto & part : subcolumn_indentifier) - new_identifier.push_back(part); - - valid_identifiers_result.insert(std::move(new_identifier)); - } - }, ISerialization::SubstreamData(compound_expression_type->getDefaultSerialization())); -} - -/// Get valid identifiers for typo correction from table expression -void QueryAnalyzer::collectTableExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result) -{ - for (const auto & [column_name, column_node] : table_expression_data.column_name_to_column_node) - { - Identifier column_identifier(column_name); - if (unresolved_identifier.getPartsSize() == column_identifier.getPartsSize()) - valid_identifiers_result.insert(column_identifier); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier, - valid_identifiers_result); - - if (table_expression->hasAlias()) - { - Identifier column_identifier_with_alias({table_expression->getAlias()}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_alias.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_alias.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_alias); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_alias, - valid_identifiers_result); - } - - if (!table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name({table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name, - valid_identifiers_result); - } - - if (!table_expression_data.database_name.empty() && !table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name_and_database_name({table_expression_data.database_name, table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name_and_database_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name_and_database_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name_and_database_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name_and_database_name, - valid_identifiers_result); - } - } -} - -/// Get valid identifiers for typo correction from scope without looking at parent scopes -void QueryAnalyzer::collectScopeValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - bool identifier_is_short = unresolved_identifier.isShort(); - bool identifier_is_compound = unresolved_identifier.isCompound(); - - if (allow_expression_identifiers) - { - for (const auto & [name, expression] : *scope.aliases.alias_name_to_expression_node) - { - assert(expression); - auto expression_identifier = Identifier(name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - - for (const auto & [table_expression, table_expression_data] : scope.table_expression_node_to_data) - { - collectTableExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - table_expression, - table_expression_data, - valid_identifiers_result); - } - } - - if (identifier_is_short) - { - if (allow_function_identifiers) - { - for (const auto & [name, _] : *scope.aliases.alias_name_to_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - - if (allow_table_expression_identifiers) - { - for (const auto & [name, _] : scope.aliases.alias_name_to_table_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - } - - for (const auto & [argument_name, expression] : scope.expression_argument_name_to_node) - { - assert(expression); - auto expression_node_type = expression->getNodeType(); - - if (allow_expression_identifiers && isExpressionNodeType(expression_node_type)) - { - auto expression_identifier = Identifier(argument_name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - else if (identifier_is_short && allow_function_identifiers && isFunctionExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - else if (allow_table_expression_identifiers && isTableExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - } -} - -void QueryAnalyzer::collectScopeWithParentScopesValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - const IdentifierResolveScope * current_scope = &scope; - - while (current_scope) - { - collectScopeValidIdentifiersForTypoCorrection(unresolved_identifier, - *current_scope, - allow_expression_identifiers, - allow_function_identifiers, - allow_table_expression_identifiers, - valid_identifiers_result); - - current_scope = current_scope->parent_scope; - } -} - -std::vector QueryAnalyzer::collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers) -{ - std::vector prompting_strings; - prompting_strings.reserve(valid_identifiers.size()); - - for (const auto & valid_identifier : valid_identifiers) - prompting_strings.push_back(valid_identifier.getFullName()); - - return NamePrompter<1>::getHints(unresolved_identifier.getFullName(), prompting_strings); -} - -/** Wrap expression node in tuple element function calls for nested paths. - * Example: Expression node: compound_expression. Nested path: nested_path_1.nested_path_2. - * Result: tupleElement(tupleElement(compound_expression, 'nested_path_1'), 'nested_path_2'). - */ -QueryTreeNodePtr QueryAnalyzer::wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path) -{ - size_t nested_path_parts_size = nested_path.getPartsSize(); - for (size_t i = 0; i < nested_path_parts_size; ++i) - { - const auto & nested_path_part = nested_path[i]; - auto tuple_element_function = std::make_shared("tupleElement"); - - auto & tuple_element_function_arguments_nodes = tuple_element_function->getArguments().getNodes(); - tuple_element_function_arguments_nodes.reserve(2); - tuple_element_function_arguments_nodes.push_back(expression_node); - tuple_element_function_arguments_nodes.push_back(std::make_shared(nested_path_part)); - - expression_node = std::move(tuple_element_function); - } - - return expression_node; -} - -/** Try to get lambda node from sql user defined functions if sql user defined function with function name exists. - * Returns lambda node if function exists, nullptr otherwise. - */ -QueryTreeNodePtr QueryAnalyzer::tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context) -{ - auto user_defined_function = UserDefinedSQLFunctionFactory::instance().tryGet(function_name); - if (!user_defined_function) - return {}; - - auto it = function_name_to_user_defined_lambda.find(function_name); - if (it != function_name_to_user_defined_lambda.end()) - return it->second; - - const auto & create_function_query = user_defined_function->as(); - auto result_node = buildQueryTree(create_function_query->function_core, context); - if (result_node->getNodeType() != QueryTreeNodeType::LAMBDA) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "SQL user defined function {} must represent lambda expression. Actual {}", - function_name, - create_function_query->function_core->formatForErrorMessage()); - - function_name_to_user_defined_lambda.emplace(function_name, result_node); - - return result_node; -} - -bool subtreeHasViewSource(const IQueryTreeNode * node, const Context & context) -{ - if (!node) - return false; - - if (const auto * table_node = node->as()) - { - if (table_node->getStorageID().getFullNameNotQuoted() == context.getViewSource()->getStorageID().getFullNameNotQuoted()) - return true; - } - - for (const auto & child : node->getChildren()) - if (subtreeHasViewSource(child.get(), context)) - return true; - - return false; -} - -/// Evaluate scalar subquery and perform constant folding if scalar subquery does not have constant value -void QueryAnalyzer::evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - auto * query_node = node->as(); - auto * union_node = node->as(); - if (!query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node must have query or union type. Actual {} {}", - node->getNodeTypeName(), - node->formatASTForErrorMessage()); - - auto & context = scope.context; - - Block scalar_block; - - auto node_without_alias = node->clone(); - node_without_alias->removeAlias(); - - QueryTreeNodePtrWithHash node_with_hash(node_without_alias); - auto str_hash = DB::toString(node_with_hash.hash); - - bool can_use_global_scalars = !only_analyze && !(context->getViewSource() && subtreeHasViewSource(node_without_alias.get(), *context)); - - auto & scalars_cache = can_use_global_scalars ? scalar_subquery_to_scalar_value_global : scalar_subquery_to_scalar_value_local; - - if (scalars_cache.contains(node_with_hash)) - { - if (can_use_global_scalars) - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - else - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesLocalCacheHit); - - scalar_block = scalars_cache.at(node_with_hash); - } - else if (context->hasQueryContext() && can_use_global_scalars && context->getQueryContext()->hasScalar(str_hash)) - { - scalar_block = context->getQueryContext()->getScalar(str_hash); - scalar_subquery_to_scalar_value_global.emplace(node_with_hash, scalar_block); - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - } - else - { - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesCacheMiss); - auto subquery_context = Context::createCopy(context); - - Settings subquery_settings = context->getSettings(); - subquery_settings.max_result_rows = 1; - subquery_settings.extremes = false; - subquery_context->setSettings(subquery_settings); - /// When execute `INSERT INTO t WITH ... SELECT ...`, it may lead to `Unknown columns` - /// exception with this settings enabled(https://github.com/ClickHouse/ClickHouse/issues/52494). - subquery_context->setSetting("use_structure_from_insertion_table_in_table_functions", false); - - auto options = SelectQueryOptions(QueryProcessingStage::Complete, scope.subquery_depth, true /*is_subquery*/); - options.only_analyze = only_analyze; - auto interpreter = std::make_unique(node->toAST(), subquery_context, subquery_context->getViewSource(), options); - - if (only_analyze) - { - /// If query is only analyzed, then constants are not correct. - scalar_block = interpreter->getSampleBlock(); - for (auto & column : scalar_block) - { - if (column.column->empty()) - { - auto mut_col = column.column->cloneEmpty(); - mut_col->insertDefault(); - column.column = std::move(mut_col); - } - } - } - else - { - auto io = interpreter->execute(); - PullingAsyncPipelineExecutor executor(io.pipeline); - io.pipeline.setProgressCallback(context->getProgressCallback()); - io.pipeline.setProcessListElement(context->getProcessListElement()); - - Block block; - - while (block.rows() == 0 && executor.pull(block)) - { - } - - if (block.rows() == 0) - { - auto types = interpreter->getSampleBlock().getDataTypes(); - if (types.size() != 1) - types = {std::make_shared(types)}; - - auto & type = types[0]; - if (!type->isNullable()) - { - if (!type->canBeInsideNullable()) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, - "Scalar subquery returned empty result of type {} which cannot be Nullable", - type->getName()); - - type = makeNullable(type); - } - - auto scalar_column = type->createColumn(); - scalar_column->insert(Null()); - scalar_block.insert({std::move(scalar_column), type, "null"}); - } - else - { - if (block.rows() != 1) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - Block tmp_block; - while (tmp_block.rows() == 0 && executor.pull(tmp_block)) - { - } - - if (tmp_block.rows() != 0) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - block = materializeBlock(block); - size_t columns = block.columns(); - - if (columns == 1) - { - auto & column = block.getByPosition(0); - /// Here we wrap type to nullable if we can. - /// It is needed cause if subquery return no rows, it's result will be Null. - /// In case of many columns, do not check it cause tuple can't be nullable. - if (!column.type->isNullable() && column.type->canBeInsideNullable()) - { - column.type = makeNullable(column.type); - column.column = makeNullable(column.column); - } - - scalar_block = block; - } - else - { - /** Make unique column names for tuple. - * - * Example: SELECT (SELECT 2 AS x, x) - */ - makeUniqueColumnNamesInBlock(block); - - scalar_block.insert({ - ColumnTuple::create(block.getColumns()), - std::make_shared(block.getDataTypes(), block.getNames()), - "tuple"}); - } - } - } - - scalars_cache.emplace(node_with_hash, scalar_block); - if (can_use_global_scalars && context->hasQueryContext()) - context->getQueryContext()->addScalar(str_hash, scalar_block); - } - - const auto & scalar_column_with_type = scalar_block.safeGetByPosition(0); - const auto & scalar_type = scalar_column_with_type.type; - - Field scalar_value; - scalar_column_with_type.column->get(0, scalar_value); - - const auto * scalar_type_name = scalar_block.safeGetByPosition(0).type->getFamilyName(); - static const std::set useless_literal_types = {"Array", "Tuple", "AggregateFunction", "Function", "Set", "LowCardinality"}; - auto * nearest_query_scope = scope.getNearestQueryScope(); - - /// Always convert to literals when there is no query context - if (!context->getSettingsRef().enable_scalar_subquery_optimization || - !useless_literal_types.contains(scalar_type_name) || - !context->hasQueryContext() || - !nearest_query_scope) - { - auto constant_value = std::make_shared(std::move(scalar_value), scalar_type); - auto constant_node = std::make_shared(constant_value, node); - - if (constant_node->getValue().isNull()) - { - node = buildCastFunction(constant_node, constant_node->getResultType(), context); - node = std::make_shared(std::move(constant_value), node); - } - else - node = std::move(constant_node); - - return; - } - - auto & nearest_query_scope_query_node = nearest_query_scope->scope_node->as(); - auto & mutable_context = nearest_query_scope_query_node.getMutableContext(); - - auto scalar_query_hash_string = DB::toString(node_with_hash.hash) + (only_analyze ? "_analyze" : ""); - - if (mutable_context->hasQueryContext()) - mutable_context->getQueryContext()->addScalar(scalar_query_hash_string, scalar_block); - - mutable_context->addScalar(scalar_query_hash_string, scalar_block); - - std::string get_scalar_function_name = "__getScalar"; - - auto scalar_query_hash_constant_value = std::make_shared(std::move(scalar_query_hash_string), std::make_shared()); - auto scalar_query_hash_constant_node = std::make_shared(std::move(scalar_query_hash_constant_value)); - - auto get_scalar_function_node = std::make_shared(get_scalar_function_name); - get_scalar_function_node->getArguments().getNodes().push_back(std::move(scalar_query_hash_constant_node)); - - auto get_scalar_function = FunctionFactory::instance().get(get_scalar_function_name, mutable_context); - get_scalar_function_node->resolveAsFunction(get_scalar_function->build(get_scalar_function_node->getArgumentColumns())); - - node = std::move(get_scalar_function_node); -} - -void QueryAnalyzer::mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope) -{ - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - - auto & parent_window_node_typed = parent_window_node->as(); - - /** If an existing_window_name is specified it must refer to an earlier - * entry in the WINDOW list; the new window copies its partitioning clause - * from that entry, as well as its ordering clause if any. In this case - * the new window cannot specify its own PARTITION BY clause, and it can - * specify ORDER BY only if the copied window does not have one. The new - * window always uses its own frame clause; the copied window must not - * specify a frame clause. - * https://www.postgresql.org/docs/current/sql-select.html - */ - if (window_node_typed.hasPartitionBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override PARTITION BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (window_node_typed.hasOrderBy() && parent_window_node_typed.hasOrderBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override a non-empty ORDER BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (!parent_window_node_typed.getWindowFrame().is_default) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parent window '{}' is not allowed to define a frame: while processing derived window definition '{}'. In scope {}", - parent_window_name, - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - window_node_typed.getPartitionByNode() = parent_window_node_typed.getPartitionBy().clone(); - - if (parent_window_node_typed.hasOrderBy()) - window_node_typed.getOrderByNode() = parent_window_node_typed.getOrderBy().clone(); -} - -/** Replace nodes in node list with positional arguments. - * - * Example: SELECT id, value FROM test_table GROUP BY 1, 2; - * Example: SELECT id, value FROM test_table ORDER BY 1, 2; - * Example: SELECT id, value FROM test_table LIMIT 5 BY 1, 2; - */ -void QueryAnalyzer::replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope) -{ - const auto & settings = scope.context->getSettingsRef(); - if (!settings.enable_positional_arguments || scope.context->getClientInfo().query_kind != ClientInfo::QueryKind::INITIAL_QUERY) - return; - - auto & node_list_typed = node_list->as(); - - for (auto & node : node_list_typed.getNodes()) - { - auto * node_to_replace = &node; - - if (auto * sort_node = node->as()) - node_to_replace = &sort_node->getExpression(); - - auto * constant_node = (*node_to_replace)->as(); - - if (!constant_node - || (constant_node->getValue().getType() != Field::Types::UInt64 - && constant_node->getValue().getType() != Field::Types::Int64)) - continue; - - UInt64 pos; - if (constant_node->getValue().getType() == Field::Types::UInt64) - { - pos = constant_node->getValue().get(); - } - else // Int64 - { - auto value = constant_node->getValue().get(); - if (value > 0) - pos = value; - else - { - if (value < -static_cast(projection_nodes.size())) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Negative positional argument number {} is out of bounds. Expected in range [-{}, -1]. In scope {}", - value, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - pos = projection_nodes.size() + value + 1; - } - } - - if (!pos || pos > projection_nodes.size()) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Positional argument number {} is out of bounds. Expected in range [1, {}]. In scope {}", - pos, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - - --pos; - *node_to_replace = projection_nodes[pos]->clone(); - if (auto it = resolved_expressions.find(projection_nodes[pos]); it != resolved_expressions.end()) - { - resolved_expressions[*node_to_replace] = it->second; - } - } -} - -void QueryAnalyzer::convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope) -{ - const auto * limit_offset_constant_node = expression_node->as(); - if (!limit_offset_constant_node || !isNativeNumber(removeNullable(limit_offset_constant_node->getResultType()))) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} expression must be constant with numeric type. Actual {}. In scope {}", - expression_description, - expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - Field converted_value = convertFieldToType(limit_offset_constant_node->getValue(), DataTypeUInt64()); - if (converted_value.isNull()) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} numeric constant expression is not representable as UInt64", - expression_description); - - auto constant_value = std::make_shared(std::move(converted_value), std::make_shared()); - auto result_constant_node = std::make_shared(std::move(constant_value)); - result_constant_node->getSourceExpression() = limit_offset_constant_node->getSourceExpression(); - - expression_node = std::move(result_constant_node); -} - -void QueryAnalyzer::validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unexpected table expression. Expected table, table function, query or union node. Table node: {}, scope node: {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (table_node || table_function_node) - { - auto table_expression_modifiers = table_node ? table_node->getTableExpressionModifiers() : table_function_node->getTableExpressionModifiers(); - - if (table_expression_modifiers.has_value()) - { - const auto & storage = table_node ? table_node->getStorage() : table_function_node->getStorage(); - if (table_expression_modifiers->hasFinal() && !storage->supportsFinal()) - throw Exception(ErrorCodes::ILLEGAL_FINAL, - "Storage {} doesn't support FINAL", - storage->getName()); - - if (table_expression_modifiers->hasSampleSizeRatio() && !storage->supportsSampling()) - throw Exception(ErrorCodes::SAMPLING_NOT_SUPPORTED, - "Storage {} doesn't support sampling", - storage->getStorageID().getFullNameNotQuoted()); - } - } -} - -void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - bool table_expression_has_alias = table_expression_node->hasAlias(); - if (table_expression_has_alias) - return; - - if (join_node->as().getKind() == JoinKind::Paste) - return; - - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - if ((query_node && !query_node->getCTEName().empty()) || (union_node && !union_node->getCTEName().empty())) - return; - - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || - table_expression_node_type == QueryTreeNodeType::QUERY || - table_expression_node_type == QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::ALIAS_REQUIRED, - "JOIN {} no alias for subquery or table function {}. " - "In scope {} (set joined_subquery_requires_alias = 0 to disable restriction)", - join_node->formatASTForErrorMessage(), - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); -} - -std::pair QueryAnalyzer::recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into) -{ - checkStackSize(); - - if (node->as()) - { - into.push_back(node); - return {false, 1}; - } - - auto * function = node->as(); - - if (!function) - return {false, 0}; - - if (function->isAggregateFunction()) - return {true, 0}; - - UInt64 pushed_children = 0; - bool has_aggregate = false; - - for (auto & child : function->getArguments().getNodes()) - { - auto [child_has_aggregate, child_pushed_children] = recursivelyCollectMaxOrdinaryExpressions(child, into); - has_aggregate |= child_has_aggregate; - pushed_children += child_pushed_children; - } - - /// The current function is not aggregate function and there is no aggregate function in its arguments, - /// so use the current function to replace its arguments - if (!has_aggregate) - { - for (UInt64 i = 0; i < pushed_children; i++) - into.pop_back(); - - into.push_back(node); - pushed_children = 1; - } - - return {has_aggregate, pushed_children}; -} - -/** Expand GROUP BY ALL by extracting all the SELECT-ed expressions that are not aggregate functions. - * - * For a special case that if there is a function having both aggregate functions and other fields as its arguments, - * the `GROUP BY` keys will contain the maximum non-aggregate fields we can extract from it. - * - * Example: - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY ALL - * will expand as - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY substring(a, 4, 2), substring(a, 1, 2) - */ -void QueryAnalyzer::expandGroupByAll(QueryNode & query_tree_node_typed) -{ - if (!query_tree_node_typed.isGroupByAll()) - return; - - auto & group_by_nodes = query_tree_node_typed.getGroupBy().getNodes(); - auto & projection_list = query_tree_node_typed.getProjection(); - - for (auto & node : projection_list.getNodes()) - recursivelyCollectMaxOrdinaryExpressions(node, group_by_nodes); - query_tree_node_typed.setIsGroupByAll(false); -} - -void QueryAnalyzer::expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings) -{ - if (!settings.enable_order_by_all || !query_tree_node_typed.isOrderByAll()) - return; - - auto * all_node = query_tree_node_typed.getOrderBy().getNodes()[0]->as(); - if (!all_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Select analyze for not sort node."); - - auto & projection_nodes = query_tree_node_typed.getProjection().getNodes(); - auto list_node = std::make_shared(); - list_node->getNodes().reserve(projection_nodes.size()); - - for (auto & node : projection_nodes) - { - /// Detect and reject ambiguous statements: - /// E.g. for a table with columns "all", "a", "b": - /// - SELECT all, a, b ORDER BY all; -- should we sort by all columns in SELECT or by column "all"? - /// - SELECT a, b AS all ORDER BY all; -- like before but "all" as alias - /// - SELECT func(...) AS all ORDER BY all; -- like before but "all" as function - /// - SELECT a, b ORDER BY all; -- tricky in other way: does the user want to sort by columns in SELECT clause or by not SELECTed column "all"? - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - auto projection_names = resolved_expression_it->second; - if (projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected 1 projection names. Actual {}", - projection_names.size()); - if (boost::iequals(projection_names[0], "all")) - throw Exception(ErrorCodes::UNEXPECTED_EXPRESSION, - "Cannot use ORDER BY ALL to sort a column with name 'all', please disable setting `enable_order_by_all` and try again"); - } - - auto sort_node = std::make_shared(node, all_node->getSortDirection(), all_node->getNullsSortDirection()); - list_node->getNodes().push_back(sort_node); - } - - query_tree_node_typed.getOrderByNode() = list_node; - query_tree_node_typed.setIsOrderByAll(false); -} - -std::string QueryAnalyzer::rewriteAggregateFunctionNameIfNeeded( - const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context) -{ - std::string result_aggregate_function_name = aggregate_function_name; - auto aggregate_function_name_lowercase = Poco::toLower(aggregate_function_name); - - const auto & settings = context->getSettingsRef(); - - if (aggregate_function_name_lowercase == "countdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - } - else if (aggregate_function_name_lowercase == "countdistinctif" || aggregate_function_name_lowercase == "countifdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - result_aggregate_function_name += "If"; - } - - /// Replace aggregateFunctionIfDistinct into aggregateFunctionDistinctIf to make execution more optimal - if (result_aggregate_function_name.ends_with("ifdistinct")) - { - size_t prefix_length = result_aggregate_function_name.size() - strlen("ifdistinct"); - result_aggregate_function_name = result_aggregate_function_name.substr(0, prefix_length) + "DistinctIf"; - } - - bool need_add_or_null = settings.aggregate_functions_null_for_empty && !result_aggregate_function_name.ends_with("OrNull"); - if (need_add_or_null) - { - auto properties = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (!properties->returns_default_when_only_null) - result_aggregate_function_name += "OrNull"; - } - - /** Move -OrNull suffix ahead, this should execute after add -OrNull suffix. - * Used to rewrite aggregate functions with -OrNull suffix in some cases. - * Example: sumIfOrNull. - * Result: sumOrNullIf. - */ - if (result_aggregate_function_name.ends_with("OrNull")) - { - auto function_properies = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (function_properies && !function_properies->returns_default_when_only_null) - { - size_t function_name_size = result_aggregate_function_name.size(); - - static constexpr std::array suffixes_to_replace = {"MergeState", "Merge", "State", "If"}; - for (const auto & suffix : suffixes_to_replace) - { - auto suffix_string_value = String(suffix); - auto suffix_to_check = suffix_string_value + "OrNull"; - - if (!result_aggregate_function_name.ends_with(suffix_to_check)) - continue; - - result_aggregate_function_name = result_aggregate_function_name.substr(0, function_name_size - suffix_to_check.size()); - result_aggregate_function_name += "OrNull"; - result_aggregate_function_name += suffix_string_value; - - break; - } - } - } - - return result_aggregate_function_name; -} - -/// Resolve identifier functions implementation - -/// Try resolve table identifier from database catalog -QueryTreeNodePtr QueryAnalyzer::tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context) -{ - size_t parts_size = table_identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected table identifier to contain 1 or 2 parts. Actual '{}'", - table_identifier.getFullName()); - - std::string database_name; - std::string table_name; - - if (table_identifier.isCompound()) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - else - { - table_name = table_identifier[0]; - } - - StorageID storage_id(database_name, table_name); - storage_id = context->resolveStorageID(storage_id); - bool is_temporary_table = storage_id.getDatabaseName() == DatabaseCatalog::TEMPORARY_DATABASE; - - StoragePtr storage; - - if (is_temporary_table) - storage = DatabaseCatalog::instance().getTable(storage_id, context); - else - storage = DatabaseCatalog::instance().tryGetTable(storage_id, context); - - if (!storage) - return {}; - - auto storage_lock = storage->lockForShare(context->getInitialQueryId(), context->getSettingsRef().lock_acquire_timeout); - auto storage_snapshot = storage->getStorageSnapshot(storage->getInMemoryMetadataPtr(), context); - auto result = std::make_shared(std::move(storage), std::move(storage_lock), std::move(storage_snapshot)); - if (is_temporary_table) - result->setTemporaryTableName(table_name); - - return result; -} - -/// Resolve identifier from compound expression -/// If identifier cannot be resolved throw exception or return nullptr if can_be_not_found is true -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found) -{ - Identifier compound_expression_identifier; - for (size_t i = 0; i < identifier_bind_size; ++i) - compound_expression_identifier.push_back(expression_identifier[i]); - - IdentifierView nested_path(expression_identifier); - nested_path.popFirst(identifier_bind_size); - - auto expression_type = compound_expression->getResultType(); - - if (!expression_type->hasSubcolumn(nested_path.getFullName())) - { - if (auto * column = compound_expression->as()) - { - const DataTypePtr & column_type = column->getColumn().getTypeInStorage(); - if (column_type->getTypeId() == TypeIndex::Object) - { - const auto * object_type = checkAndGetDataType(column_type.get()); - if (object_type->getSchemaFormat() == "json" && object_type->hasNullableSubcolumns()) - { - QueryTreeNodePtr constant_node_null = std::make_shared(Field()); - return constant_node_null; - } - } - } - - if (can_be_not_found) - return {}; - - std::unordered_set valid_identifiers; - collectCompoundExpressionValidIdentifiersForTypoCorrection(expression_identifier, - expression_type, - compound_expression_identifier, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(expression_identifier, valid_identifiers); - - String compound_expression_from_error_message; - if (!compound_expression_source.empty()) - { - compound_expression_from_error_message += " from "; - compound_expression_from_error_message += compound_expression_source; - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier {} nested path {} cannot be resolved from type {}{}. In scope {}{}", - expression_identifier, - nested_path, - expression_type->getName(), - compound_expression_from_error_message, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - QueryTreeNodePtr get_subcolumn_function = std::make_shared("getSubcolumn"); - auto & get_subcolumn_function_arguments_nodes = get_subcolumn_function->as()->getArguments().getNodes(); - - get_subcolumn_function_arguments_nodes.reserve(2); - get_subcolumn_function_arguments_nodes.push_back(compound_expression); - get_subcolumn_function_arguments_nodes.push_back(std::make_shared(nested_path.getFullName())); - - resolveFunction(get_subcolumn_function, scope); - return get_subcolumn_function; -} - -/** Resolve identifier from expression arguments. - * - * Expression arguments can be initialized during lambda analysis or they could be provided externally. - * Expression arguments must be already resolved nodes. This is client responsibility to resolve them. - * - * Example: SELECT arrayMap(x -> x + 1, [1,2,3]); - * For lambda x -> x + 1, `x` is lambda expression argument. - * - * Resolve strategy: - * 1. Try to bind identifier to scope argument name to node map. - * 2. If identifier is binded but expression context and node type are incompatible return nullptr. - * - * It is important to support edge cases, where we lookup for table or function node, but argument has same name. - * Example: WITH (x -> x + 1) AS func, (func -> func(1) + func) AS lambda SELECT lambda(1); - * - * 3. If identifier is compound and identifier lookup is in expression context use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - auto it = scope.expression_argument_name_to_node.find(identifier_lookup.identifier.getFullName()); - bool resolve_full_identifier = it != scope.expression_argument_name_to_node.end(); - - if (!resolve_full_identifier) - { - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - it = scope.expression_argument_name_to_node.find(identifier_bind_part); - if (it == scope.expression_argument_name_to_node.end()) - return {}; - } - - auto node_type = it->second->getNodeType(); - if (identifier_lookup.isExpressionLookup() && !isExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isTableExpressionLookup() && !isTableExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isFunctionLookup() && !isFunctionExpressionNodeType(node_type)) - return {}; - - if (!resolve_full_identifier && identifier_lookup.identifier.isCompound() && identifier_lookup.isExpressionLookup()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return it->second; -} - -bool QueryAnalyzer::tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope) -{ - return scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME) != nullptr || scope.aliases.array_join_aliases.contains(identifier_lookup.identifier.front()); -} - -/** Resolve identifier from scope aliases. - * - * Resolve strategy: - * 1. If alias is registered in current expressions that are in resolve process and if top expression is not part of bottom expression with the same alias subtree - * throw cyclic aliases exception. - * Otherwise prevent cache usage for identifier lookup and return nullptr. - * - * This is special scenario where identifier has name the same as alias name in one of its parent expressions including itself. - * In such case we cannot resolve identifier from aliases because of recursion. It is client responsibility to register and deregister alias - * names during expressions resolve. - * - * We must prevent cache usage for lookup because lookup outside of expression is supposed to return other value. - * Example: SELECT (id + 1) AS id, id + 2. Lookup for id inside (id + 1) as id should return id from table, but lookup (id + 2) should return - * (id + 1) AS id. - * - * Below cases should work: - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * SELECT (id + 1) AS id FROM test_table; - * SELECT (1 + (1 + id)) AS id FROM test_table; - * - * Below cases should throw cyclic aliases exception: - * SELECT (id + b) AS id, id as b FROM test_table; - * SELECT (1 + b + 1 + id) AS id, b as c, id as b FROM test_table; - * - * 2. Depending on IdentifierLookupContext get alias name to node map from IdentifierResolveScope. - * 3. Try to bind identifier to alias name in map. If there are no such binding return nullptr. - * 4. If node in map is not resolved, resolve it. It is important in case of compound expressions. - * Example: SELECT value.a, cast('(1)', 'Tuple(a UInt64)') AS value; - * - * Special case if node is identifier node. - * Example: SELECT value, id AS value FROM test_table; - * - * Add node in current scope expressions in resolve process stack. - * Try to resolve identifier. - * If identifier is resolved, depending on lookup context, erase entry from expression or lambda map. Check QueryExpressionsAliasVisitor documentation. - * Pop node from current scope expressions in resolve process stack. - * - * 5. If identifier is compound and identifier lookup is in expression context, use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - auto * it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME); - if (it == nullptr) - return {}; - - QueryTreeNodePtr & alias_node = *it; - - if (!alias_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node with alias {} is not valid. In scope {}", - identifier_bind_part, - scope.scope_node->formatASTForErrorMessage()); - - if (auto root_expression_with_alias = scope.expressions_in_resolve_process_stack.getExpressionWithAlias(identifier_bind_part)) - { - const auto top_expression = scope.expressions_in_resolve_process_stack.getTop(); - - if (!isNodePartOfTree(top_expression.get(), root_expression_with_alias.get())) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - scope.non_cached_identifier_lookups_during_expression_resolve.insert(identifier_lookup); - return {}; - } - - auto node_type = alias_node->getNodeType(); - - /// Resolve expression if necessary - if (node_type == QueryTreeNodeType::IDENTIFIER) - { - scope.pushExpressionNode(alias_node); - - auto & alias_identifier_node = alias_node->as(); - auto identifier = alias_identifier_node.getIdentifier(); - auto lookup_result = tryResolveIdentifier(IdentifierLookup{identifier, identifier_lookup.lookup_context}, scope, identifier_resolve_settings); - if (!lookup_result.resolved_identifier) - { - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(identifier, scope, true, false, false, valid_identifiers); - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {} identifier '{}'. In scope {}{}", - toStringLowercase(identifier_lookup.lookup_context), - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - alias_node = lookup_result.resolved_identifier; - scope.popExpressionNode(); - } - else if (node_type == QueryTreeNodeType::FUNCTION) - { - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - else if (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION) - { - if (identifier_resolve_settings.allow_to_resolve_subquery_during_identifier_resolution) - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, identifier_lookup.isTableExpressionLookup() /*allow_table_expression*/); - } - - if (identifier_lookup.identifier.isCompound() && alias_node) - { - if (identifier_lookup.isExpressionLookup()) - { - return tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - 1 /*identifier_bind_size*/, - alias_node, - {} /* compound_expression_source */, - scope, - identifier_resolve_settings.allow_to_check_join_tree /* can_be_not_found */); - } - else if (identifier_lookup.isFunctionLookup() || identifier_lookup.isTableExpressionLookup()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Compound identifier '{}' cannot be resolved as {}. In scope {}", - identifier_lookup.identifier.getFullName(), - identifier_lookup.isFunctionLookup() ? "function" : "table expression", - scope.scope_node->formatASTForErrorMessage()); - } - } - - return alias_node; -} - -/** Resolve identifier from table columns. - * - * 1. If table column nodes are empty or identifier is not expression lookup return nullptr. - * 2. If identifier full name match table column use column. Save information that we resolve identifier using full name. - * 3. Else if identifier binds to table column, use column. - * 4. Try to resolve column ALIAS expression if it exists. - * 5. If identifier was compound and was not resolved using full name during step 1 use `tryResolveIdentifierFromCompoundExpression`. - * This can be the case with compound ALIAS columns. - * - * Example: - * CREATE TABLE test_table (id UInt64, value Tuple(id UInt64, value String), alias_value ALIAS value.id) ENGINE=TinyLog; - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - if (scope.column_name_to_column_node.empty() || !identifier_lookup.isExpressionLookup()) - return {}; - - const auto & identifier = identifier_lookup.identifier; - auto it = scope.column_name_to_column_node.find(identifier.getFullName()); - bool full_column_name_match = it != scope.column_name_to_column_node.end(); - - if (!full_column_name_match) - { - it = scope.column_name_to_column_node.find(identifier_lookup.identifier[0]); - if (it == scope.column_name_to_column_node.end()) - return {}; - } - - if (it->second->hasExpression()) - resolveExpressionNode(it->second->getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - QueryTreeNodePtr result = it->second; - - if (!full_column_name_match && identifier.isCompound()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return result; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - if (parts_size == 1 && path_start == table_name) - return true; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return true; - else - return false; - } - - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier)) || table_expression_data.canBindIdentifier(IdentifierView(identifier))) - return true; - - if (identifier.getPartsSize() == 1) - return false; - - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return true; - - if (identifier.getPartsSize() == 2) - return false; - - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return true; - - return false; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node_to_ignore, - const IdentifierResolveScope & scope) -{ - bool can_bind_identifier_to_table_expression = false; - - for (const auto & [table_expression_node, _] : scope.table_expression_node_to_data) - { - if (table_expression_node.get() == table_expression_node_to_ignore.get()) - continue; - - can_bind_identifier_to_table_expression = tryBindIdentifierToTableExpression(identifier_lookup, table_expression_node, scope); - if (can_bind_identifier_to_table_expression) - break; - } - - return can_bind_identifier_to_table_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found) -{ - auto identifier_without_column_qualifier = identifier; - identifier_without_column_qualifier.popFirst(identifier_column_qualifier_parts); - - /** Compound identifier cannot be resolved directly from storage if storage is not table. - * - * Example: SELECT test_table.id.value1.value2 FROM test_table; - * In table storage column test_table.id.value1.value2 will exists. - * - * Example: SELECT test_subquery.compound_expression.value FROM (SELECT compound_expression AS value) AS test_subquery; - * Here there is no column with name test_subquery.compound_expression.value, and additional wrap in tuple element is required. - */ - - QueryTreeNodePtr result_expression; - bool match_full_identifier = false; - - const auto & identifier_full_name = identifier_without_column_qualifier.getFullName(); - auto it = table_expression_data.column_name_to_column_node.find(identifier_full_name); - bool can_resolve_directly_from_storage = it != table_expression_data.column_name_to_column_node.end(); - if (can_resolve_directly_from_storage && table_expression_data.subcolumn_names.contains(identifier_full_name)) - { - /** In the case when we have an ARRAY JOIN, we should not resolve subcolumns directly from storage. - * For example, consider the following SQL query: - * SELECT ProfileEvents.Values FROM system.query_log ARRAY JOIN ProfileEvents - * In this case, ProfileEvents.Values should also be array joined, not directly resolved from storage. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - if (nearest_query_scope_query_node && nearest_query_scope_query_node->getJoinTree()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - can_resolve_directly_from_storage = false; - } - - if (can_resolve_directly_from_storage) - { - match_full_identifier = true; - result_expression = it->second; - } - else - { - it = table_expression_data.column_name_to_column_node.find(identifier_without_column_qualifier.at(0)); - if (it != table_expression_data.column_name_to_column_node.end()) - result_expression = it->second; - } - - bool clone_is_needed = true; - - String table_expression_source = table_expression_data.table_expression_description; - if (!table_expression_data.table_expression_name.empty()) - table_expression_source += " with name " + table_expression_data.table_expression_name; - - if (result_expression && !match_full_identifier && identifier_without_column_qualifier.isCompound()) - { - size_t identifier_bind_size = identifier_column_qualifier_parts + 1; - result_expression = tryResolveIdentifierFromCompoundExpression(identifier, - identifier_bind_size, - result_expression, - table_expression_source, - scope, - can_be_not_found); - if (can_be_not_found && !result_expression) - return {}; - clone_is_needed = false; - } - - if (!result_expression) - { - QueryTreeNodes nested_column_nodes; - DataTypes nested_types; - Array nested_names_array; - - for (const auto & [column_name, _] : table_expression_data.column_names_and_types) - { - Identifier column_name_identifier_without_last_part(column_name); - auto column_name_identifier_last_part = column_name_identifier_without_last_part.getParts().back(); - column_name_identifier_without_last_part.popLast(); - - if (identifier_without_column_qualifier.getFullName() != column_name_identifier_without_last_part.getFullName()) - continue; - - auto column_node_it = table_expression_data.column_name_to_column_node.find(column_name); - if (column_node_it == table_expression_data.column_name_to_column_node.end()) - continue; - - const auto & column_node = column_node_it->second; - const auto & column_type = column_node->getColumnType(); - const auto * column_type_array = typeid_cast(column_type.get()); - if (!column_type_array) - continue; - - nested_column_nodes.push_back(column_node); - nested_types.push_back(column_type_array->getNestedType()); - nested_names_array.push_back(Field(std::move(column_name_identifier_last_part))); - } - - if (!nested_types.empty()) - { - auto nested_function_node = std::make_shared("nested"); - auto & nested_function_node_arguments = nested_function_node->getArguments().getNodes(); - - auto nested_function_names_array_type = std::make_shared(std::make_shared()); - auto nested_function_names_constant_node = std::make_shared(std::move(nested_names_array), - std::move(nested_function_names_array_type)); - nested_function_node_arguments.push_back(std::move(nested_function_names_constant_node)); - nested_function_node_arguments.insert(nested_function_node_arguments.end(), - nested_column_nodes.begin(), - nested_column_nodes.end()); - - auto nested_function = FunctionFactory::instance().get(nested_function_node->getFunctionName(), scope.context); - nested_function_node->resolveAsFunction(nested_function->build(nested_function_node->getArgumentColumns())); - - clone_is_needed = false; - result_expression = std::move(nested_function_node); - } - } - - if (!result_expression) - { - if (can_be_not_found) - return {}; - std::unordered_set valid_identifiers; - collectTableExpressionValidIdentifiersForTypoCorrection(identifier, - table_expression_node, - table_expression_data, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Identifier '{}' cannot be resolved from {}. In scope {}{}", - identifier.getFullName(), - table_expression_source, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (clone_is_needed) - result_expression = result_expression->clone(); - - auto qualified_identifier = identifier; - - for (size_t i = 0; i < identifier_column_qualifier_parts; ++i) - { - auto qualified_identifier_with_removed_part = qualified_identifier; - qualified_identifier_with_removed_part.popFirst(); - - if (qualified_identifier_with_removed_part.empty()) - break; - - IdentifierLookup column_identifier_lookup = {qualified_identifier_with_removed_part, IdentifierLookupContext::EXPRESSION}; - if (tryBindIdentifierToAliases(column_identifier_lookup, scope)) - break; - - if (table_expression_data.should_qualify_columns && - tryBindIdentifierToTableExpressions(column_identifier_lookup, table_expression_node, scope)) - break; - - qualified_identifier = std::move(qualified_identifier_with_removed_part); - } - - auto qualified_identifier_full_name = qualified_identifier.getFullName(); - node_to_projection_name.emplace(result_expression, std::move(qualified_identifier_full_name)); - - return result_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (parts_size == 1 && path_start == table_name) - return table_expression_node; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return table_expression_node; - else - return {}; - } - - /** If identifier first part binds to some column start or table has full identifier name. Then we can try to find whole identifier in table. - * 1. Try to bind identifier first part to column in table, if true get full identifier from table or throw exception. - * 2. Try to bind identifier first part to table name or storage alias, if true remove first part and try to get full identifier from table or throw exception. - * Storage alias works for subquery, table function as well. - * 3. Try to bind identifier first parts to database name and table name, if true remove first two parts and try to get full identifier from table or throw exception. - */ - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier))) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/); - - if (table_expression_data.canBindIdentifier(IdentifierView(identifier))) - { - /** This check is insufficient to determine whether and identifier can be resolved from table expression. - * A further check will be performed in `tryResolveIdentifierFromStorage` to see if we have such a subcolumn. - * In cases where the subcolumn cannot be found we want to have `nullptr` instead of exception. - * So, we set `can_be_not_found = true` to have an attempt to resolve the identifier from another table expression. - * Example: `SELECT t.t from (SELECT 1 as t) AS a FULL JOIN (SELECT 1 as t) as t ON a.t = t.t;` - * Initially, we will try to resolve t.t from `a` because `t.` is bound to `1 as t`. However, as it is not a nested column, we will need to resolve it from the second table expression. - */ - auto resolved_identifier = tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/, true /*can_be_not_found*/); - if (resolved_identifier) - return resolved_identifier; - } - - if (identifier.getPartsSize() == 1) - return {}; - - const auto & table_name = table_expression_data.table_name; - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 1 /*identifier_column_qualifier_parts*/); - - if (identifier.getPartsSize() == 2) - return {}; - - const auto & database_name = table_expression_data.database_name; - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 2 /*identifier_column_qualifier_parts*/); - - return {}; -} - -QueryTreeNodePtr checkIsMissedObjectJSONSubcolumn(const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier) -{ - if (left_resolved_identifier && right_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT - && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL" && right_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (left_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (right_resolved_identifier && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & right_resolved_column = right_resolved_identifier->as(); - if (right_resolved_column.getValueStringRepresentation() == "NULL") - return right_resolved_identifier; - } - return {}; -} - -/// Used to replace columns that changed type because of JOIN to their original type -class ReplaceColumnsVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit ReplaceColumnsVisitor(const QueryTreeNodePtrWithHashMap & replacement_map_, const ContextPtr & context_) - : replacement_map(replacement_map_) - , context(context_) - {} - - /// Apply replacement transitively, because column may change it's type twice, one to have a supertype and then because of `joun_use_nulls` - static QueryTreeNodePtr findTransitiveReplacement(QueryTreeNodePtr node, const QueryTreeNodePtrWithHashMap & replacement_map_) - { - auto it = replacement_map_.find(node); - QueryTreeNodePtr result_node = nullptr; - for (; it != replacement_map_.end(); it = replacement_map_.find(result_node)) - { - if (result_node && result_node->isEqual(*it->second)) - { - Strings map_dump; - for (const auto & [k, v]: replacement_map_) - map_dump.push_back(fmt::format("{} -> {} (is_equals: {}, is_same: {})", - k.node->dumpTree(), v->dumpTree(), k.node->isEqual(*v), k.node == v)); - throw Exception(ErrorCodes::LOGICAL_ERROR, "Infinite loop in query tree replacement map: {}", fmt::join(map_dump, "; ")); - } - chassert(it->second); - - result_node = it->second; - } - return result_node; - } - - void visitImpl(QueryTreeNodePtr & node) - { - if (auto replacement_node = findTransitiveReplacement(node, replacement_map)) - node = replacement_node; - - if (auto * function_node = node->as(); function_node && function_node->isResolved()) - rerunFunctionResolve(function_node, context); - } - - /// We want to re-run resolve for function _after_ its arguments are replaced - bool shouldTraverseTopToBottom() const { return false; } - - bool needChildVisit(QueryTreeNodePtr & /* parent */, QueryTreeNodePtr & child) - { - /// Visit only expressions, but not subqueries - return child->getNodeType() == QueryTreeNodeType::IDENTIFIER - || child->getNodeType() == QueryTreeNodeType::LIST - || child->getNodeType() == QueryTreeNodeType::FUNCTION - || child->getNodeType() == QueryTreeNodeType::COLUMN; - } - -private: - const QueryTreeNodePtrWithHashMap & replacement_map; - const ContextPtr & context; -}; - -/// Compare resolved identifiers considering columns that become nullable after JOIN -bool resolvedIdenfiersFromJoinAreEquals( - const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier, - const IdentifierResolveScope & scope) -{ - auto left_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(left_resolved_identifier, scope.join_columns_with_changed_types); - const auto & left_resolved_to_compare = left_original_node ? left_original_node : left_resolved_identifier; - - auto right_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(right_resolved_identifier, scope.join_columns_with_changed_types); - const auto & right_resolved_to_compare = right_original_node ? right_original_node : right_resolved_identifier; - - return left_resolved_to_compare->isEqual(*right_resolved_to_compare, IQueryTreeNode::CompareOptions{.compare_aliases = false}); -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_join_node = table_expression_node->as(); - auto left_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getLeftTableExpression(), scope); - auto right_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getRightTableExpression(), scope); - - if (!identifier_lookup.isExpressionLookup()) - { - if (left_resolved_identifier && right_resolved_identifier) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.dump(), - scope.scope_node->formatASTForErrorMessage()); - - return left_resolved_identifier ? left_resolved_identifier : right_resolved_identifier; - } - - bool join_node_in_resolve_process = scope.table_expressions_in_resolve_process.contains(table_expression_node.get()); - - std::unordered_map join_using_column_name_to_column_node; - - if (!join_node_in_resolve_process && from_join_node.isUsingJoinExpression()) - { - auto & join_using_list = from_join_node.getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & column_node = join_using_node->as(); - join_using_column_name_to_column_node.emplace(column_node.getColumnName(), std::static_pointer_cast(join_using_node)); - } - } - - auto check_nested_column_not_in_using = [&join_using_column_name_to_column_node, &identifier_lookup](const QueryTreeNodePtr & node) - { - /** tldr: When an identifier is resolved into the function `nested` or `getSubcolumn`, and - * some column in its argument is in the USING list and its type has to be updated, we throw an error to avoid overcomplication. - * - * Identifiers can be resolved into functions in case of nested or subcolumns. - * For example `t.t.t` can be resolved into `getSubcolumn(t, 't.t')` function in case of `t` is `Tuple`. - * So, `t` in USING list is resolved from JOIN itself and has supertype of columns from left and right table. - * But `t` in `getSubcolumn` argument is still resolved from table and we need to update its type. - * - * Example: - * - * SELECT t.t FROM ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t UInt32, s1 String), s1 String) as t - * ) AS a FULL JOIN ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t Int32, s2 String), s2 String) as t - * ) AS b USING t; - * - * Result type of `t` is `Tuple(Tuple(Int64, String), String)` (different type and no names for subcolumns), - * so it may be tricky to have a correct type for `t.t` that is resolved into getSubcolumn(t, 't'). - * - * It can be more complicated in case of Nested subcolumns, in that case in query: - * SELECT t FROM ... JOIN ... USING (t.t) - * Here, `t` is resolved into function `nested(['t', 's'], t.t, t.s) so, `t.t` should be from JOIN and `t.s` should be from table. - * - * Updating type accordingly is pretty complicated, so just forbid such cases. - * - * While it still may work for storages that support selecting subcolumns directly without `getSubcolumn` function: - * SELECT t, t.t, toTypeName(t), toTypeName(t.t) FROM t1 AS a FULL JOIN t2 AS b USING t.t; - * We just support it as a best-effort: `t` will have original type from table, but `t.t` will have super-type from JOIN. - * Probably it's good to prohibit such cases as well, but it's not clear how to check it in general case. - */ - if (node->getNodeType() != QueryTreeNodeType::FUNCTION) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {}, expected function node", node->getNodeType()); - - const auto & function_argument_nodes = node->as().getArguments().getNodes(); - for (const auto & argument_node : function_argument_nodes) - { - if (argument_node->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_name = argument_node->as().getColumnName(); - if (join_using_column_name_to_column_node.contains(column_name)) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Cannot select subcolumn for identifier '{}' while joining using column '{}'", - identifier_lookup.identifier, column_name); - } - else if (argument_node->getNodeType() == QueryTreeNodeType::CONSTANT) - { - continue; - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {} for argument node in {}", - argument_node->getNodeType(), node->formatASTForErrorMessage()); - } - } - }; - - std::optional resolved_side; - QueryTreeNodePtr resolved_identifier; - - JoinKind join_kind = from_join_node.getKind(); - - /// If columns from left or right table were missed Object(Nullable('json')) subcolumns, they will be replaced - /// to ConstantNode(NULL), which can't be cast to ColumnNode, so we resolve it here. - if (auto missed_subcolumn_identifier = checkIsMissedObjectJSONSubcolumn(left_resolved_identifier, right_resolved_identifier)) - return missed_subcolumn_identifier; - - if (left_resolved_identifier && right_resolved_identifier) - { - auto using_column_node_it = join_using_column_name_to_column_node.end(); - if (left_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && right_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getColumnName() == right_resolved_column.getColumnName()) - using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - } - else - { - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(left_resolved_identifier); - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(right_resolved_identifier); - } - - if (using_column_node_it != join_using_column_name_to_column_node.end()) - { - JoinTableSide using_column_inner_column_table_side = isRight(join_kind) ? JoinTableSide::Right : JoinTableSide::Left; - auto & using_column_node = using_column_node_it->second->as(); - auto & using_expression_list = using_column_node.getExpression()->as(); - - size_t inner_column_node_index = using_column_inner_column_table_side == JoinTableSide::Left ? 0 : 1; - const auto & inner_column_node = using_expression_list.getNodes().at(inner_column_node_index); - - auto result_column_node = inner_column_node->clone(); - auto & result_column = result_column_node->as(); - result_column.setColumnType(using_column_node.getColumnType()); - - const auto & join_using_left_column = using_expression_list.getNodes().at(0); - if (!result_column_node->isEqual(*join_using_left_column)) - scope.join_columns_with_changed_types[result_column_node] = join_using_left_column; - - resolved_identifier = std::move(result_column_node); - } - else if (resolvedIdenfiersFromJoinAreEquals(left_resolved_identifier, right_resolved_identifier, scope)) - { - const auto & identifier_path_part = identifier_lookup.identifier.front(); - auto * left_resolved_identifier_column = left_resolved_identifier->as(); - auto * right_resolved_identifier_column = right_resolved_identifier->as(); - - if (left_resolved_identifier_column && right_resolved_identifier_column) - { - const auto & left_column_source_alias = left_resolved_identifier_column->getColumnSource()->getAlias(); - const auto & right_column_source_alias = right_resolved_identifier_column->getColumnSource()->getAlias(); - - /** If column from right table was resolved using alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one JOIN system.one AS A ON A.dummy = system.one.dummy; - * - * If alias is specified for left table, and alias is not specified for right table and identifier was resolved - * without using left table alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one AS A JOIN system.one ON A.dummy = system.one.dummy; - * - * Otherwise we prefer column from left table. - */ - bool column_resolved_using_right_alias = identifier_path_part == right_column_source_alias; - bool column_resolved_without_using_left_alias = !left_column_source_alias.empty() - && right_column_source_alias.empty() - && identifier_path_part != left_column_source_alias; - if (column_resolved_using_right_alias || column_resolved_without_using_left_alias) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else if (scope.joins_count == 1 && scope.context->getSettingsRef().single_join_prefer_left_table) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - else - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier '{}'. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - else if (left_resolved_identifier) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(left_resolved_identifier); - } - else - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*left_resolved_column.getColumnType())) - { - auto left_resolved_column_clone = std::static_pointer_cast(left_resolved_column.clone()); - left_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(left_resolved_column_clone); - - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - else if (right_resolved_identifier) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(right_resolved_identifier); - } - else - { - auto & right_resolved_column = right_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(right_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*right_resolved_column.getColumnType())) - { - auto right_resolved_column_clone = std::static_pointer_cast(right_resolved_column.clone()); - right_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(right_resolved_column_clone); - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - - if (join_node_in_resolve_process || !resolved_identifier) - return resolved_identifier; - - if (scope.join_use_nulls) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier); - auto nullable_resolved_identifier = convertJoinedColumnTypeToNullIfNeeded(resolved_identifier, join_kind, resolved_side, scope); - if (nullable_resolved_identifier) - { - resolved_identifier = nullable_resolved_identifier; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(resolved_identifier, projection_name_it->second); - } - } - } - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope) -{ - const auto * resolved_function = resolved_expression->as(); - if (!resolved_function || resolved_function->getFunctionName() != "getSubcolumn") - return {}; - - const auto * array_join_parent_column = array_join_column_inner_expression.get(); - - /** If both resolved and array-joined expressions are subcolumns, try to match them: - * For example, in `SELECT t.map.values FROM (SELECT * FROM tbl) ARRAY JOIN t.map` - * Identifier `t.map.values` is resolved into `getSubcolumn(t, 'map.values')` and t.map is resolved into `getSubcolumn(t, 'map')` - * Since we need to perform array join on `getSubcolumn(t, 'map')`, `t.map.values` should become `getSubcolumn(getSubcolumn(t, 'map'), 'values')` - * - * Note: It doesn't work when subcolumn in ARRAY JOIN is transformed by another expression, for example - * SELECT c.map, c.map.values FROM (SELECT * FROM tbl) ARRAY JOIN mapApply(x -> x, t.map); - */ - String array_join_subcolumn_prefix; - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "getSubcolumn") - { - const auto & argument_nodes = array_join_column_inner_expression_function->getArguments().getNodes(); - if (argument_nodes.size() == 2 && argument_nodes.at(1)->getNodeType() == QueryTreeNodeType::CONSTANT) - { - const auto & constant_node = argument_nodes.at(1)->as(); - const auto & constant_node_value = constant_node.getValue(); - if (constant_node_value.getType() == Field::Types::String) - { - array_join_subcolumn_prefix = constant_node_value.get() + "."; - array_join_parent_column = argument_nodes.at(0).get(); - } - } - } - - const auto & argument_nodes = resolved_function->getArguments().getNodes(); - if (argument_nodes.size() != 2 && !array_join_parent_column->isEqual(*argument_nodes.at(0))) - return {}; - - const auto * second_argument = argument_nodes.at(1)->as(); - if (!second_argument || second_argument->getValue().getType() != Field::Types::String) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected constant string as second argument of getSubcolumn function {}", resolved_function->dumpTree()); - - const auto & resolved_subcolumn_path = second_argument->getValue().get(); - if (!startsWith(resolved_subcolumn_path, array_join_subcolumn_prefix)) - return {}; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(array_join_column_expression_typed.getColumn(), array_join_column_expression_typed.getColumnSource())); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(resolved_subcolumn_path.substr(array_join_subcolumn_prefix.size()))); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - return function_query_node; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & array_join_node = table_expression_node->as(); - const auto & array_join_column_expressions_list = array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions_list.getNodes(); - - QueryTreeNodePtr array_join_resolved_expression; - - /** Special case when qualified or unqualified identifier point to array join expression without alias. - * - * CREATE TABLE test_table (id UInt64, value String, value_array Array(UInt8)) ENGINE=TinyLog; - * SELECT id, value, value_array, test_table.value_array, default.test_table.value_array FROM test_table ARRAY JOIN value_array; - * - * value_array, test_table.value_array, default.test_table.value_array must be resolved into array join expression. - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - if (array_join_column_expression_typed.hasAlias()) - continue; - - auto & array_join_column_inner_expression = array_join_column_expression_typed.getExpressionOrThrow(); - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "nested" && - array_join_column_inner_expression_function->getArguments().getNodes().size() > 1 && - isTuple(array_join_column_expression_typed.getResultType())) - { - const auto & nested_function_arguments = array_join_column_inner_expression_function->getArguments().getNodes(); - size_t nested_function_arguments_size = nested_function_arguments.size(); - - const auto & nested_keys_names_constant_node = nested_function_arguments[0]->as(); - const auto & nested_keys_names = nested_keys_names_constant_node.getValue().get(); - size_t nested_keys_names_size = nested_keys_names.size(); - - if (nested_keys_names_size == nested_function_arguments_size - 1) - { - for (size_t i = 1; i < nested_function_arguments_size; ++i) - { - if (!nested_function_arguments[i]->isEqual(*resolved_expression)) - continue; - - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - - const auto & nested_key_name = nested_keys_names[i - 1].get(); - Identifier nested_identifier = Identifier(nested_key_name); - auto tuple_element_function = wrapExpressionNodeInTupleElement(array_join_column, nested_identifier); - resolveFunction(tuple_element_function, scope); - - array_join_resolved_expression = std::move(tuple_element_function); - break; - } - } - } - - if (array_join_resolved_expression) - break; - - if (array_join_column_inner_expression->isEqual(*resolved_expression)) - { - array_join_resolved_expression = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - break; - } - - /// When we select subcolumn of array joined column it also should be array joined - array_join_resolved_expression = matchArrayJoinSubcolumns(array_join_column_inner_expression, array_join_column_expression_typed, resolved_expression, scope); - if (array_join_resolved_expression) - break; - } - return array_join_resolved_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_array_join_node = table_expression_node->as(); - auto resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_array_join_node.getTableExpression(), scope); - - if (scope.table_expressions_in_resolve_process.contains(table_expression_node.get()) || !identifier_lookup.isExpressionLookup()) - return resolved_identifier; - - const auto & array_join_column_expressions = from_array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions.getNodes(); - - /** Allow JOIN with USING with ARRAY JOIN. - * - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN [1,2,3] AS id INNER JOIN test_table_2 AS t2 USING (id); - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN t1.id AS id INNER JOIN test_table_2 AS t2 USING (id); - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - - IdentifierView identifier_view(identifier_lookup.identifier); - - if (identifier_view.isCompound() && from_array_join_node.hasAlias() && identifier_view.front() == from_array_join_node.getAlias()) - identifier_view.popFirst(); - - const auto & alias_or_name = array_join_column_expression_typed.hasAlias() - ? array_join_column_expression_typed.getAlias() - : array_join_column_expression_typed.getColumnName(); - - if (identifier_view.front() == alias_or_name) - identifier_view.popFirst(); - else if (identifier_view.getFullName() == alias_or_name) - identifier_view.popFirst(identifier_view.getPartsSize()); /// Clear - else - continue; - - if (identifier_view.empty()) - { - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - return array_join_column; - } - - auto compound_expr = tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - identifier_lookup.identifier.getPartsSize() - identifier_view.getPartsSize() /*identifier_bind_size*/, - array_join_column_expression, - {} /* compound_expression_source */, - scope, - true /* can_be_not_found */); - - if (compound_expr) - return compound_expr; - } - - if (!resolved_identifier) - return nullptr; - - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(resolved_identifier, table_expression_node, scope); - if (array_join_resolved_expression) - resolved_identifier = std::move(array_join_resolved_expression); - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope) -{ - auto join_tree_node_type = join_tree_node->getNodeType(); - - switch (join_tree_node_type) - { - case QueryTreeNodeType::JOIN: - return tryResolveIdentifierFromJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::ARRAY_JOIN: - return tryResolveIdentifierFromArrayJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - [[fallthrough]]; - case QueryTreeNodeType::TABLE: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - { - /** Edge case scenario when subquery in FROM node try to resolve identifier from parent scopes, when FROM is not resolved. - * SELECT subquery.b AS value FROM (SELECT value, 1 AS b) AS subquery; - * TODO: This can be supported - */ - if (scope.table_expressions_in_resolve_process.contains(join_tree_node.get())) - return {}; - - return tryResolveIdentifierFromTableExpression(identifier_lookup, join_tree_node, scope); - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Scope FROM section expected table, table function, query, union, join or array join. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } -} - -/** Resolve identifier from scope join tree. - * - * 1. If identifier is in function lookup context return nullptr. - * 2. Try to resolve identifier from table columns. - * 3. If there is no FROM section return nullptr. - * 4. If identifier is in table lookup context, check if it has 1 or 2 parts, otherwise throw exception. - * If identifier has 2 parts try to match it with database_name and table_name. - * If identifier has 1 part try to match it with table_name, then try to match it with table alias. - * 5. If identifier is in expression lookup context, we first need to bind identifier to some table column using identifier first part. - * Start with identifier first part, if it match some column name in table try to get column with full identifier name. - * TODO: Need to check if it is okay to throw exception if compound identifier first part bind to column but column is not valid. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope) -{ - if (identifier_lookup.isFunctionLookup()) - return {}; - - /// Try to resolve identifier from table columns - if (auto resolved_identifier = tryResolveIdentifierFromTableColumns(identifier_lookup, scope)) - return resolved_identifier; - - if (scope.expression_join_tree_node) - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, scope.expression_join_tree_node, scope); - - auto * query_scope_node = scope.scope_node->as(); - if (!query_scope_node || !query_scope_node->getJoinTree()) - return {}; - - const auto & join_tree_node = query_scope_node->getJoinTree(); - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_tree_node, scope); -} - -/** Try resolve identifier in current scope parent scopes. - * - * TODO: If column is matched, throw exception that nested subqueries are not supported. - * - * If initial scope is expression. Then try to resolve identifier in parent scopes until query scope is hit. - * For query scope resolve strategy is same as if initial scope if query. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - bool initial_scope_is_query = scope.scope_node->getNodeType() == QueryTreeNodeType::QUERY; - bool initial_scope_is_expression = !initial_scope_is_query; - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_parent_scopes = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - IdentifierResolveScope * scope_to_check = scope.parent_scope; - - if (initial_scope_is_expression) - { - while (scope_to_check != nullptr) - { - auto resolve_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - if (resolve_result.resolved_identifier) - return resolve_result; - - bool scope_was_query = scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY; - scope_to_check = scope_to_check->parent_scope; - - if (scope_was_query) - break; - } - } - - if (!scope.context->getSettingsRef().enable_global_with_statement) - return {}; - - /** Nested subqueries cannot access outer subqueries table expressions from JOIN tree because - * that can prevent resolution of table expression from CTE. - * - * Example: WITH a AS (SELECT number FROM numbers(1)), b AS (SELECT number FROM a) SELECT * FROM a as l, b as r; - */ - if (identifier_lookup.isTableExpressionLookup()) - identifier_resolve_settings.allow_to_check_join_tree = false; - - while (scope_to_check != nullptr) - { - auto lookup_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - const auto & resolved_identifier = lookup_result.resolved_identifier; - - scope_to_check = scope_to_check->parent_scope; - - if (resolved_identifier) - { - auto * subquery_node = resolved_identifier->as(); - auto * union_node = resolved_identifier->as(); - - bool is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - bool is_table_from_expression_arguments = lookup_result.resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS && - resolved_identifier->getNodeType() == QueryTreeNodeType::TABLE; - bool is_valid_table_expression = is_cte || is_table_from_expression_arguments; - - /** From parent scopes we can resolve table identifiers only as CTE. - * Example: SELECT (SELECT 1 FROM a) FROM test_table AS a; - * - * During child scope table identifier resolve a, table node test_table with alias a from parent scope - * is invalid. - */ - if (identifier_lookup.isTableExpressionLookup() && !is_valid_table_expression) - continue; - - if (is_valid_table_expression || resolved_identifier->as()) - { - return lookup_result; - } - else if (auto * resolved_function = resolved_identifier->as()) - { - /// Special case: scalar subquery was executed and replaced by __getScalar function. - /// Handle it as a constant. - if (resolved_function->getFunctionName() == "__getScalar") - return lookup_result; - } - - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Resolve identifier '{}' from parent scope only supported for constants and CTE. Actual {} node type {}. In scope {}", - identifier_lookup.identifier.getFullName(), - resolved_identifier->formatASTForErrorMessage(), - resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - return {}; -} - -/** Resolve identifier in scope. - * - * If identifier was resolved resolve identified lookup status will be updated. - * - * Steps: - * 1. Register identifier lookup in scope identifier lookup to resolve status table. - * If entry is already registered and is not resolved, that means that we have cyclic aliases for identifier. - * Example: SELECT a AS b, b AS a; - * Try resolve identifier in current scope: - * 3. Try resolve identifier from expression arguments. - * - * If prefer_column_name_to_alias = true. - * 4. Try to resolve identifier from join tree. - * 5. Try to resolve identifier from aliases. - * Otherwise. - * 4. Try to resolve identifier from aliases. - * 5. Try to resolve identifier from join tree. - * - * 6. If it is table identifier lookup try to lookup identifier in current scope CTEs. - * - * 7. If identifier is not resolved in current scope, try to resolve it in parent scopes. - * 8. If identifier is not resolved from parent scopes and it is table identifier lookup try to lookup identifier - * in database catalog. - * - * Same is not done for functions because function resolution is more complex, and in case of aggregate functions requires not only name - * but also argument types, it is responsibility of resolve function method to handle resolution of function name. - * - * 9. If identifier was not resolved, or identifier caching was disabled remove it from identifier lookup to resolve status table. - * - * It is okay for identifier to be not resolved, in case we want first try to lookup identifier in one context, - * then if there is no identifier in this context, try to lookup in another context. - * Example: Try to lookup identifier as expression, if it is not found, lookup as function. - * Example: Try to lookup identifier as expression, if it is not found, lookup as table. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - auto it = scope.identifier_lookup_to_resolve_state.find(identifier_lookup); - if (it != scope.identifier_lookup_to_resolve_state.end()) - { - if (it->second.cyclic_identifier_resolve) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (!it->second.resolve_result.isResolved()) - it->second.cyclic_identifier_resolve = true; - - if (it->second.resolve_result.isResolved() && - scope.use_identifier_lookup_to_result_cache && - !scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) && - (!it->second.resolve_result.isResolvedFromCTEs() || !ctes_in_resolve_process.contains(identifier_lookup.identifier.getFullName()))) - return it->second.resolve_result; - } - else - { - auto [insert_it, _] = scope.identifier_lookup_to_resolve_state.insert({identifier_lookup, IdentifierResolveState()}); - it = insert_it; - } - - /// Resolve identifier from current scope - - IdentifierResolveResult resolve_result; - resolve_result.resolved_identifier = tryResolveIdentifierFromExpressionArguments(identifier_lookup, scope); - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - - if (!resolve_result.resolved_identifier) - { - bool prefer_column_name_to_alias = scope.context->getSettingsRef().prefer_column_name_to_alias; - - if (identifier_lookup.isExpressionLookup()) - { - /* For aliases from ARRAY JOIN we prefer column from join tree: - * SELECT id FROM ( SELECT ... ) AS subquery ARRAY JOIN [0] AS id INNER JOIN second_table USING (id) - * In the example, identifier `id` should be resolved into one from USING (id) column. - */ - - auto * alias_it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FULL_NAME); - if (alias_it && (*alias_it)->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_node = (*alias_it)->as(); - if (column_node.getColumnSource()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - prefer_column_name_to_alias = true; - } - } - - if (unlikely(prefer_column_name_to_alias)) - { - if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - - if (!resolve_result.resolved_identifier) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - } - else - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - { - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - else if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - } - } - - if (!resolve_result.resolved_identifier && identifier_lookup.isTableExpressionLookup()) - { - auto full_name = identifier_lookup.identifier.getFullName(); - auto cte_query_node_it = scope.cte_name_to_query_node.find(full_name); - - /// CTE may reference table expressions with the same name, e.g.: - /// - /// WITH test1 AS (SELECT * FROM test1) SELECT * FROM test1; - /// - /// Since we don't support recursive CTEs, `test1` identifier inside of CTE - /// references to table .test1. - /// This means that the example above is equivalent to the following query: - /// - /// SELECT * FROM test1; - /// - /// To accomplish this behaviour it's not allowed to resolve identifiers to - /// CTE that is being resolved. - if (cte_query_node_it != scope.cte_name_to_query_node.end() - && !ctes_in_resolve_process.contains(full_name)) - { - resolve_result.resolved_identifier = cte_query_node_it->second; - resolve_result.resolve_place = IdentifierResolvePlace::CTE; - } - } - - /// Try to resolve identifier from parent scopes - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_parent_scopes) - { - resolve_result = tryResolveIdentifierInParentScopes(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolved_from_parent_scopes = true; - } - - /// Try to resolve table identifier from database catalog - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_database_catalog && identifier_lookup.isTableExpressionLookup()) - { - resolve_result.resolved_identifier = tryResolveTableIdentifierFromDatabaseCatalog(identifier_lookup.identifier, scope.context); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::DATABASE_CATALOG; - } - - bool was_cyclic_identifier_resolve = it->second.cyclic_identifier_resolve; - if (!was_cyclic_identifier_resolve) - it->second.resolve_result = resolve_result; - it->second.cyclic_identifier_resolve = false; - - /** If identifier was not resolved, or during expression resolution identifier was explicitly added into non cached set, - * or identifier caching was disabled in resolve scope we remove identifier lookup result from identifier lookup to result table. - */ - if (!was_cyclic_identifier_resolve && (!resolve_result.resolved_identifier || - scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) || - !scope.use_identifier_lookup_to_result_cache)) - scope.identifier_lookup_to_resolve_state.erase(it); - - return resolve_result; -} - -/// Resolve query tree nodes functions implementation - -/** Qualify column nodes with projection names. - * - * Example: SELECT * FROM test_table AS t1, test_table AS t2; - */ -void QueryAnalyzer::qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - /// Build additional column qualification parts array - std::vector additional_column_qualification_parts; - - if (table_expression_node->hasAlias()) - additional_column_qualification_parts = {table_expression_node->getAlias()}; - else if (auto * table_node = table_expression_node->as()) - additional_column_qualification_parts = {table_node->getStorageID().getDatabaseName(), table_node->getStorageID().getTableName()}; - - size_t additional_column_qualification_parts_size = additional_column_qualification_parts.size(); - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - /** For each matched column node iterate over additional column qualifications and apply them if column needs to be qualified. - * To check if column needs to be qualified we check if column name can bind to any other table expression in scope or to scope aliases. - */ - std::vector column_qualified_identifier_parts; - - for (const auto & column_node : column_nodes) - { - const auto & column_name = column_node->as().getColumnName(); - column_qualified_identifier_parts = Identifier(column_name).getParts(); - - /// Iterate over additional column qualifications and apply them if needed - for (size_t i = 0; i < additional_column_qualification_parts_size; ++i) - { - auto identifier_to_check = Identifier(column_qualified_identifier_parts); - IdentifierLookup identifier_lookup{identifier_to_check, IdentifierLookupContext::EXPRESSION}; - bool need_to_qualify = table_expression_data.should_qualify_columns; - if (need_to_qualify) - need_to_qualify = tryBindIdentifierToTableExpressions(identifier_lookup, table_expression_node, scope); - - if (tryBindIdentifierToAliases(identifier_lookup, scope)) - need_to_qualify = true; - - if (need_to_qualify) - { - /** Add last qualification part that was not used into column qualified identifier. - * If additional column qualification parts consists from [database_name, table_name]. - * On first iteration if column is needed to be qualified to qualify it with table_name. - * On second iteration if column is needed to be qualified to qualify it with database_name. - */ - size_t part_index_to_use_for_qualification = additional_column_qualification_parts_size - i - 1; - const auto & part_to_use = additional_column_qualification_parts[part_index_to_use_for_qualification]; - column_qualified_identifier_parts.insert(column_qualified_identifier_parts.begin(), part_to_use); - } - else - { - break; - } - } - - auto qualified_node_name = Identifier(column_qualified_identifier_parts).getFullName(); - node_to_projection_name.emplace(column_node, qualified_node_name); - } -} - -/// Build get columns options for matcher -GetColumnsOptions QueryAnalyzer::buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context) -{ - auto & matcher_node_typed = matcher_node->as(); - UInt8 get_columns_options_kind = GetColumnsOptions::AllPhysicalAndAliases; - - if (matcher_node_typed.isAsteriskMatcher()) - { - get_columns_options_kind = GetColumnsOptions::Ordinary; - - const auto & settings = context->getSettingsRef(); - - if (settings.asterisk_include_alias_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Aliases; - - if (settings.asterisk_include_materialized_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Materialized; - } - - return GetColumnsOptions(static_cast(get_columns_options_kind)); -} - -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - /** Use resolved columns from table expression data in nearest query scope if available. - * It is important for ALIAS columns to use column nodes with resolved ALIAS expression. - */ - const TableExpressionData * table_expression_data = nullptr; - const auto * nearest_query_scope = scope.getNearestQueryScope(); - if (nearest_query_scope) - table_expression_data = &nearest_query_scope->getTableExpressionDataOrThrow(table_expression_node); - - QueryTreeNodes matched_column_nodes; - - for (const auto & column : matched_columns) - { - const auto & column_name = column.name; - if (!matcher_node_typed.isMatchingColumn(column_name)) - continue; - - if (table_expression_data) - { - auto column_node_it = table_expression_data->column_name_to_column_node.find(column_name); - if (column_node_it != table_expression_data->column_name_to_column_node.end()) - { - matched_column_nodes.emplace_back(column_node_it->second); - continue; - } - } - - matched_column_nodes.emplace_back(std::make_shared(column, table_expression_node)); - } - - const auto & qualify_matched_column_nodes_scope = nearest_query_scope ? *nearest_query_scope : scope; - qualifyColumnNodesWithProjectionNames(matched_column_nodes, table_expression_node, qualify_matched_column_nodes_scope); - - QueryAnalyzer::QueryTreeNodesWithNames matched_column_nodes_with_names; - matched_column_nodes_with_names.reserve(matched_column_nodes.size()); - - for (auto && matched_column_node : matched_column_nodes) - { - auto column_name = matched_column_node->as().getColumnName(); - matched_column_nodes_with_names.emplace_back(std::move(matched_column_node), std::move(column_name)); - } - - return matched_column_nodes_with_names; -} - -bool hasTableExpressionInJoinTree(const QueryTreeNodePtr & join_tree_node, const QueryTreeNodePtr & table_expression) -{ - QueryTreeNodes nodes_to_process; - nodes_to_process.push_back(join_tree_node); - - while (!nodes_to_process.empty()) - { - auto node_to_process = std::move(nodes_to_process.back()); - nodes_to_process.pop_back(); - if (node_to_process == table_expression) - return true; - - if (node_to_process->getNodeType() == QueryTreeNodeType::JOIN) - { - const auto & join_node = node_to_process->as(); - nodes_to_process.push_back(join_node.getLeftTableExpression()); - nodes_to_process.push_back(join_node.getRightTableExpression()); - } - } - return false; -} - -/// Columns that resolved from matcher can also match columns from JOIN USING. -/// In that case we update type to type of column in USING section. -/// TODO: It's not completely correct for qualified matchers, so t1.* should be resolved to left table column type. -/// But in planner we do not distinguish such cases. -void QueryAnalyzer::updateMatchedColumnsFromJoinUsing( - QueryTreeNodesWithNames & result_matched_column_nodes_with_names, - const QueryTreeNodePtr & source_table_expression, - IdentifierResolveScope & scope) -{ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "There are no table sources. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - const auto & join_tree = nearest_query_scope_query_node->getJoinTree(); - - const auto * join_node = join_tree->as(); - if (join_node && join_node->isUsingJoinExpression()) - { - const auto & join_using_list = join_node->getJoinExpression()->as(); - const auto & join_using_nodes = join_using_list.getNodes(); - - for (auto & [matched_column_node, _] : result_matched_column_nodes_with_names) - { - auto & matched_column_node_typed = matched_column_node->as(); - const auto & matched_column_name = matched_column_node_typed.getColumnName(); - - for (const auto & join_using_node : join_using_nodes) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (matched_column_name != join_using_column_name) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - auto it = node_to_projection_name.find(matched_column_node); - - if (hasTableExpressionInJoinTree(join_node->getLeftTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(0); - else if (hasTableExpressionInJoinTree(join_node->getRightTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(1); - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Cannot find column {} in JOIN USING section {}", - matched_column_node->dumpTree(), join_node->dumpTree()); - - matched_column_node = matched_column_node->clone(); - if (it != node_to_projection_name.end()) - node_to_projection_name.emplace(matched_column_node, it->second); - - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - } - } - } -} - -/** Resolve qualified tree matcher. - * - * First try to match qualified identifier to expression. If qualified identifier matched expression node then - * if expression is compound match it column names using matcher `isMatchingColumn` method, if expression is not compound, throw exception. - * If qualified identifier did not match expression in query tree, try to lookup qualified identifier in table context. - */ -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isQualified()); - - auto expression_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::EXPRESSION}; - auto expression_identifier_resolve_result = tryResolveIdentifier(expression_identifier_lookup, scope); - auto expression_query_tree_node = expression_identifier_resolve_result.resolved_identifier; - - /// Try to resolve unqualified matcher for query expression - - if (expression_query_tree_node) - { - auto result_type = expression_query_tree_node->getResultType(); - - while (true) - { - if (const auto * array_type = typeid_cast(result_type.get())) - result_type = array_type->getNestedType(); - else if (const auto * map_type = typeid_cast(result_type.get())) - result_type = map_type->getNestedType(); - else - break; - } - - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Qualified matcher {} find non compound expression {} with type {}. Expected tuple or array of tuples. In scope {}", - matcher_node->formatASTForErrorMessage(), - expression_query_tree_node->formatASTForErrorMessage(), - expression_query_tree_node->getResultType()->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - auto qualified_matcher_element_identifier = matcher_node_typed.getQualifiedIdentifier(); - for (const auto & element_name : element_names) - { - if (!matcher_node_typed.isMatchingColumn(element_name)) - continue; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back(expression_query_tree_node); - get_subcolumn_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - qualified_matcher_element_identifier.push_back(element_name); - node_to_projection_name.emplace(function_query_node, qualified_matcher_element_identifier.getFullName()); - qualified_matcher_element_identifier.pop_back(); - - matched_expression_nodes_with_column_names.emplace_back(std::move(function_query_node), element_name); - } - - return matched_expression_nodes_with_column_names; - } - - /// Try to resolve qualified matcher for table expression - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_cte = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - auto table_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, identifier_resolve_settings); - auto table_expression_node = table_identifier_resolve_result.resolved_identifier; - - if (!table_expression_node) - { - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Qualified matcher {} does not find table. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - NamesAndTypes matched_columns; - - auto * table_expression_query_node = table_expression_node->as(); - auto * table_expression_union_node = table_expression_node->as(); - auto * table_expression_table_node = table_expression_node->as(); - auto * table_expression_table_function_node = table_expression_node->as(); - - if (table_expression_query_node || table_expression_union_node) - { - matched_columns = table_expression_query_node ? table_expression_query_node->getProjectionColumns() - : table_expression_union_node->computeProjectionColumns(); - } - else if (table_expression_table_node || table_expression_table_function_node) - { - const auto & storage_snapshot = table_expression_table_node ? table_expression_table_node->getStorageSnapshot() - : table_expression_table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - matched_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Invalid table expression node {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto result_matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression_node, - matched_columns, - scope); - - updateMatchedColumnsFromJoinUsing(result_matched_column_nodes_with_names, table_expression_node, scope); - - return result_matched_column_nodes_with_names; -} - -/// Resolve non qualified matcher, using scope join tree node. -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isUnqualified()); - - /** There can be edge case if matcher is inside lambda expression. - * Try to find parent query expression using parent scopes. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unqualified matcher {} cannot be resolved. There are no table sources. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** For unqualifited matcher resolve we build table expressions stack from JOIN tree and then process it. - * For table, table function, query, union table expressions add matched columns into table expressions columns stack. - * For array join continue processing. - * For join node combine last left and right table expressions columns on stack together. It is important that if JOIN has USING - * we must add USING columns before combining left and right table expressions columns. Columns from left and right table - * expressions that have same names as columns in USING clause must be skipped. - */ - - auto table_expressions_stack = buildTableExpressionsStack(nearest_query_scope_query_node->getJoinTree()); - std::vector table_expressions_column_nodes_with_names_stack; - - std::unordered_set table_expression_column_names_to_skip; - - QueryTreeNodesWithNames result; - - if (matcher_node_typed.getMatcherType() == MatcherNodeType::COLUMNS_LIST) - { - auto identifiers = matcher_node_typed.getColumnsIdentifiers(); - result.reserve(identifiers.size()); - - for (const auto & identifier : identifiers) - { - auto resolve_result = tryResolveIdentifier(IdentifierLookup{identifier, IdentifierLookupContext::EXPRESSION}, scope); - if (!resolve_result.isResolved()) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Unknown identifier '{}' inside COLUMNS matcher. In scope {}", - identifier.getFullName(), scope.dump()); - - // TODO: Introduce IdentifierLookupContext::COLUMN and get rid of this check - auto * resolved_column = resolve_result.resolved_identifier->as(); - if (!resolved_column) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier '{}' inside COLUMNS matcher must resolve into a column, but got {}. In scope {}", - identifier.getFullName(), - resolve_result.resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - result.emplace_back(resolve_result.resolved_identifier, resolved_column->getColumnName()); - } - return result; - } - - result.resize(matcher_node_typed.getColumnsIdentifiers().size()); - - for (auto & table_expression : table_expressions_stack) - { - bool table_expression_in_resolve_process = nearest_query_scope->table_expressions_in_resolve_process.contains(table_expression.get()); - - if (auto * array_join_node = table_expression->as()) - { - if (table_expressions_column_nodes_with_names_stack.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 1 table expressions on stack before ARRAY JOIN processing"); - - if (table_expression_in_resolve_process) - continue; - - auto & table_expression_column_nodes_with_names = table_expressions_column_nodes_with_names_stack.back(); - - for (auto & [table_expression_column_node, _] : table_expression_column_nodes_with_names) - { - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(table_expression_column_node, - table_expression, - scope); - if (array_join_resolved_expression) - table_expression_column_node = std::move(array_join_resolved_expression); - } - - continue; - } - - auto * join_node = table_expression->as(); - - if (join_node) - { - size_t table_expressions_column_nodes_with_names_stack_size = table_expressions_column_nodes_with_names_stack.size(); - if (table_expressions_column_nodes_with_names_stack_size < 2) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 2 table expressions on stack before JOIN processing. Actual {}", - table_expressions_column_nodes_with_names_stack_size); - - auto right_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - auto left_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - table_expression_column_names_to_skip.clear(); - - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - /** If there is JOIN with USING we need to match only single USING column and do not use left table expression - * and right table expression column with same name. - * - * Example: SELECT id FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING (id); - */ - if (!table_expression_in_resolve_process && join_node->isUsingJoinExpression()) - { - auto & join_using_list = join_node->getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (!matcher_node_typed.isMatchingColumn(join_using_column_name)) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - /** If column doesn't exists in the table, then do not match column from USING clause. - * Example: SELECT a + 1 AS id, * FROM (SELECT 1 AS a) AS t1 JOIN (SELECT 2 AS id) AS t2 USING (id); - * In this case `id` is not present in the left table expression, - * so asterisk should return `id` from the right table expression. - */ - auto is_column_from_parent_scope = [&scope](const QueryTreeNodePtr & using_node_from_table) - { - const auto & using_column_from_table = using_node_from_table->as(); - auto table_expression_data_it = scope.table_expression_node_to_data.find(using_column_from_table.getColumnSource()); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - { - const auto & table_expression_data = table_expression_data_it->second; - const auto & column_name = using_column_from_table.getColumnName(); - return !table_expression_data.column_name_to_column_node.contains(column_name); - } - return false; - }; - - if (is_column_from_parent_scope(join_using_column_nodes.at(0)) || - is_column_from_parent_scope(join_using_column_nodes.at(1))) - continue; - - QueryTreeNodePtr matched_column_node; - - if (isRight(join_node->getKind())) - matched_column_node = join_using_column_nodes.at(1); - else - matched_column_node = join_using_column_nodes.at(0); - - matched_column_node = matched_column_node->clone(); - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - - table_expression_column_names_to_skip.insert(join_using_column_name); - matched_expression_nodes_with_column_names.emplace_back(std::move(matched_column_node), join_using_column_name); - } - } - - for (auto && left_table_column_with_name : left_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(left_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(left_table_column_with_name)); - } - - for (auto && right_table_column_with_name : right_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(right_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(right_table_column_with_name)); - } - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_expression_nodes_with_column_names)); - continue; - } - - if (table_expression_in_resolve_process) - { - table_expressions_column_nodes_with_names_stack.emplace_back(); - continue; - } - - auto * table_node = table_expression->as(); - auto * table_function_node = table_expression->as(); - auto * query_node = table_expression->as(); - auto * union_node = table_expression->as(); - - NamesAndTypes table_expression_columns; - - if (query_node || union_node) - { - table_expression_columns = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - } - else if (table_node || table_function_node) - { - const auto & storage_snapshot - = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - table_expression_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unqualified matcher {} resolve unexpected table expression. In scope {}", - matcher_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression, - table_expression_columns, - scope); - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_column_nodes_with_names)); - } - - for (auto & table_expression_column_nodes_with_names : table_expressions_column_nodes_with_names_stack) - { - for (auto && table_expression_column_node_with_name : table_expression_column_nodes_with_names) - result.push_back(std::move(table_expression_column_node_with_name)); - } - - return result; -} - - -/** Resolve query tree matcher. Check MatcherNode.h for detailed matcher description. Check ColumnTransformers.h for detailed transformers description. - * - * 1. Populate matched expression nodes resolving qualified or unqualified matcher. - * 2. Apply column transformers to matched expression nodes. For strict column transformers save used column names. - * 3. Validate strict column transformers. - */ -ProjectionNames QueryAnalyzer::resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - QueryTreeNodesWithNames matched_expression_nodes_with_names; - - if (matcher_node_typed.isQualified()) - matched_expression_nodes_with_names = resolveQualifiedMatcher(matcher_node, scope); - else - matched_expression_nodes_with_names = resolveUnqualifiedMatcher(matcher_node, scope); - - if (scope.join_use_nulls) - { - /** If we are resolving matcher came from the result of JOIN and `join_use_nulls` is set, - * we need to convert joined column type to Nullable. - * We are taking the nearest JoinNode to check to which table column belongs, - * because for LEFT/RIGHT join, we convert only the corresponding side. - */ - const auto * nearest_query_scope = scope.getNearestQueryScope(); - const QueryNode * nearest_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - const QueryTreeNodePtr & nearest_scope_join_tree = nearest_scope_query_node ? nearest_scope_query_node->getJoinTree() : nullptr; - const JoinNode * nearest_scope_join_node = nearest_scope_join_tree ? nearest_scope_join_tree->as() : nullptr; - if (nearest_scope_join_node) - { - for (auto & [node, node_name] : matched_expression_nodes_with_names) - { - auto join_identifier_side = getColumnSideFromJoinTree(node, *nearest_scope_join_node); - auto projection_name_it = node_to_projection_name.find(node); - auto nullable_node = convertJoinedColumnTypeToNullIfNeeded(node, nearest_scope_join_node->getKind(), join_identifier_side, scope); - if (nullable_node) - { - node = nullable_node; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(node, projection_name_it->second); - } - } - } - } - } - - if (!scope.expressions_in_resolve_process_stack.hasAggregateFunction()) - { - for (auto & [node, _] : matched_expression_nodes_with_names) - { - auto it = scope.nullable_group_by_keys.find(node); - if (it != scope.nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - } - } - } - - std::unordered_map> strict_transformer_to_used_column_names; - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - auto * except_transformer = transformer->as(); - auto * replace_transformer = transformer->as(); - - if (except_transformer && except_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(except_transformer, std::unordered_set()); - else if (replace_transformer && replace_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(replace_transformer, std::unordered_set()); - } - - ListNodePtr list = std::make_shared(); - ProjectionNames result_projection_names; - ProjectionNames node_projection_names; - - for (auto & [node, column_name] : matched_expression_nodes_with_names) - { - bool apply_transformer_was_used = false; - bool replace_transformer_was_used = false; - bool execute_apply_transformer = false; - bool execute_replace_transformer = false; - - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - else - result_projection_names.push_back(column_name); - - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - if (auto * apply_transformer = transformer->as()) - { - const auto & expression_node = apply_transformer->getExpressionNode(); - apply_transformer_was_used = true; - - if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::LAMBDA) - { - auto lambda_expression_to_resolve = expression_node->clone(); - IdentifierResolveScope lambda_scope(expression_node, &scope /*parent_scope*/); - node_projection_names = resolveLambda(expression_node, lambda_expression_to_resolve, {node}, lambda_scope); - auto & lambda_expression_to_resolve_typed = lambda_expression_to_resolve->as(); - node = lambda_expression_to_resolve_typed.getExpression(); - } - else if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::FUNCTION) - { - auto function_to_resolve_untyped = expression_node->clone(); - auto & function_to_resolve_typed = function_to_resolve_untyped->as(); - function_to_resolve_typed.getArguments().getNodes().push_back(node); - node_projection_names = resolveFunction(function_to_resolve_untyped, scope); - node = function_to_resolve_untyped; - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unsupported apply matcher expression type. Expected lambda or function apply transformer. Actual {}. In scope {}", - transformer->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - execute_apply_transformer = true; - } - else if (auto * except_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - if (except_transformer->isColumnMatching(column_name)) - { - if (except_transformer->isStrict()) - strict_transformer_to_used_column_names[except_transformer].insert(column_name); - - node = {}; - break; - } - } - else if (auto * replace_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - auto replace_expression = replace_transformer->findReplacementExpression(column_name); - if (!replace_expression) - continue; - - replace_transformer_was_used = true; - - if (replace_transformer->isStrict()) - strict_transformer_to_used_column_names[replace_transformer].insert(column_name); - - node = replace_expression->clone(); - node_projection_names = resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** If replace expression resolved as single node, we want to use replace column name as result projection name, instead - * of using replace expression projection name. - * - * Example: SELECT * REPLACE id + 5 AS id FROM test_table; - */ - if (node_projection_names.size() == 1) - node_projection_names[0] = column_name; - - execute_replace_transformer = true; - } - - if (execute_apply_transformer || execute_replace_transformer) - { - if (auto * node_list = node->as()) - { - auto & node_list_nodes = node_list->getNodes(); - size_t node_list_nodes_size = node_list_nodes.size(); - - if (node_list_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "{} transformer {} resolved as list node with size {}. Expected 1. In scope {}", - execute_apply_transformer ? "APPLY" : "REPLACE", - transformer->formatASTForErrorMessage(), - node_list_nodes_size, - scope.scope_node->formatASTForErrorMessage()); - - node = node_list_nodes[0]; - } - - if (node_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Matcher node expected 1 projection name. Actual {}", node_projection_names.size()); - - result_projection_names.back() = std::move(node_projection_names[0]); - node_to_projection_name.emplace(node, result_projection_names.back()); - node_projection_names.clear(); - } - } - - if (node) - list->getNodes().push_back(node); - else - result_projection_names.pop_back(); - } - - for (auto & [strict_transformer, used_column_names] : strict_transformer_to_used_column_names) - { - auto strict_transformer_type = strict_transformer->getTransformerType(); - const Names * strict_transformer_column_names = nullptr; - - switch (strict_transformer_type) - { - case ColumnTransfomerType::EXCEPT: - { - const auto * except_transformer = static_cast(strict_transformer); - const auto & except_names = except_transformer->getExceptColumnNames(); - - if (except_names.size() != used_column_names.size()) - strict_transformer_column_names = &except_transformer->getExceptColumnNames(); - - break; - } - case ColumnTransfomerType::REPLACE: - { - const auto * replace_transformer = static_cast(strict_transformer); - const auto & replacement_names = replace_transformer->getReplacementsNames(); - - if (replacement_names.size() != used_column_names.size()) - strict_transformer_column_names = &replace_transformer->getReplacementsNames(); - - break; - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected strict EXCEPT or REPLACE column transformer. Actual type {}. In scope {}", - toString(strict_transformer_type), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (!strict_transformer_column_names) - continue; - - Names non_matched_column_names; - size_t strict_transformer_column_names_size = strict_transformer_column_names->size(); - for (size_t i = 0; i < strict_transformer_column_names_size; ++i) - { - const auto & column_name = (*strict_transformer_column_names)[i]; - if (used_column_names.find(column_name) == used_column_names.end()) - non_matched_column_names.push_back(column_name); - } - - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Strict {} column transformer {} expects following column(s) : {}. In scope {}", - toString(strict_transformer_type), - strict_transformer->formatASTForErrorMessage(), - fmt::join(non_matched_column_names, ", "), - scope.scope_node->formatASTForErrorMessage()); - } - - auto original_ast = matcher_node->getOriginalAST(); - matcher_node = std::move(list); - if (original_ast) - matcher_node->setOriginalAST(original_ast); - - return result_projection_names; -} - -/** Resolve window function window node. - * - * Node can be identifier or window node. - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - * Example: SELECT count(*) OVER (PARTITION BY id); - * - * If node has parent window name specified, then parent window definition is searched in nearest query scope WINDOW section. - * If node is identifier, than node is replaced with window definition. - * If node is window, that window node is merged with parent window node. - * - * Window node PARTITION BY and ORDER BY parts are resolved. - * If window node has frame begin OFFSET or frame end OFFSET specified, they are resolved, and window node frame constants are updated. - * Window node frame is validated. - */ -ProjectionName QueryAnalyzer::resolveWindow(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - std::string parent_window_name; - auto * identifier_node = node->as(); - - ProjectionName result_projection_name; - QueryTreeNodePtr parent_window_node; - - if (identifier_node) - parent_window_name = identifier_node->getIdentifier().getFullName(); - else if (auto * window_node = node->as()) - parent_window_name = window_node->getParentWindowName(); - - if (!parent_window_name.empty()) - { - auto * nearest_query_scope = scope.getNearestQueryScope(); - - if (!nearest_query_scope) - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Window '{}' does not exist.", parent_window_name); - - auto & scope_window_name_to_window_node = nearest_query_scope->window_name_to_window_node; - - auto window_node_it = scope_window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope_window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - nearest_query_scope->scope_node->formatASTForErrorMessage()); - - parent_window_node = window_node_it->second; - - if (identifier_node) - { - node = parent_window_node->clone(); - result_projection_name = parent_window_name; - } - else - { - mergeWindowWithParentWindow(node, parent_window_node, scope); - } - } - - auto & window_node = node->as(); - window_node.setParentWindowName({}); - - ProjectionNames partition_by_projection_names = resolveExpressionNodeList(window_node.getPartitionByNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - ProjectionNames order_by_projection_names = resolveSortNodeList(window_node.getOrderByNode(), scope); - - ProjectionNames frame_begin_offset_projection_names; - ProjectionNames frame_end_offset_projection_names; - - if (window_node.hasFrameBeginOffset()) - { - frame_begin_offset_projection_names = resolveExpressionNode(window_node.getFrameBeginOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_begin_constant_node = window_node.getFrameBeginOffsetNode()->as(); - if (!window_frame_begin_constant_node || !isNativeNumber(removeNullable(window_frame_begin_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameBeginOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().begin_offset = window_frame_begin_constant_node->getValue(); - if (frame_begin_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_begin_offset_projection_names.size()); - } - - if (window_node.hasFrameEndOffset()) - { - frame_end_offset_projection_names = resolveExpressionNode(window_node.getFrameEndOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_end_constant_node = window_node.getFrameEndOffsetNode()->as(); - if (!window_frame_end_constant_node || !isNativeNumber(removeNullable(window_frame_end_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameEndOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().end_offset = window_frame_end_constant_node->getValue(); - if (frame_end_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_end_offset_projection_names.size()); - } - - window_node.getWindowFrame().checkValid(); - - if (result_projection_name.empty()) - { - result_projection_name = calculateWindowProjectionName(node, - parent_window_node, - parent_window_name, - partition_by_projection_names, - order_by_projection_names, - frame_begin_offset_projection_names.empty() ? "" : frame_begin_offset_projection_names.front(), - frame_end_offset_projection_names.empty() ? "" : frame_end_offset_projection_names.front()); - } - - return result_projection_name; -} - -/** Resolve lambda function. - * This function modified lambda_node during resolve. It is caller responsibility to clone lambda before resolve - * if it is needed for later use. - * - * Lambda body expression result projection names is used as lambda projection names. - * - * Lambda expression can be resolved into list node. It is caller responsibility to handle it properly. - * - * lambda_node - node that must have LambdaNode type. - * lambda_node_to_resolve - lambda node to resolve that must have LambdaNode type. - * arguments - lambda arguments. - * scope - lambda scope. It is client responsibility to create it. - * - * Resolve steps: - * 1. Validate arguments. - * 2. Register lambda node in lambdas in resolve process. This is necessary to prevent recursive lambda resolving. - * 3. Initialize scope with lambda aliases. - * 4. Validate lambda argument names, and scope expressions. - * 5. Resolve lambda body expression. - * 6. Deregister lambda node from lambdas in resolve process. - */ -ProjectionNames QueryAnalyzer::resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope) -{ - auto & lambda_to_resolve = lambda_node_to_resolve->as(); - auto & lambda_arguments_nodes = lambda_to_resolve.getArguments().getNodes(); - size_t lambda_arguments_nodes_size = lambda_arguments_nodes.size(); - - /** Register lambda as being resolved, to prevent recursive lambdas resolution. - * Example: WITH (x -> x + lambda_2(x)) AS lambda_1, (x -> x + lambda_1(x)) AS lambda_2 SELECT 1; - */ - auto it = lambdas_in_resolve_process.find(lambda_node.get()); - if (it != lambdas_in_resolve_process.end()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive lambda {}. In scope {}", - lambda_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - lambdas_in_resolve_process.emplace(lambda_node.get()); - - size_t arguments_size = lambda_arguments.size(); - if (lambda_arguments_nodes_size != arguments_size) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} expect {} arguments. Actual {}. In scope {}", - lambda_to_resolve.formatASTForErrorMessage(), - lambda_arguments_nodes_size, - arguments_size, - scope.scope_node->formatASTForErrorMessage()); - - /// Initialize aliases in lambda scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - visitor.visit(lambda_to_resolve.getExpression()); - - /** Replace lambda arguments with new arguments. - * Additionally validate that there are no aliases with same name as lambda arguments. - * Arguments are registered in current scope expression_argument_name_to_node map. - */ - QueryTreeNodes lambda_new_arguments_nodes; - lambda_new_arguments_nodes.reserve(lambda_arguments_nodes_size); - - for (size_t i = 0; i < lambda_arguments_nodes_size; ++i) - { - auto & lambda_argument_node = lambda_arguments_nodes[i]; - const auto * lambda_argument_identifier = lambda_argument_node->as(); - const auto * lambda_argument_column = lambda_argument_node->as(); - if (!lambda_argument_identifier && !lambda_argument_column) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected IDENTIFIER or COLUMN as lambda argument, got {}", lambda_node->dumpTree()); - const auto & lambda_argument_name = lambda_argument_identifier ? lambda_argument_identifier->getIdentifier().getFullName() - : lambda_argument_column->getColumnName(); - - bool has_expression_node = scope.aliases.alias_name_to_expression_node->contains(lambda_argument_name); - bool has_alias_node = scope.aliases.alias_name_to_lambda_node.contains(lambda_argument_name); - - if (has_expression_node || has_alias_node) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Alias name '{}' inside lambda {} cannot have same name as lambda argument. In scope {}", - lambda_argument_name, - lambda_argument_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - scope.expression_argument_name_to_node.emplace(lambda_argument_name, lambda_arguments[i]); - lambda_new_arguments_nodes.push_back(lambda_arguments[i]); - } - - lambda_to_resolve.getArguments().getNodes() = std::move(lambda_new_arguments_nodes); - - /// Lambda body expression is resolved as standard query expression node. - auto result_projection_names = resolveExpressionNode(lambda_to_resolve.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - lambdas_in_resolve_process.erase(lambda_node.get()); - - return result_projection_names; -} - -namespace -{ -void checkFunctionNodeHasEmptyNullsAction(FunctionNode const & node) -{ - if (node.getNullsAction() != NullsAction::EMPTY) - throw Exception( - ErrorCodes::SYNTAX_ERROR, - "Function with name '{}' cannot use {} NULLS", - node.getFunctionName(), - node.getNullsAction() == NullsAction::IGNORE_NULLS ? "IGNORE" : "RESPECT"); -} -} - -/** Resolve function node in scope. - * During function node resolve, function node can be replaced with another expression (if it match lambda or sql user defined function), - * with constant (if it allow constant folding), or with expression list. It is caller responsibility to handle such cases appropriately. - * - * Steps: - * 1. Resolve function parameters. Validate that each function parameter must be constant node. - * 2. Try to lookup function as lambda in current scope. If it is lambda we can skip `in` and `count` special handling. - * 3. If function is count function, that take unqualified ASTERISK matcher, remove it from its arguments. Example: SELECT count(*) FROM test_table; - * 4. If function is `IN` function, then right part of `IN` function is replaced as subquery. - * 5. Resolve function arguments list, lambda expressions are allowed as function arguments. - * For `IN` function table expressions are allowed as function arguments. - * 6. Initialize argument_columns, argument_types, function_lambda_arguments_indexes arrays from function arguments. - * 7. If function name identifier was not resolved as function in current scope, try to lookup lambda from sql user defined functions factory. - * 8. If function was resolve as lambda from step 2 or 7, then resolve lambda using function arguments and replace function node with lambda result. - * After than function node is resolved. - * 9. If function was not resolved during step 6 as lambda, then try to resolve function as window function or executable user defined function - * or ordinary function or aggregate function. - * - * If function is resolved as window function or executable user defined function or aggregate function, function node is resolved - * no additional special handling is required. - * - * 8. If function was resolved as non aggregate function. Then if some of function arguments are lambda expressions, their result types need to be initialized and - * they must be resolved. - * 9. If function is suitable for constant folding, try to perform constant folding for function node. - */ -ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - FunctionNodePtr function_node_ptr = std::static_pointer_cast(node); - auto function_name = function_node_ptr->getFunctionName(); - - /// Resolve function parameters - - auto parameters_projection_names = resolveExpressionNodeList(function_node_ptr->getParametersNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - /// Convert function parameters into constant parameters array - - Array parameters; - - auto & parameters_nodes = function_node_ptr->getParameters().getNodes(); - parameters.reserve(parameters_nodes.size()); - - for (auto & parameter_node : parameters_nodes) - { - const auto * constant_node = parameter_node->as(); - if (!constant_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parameter for function '{}' expected to have constant value. Actual {}. In scope {}", - function_name, - parameter_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - parameters.push_back(constant_node->getValue()); - } - - //// If function node is not window function try to lookup function node name as lambda identifier. - QueryTreeNodePtr lambda_expression_untyped; - if (!function_node_ptr->isWindowFunction()) - { - auto function_lookup_result = tryResolveIdentifier({Identifier{function_name}, IdentifierLookupContext::FUNCTION}, scope); - lambda_expression_untyped = function_lookup_result.resolved_identifier; - } - - bool is_special_function_in = false; - bool is_special_function_dict_get = false; - bool is_special_function_join_get = false; - bool is_special_function_exists = false; - bool is_special_function_if = false; - - if (!lambda_expression_untyped) - { - is_special_function_in = isNameOfInFunction(function_name); - is_special_function_dict_get = functionIsDictGet(function_name); - is_special_function_join_get = functionIsJoinGet(function_name); - is_special_function_exists = function_name == "exists"; - is_special_function_if = function_name == "if"; - - auto function_name_lowercase = Poco::toLower(function_name); - - /** Special handling for count and countState functions. - * - * Example: SELECT count(*) FROM test_table - * Example: SELECT countState(*) FROM test_table; - */ - if (function_node_ptr->getArguments().getNodes().size() == 1 && - (function_name_lowercase == "count" || function_name_lowercase == "countstate")) - { - auto * matcher_node = function_node_ptr->getArguments().getNodes().front()->as(); - if (matcher_node && matcher_node->isUnqualified()) - function_node_ptr->getArguments().getNodes().clear(); - } - } - - /** Special functions dictGet and its variations and joinGet can be executed when first argument is identifier. - * Example: SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Try to resolve identifier as expression identifier and if it is resolved use it. - * Example: WITH 'dict_name' AS identifier SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Otherwise replace identifier with identifier full name constant. - * Validation that dictionary exists or table exists will be performed during function `getReturnType` method call. - */ - if ((is_special_function_dict_get || is_special_function_join_get) && - !function_node_ptr->getArguments().getNodes().empty() && - function_node_ptr->getArguments().getNodes()[0]->getNodeType() == QueryTreeNodeType::IDENTIFIER) - { - auto & first_argument = function_node_ptr->getArguments().getNodes()[0]; - auto & first_argument_identifier = first_argument->as(); - auto identifier = first_argument_identifier.getIdentifier(); - - IdentifierLookup identifier_lookup{identifier, IdentifierLookupContext::EXPRESSION}; - auto resolve_result = tryResolveIdentifier(identifier_lookup, scope); - - if (resolve_result.isResolved()) - { - first_argument = std::move(resolve_result.resolved_identifier); - } - else - { - size_t parts_size = identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected {} function first argument identifier to contain 1 or 2 parts. Actual '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_special_function_dict_get) - { - scope.context->getExternalDictionariesLoader().assertDictionaryStructureExists(identifier.getFullName(), scope.context); - } - else - { - auto table_node = tryResolveTableIdentifierFromDatabaseCatalog(identifier, scope.context); - if (!table_node) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} first argument expected table identifier '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node_typed = table_node->as(); - if (!std::dynamic_pointer_cast(table_node_typed.getStorage())) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} table '{}' should have engine StorageJoin. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - first_argument = std::make_shared(identifier.getFullName()); - } - } - - if (is_special_function_exists) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /// Rewrite EXISTS (subquery) into 1 IN (SELECT 1 FROM (subquery) LIMIT 1). - auto & exists_subquery_argument = function_node_ptr->getArguments().getNodes().at(0); - - auto constant_data_type = std::make_shared(); - - auto in_subquery = std::make_shared(Context::createCopy(scope.context)); - in_subquery->setIsSubquery(true); - in_subquery->getProjection().getNodes().push_back(std::make_shared(1UL, constant_data_type)); - in_subquery->getJoinTree() = exists_subquery_argument; - in_subquery->getLimit() = std::make_shared(1UL, constant_data_type); - - function_node_ptr = std::make_shared("in"); - function_node_ptr->getArguments().getNodes() = {std::make_shared(1UL, constant_data_type), in_subquery}; - node = function_node_ptr; - function_name = "in"; - is_special_function_in = true; - } - - if (is_special_function_if && !function_node_ptr->getArguments().getNodes().empty()) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /** Handle special case with constant If function, even if some of the arguments are invalid. - * - * SELECT if(hasColumnInTable('system', 'numbers', 'not_existing_column'), not_existing_column, 5) FROM system.numbers; - */ - auto & if_function_arguments = function_node_ptr->getArguments().getNodes(); - auto if_function_condition = if_function_arguments[0]; - resolveExpressionNode(if_function_condition, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto constant_condition = tryExtractConstantFromConditionNode(if_function_condition); - - if (constant_condition.has_value() && if_function_arguments.size() == 3) - { - QueryTreeNodePtr constant_if_result_node; - QueryTreeNodePtr possibly_invalid_argument_node; - - if (*constant_condition) - { - possibly_invalid_argument_node = if_function_arguments[2]; - constant_if_result_node = if_function_arguments[1]; - } - else - { - possibly_invalid_argument_node = if_function_arguments[1]; - constant_if_result_node = if_function_arguments[2]; - } - - bool apply_constant_if_optimization = false; - - try - { - resolveExpressionNode(possibly_invalid_argument_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - } - catch (...) - { - apply_constant_if_optimization = true; - } - - if (apply_constant_if_optimization) - { - auto result_projection_names = resolveExpressionNode(constant_if_result_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - node = std::move(constant_if_result_node); - return result_projection_names; - } - } - } - - /// Resolve function arguments - bool allow_table_expressions = is_special_function_in; - auto arguments_projection_names = resolveExpressionNodeList(function_node_ptr->getArgumentsNode(), - scope, - true /*allow_lambda_expression*/, - allow_table_expressions /*allow_table_expression*/); - - /// Mask arguments if needed - if (!scope.context->getSettingsRef().format_display_secrets_in_show_and_select) - { - if (FunctionSecretArgumentsFinder::Result secret_arguments = FunctionSecretArgumentsFinderTreeNode(*function_node_ptr).getResult(); secret_arguments.count) - { - auto & argument_nodes = function_node_ptr->getArgumentsNode()->as().getNodes(); - - for (size_t n = secret_arguments.start; n < secret_arguments.start + secret_arguments.count; ++n) - { - if (auto * constant = argument_nodes[n]->as()) - { - auto mask = scope.projection_mask_map->insert({constant->getTreeHash(), scope.projection_mask_map->size() + 1}).first->second; - constant->setMaskId(mask); - arguments_projection_names[n] = "[HIDDEN id: " + std::to_string(mask) + "]"; - } - } - } - } - - auto & function_node = *function_node_ptr; - - /// Replace right IN function argument if it is table or table function with subquery that read ordinary columns - if (is_special_function_in) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - if (scope.context->getSettingsRef().transform_null_in) - { - static constexpr std::array, 4> in_function_to_replace_null_in_function_map = - {{ - {"in", "nullIn"}, - {"notIn", "notNullIn"}, - {"globalIn", "globalNullIn"}, - {"globalNotIn", "globalNotNullIn"}, - }}; - - for (const auto & [in_function_name, in_function_name_to_replace] : in_function_to_replace_null_in_function_map) - { - if (function_name == in_function_name) - { - function_name = in_function_name_to_replace; - break; - } - } - } - - auto & function_in_arguments_nodes = function_node.getArguments().getNodes(); - if (function_in_arguments_nodes.size() != 2) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function '{}' expects 2 arguments", function_name); - - auto & in_second_argument = function_in_arguments_nodes[1]; - auto * table_node = in_second_argument->as(); - auto * table_function_node = in_second_argument->as(); - - if (table_node) - { - /// If table is already prepared set, we do not replace it with subquery. - /// If table is not a StorageSet, we'll create plan to build set in the Planner. - } - else if (table_function_node) - { - const auto & storage_snapshot = table_function_node->getStorageSnapshot(); - auto columns_to_select = storage_snapshot->getColumns(GetColumnsOptions(GetColumnsOptions::Ordinary)); - - size_t columns_to_select_size = columns_to_select.size(); - - auto column_nodes_to_select = std::make_shared(); - column_nodes_to_select->getNodes().reserve(columns_to_select_size); - - NamesAndTypes projection_columns; - projection_columns.reserve(columns_to_select_size); - - for (auto & column : columns_to_select) - { - column_nodes_to_select->getNodes().emplace_back(std::make_shared(column, in_second_argument)); - projection_columns.emplace_back(column.name, column.type); - } - - auto in_second_argument_query_node = std::make_shared(Context::createCopy(scope.context)); - in_second_argument_query_node->setIsSubquery(true); - in_second_argument_query_node->getProjectionNode() = std::move(column_nodes_to_select); - in_second_argument_query_node->getJoinTree() = std::move(in_second_argument); - in_second_argument_query_node->resolveProjectionColumns(std::move(projection_columns)); - - in_second_argument = std::move(in_second_argument_query_node); - } - else - { - /// Replace storage with values storage of insertion block - if (StoragePtr storage = scope.context->getViewSource()) - { - QueryTreeNodePtr table_expression; - /// Process possibly nested sub-selects - for (auto * query_node = in_second_argument->as(); query_node; query_node = table_expression->as()) - table_expression = extractLeftTableExpression(query_node->getJoinTree()); - - if (table_expression) - { - if (auto * query_table_node = table_expression->as()) - { - if (query_table_node->getStorageID().getFullNameNotQuoted() == storage->getStorageID().getFullNameNotQuoted()) - { - auto replacement_table_expression = std::make_shared(storage, scope.context); - if (std::optional table_expression_modifiers = query_table_node->getTableExpressionModifiers()) - replacement_table_expression->setTableExpressionModifiers(*table_expression_modifiers); - in_second_argument = in_second_argument->cloneAndReplace(table_expression, std::move(replacement_table_expression)); - } - } - } - } - - resolveExpressionNode(in_second_argument, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - } - } - - /// Initialize function argument columns - - ColumnsWithTypeAndName argument_columns; - DataTypes argument_types; - bool all_arguments_constants = true; - std::vector function_lambda_arguments_indexes; - - auto & function_arguments = function_node.getArguments().getNodes(); - size_t function_arguments_size = function_arguments.size(); - - for (size_t function_argument_index = 0; function_argument_index < function_arguments_size; ++function_argument_index) - { - auto & function_argument = function_arguments[function_argument_index]; - - ColumnWithTypeAndName argument_column; - argument_column.name = arguments_projection_names[function_argument_index]; - - /** If function argument is lambda, save lambda argument index and initialize argument type as DataTypeFunction - * where function argument types are initialized with empty array of lambda arguments size. - */ - if (const auto * lambda_node = function_argument->as()) - { - size_t lambda_arguments_size = lambda_node->getArguments().getNodes().size(); - argument_column.type = std::make_shared(DataTypes(lambda_arguments_size, nullptr), nullptr); - function_lambda_arguments_indexes.push_back(function_argument_index); - } - else if (is_special_function_in && function_argument_index == 1) - { - argument_column.type = std::make_shared(); - } - else - { - argument_column.type = function_argument->getResultType(); - } - - if (!argument_column.type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' argument is not resolved. In scope {}", - function_name, - scope.scope_node->formatASTForErrorMessage()); - - bool argument_is_constant = false; - const auto * constant_node = function_argument->as(); - if (constant_node) - { - argument_column.column = constant_node->getResultType()->createColumnConst(1, constant_node->getValue()); - argument_column.type = constant_node->getResultType(); - argument_is_constant = true; - } - else if (const auto * get_scalar_function_node = function_argument->as(); - get_scalar_function_node && get_scalar_function_node->getFunctionName() == "__getScalar") - { - /// Allow constant folding through getScalar - const auto * get_scalar_const_arg = get_scalar_function_node->getArguments().getNodes().at(0)->as(); - if (get_scalar_const_arg && scope.context->hasQueryContext()) - { - auto query_context = scope.context->getQueryContext(); - auto scalar_string = toString(get_scalar_const_arg->getValue()); - if (query_context->hasScalar(scalar_string)) - { - auto scalar = query_context->getScalar(scalar_string); - argument_column.column = ColumnConst::create(scalar.getByPosition(0).column, 1); - argument_column.type = get_scalar_function_node->getResultType(); - argument_is_constant = true; - } - } - } - - all_arguments_constants &= argument_is_constant; - - argument_types.push_back(argument_column.type); - argument_columns.emplace_back(std::move(argument_column)); - } - - /// Calculate function projection name - ProjectionNames result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - - /** Try to resolve function as - * 1. Lambda function in current scope. Example: WITH (x -> x + 1) AS lambda SELECT lambda(1); - * 2. Lambda function from sql user defined functions. - * 3. Special `untuple` function. - * 4. Special `grouping` function. - * 5. Window function. - * 6. Executable user defined function. - * 7. Ordinary function. - * 8. Aggregate function. - * - * TODO: Provide better error hints. - */ - if (!function_node.isWindowFunction()) - { - if (!lambda_expression_untyped) - lambda_expression_untyped = tryGetLambdaFromSQLUserDefinedFunctions(function_node.getFunctionName(), scope.context); - - /** If function is resolved as lambda. - * Clone lambda before resolve. - * Initialize lambda arguments as function arguments. - * Resolve lambda and then replace function node with resolved lambda expression body. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(value) FROM test_table; - * Result: SELECT value + 1 FROM test_table; - */ - if (lambda_expression_untyped) - { - auto * lambda_expression = lambda_expression_untyped->as(); - if (!lambda_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function identifier '{}' must be resolved as lambda. Actual {}. In scope {}", - function_node.getFunctionName(), - lambda_expression_untyped->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - if (!parameters.empty()) - { - throw Exception( - ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_node.formatASTForErrorMessage()); - } - - auto lambda_expression_clone = lambda_expression_untyped->clone(); - - IdentifierResolveScope lambda_scope(lambda_expression_clone, &scope /*parent_scope*/); - ProjectionNames lambda_projection_names = resolveLambda(lambda_expression_untyped, lambda_expression_clone, function_arguments, lambda_scope); - - auto & resolved_lambda = lambda_expression_clone->as(); - node = resolved_lambda.getExpression(); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(lambda_projection_names); - - return result_projection_names; - } - - if (function_name == "untuple") - { - /// Special handling of `untuple` function - - if (function_arguments.size() != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' must have 1 argument. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - const auto & untuple_argument = function_arguments[0]; - /// Handle this special case first as `getResultType()` might return nullptr - if (untuple_argument->as()) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Function untuple can't have lambda-expressions as arguments"); - - auto result_type = untuple_argument->getResultType(); - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' argument must have compound type. Actual type {}. In scope {}", - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - - auto result_list = std::make_shared(); - result_list->getNodes().reserve(element_names.size()); - - for (const auto & element_name : element_names) - { - auto tuple_element_function = std::make_shared("tupleElement"); - tuple_element_function->getArguments().getNodes().push_back(untuple_argument); - tuple_element_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = tuple_element_function; - resolveFunction(function_query_node, scope); - - result_list->getNodes().push_back(std::move(function_query_node)); - } - - auto untuple_argument_projection_name = arguments_projection_names.at(0); - result_projection_names.clear(); - - for (const auto & element_name : element_names) - { - if (node->hasAlias()) - result_projection_names.push_back(node->getAlias() + '.' + element_name); - else - result_projection_names.push_back(fmt::format("tupleElement({}, '{}')", untuple_argument_projection_name, element_name)); - } - - node = std::move(result_list); - return result_projection_names; - } - else if (function_name == "grouping") - { - /// It is responsibility of planner to perform additional handling of grouping function - if (function_arguments_size == 0) - throw Exception(ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING expects at least one argument"); - else if (function_arguments_size > 64) - throw Exception(ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING can have up to 64 arguments, but {} provided", - function_arguments_size); - checkFunctionNodeHasEmptyNullsAction(function_node); - - bool force_grouping_standard_compatibility = scope.context->getSettingsRef().force_grouping_standard_compatibility; - auto grouping_function = std::make_shared(force_grouping_standard_compatibility); - auto grouping_function_adaptor = std::make_shared(std::move(grouping_function)); - function_node.resolveAsFunction(grouping_function_adaptor->build(argument_columns)); - - return result_projection_names; - } - } - - if (function_node.isWindowFunction()) - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - throw Exception(ErrorCodes::UNKNOWN_AGGREGATE_FUNCTION, "Aggregate function with name '{}' does not exist. In scope {}{}", - function_name, scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(AggregateFunctionFactory::instance().getHints(function_name))); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Window function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsWindowFunction(std::move(aggregate_function)); - - bool window_node_is_identifier = function_node.getWindowNode()->getNodeType() == QueryTreeNodeType::IDENTIFIER; - ProjectionName window_projection_name = resolveWindow(function_node.getWindowNode(), scope); - - if (window_node_is_identifier) - result_projection_names[0] += " OVER " + window_projection_name; - else - result_projection_names[0] += " OVER (" + window_projection_name + ')'; - - return result_projection_names; - } - - FunctionOverloadResolverPtr function = UserDefinedExecutableFunctionFactory::instance().tryGet(function_name, scope.context, parameters); /// NOLINT(readability-static-accessed-through-instance) - bool is_executable_udf = true; - - IdentifierResolveScope::ResolvedFunctionsCache * function_cache = nullptr; - - if (!function) - { - /// This is a hack to allow a query like `select randConstant(), randConstant(), randConstant()`. - /// Function randConstant() would return the same value for the same arguments (in scope). - - auto hash = function_node_ptr->getTreeHash(); - function_cache = &scope.functions_cache[hash]; - if (!function_cache->resolver) - function_cache->resolver = FunctionFactory::instance().tryGet(function_name, scope.context); - - function = function_cache->resolver; - - is_executable_udf = false; - } - - if (function) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - } - else - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - std::vector possible_function_names; - - auto function_names = UserDefinedExecutableFunctionFactory::instance().getRegisteredNames(scope.context); /// NOLINT(readability-static-accessed-through-instance) - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = UserDefinedSQLFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = FunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = AggregateFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - for (auto & [name, lambda_node] : scope.aliases.alias_name_to_lambda_node) - { - if (lambda_node->getNodeType() == QueryTreeNodeType::LAMBDA) - possible_function_names.push_back(name); - } - - auto hints = NamePrompter<2>::getHints(function_name, possible_function_names); - - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Function with name '{}' does not exist. In scope {}{}", - function_name, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Aggregate function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsAggregateFunction(std::move(aggregate_function)); - - return result_projection_names; - } - - /// Executable UDFs may have parameters. They are checked in UserDefinedExecutableFunctionFactory. - if (!parameters.empty() && !is_executable_udf) - { - throw Exception(ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_name); - } - - /** For lambda arguments we need to initialize lambda argument types DataTypeFunction using `getLambdaArgumentTypes` function. - * Then each lambda arguments are initialized with columns, where column source is lambda. - * This information is important for later steps of query processing. - * Example: SELECT arrayMap(x -> x + 1, [1, 2, 3]). - * lambda node x -> x + 1 identifier x is resolved as column where source is lambda node. - */ - bool has_lambda_arguments = !function_lambda_arguments_indexes.empty(); - if (has_lambda_arguments) - { - function->getLambdaArgumentTypes(argument_types); - - ProjectionNames lambda_projection_names; - for (auto & function_lambda_argument_index : function_lambda_arguments_indexes) - { - auto & lambda_argument = function_arguments[function_lambda_argument_index]; - auto lambda_to_resolve = lambda_argument->clone(); - auto & lambda_to_resolve_typed = lambda_to_resolve->as(); - - const auto & lambda_argument_names = lambda_to_resolve_typed.getArgumentNames(); - size_t lambda_arguments_size = lambda_to_resolve_typed.getArguments().getNodes().size(); - - const auto * function_data_type = typeid_cast(argument_types[function_lambda_argument_index].get()); - if (!function_data_type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' expected function data type for lambda argument with index {}. Actual {}. In scope {}", - function_name, - function_lambda_argument_index, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & function_data_type_argument_types = function_data_type->getArgumentTypes(); - size_t function_data_type_arguments_size = function_data_type_argument_types.size(); - if (function_data_type_arguments_size != lambda_arguments_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}" - "' function data type for lambda argument with index {} arguments size mismatch. " - "Actual {}. Expected {}. In scope {}", - function_name, - function_data_type_arguments_size, - lambda_arguments_size, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - QueryTreeNodes lambda_arguments; - lambda_arguments.reserve(lambda_arguments_size); - - for (size_t i = 0; i < lambda_arguments_size; ++i) - { - const auto & argument_type = function_data_type_argument_types[i]; - auto column_name_and_type = NameAndTypePair{lambda_argument_names[i], argument_type}; - lambda_arguments.push_back(std::make_shared(std::move(column_name_and_type), lambda_to_resolve)); - } - - IdentifierResolveScope lambda_scope(lambda_to_resolve, &scope /*parent_scope*/); - lambda_projection_names = resolveLambda(lambda_argument, lambda_to_resolve, lambda_arguments, lambda_scope); - - if (auto * lambda_list_node_result = lambda_to_resolve_typed.getExpression()->as()) - { - size_t lambda_list_node_result_nodes_size = lambda_list_node_result->getNodes().size(); - - if (lambda_list_node_result_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Lambda as function argument resolved as list node with size {}. Expected 1. In scope {}", - lambda_list_node_result_nodes_size, - lambda_to_resolve->formatASTForErrorMessage()); - - lambda_to_resolve_typed.getExpression() = lambda_list_node_result->getNodes().front(); - } - - if (arguments_projection_names.at(function_lambda_argument_index) == PROJECTION_NAME_PLACEHOLDER) - { - size_t lambda_projection_names_size =lambda_projection_names.size(); - if (lambda_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Lambda argument inside function expected to have 1 projection name. Actual {}", - lambda_projection_names_size); - - WriteBufferFromOwnString lambda_argument_projection_name_buffer; - lambda_argument_projection_name_buffer << "lambda("; - lambda_argument_projection_name_buffer << "tuple("; - - size_t lambda_argument_names_size = lambda_argument_names.size(); - - for (size_t i = 0; i < lambda_argument_names_size; ++i) - { - const auto & lambda_argument_name = lambda_argument_names[i]; - lambda_argument_projection_name_buffer << lambda_argument_name; - - if (i + 1 != lambda_argument_names_size) - lambda_argument_projection_name_buffer << ", "; - } - - lambda_argument_projection_name_buffer << "), "; - lambda_argument_projection_name_buffer << lambda_projection_names[0]; - lambda_argument_projection_name_buffer << ")"; - - lambda_projection_names.clear(); - - arguments_projection_names[function_lambda_argument_index] = lambda_argument_projection_name_buffer.str(); - } - - auto lambda_resolved_type = std::make_shared(function_data_type_argument_types, lambda_to_resolve_typed.getExpression()->getResultType()); - lambda_to_resolve_typed.resolve(lambda_resolved_type); - - argument_types[function_lambda_argument_index] = lambda_resolved_type; - argument_columns[function_lambda_argument_index].type = lambda_resolved_type; - function_arguments[function_lambda_argument_index] = std::move(lambda_to_resolve); - } - - /// Recalculate function projection name after lambda resolution - result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - } - - /** Create SET column for special function IN to allow constant folding - * if left and right arguments are constants. - * - * Example: SELECT * FROM test_table LIMIT 1 IN 1; - */ - if (is_special_function_in) - { - const auto * first_argument_constant_node = function_arguments[0]->as(); - const auto * second_argument_constant_node = function_arguments[1]->as(); - - if (first_argument_constant_node && second_argument_constant_node) - { - const auto & first_argument_constant_type = first_argument_constant_node->getResultType(); - const auto & second_argument_constant_literal = second_argument_constant_node->getValue(); - const auto & second_argument_constant_type = second_argument_constant_node->getResultType(); - - const auto & settings = scope.context->getSettingsRef(); - - auto result_block = getSetElementsForConstantValue(first_argument_constant_type, - second_argument_constant_literal, - second_argument_constant_type, - settings.transform_null_in); - - SizeLimits size_limits_for_set = {settings.max_rows_in_set, settings.max_bytes_in_set, settings.set_overflow_mode}; - - auto set = std::make_shared(size_limits_for_set, 0, settings.transform_null_in); - - set->setHeader(result_block.cloneEmpty().getColumnsWithTypeAndName()); - set->insertFromBlock(result_block.getColumnsWithTypeAndName()); - set->finishInsert(); - - auto future_set = std::make_shared(std::move(set)); - - /// Create constant set column for constant folding - - auto column_set = ColumnSet::create(1, std::move(future_set)); - argument_columns[1].column = ColumnConst::create(std::move(column_set), 1); - } - - argument_columns[1].type = std::make_shared(); - } - - std::shared_ptr constant_value; - - try - { - FunctionBasePtr function_base; - if (function_cache) - { - auto & cached_function = function_cache->function_base; - if (!cached_function) - cached_function = function->build(argument_columns); - - function_base = cached_function; - } - else - function_base = function->build(argument_columns); - - /// Do not constant fold get scalar functions - bool disable_constant_folding = function_name == "__getScalar" || function_name == "shardNum" || - function_name == "shardCount" || function_name == "hostName" || function_name == "tcpPort"; - - /** If function is suitable for constant folding try to convert it to constant. - * Example: SELECT plus(1, 1); - * Result: SELECT 2; - */ - if (function_base->isSuitableForConstantFolding() && !disable_constant_folding) - { - auto result_type = function_base->getResultType(); - auto executable_function = function_base->prepare(argument_columns); - - ColumnPtr column; - - if (all_arguments_constants) - { - size_t num_rows = function_arguments.empty() ? 0 : argument_columns.front().column->size(); - column = executable_function->execute(argument_columns, result_type, num_rows, true); - } - else - { - column = function_base->getConstantResultForNonConstArguments(argument_columns, result_type); - } - - if (column && column->getDataType() != result_type->getColumnType()) - throw Exception( - ErrorCodes::LOGICAL_ERROR, - "Unexpected return type from {}. Expected {}. Got {}", - function->getName(), - result_type->getColumnType(), - column->getDataType()); - - /** Do not perform constant folding if there are aggregate or arrayJoin functions inside function. - * Example: SELECT toTypeName(sum(number)) FROM numbers(10); - */ - if (column && isColumnConst(*column) && !typeid_cast(column.get())->getDataColumn().isDummy() && - !hasAggregateFunctionNodes(node) && !hasFunctionNode(node, "arrayJoin") && - /// Sanity check: do not convert large columns to constants - column->byteSize() < 1_MiB) - { - /// Replace function node with result constant node - Field column_constant_value; - column->get(0, column_constant_value); - constant_value = std::make_shared(std::move(column_constant_value), result_type); - } - } - - function_node.resolveAsFunction(std::move(function_base)); - } - catch (Exception & e) - { - e.addMessage("In scope {}", scope.scope_node->formatASTForErrorMessage()); - throw; - } - - if (constant_value) - node = std::make_shared(std::move(constant_value), node); - - return result_projection_names; -} - -/** Resolve expression node. - * Argument node can be replaced with different node, or even with list node in case of matcher resolution. - * Example: SELECT * FROM test_table; - * * - is matcher node, and it can be resolved into ListNode. - * - * Steps: - * 1. If node has alias, replace node with its value in scope alias map. Register alias in expression_aliases_in_resolve_process, to prevent resolving identifier - * which can bind to expression alias name. Check tryResolveIdentifierFromAliases documentation for additional explanation. - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * - * 2. Call specific resolve method depending on node type. - * - * If allow_table_expression = true and node is query node, then it is not evaluated as scalar subquery. - * Although if node is identifier that is resolved into query node that query is evaluated as scalar subquery. - * SELECT id, (SELECT 1) AS c FROM test_table WHERE a IN c; - * SELECT id, FROM test_table WHERE a IN (SELECT 1); - * - * 3. Special case identifier node. - * Try resolve it as expression identifier. - * Then if allow_lambda_expression = true try to resolve it as function. - * Then if allow_table_expression = true try to resolve it as table expression. - * - * 4. If node has alias, update its value in scope alias map. Deregister alias from expression_aliases_in_resolve_process. - */ -ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias) -{ - checkStackSize(); - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - /** There can be edge case, when subquery for IN function is resolved multiple times in different context. - * SELECT id IN (subquery AS value), value FROM test_table; - * When we start to resolve `value` identifier, subquery is already resolved but constant folding is not performed. - */ - auto node_type = node->getNodeType(); - if (!allow_table_expression && (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION)) - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - } - - return resolved_expression_it->second; - } - - String node_alias = node->getAlias(); - ProjectionNames result_projection_names; - - if (node_alias.empty()) - { - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - else - { - result_projection_names.push_back(node_alias); - } - - bool is_duplicated_alias = scope.aliases.nodes_with_duplicated_aliases.contains(node); - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.insert({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - /** Do not use alias table if node has alias same as some other node. - * Example: WITH x -> x + 1 AS lambda SELECT 1 AS lambda; - * During 1 AS lambda resolve if we use alias table we replace node with x -> x + 1 AS lambda. - * - * Do not use alias table if allow_table_expression = true and we resolve query node directly. - * Example: SELECT a FROM test_table WHERE id IN (SELECT 1) AS a; - * To support both (SELECT 1) AS expression in projection and (SELECT 1) as subquery in IN, do not use - * alias table because in alias table subquery could be evaluated as scalar. - */ - bool use_alias_table = !ignore_alias; - if (is_duplicated_alias || (allow_table_expression && isSubqueryNodeType(node->getNodeType()))) - use_alias_table = false; - - if (!node_alias.empty() && use_alias_table) - { - /** Node could be potentially resolved by resolving other nodes. - * SELECT b, a as b FROM test_table; - * - * To resolve b we need to resolve a. - */ - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - node = it->second; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - node = it->second; - } - } - - scope.pushExpressionNode(node); - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & identifier_node = node->as(); - auto unresolved_identifier = identifier_node.getIdentifier(); - auto resolve_identifier_expression_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier_node = resolve_identifier_expression_result.resolved_identifier; - - if (resolved_identifier_node && result_projection_names.empty() && - (resolve_identifier_expression_result.isResolvedFromJoinTree() || resolve_identifier_expression_result.isResolvedFromExpressionArguments())) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier_node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - - if (!resolved_identifier_node && allow_lambda_expression) - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::FUNCTION}, scope).resolved_identifier; - - if (!resolved_identifier_node && allow_table_expression) - { - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::TABLE_EXPRESSION}, scope).resolved_identifier; - - if (resolved_identifier_node) - { - /// If table identifier is resolved as CTE clone it and resolve - auto * subquery_node = resolved_identifier_node->as(); - auto * union_node = resolved_identifier_node->as(); - bool resolved_as_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - - if (resolved_as_cte) - { - resolved_identifier_node = resolved_identifier_node->clone(); - subquery_node = resolved_identifier_node->as(); - union_node = resolved_identifier_node->as(); - - std::string_view cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - if (subquery_node) - subquery_node->setIsCTE(false); - else - union_node->setIsCTE(false); - - IdentifierResolveScope subquery_scope(resolved_identifier_node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - /// CTE is being resolved, it's required to forbid to resolve to it again - /// because recursive CTEs are not supported, e.g.: - /// - /// WITH test1 AS (SELECT i + 1, j + 1 FROM test1) SELECT toInt64(4) i, toInt64(5) j FROM numbers(3) WHERE (i, j) IN test1; - /// - /// In this example argument of function `in` is being resolve here. If CTE `test1` is not forbidden, - /// `test1` is resolved to CTE (not to the table) in `initializeQueryJoinTreeNode` function. - ctes_in_resolve_process.insert(cte_name); - - if (subquery_node) - resolveQuery(resolved_identifier_node, subquery_scope); - else - resolveUnion(resolved_identifier_node, subquery_scope); - - ctes_in_resolve_process.erase(cte_name); - } - } - } - - if (!resolved_identifier_node) - { - std::string message_clarification; - if (allow_lambda_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::FUNCTION); - - if (allow_table_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::TABLE_EXPRESSION); - - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(unresolved_identifier, - scope, - true, - allow_lambda_expression, - allow_table_expression, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(unresolved_identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {}{} identifier '{}' in scope {}{}", - toStringLowercase(IdentifierLookupContext::EXPRESSION), - message_clarification, - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - node = std::move(resolved_identifier_node); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - { - result_projection_names.clear(); - resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - return resolved_expression_it->second; - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier '{}' resolve into list node and list node projection names are not initialized. In scope {}", - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_projection_names.empty()) - result_projection_names.push_back(unresolved_identifier.getFullName()); - - break; - } - case QueryTreeNodeType::MATCHER: - { - result_projection_names = resolveMatcher(node, scope); - break; - } - case QueryTreeNodeType::LIST: - { - /** Edge case if list expression has alias. - * Matchers cannot have aliases, but `untuple` function can. - * Example: SELECT a, untuple(CAST(('hello', 1) AS Tuple(name String, count UInt32))) AS a; - * During resolveFunction `untuple` function is replaced by list of 2 constants 'hello', 1. - */ - result_projection_names = resolveExpressionNodeList(node, scope, allow_lambda_expression, allow_lambda_expression); - break; - } - case QueryTreeNodeType::CONSTANT: - { - if (result_projection_names.empty()) - { - const auto & constant_node = node->as(); - result_projection_names.push_back(constant_node.getValueStringRepresentation()); - } - - /// Already resolved - break; - } - case QueryTreeNodeType::COLUMN: - { - auto & column_node = node->as(); - if (column_node.hasExpression()) - resolveExpressionNode(column_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (result_projection_names.empty()) - result_projection_names.push_back(column_node.getColumnName()); - - break; - } - case QueryTreeNodeType::FUNCTION: - { - auto function_projection_names = resolveFunction(node, scope); - - if (result_projection_names.empty() || node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(function_projection_names); - - break; - } - case QueryTreeNodeType::LAMBDA: - { - if (!allow_lambda_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (result_projection_names.empty()) - result_projection_names.push_back(PROJECTION_NAME_PLACEHOLDER); - - /// Lambda must be resolved by caller - break; - } - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - std::string projection_name = "_subquery_" + std::to_string(subquery_counter); - ++subquery_counter; - - if (node_type == QueryTreeNodeType::QUERY) - resolveQuery(node, subquery_scope); - else - resolveUnion(node, subquery_scope); - - if (!allow_table_expression) - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - - if (result_projection_names.empty()) - result_projection_names.push_back(std::move(projection_name)); - - break; - } - case QueryTreeNodeType::TABLE: - { - if (!allow_table_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Table {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node = node->as(); - result_projection_names.push_back(table_node.getStorageID().getFullNameNotQuoted()); - - break; - } - case QueryTreeNodeType::TRANSFORMER: - [[fallthrough]]; - case QueryTreeNodeType::SORT: - [[fallthrough]]; - case QueryTreeNodeType::INTERPOLATE: - [[fallthrough]]; - case QueryTreeNodeType::WINDOW: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::ARRAY_JOIN: - [[fallthrough]]; - case QueryTreeNodeType::JOIN: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "{} {} is not allowed in expression context. In scope {}", - node->getNodeType(), - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - validateTreeSize(node, scope.context->getSettingsRef().max_expanded_ast_elements, node_to_tree_size); - - /// Lambda can be inside the aggregate function, so we should check parent scopes. - /// Most likely only the root scope can have an arrgegate function, but let's check all just in case. - bool in_aggregate_function_scope = false; - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - in_aggregate_function_scope = in_aggregate_function_scope || scope_ptr->expressions_in_resolve_process_stack.hasAggregateFunction(); - - if (!in_aggregate_function_scope) - { - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - { - auto it = scope_ptr->nullable_group_by_keys.find(node); - if (it != scope_ptr->nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - break; - } - } - } - - /** Update aliases after expression node was resolved. - * Do not update node in alias table if we resolve it for duplicate alias. - */ - if (!node_alias.empty() && use_alias_table && !scope.group_by_use_nulls) - { - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - it->second = node; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - it->second = node; - } - } - - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.erase({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - if (!ignore_alias) - resolved_expressions.emplace(node, result_projection_names); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - return result_projection_names; -} - -/** Resolve expression node list. - * If expression is CTE subquery node it is skipped. - * If expression is resolved in list, it is flattened into initial node list. - * - * Such examples must work: - * Example: CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; SELECT plus(*) FROM test_table; - * Example: SELECT *** FROM system.one; - */ -ProjectionNames QueryAnalyzer::resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression) -{ - auto & node_list_typed = node_list->as(); - size_t node_list_size = node_list_typed.getNodes().size(); - - QueryTreeNodes result_nodes; - result_nodes.reserve(node_list_size); - - ProjectionNames result_projection_names; - - for (auto & node : node_list_typed.getNodes()) - { - auto node_to_resolve = node; - auto expression_node_projection_names = resolveExpressionNode(node_to_resolve, scope, allow_lambda_expression, allow_table_expression); - size_t expected_projection_names_size = 1; - if (auto * expression_list = node_to_resolve->as()) - { - expected_projection_names_size = expression_list->getNodes().size(); - for (auto & expression_list_node : expression_list->getNodes()) - result_nodes.push_back(expression_list_node); - } - else - { - result_nodes.push_back(std::move(node_to_resolve)); - } - - if (expression_node_projection_names.size() != expected_projection_names_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected {} projection names. Actual {}", - expected_projection_names_size, - expression_node_projection_names.size()); - - result_projection_names.insert(result_projection_names.end(), expression_node_projection_names.begin(), expression_node_projection_names.end()); - expression_node_projection_names.clear(); - } - - node_list_typed.getNodes() = std::move(result_nodes); - - return result_projection_names; -} - -/** Resolve sort columns nodes list. - */ -ProjectionNames QueryAnalyzer::resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames result_projection_names; - ProjectionNames sort_expression_projection_names; - ProjectionNames fill_from_expression_projection_names; - ProjectionNames fill_to_expression_projection_names; - ProjectionNames fill_step_expression_projection_names; - - auto & sort_node_list_typed = sort_node_list->as(); - for (auto & node : sort_node_list_typed.getNodes()) - { - auto & sort_node = node->as(); - sort_expression_projection_names = resolveExpressionNode(sort_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (auto * sort_column_list_node = sort_node.getExpression()->as()) - { - size_t sort_column_list_node_size = sort_column_list_node->getNodes().size(); - if (sort_column_list_node_size != 1) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Sort column node expression resolved into list with size {}. Expected 1. In scope {}", - sort_column_list_node_size, - scope.scope_node->formatASTForErrorMessage()); - } - - sort_node.getExpression() = sort_column_list_node->getNodes().front(); - } - - size_t sort_expression_projection_names_size = sort_expression_projection_names.size(); - if (sort_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort expression expected 1 projection name. Actual {}", - sort_expression_projection_names_size); - - if (sort_node.hasFillFrom()) - { - fill_from_expression_projection_names = resolveExpressionNode(sort_node.getFillFrom(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillFrom()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL FROM expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_from_expression_projection_names_size = fill_from_expression_projection_names.size(); - if (fill_from_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL FROM expression expected 1 projection name. Actual {}", - fill_from_expression_projection_names_size); - } - - if (sort_node.hasFillTo()) - { - fill_to_expression_projection_names = resolveExpressionNode(sort_node.getFillTo(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillTo()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL TO expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_to_expression_projection_names_size = fill_to_expression_projection_names.size(); - if (fill_to_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL TO expression expected 1 projection name. Actual {}", - fill_to_expression_projection_names_size); - } - - if (sort_node.hasFillStep()) - { - fill_step_expression_projection_names = resolveExpressionNode(sort_node.getFillStep(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillStep()->as(); - if (!constant_node) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - bool is_number = isColumnedAsNumber(constant_node->getResultType()); - bool is_interval = WhichDataType(constant_node->getResultType()).isInterval(); - if (!is_number && !is_interval) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_step_expression_projection_names_size = fill_step_expression_projection_names.size(); - if (fill_step_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort FILL STEP expression expected 1 projection name. Actual {}", - fill_step_expression_projection_names_size); - } - - auto sort_column_projection_name = calculateSortColumnProjectionName(node, - sort_expression_projection_names[0], - fill_from_expression_projection_names.empty() ? "" : fill_from_expression_projection_names.front(), - fill_to_expression_projection_names.empty() ? "" : fill_to_expression_projection_names.front(), - fill_step_expression_projection_names.empty() ? "" : fill_step_expression_projection_names.front()); - - result_projection_names.push_back(std::move(sort_column_projection_name)); - - sort_expression_projection_names.clear(); - fill_from_expression_projection_names.clear(); - fill_to_expression_projection_names.clear(); - fill_step_expression_projection_names.clear(); - } - - return result_projection_names; -} - -namespace -{ - -void expandTuplesInList(QueryTreeNodes & key_list) -{ - QueryTreeNodes expanded_keys; - expanded_keys.reserve(key_list.size()); - for (auto const & key : key_list) - { - if (auto * function = key->as(); function != nullptr && function->getFunctionName() == "tuple") - { - std::copy(function->getArguments().begin(), function->getArguments().end(), std::back_inserter(expanded_keys)); - } - else - expanded_keys.push_back(key); - } - key_list = std::move(expanded_keys); -} - -} - -/** Resolve GROUP BY clause. - */ -void QueryAnalyzer::resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope) -{ - if (query_node_typed.isGroupByWithGroupingSets()) - { - for (auto & grouping_sets_keys_list_node : query_node_typed.getGroupBy().getNodes()) - { - replaceNodesWithPositionalArguments(grouping_sets_keys_list_node, query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(grouping_sets_keys_list_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = grouping_sets_keys_list_node->as().getNodes(); - expandTuplesInList(group_by_list); - } - - if (scope.group_by_use_nulls) - { - for (const auto & grouping_set : query_node_typed.getGroupBy().getNodes()) - { - for (const auto & group_by_elem : grouping_set->as()->getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } - } - else - { - replaceNodesWithPositionalArguments(query_node_typed.getGroupByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getGroupByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = query_node_typed.getGroupBy().getNodes(); - expandTuplesInList(group_by_list); - - if (scope.group_by_use_nulls) - { - for (const auto & group_by_elem : query_node_typed.getGroupBy().getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } -} - -/** Resolve interpolate columns nodes list. - */ -void QueryAnalyzer::resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope) -{ - auto & interpolate_node_list_typed = interpolate_node_list->as(); - - for (auto & interpolate_node : interpolate_node_list_typed.getNodes()) - { - auto & interpolate_node_typed = interpolate_node->as(); - - auto * column_to_interpolate = interpolate_node_typed.getExpression()->as(); - if (!column_to_interpolate) - throw Exception(ErrorCodes::LOGICAL_ERROR, "INTERPOLATE can work only for indentifiers, but {} is found", - interpolate_node_typed.getExpression()->formatASTForErrorMessage()); - auto column_to_interpolate_name = column_to_interpolate->getIdentifier().getFullName(); - - resolveExpressionNode(interpolate_node_typed.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool is_column_constant = interpolate_node_typed.getExpression()->getNodeType() == QueryTreeNodeType::CONSTANT; - - auto & interpolation_to_resolve = interpolate_node_typed.getInterpolateExpression(); - IdentifierResolveScope interpolate_scope(interpolation_to_resolve, &scope /*parent_scope*/); - - auto fake_column_node = std::make_shared(NameAndTypePair(column_to_interpolate_name, interpolate_node_typed.getExpression()->getResultType()), interpolate_node_typed.getExpression()); - if (is_column_constant) - interpolate_scope.expression_argument_name_to_node.emplace(column_to_interpolate_name, fake_column_node); - - resolveExpressionNode(interpolation_to_resolve, interpolate_scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (is_column_constant) - interpolation_to_resolve = interpolation_to_resolve->cloneAndReplace(fake_column_node, interpolate_node_typed.getExpression()); - } -} - -/** Resolve window nodes list. - */ -void QueryAnalyzer::resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope) -{ - auto & window_node_list_typed = window_node_list->as(); - for (auto & node : window_node_list_typed.getNodes()) - resolveWindow(node, scope); -} - -NamesAndTypes QueryAnalyzer::resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames projection_names = resolveExpressionNodeList(projection_node_list, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto projection_nodes = projection_node_list->as().getNodes(); - size_t projection_nodes_size = projection_nodes.size(); - - NamesAndTypes projection_columns; - projection_columns.reserve(projection_nodes_size); - - for (size_t i = 0; i < projection_nodes_size; ++i) - { - auto projection_node = projection_nodes[i]; - - if (!isExpressionNodeType(projection_node->getNodeType())) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Projection node must be constant, function, column, query or union"); - - projection_columns.emplace_back(projection_names[i], projection_node->getResultType()); - } - - return projection_columns; -} - -/** Initialize query join tree node. - * - * 1. Resolve identifiers. - * 2. Register table, table function, query, union, join, array join nodes in scope table expressions in resolve process. - */ -void QueryAnalyzer::initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope) -{ - std::deque join_tree_node_ptrs_to_process_queue; - join_tree_node_ptrs_to_process_queue.push_back(&join_tree_node); - - while (!join_tree_node_ptrs_to_process_queue.empty()) - { - auto * current_join_tree_node_ptr = join_tree_node_ptrs_to_process_queue.front(); - join_tree_node_ptrs_to_process_queue.pop_front(); - - auto & current_join_tree_node = *current_join_tree_node_ptr; - auto current_join_tree_node_type = current_join_tree_node->getNodeType(); - - switch (current_join_tree_node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & from_table_identifier = current_join_tree_node->as(); - auto table_identifier_lookup = IdentifierLookup{from_table_identifier.getIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - - auto from_table_identifier_alias = from_table_identifier.getAlias(); - - IdentifierResolveSettings resolve_settings; - /// In join tree initialization ignore join tree as identifier lookup source - resolve_settings.allow_to_check_join_tree = false; - /** Disable resolve of subquery during identifier resolution. - * Example: SELECT * FROM (SELECT 1) AS t1, t1; - * During `t1` identifier resolution we resolve it into subquery SELECT 1, but we want to disable - * subquery resolution at this stage, because JOIN TREE of parent query is not resolved. - */ - resolve_settings.allow_to_resolve_subquery_during_identifier_resolution = false; - - scope.pushExpressionNode(current_join_tree_node); - - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, resolve_settings); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - auto resolved_identifier = table_identifier_resolve_result.resolved_identifier; - - if (!resolved_identifier) - throw Exception(ErrorCodes::UNKNOWN_TABLE, - "Unknown table expression identifier '{}' in scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - resolved_identifier = resolved_identifier->clone(); - - /// Update alias name to table expression map - auto table_expression_it = scope.aliases.alias_name_to_table_expression_node.find(from_table_identifier_alias); - if (table_expression_it != scope.aliases.alias_name_to_table_expression_node.end()) - table_expression_it->second = resolved_identifier; - - auto table_expression_modifiers = from_table_identifier.getTableExpressionModifiers(); - - auto * resolved_identifier_query_node = resolved_identifier->as(); - auto * resolved_identifier_union_node = resolved_identifier->as(); - - if (resolved_identifier_query_node || resolved_identifier_union_node) - { - if (table_expression_modifiers.has_value()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Table expression modifiers {} are not supported for subquery {}", - table_expression_modifiers->formatForErrorMessage(), - resolved_identifier->formatASTForErrorMessage()); - } - } - else if (auto * resolved_identifier_table_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else if (auto * resolved_identifier_table_function_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_function_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier in JOIN TREE '{}' resolved into unexpected table expression. In scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto current_join_tree_node_alias = current_join_tree_node->getAlias(); - resolved_identifier->setAlias(current_join_tree_node_alias); - current_join_tree_node = resolved_identifier; - - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::QUERY: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::UNION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - auto & array_join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&array_join.getTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::JOIN: - { - auto & join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&join.getLeftTableExpression()); - join_tree_node_ptrs_to_process_queue.push_back(&join.getRightTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - ++scope.joins_count; - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, UNION, ARRAY JOIN or JOIN. Actual {} {}. In scope {}", - current_join_tree_node->getNodeTypeName(), - current_join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - } -} - -/// Initialize table expression data for table expression node -void QueryAnalyzer::initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto table_expression_data_it = scope.table_expression_node_to_data.find(table_expression_node); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - return; - - TableExpressionData table_expression_data; - - if (table_node) - { - if (!table_node->getTemporaryTableName().empty()) - { - table_expression_data.table_name = table_node->getTemporaryTableName(); - table_expression_data.table_expression_name = table_node->getTemporaryTableName(); - } - else - { - const auto & table_storage_id = table_node->getStorageID(); - table_expression_data.database_name = table_storage_id.database_name; - table_expression_data.table_name = table_storage_id.table_name; - table_expression_data.table_expression_name = table_storage_id.getFullNameNotQuoted(); - } - - table_expression_data.table_expression_description = "table"; - } - else if (query_node || union_node) - { - table_expression_data.table_name = query_node ? query_node->getCTEName() : union_node->getCTEName(); - table_expression_data.table_expression_description = "subquery"; - } - else if (table_function_node) - { - table_expression_data.table_expression_description = "table_function"; - } - - if (table_expression_node->hasAlias()) - table_expression_data.table_expression_name = table_expression_node->getAlias(); - - if (table_node || table_function_node) - { - const auto & storage_snapshot = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - - auto get_column_options = GetColumnsOptions(GetColumnsOptions::All).withExtendedObjects().withVirtuals(); - if (storage_snapshot->storage.supportsSubcolumns()) - get_column_options.withSubcolumns(); - - auto column_names_and_types = storage_snapshot->getColumns(get_column_options); - table_expression_data.column_names_and_types = NamesAndTypes(column_names_and_types.begin(), column_names_and_types.end()); - - const auto & columns_description = storage_snapshot->metadata->getColumns(); - - std::vector> alias_columns_to_resolve; - ColumnNameToColumnNodeMap column_name_to_column_node; - column_name_to_column_node.reserve(column_names_and_types.size()); - - /** For ALIAS columns in table we must additionally analyze ALIAS expressions. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + 5); - * - * To do that we collect alias columns and build table column name to column node map. - * For each alias column we build identifier resolve scope, initialize it with table column name to node map - * and resolve alias column. - */ - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - for (const auto & subcolumn : columns_description.getSubcolumns(column_name_and_type.name)) - table_expression_data.subcolumn_names.insert(subcolumn.name); - const auto & column_default = columns_description.getDefault(column_name_and_type.name); - - if (column_default && column_default->kind == ColumnDefaultKind::Alias) - { - auto alias_expression = buildQueryTree(column_default->expression, scope.context); - auto column_node = std::make_shared(column_name_and_type, std::move(alias_expression), table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - alias_columns_to_resolve.emplace_back(column_name_and_type.name, column_node); - } - else - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - for (auto & [alias_column_to_resolve_name, alias_column_to_resolve] : alias_columns_to_resolve) - { - /** Alias column could be potentially resolved during resolve of other ALIAS column. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + alias_value_2, alias_value_2 ALIAS id + 5) ENGINE=TinyLog; - * - * During resolve of alias_value_1, alias_value_2 column will be resolved. - */ - alias_column_to_resolve = column_name_to_column_node[alias_column_to_resolve_name]; - - IdentifierResolveScope alias_column_resolve_scope(alias_column_to_resolve, nullptr /*parent_scope*/); - alias_column_resolve_scope.column_name_to_column_node = std::move(column_name_to_column_node); - alias_column_resolve_scope.context = scope.context; - - /// Initialize aliases in alias column scope - QueryExpressionsAliasVisitor visitor(alias_column_resolve_scope.aliases); - visitor.visit(alias_column_to_resolve->getExpression()); - - resolveExpressionNode(alias_column_resolve_scope.scope_node, - alias_column_resolve_scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - auto & resolved_expression = alias_column_to_resolve->getExpression(); - if (!resolved_expression->getResultType()->equals(*alias_column_to_resolve->getResultType())) - resolved_expression = buildCastFunction(resolved_expression, alias_column_to_resolve->getResultType(), scope.context, true); - column_name_to_column_node = std::move(alias_column_resolve_scope.column_name_to_column_node); - column_name_to_column_node[alias_column_to_resolve_name] = alias_column_to_resolve; - } - - table_expression_data.column_name_to_column_node = std::move(column_name_to_column_node); - } - else if (query_node || union_node) - { - table_expression_data.column_names_and_types = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - table_expression_data.column_name_to_column_node.reserve(table_expression_data.column_names_and_types.size()); - - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - table_expression_data.column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - table_expression_data.column_identifier_first_parts.reserve(table_expression_data.column_name_to_column_node.size()); - - for (auto & [column_name, _] : table_expression_data.column_name_to_column_node) - { - Identifier column_name_identifier(column_name); - table_expression_data.column_identifier_first_parts.insert(column_name_identifier.at(0)); - } - - if (auto * scope_query_node = scope.scope_node->as()) - { - auto left_table_expression = extractLeftTableExpression(scope_query_node->getJoinTree()); - if (table_expression_node.get() == left_table_expression.get() && - scope.joins_count == 1 && - scope.context->getSettingsRef().single_join_prefer_left_table) - table_expression_data.should_qualify_columns = false; - } - - scope.table_expression_node_to_data.emplace(table_expression_node, std::move(table_expression_data)); -} - -bool findIdentifier(const FunctionNode & function) -{ - for (const auto & argument : function.getArguments()) - { - if (argument->as()) - return true; - if (const auto * f = argument->as(); f && findIdentifier(*f)) - return true; - } - return false; -} - -/// Resolve table function node in scope -void QueryAnalyzer::resolveTableFunction(QueryTreeNodePtr & table_function_node, - IdentifierResolveScope & scope, - QueryExpressionsAliasVisitor & expressions_visitor, - bool nested_table_function) -{ - auto & table_function_node_typed = table_function_node->as(); - - if (!nested_table_function) - expressions_visitor.visit(table_function_node_typed.getArgumentsNode()); - - const auto & table_function_name = table_function_node_typed.getTableFunctionName(); - - auto & scope_context = scope.context; - - TableFunctionPtr table_function_ptr = TableFunctionFactory::instance().tryGet(table_function_name, scope_context); - if (!table_function_ptr) - { - String database_name = scope_context->getCurrentDatabase(); - String table_name; - - auto function_ast = table_function_node->toAST(); - Identifier table_identifier{table_function_name}; - if (table_identifier.getPartsSize() == 1) - { - table_name = table_identifier[0]; - } - else if (table_identifier.getPartsSize() == 2) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - - auto parametrized_view_storage = scope_context->getQueryContext()->buildParametrizedViewStorage(function_ast, database_name, table_name); - if (parametrized_view_storage) - { - auto fake_table_node = std::make_shared(parametrized_view_storage, scope_context); - fake_table_node->setAlias(table_function_node->getAlias()); - table_function_node = fake_table_node; - return; - } - - auto hints = TableFunctionFactory::instance().getHints(table_function_name); - if (!hints.empty()) - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}. Maybe you meant: {}", - table_function_name, - DB::toString(hints)); - else - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}", - table_function_name); - } - - QueryTreeNodes result_table_function_arguments; - - auto skip_analysis_arguments_indexes = table_function_ptr->skipAnalysisForArguments(table_function_node, scope_context); - - auto & table_function_arguments = table_function_node_typed.getArguments().getNodes(); - size_t table_function_arguments_size = table_function_arguments.size(); - - for (size_t table_function_argument_index = 0; table_function_argument_index < table_function_arguments_size; ++table_function_argument_index) - { - auto & table_function_argument = table_function_arguments[table_function_argument_index]; - - auto skip_argument_index_it = std::find(skip_analysis_arguments_indexes.begin(), - skip_analysis_arguments_indexes.end(), - table_function_argument_index); - if (skip_argument_index_it != skip_analysis_arguments_indexes.end()) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - if (auto * identifier_node = table_function_argument->as()) - { - const auto & unresolved_identifier = identifier_node->getIdentifier(); - auto identifier_resolve_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier = std::move(identifier_resolve_result.resolved_identifier); - - if (resolved_identifier && resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - result_table_function_arguments.push_back(std::move(resolved_identifier)); - else - result_table_function_arguments.push_back(table_function_argument); - - continue; - } - else if (auto * table_function_argument_function = table_function_argument->as()) - { - const auto & table_function_argument_function_name = table_function_argument_function->getFunctionName(); - if (TableFunctionFactory::instance().isTableFunctionName(table_function_argument_function_name)) - { - auto table_function_node_to_resolve_typed = std::make_shared(table_function_argument_function_name); - table_function_node_to_resolve_typed->getArgumentsNode() = table_function_argument_function->getArgumentsNode(); - - QueryTreeNodePtr table_function_node_to_resolve = std::move(table_function_node_to_resolve_typed); - resolveTableFunction(table_function_node_to_resolve, scope, expressions_visitor, true /*nested_table_function*/); - - result_table_function_arguments.push_back(std::move(table_function_node_to_resolve)); - continue; - } - } - - /** Table functions arguments can contain expressions with invalid identifiers. - * We cannot skip analysis for such arguments, because some table functions cannot provide - * information if analysis for argument should be skipped until other arguments will be resolved. - * - * Example: SELECT key from remote('127.0.0.{1,2}', view(select number AS key from numbers(2)), cityHash64(key)); - * Example: SELECT id from remote('127.0.0.{1,2}', 'default', 'test_table', cityHash64(id)); - */ - try - { - resolveExpressionNode(table_function_argument, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - catch (const Exception & exception) - { - if (exception.code() == ErrorCodes::UNKNOWN_IDENTIFIER) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - throw; - } - - if (auto * expression_list = table_function_argument->as()) - { - for (auto & expression_list_node : expression_list->getNodes()) - result_table_function_arguments.push_back(expression_list_node); - } - else - { - result_table_function_arguments.push_back(table_function_argument); - } - } - - table_function_node_typed.getArguments().getNodes() = std::move(result_table_function_arguments); - - auto table_function_ast = table_function_node_typed.toAST(); - table_function_ptr->parseArguments(table_function_ast, scope_context); - - - uint64_t use_structure_from_insertion_table_in_table_functions = scope_context->getSettingsRef().use_structure_from_insertion_table_in_table_functions; - if (!nested_table_function && - use_structure_from_insertion_table_in_table_functions && - scope_context->hasInsertionTable() && - table_function_ptr->needStructureHint()) - { - const auto & insertion_table = scope_context->getInsertionTable(); - if (!insertion_table.empty()) - { - const auto & insert_columns = DatabaseCatalog::instance() - .getTable(insertion_table, scope_context) - ->getInMemoryMetadataPtr() - ->getColumns(); - const auto & insert_column_names = scope_context->hasInsertionTableColumnNames() ? *scope_context->getInsertionTableColumnNames() : insert_columns.getOrdinary().getNames(); - DB::ColumnsDescription structure_hint; - - bool use_columns_from_insert_query = true; - - /// Insert table matches columns against SELECT expression by position, so we want to map - /// insert table columns to table function columns through names from SELECT expression. - - auto insert_column_name_it = insert_column_names.begin(); - auto insert_column_names_end = insert_column_names.end(); /// end iterator of the range covered by possible asterisk - auto virtual_column_names = table_function_ptr->getVirtualsToCheckBeforeUsingStructureHint(); - bool asterisk = false; - const auto & expression_list = scope.scope_node->as().getProjection(); - auto expression = expression_list.begin(); - - /// We want to go through SELECT expression list and correspond each expression to column in insert table - /// which type will be used as a hint for the file structure inference. - for (; expression != expression_list.end() && insert_column_name_it != insert_column_names_end; ++expression) - { - if (auto * identifier_node = (*expression)->as()) - { - - if (!virtual_column_names.contains(identifier_node->getIdentifier().getFullName())) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - ColumnDescription column = insert_columns.get(*insert_column_name_it); - column.name = identifier_node->getIdentifier().getFullName(); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else if (auto * matcher_node = (*expression)->as(); matcher_node && matcher_node->getMatcherType() == MatcherNodeType::ASTERISK) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Only one asterisk can be used in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - if (!structure_hint.empty()) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - asterisk = true; - } - else if (auto * function = (*expression)->as()) - { - if (use_structure_from_insertion_table_in_table_functions == 2 && findIdentifier(*function)) - { - use_columns_from_insert_query = false; - break; - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else - { - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - } - - if (use_structure_from_insertion_table_in_table_functions == 2 && !asterisk) - { - /// For input function we should check if input format supports reading subset of columns. - if (table_function_ptr->getName() == "input") - use_columns_from_insert_query = FormatFactory::instance().checkIfFormatSupportsSubsetOfColumns(scope.context->getInsertFormat(), scope.context); - else - use_columns_from_insert_query = table_function_ptr->supportsReadingSubsetOfColumns(scope.context); - } - - if (use_columns_from_insert_query) - { - if (expression == expression_list.end()) - { - /// Append tail of insert structure to the hint - if (asterisk) - { - for (; insert_column_name_it != insert_column_names_end; ++insert_column_name_it) - { - ColumnDescription column = insert_columns.get(*insert_column_name_it); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - } - - if (!structure_hint.empty()) - table_function_ptr->setStructureHint(structure_hint); - - } else if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::NUMBER_OF_COLUMNS_DOESNT_MATCH, "Number of columns in insert table less than required by SELECT expression."); - } - } - } - - auto table_function_storage = scope_context->getQueryContext()->executeTableFunction(table_function_ast, table_function_ptr); - table_function_node_typed.resolve(std::move(table_function_ptr), std::move(table_function_storage), scope_context, std::move(skip_analysis_arguments_indexes)); -} - -/// Resolve array join node in scope -void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & array_join_node_typed = array_join_node->as(); - resolveQueryJoinTreeNode(array_join_node_typed.getTableExpression(), scope, expressions_visitor); - - std::unordered_set array_join_column_names; - - /// Wrap array join expressions into column nodes, where array join expression is inner expression - - auto & array_join_nodes = array_join_node_typed.getJoinExpressions().getNodes(); - size_t array_join_nodes_size = array_join_nodes.size(); - - if (array_join_nodes_size == 0) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, - "ARRAY JOIN requires at least single expression"); - - std::vector array_join_column_expressions; - array_join_column_expressions.reserve(array_join_nodes_size); - - for (auto & array_join_expression : array_join_nodes) - { - auto array_join_expression_alias = array_join_expression->getAlias(); - - for (const auto & elem : array_join_nodes) - { - if (elem->hasAlias()) - scope.aliases.array_join_aliases.insert(elem->getAlias()); - - for (auto & child : elem->getChildren()) - { - if (child) - expressions_visitor.visit(child); - } - } - - std::string identifier_full_name; - - if (auto * identifier_node = array_join_expression->as()) - identifier_full_name = identifier_node->getIdentifier().getFullName(); - - resolveExpressionNode(array_join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/, true /*ignore_alias*/); - - auto process_array_join_expression = [&](QueryTreeNodePtr & expression) - { - auto result_type = expression->getResultType(); - bool is_array_type = isArray(result_type); - bool is_map_type = isMap(result_type); - - if (!is_array_type && !is_map_type) - throw Exception(ErrorCodes::TYPE_MISMATCH, - "ARRAY JOIN {} requires expression {} with Array or Map type. Actual {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - expression->formatASTForErrorMessage(), - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_map_type) - result_type = assert_cast(*result_type).getNestedType(); - - result_type = assert_cast(*result_type).getNestedType(); - - String array_join_column_name; - - if (!array_join_expression_alias.empty()) - { - array_join_column_name = array_join_expression_alias; - } - else if (auto * array_join_expression_inner_column = array_join_expression->as()) - { - array_join_column_name = array_join_expression_inner_column->getColumnName(); - } - else if (!identifier_full_name.empty()) - { - array_join_column_name = identifier_full_name; - } - else - { - array_join_column_name = "__array_join_expression_" + std::to_string(array_join_expressions_counter); - ++array_join_expressions_counter; - } - - if (array_join_column_names.contains(array_join_column_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "ARRAY JOIN {} multiple columns with name {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - array_join_column_name, - scope.scope_node->formatASTForErrorMessage()); - array_join_column_names.emplace(array_join_column_name); - - NameAndTypePair array_join_column(array_join_column_name, result_type); - auto array_join_column_node = std::make_shared(std::move(array_join_column), expression, array_join_node); - array_join_column_node->setAlias(array_join_expression_alias); - array_join_column_expressions.push_back(std::move(array_join_column_node)); - }; - - // Support ARRAY JOIN COLUMNS(...). COLUMNS transformer is resolved to list of columns. - if (auto * columns_list = array_join_expression->as()) - { - for (auto & array_join_subexpression : columns_list->getNodes()) - process_array_join_expression(array_join_subexpression); - } - else - { - process_array_join_expression(array_join_expression); - } - } - - array_join_nodes = std::move(array_join_column_expressions); -} - -void QueryAnalyzer::checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope) -{ - Names column_names; - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - if (join_node->as().getKind() != JoinKind::Paste) - return; - - auto * left_node = left_table_expr->as(); - auto * right_node = right_table_expr->as(); - - if (!left_node && !right_node) - return; - - if (left_node) - for (const auto & name_and_type : left_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - if (right_node) - for (const auto & name_and_type : right_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - - if (column_names.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of projection columns cannot be empty"); - - std::sort(column_names.begin(), column_names.end()); - for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is no any duplicates because it will lead to broken result - if (column_names[i] == column_names[i+1]) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add/change aliases to avoid duplication)" - "While processing '{}'", join_node->formatASTForErrorMessage()); -} - -/// Resolve join node in scope -void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & join_node_typed = join_node->as(); - - resolveQueryJoinTreeNode(join_node_typed.getLeftTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getLeftTableExpression(), scope); - - resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); - - if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) - checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope); - - if (join_node_typed.isOnJoinExpression()) - { - expressions_visitor.visit(join_node_typed.getJoinExpression()); - auto join_expression = join_node_typed.getJoinExpression(); - resolveExpressionNode(join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - join_node_typed.getJoinExpression() = std::move(join_expression); - } - else if (join_node_typed.isUsingJoinExpression()) - { - auto & join_using_list = join_node_typed.getJoinExpression()->as(); - std::unordered_set join_using_identifiers; - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto * identifier_node = join_using_node->as(); - if (!identifier_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} USING clause expected identifier. Actual {}", - join_node_typed.formatASTForErrorMessage(), - join_using_node->formatASTForErrorMessage()); - - const auto & identifier_full_name = identifier_node->getIdentifier().getFullName(); - - if (join_using_identifiers.contains(identifier_full_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} identifier '{}' appears more than once in USING clause", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name); - - join_using_identifiers.insert(identifier_full_name); - - const auto & settings = scope.context->getSettingsRef(); - - /** While resolving JOIN USING identifier, try to resolve identifier from parent subquery projection. - * Example: SELECT a + 1 AS b FROM (SELECT 1 AS a) t1 JOIN (SELECT 2 AS b) USING b - * In this case `b` is not in the left table expression, but it is in the parent subquery projection. - */ - auto try_resolve_identifier_from_query_projection = [this](const String & identifier_full_name_, - const QueryTreeNodePtr & left_table_expression, - const IdentifierResolveScope & scope_) -> QueryTreeNodePtr - { - const QueryNode * query_node = scope_.scope_node ? scope_.scope_node->as() : nullptr; - if (!query_node) - return nullptr; - - const auto & projection_list = query_node->getProjection(); - for (const auto & projection_node : projection_list.getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name_ == projection_node->getAlias()) - { - auto left_subquery = std::make_shared(query_node->getMutableContext()); - left_subquery->getProjection().getNodes().push_back(projection_node->clone()); - left_subquery->getJoinTree() = left_table_expression; - - IdentifierResolveScope left_subquery_scope(left_subquery, nullptr /*parent_scope*/); - resolveQuery(left_subquery, left_subquery_scope); - - const auto & resolved_nodes = left_subquery->getProjection().getNodes(); - if (resolved_nodes.size() == 1) - { - /// Create ColumnNode with expression from parent projection - return std::make_shared( - NameAndTypePair{identifier_full_name_, resolved_nodes.front()->getResultType()}, - resolved_nodes.front(), left_table_expression); - } - } - } - return nullptr; - }; - - QueryTreeNodePtr result_left_table_expression = nullptr; - /** With `analyzer_compatibility_join_using_top_level_identifier` alias in projection has higher priority than column from left table. - * But if aliased expression cannot be resolved from left table, we get UNKNOW_IDENTIFIER error, - * despite the fact that column from USING could be resolved from left table. - * It's compatibility with a default behavior for old analyzer. - */ - if (settings.analyzer_compatibility_join_using_top_level_identifier) - result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - IdentifierLookup identifier_lookup{identifier_node->getIdentifier(), IdentifierLookupContext::EXPRESSION}; - if (!result_left_table_expression) - result_left_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getLeftTableExpression(), scope); - - /** Here we may try to resolve identifier from projection in case it's not resolved from left table expression - * and analyzer_compatibility_join_using_top_level_identifier is disabled. - * For now we do not do this, because not all corner cases are clear. - * But let's at least mention it in error message - */ - /// if (!settings.analyzer_compatibility_join_using_top_level_identifier && !result_left_table_expression) - /// result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - if (!result_left_table_expression) - { - String extra_message; - const QueryNode * query_node = scope.scope_node ? scope.scope_node->as() : nullptr; - if (settings.analyzer_compatibility_join_using_top_level_identifier && query_node) - { - for (const auto & projection_node : query_node->getProjection().getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name == projection_node->getAlias()) - { - extra_message = fmt::format( - ", but alias '{}' is present in SELECT list." - " You may try to SET analyzer_compatibility_join_using_top_level_identifier = 1, to allow to use it in USING clause", - projection_node->formatASTForErrorMessage()); - break; - } - } - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from left table expression{}. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - extra_message, - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_left_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from left table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto result_right_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getRightTableExpression(), scope); - if (!result_right_table_expression) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - if (result_right_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto expression_types = DataTypes{result_left_table_expression->getResultType(), result_right_table_expression->getResultType()}; - DataTypePtr common_type = tryGetLeastSupertype(expression_types); - - if (!common_type) - throw Exception(ErrorCodes::NO_COMMON_TYPE, - "JOIN {} cannot infer common type for {} and {} in USING for identifier '{}'. In scope {}", - join_node_typed.formatASTForErrorMessage(), - result_left_table_expression->getResultType()->getName(), - result_right_table_expression->getResultType()->getName(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - NameAndTypePair join_using_column(identifier_full_name, common_type); - ListNodePtr join_using_expression = std::make_shared(QueryTreeNodes{result_left_table_expression, result_right_table_expression}); - auto join_using_column_node = std::make_shared(std::move(join_using_column), std::move(join_using_expression), join_node); - join_using_node = std::move(join_using_column_node); - } - } -} - -/** Resolve query join tree. - * - * Query join tree must be initialized before calling this function. - */ -void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto from_node_type = join_tree_node->getNodeType(); - - switch (from_node_type) - { - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - resolveExpressionNode(join_tree_node, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - resolveTableFunction(join_tree_node, scope, expressions_visitor, false /*nested_table_function*/); - break; - } - case QueryTreeNodeType::TABLE: - { - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - resolveArrayJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::JOIN: - { - resolveJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::IDENTIFIER: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifiers in FROM section must be already resolved. Node {}, scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, ARRAY JOIN or JOIN. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - auto join_tree_node_type = join_tree_node->getNodeType(); - if (isTableExpressionNodeType(join_tree_node_type)) - { - validateTableExpressionModifiers(join_tree_node, scope); - initializeTableExpressionData(join_tree_node, scope); - - auto & query_node = scope.scope_node->as(); - auto & mutable_context = query_node.getMutableContext(); - - if (!mutable_context->isDistributed()) - { - bool is_distributed = false; - - if (auto * table_node = join_tree_node->as()) - is_distributed = table_node->getStorage()->isRemote(); - else if (auto * table_function_node = join_tree_node->as()) - is_distributed = table_function_node->getStorage()->isRemote(); - - mutable_context->setDistributed(is_distributed); - } - } - - auto add_table_expression_alias_into_scope = [&](const QueryTreeNodePtr & table_expression_node) - { - const auto & alias_name = table_expression_node->getAlias(); - if (alias_name.empty()) - return; - - auto [it, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(alias_name, table_expression_node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Duplicate aliases {} for table expressions in FROM section are not allowed. Try to register {}. Already registered {}.", - alias_name, - table_expression_node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage()); - }; - - add_table_expression_alias_into_scope(join_tree_node); - scope.table_expressions_in_resolve_process.erase(join_tree_node.get()); -} - -/** Resolve query. - * This function modifies query node during resolve. It is caller responsibility to clone query node before resolve - * if it is needed for later use. - * - * query_node - query_tree_node that must have QueryNode type. - * scope - query scope. It is caller responsibility to create it. - * - * Resolve steps: - * 1. Validate subqueries depth, perform GROUP BY validation that does not depend on information about aggregate functions. - * 2. Initialize query scope with aliases. - * 3. Register CTE subqueries from WITH section in scope and remove them from WITH section. - * 4. Resolve JOIN TREE. - * 5. Resolve projection columns. - * 6. Resolve expressions in other query parts. - * 7. Validate nodes with duplicate aliases. - * 8. Validate aggregate functions, GROUPING function, window functions. - * 9. Remove WITH and WINDOW sections from query. - * 10. Remove aliases from expression and lambda nodes. - * 11. Resolve query tree node with projection columns. - */ -void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope) -{ - size_t max_subquery_depth = scope.context->getSettingsRef().max_subquery_depth; - if (max_subquery_depth && scope.subquery_depth > max_subquery_depth) - throw Exception(ErrorCodes::TOO_DEEP_SUBQUERIES, - "Too deep subqueries. Maximum: {}", - max_subquery_depth); - - auto & query_node_typed = query_node->as(); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.insert(query_node_typed.getCTEName()); - - bool is_rollup_or_cube = query_node_typed.isGroupByWithRollup() || query_node_typed.isGroupByWithCube(); - - if (query_node_typed.isGroupByWithGroupingSets() - && query_node_typed.isGroupByWithTotals() - && query_node_typed.getGroupBy().getNodes().size() != 1) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and GROUPING SETS are not supported together"); - - if (query_node_typed.isGroupByWithGroupingSets() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "GROUPING SETS are not supported together with ROLLUP and CUBE"); - - if (query_node_typed.isGroupByWithRollup() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithCube())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "ROLLUP is not supported together with GROUPING SETS and CUBE"); - - if (query_node_typed.isGroupByWithCube() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithRollup())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "CUBE is not supported together with GROUPING SETS and ROLLUP"); - - if (query_node_typed.hasHaving() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of HAVING"); - - if (query_node_typed.hasQualify() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of QUALIFY"); - - /// Initialize aliases in query node scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - - if (query_node_typed.hasWith()) - visitor.visit(query_node_typed.getWithNode()); - - if (!query_node_typed.getProjection().getNodes().empty()) - visitor.visit(query_node_typed.getProjectionNode()); - - if (query_node_typed.getPrewhere()) - visitor.visit(query_node_typed.getPrewhere()); - - if (query_node_typed.getWhere()) - visitor.visit(query_node_typed.getWhere()); - - if (query_node_typed.hasGroupBy()) - visitor.visit(query_node_typed.getGroupByNode()); - - if (query_node_typed.hasHaving()) - visitor.visit(query_node_typed.getHaving()); - - if (query_node_typed.hasWindow()) - visitor.visit(query_node_typed.getWindowNode()); - - if (query_node_typed.hasQualify()) - visitor.visit(query_node_typed.getQualify()); - - if (query_node_typed.hasOrderBy()) - visitor.visit(query_node_typed.getOrderByNode()); - - if (query_node_typed.hasInterpolate()) - visitor.visit(query_node_typed.getInterpolate()); - - if (query_node_typed.hasLimitByLimit()) - visitor.visit(query_node_typed.getLimitByLimit()); - - if (query_node_typed.hasLimitByOffset()) - visitor.visit(query_node_typed.getLimitByOffset()); - - if (query_node_typed.hasLimitBy()) - visitor.visit(query_node_typed.getLimitByNode()); - - if (query_node_typed.hasLimit()) - visitor.visit(query_node_typed.getLimit()); - - if (query_node_typed.hasOffset()) - visitor.visit(query_node_typed.getOffset()); - - /// Register CTE subqueries and remove them from WITH section - - auto & with_nodes = query_node_typed.getWith().getNodes(); - - for (auto & node : with_nodes) - { - auto * subquery_node = node->as(); - auto * union_node = node->as(); - - bool subquery_is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - if (!subquery_is_cte) - continue; - - const auto & cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - auto [_, inserted] = scope.cte_name_to_query_node.emplace(cte_name, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "CTE with name {} already exists. In scope {}", - cte_name, - scope.scope_node->formatASTForErrorMessage()); - } - - /** WITH section can be safely removed, because WITH section only can provide aliases to query expressions - * and CTE for other sections to use. - * - * Example: WITH 1 AS constant, (x -> x + 1) AS lambda, a AS (SELECT * FROM test_table); - */ - query_node_typed.getWith().getNodes().clear(); - - for (auto & window_node : query_node_typed.getWindow().getNodes()) - { - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - if (!parent_window_name.empty()) - { - auto window_node_it = scope.window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope.window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - scope.scope_node->formatASTForErrorMessage()); - - mergeWindowWithParentWindow(window_node, window_node_it->second, scope); - window_node_typed.setParentWindowName({}); - } - - auto [_, inserted] = scope.window_name_to_window_node.emplace(window_node_typed.getAlias(), window_node); - if (!inserted) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' is already defined. In scope {}", - window_node_typed.getAlias(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** Disable identifier cache during JOIN TREE resolve. - * Depending on JOIN expression section, identifier with same name - * can be resolved in different columns. - * - * Example: SELECT id FROM test_table AS t1 INNER JOIN test_table AS t2 ON t1.id = t2.id INNER JOIN test_table AS t3 ON t1.id = t3.id - * In first join expression ON t1.id = t2.id t1.id is resolved into test_table.id column. - * In second join expression ON t1.id = t3.id t1.id must be resolved into test_table.id column after first JOIN. - */ - scope.use_identifier_lookup_to_result_cache = false; - - if (query_node_typed.getJoinTree()) - { - TableExpressionsAliasVisitor table_expressions_visitor(scope); - table_expressions_visitor.visit(query_node_typed.getJoinTree()); - - initializeQueryJoinTreeNode(query_node_typed.getJoinTree(), scope); - scope.aliases.alias_name_to_table_expression_node.clear(); - - resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor); - } - - if (!scope.group_by_use_nulls) - scope.use_identifier_lookup_to_result_cache = true; - - /// Resolve query node sections. - - NamesAndTypes projection_columns; - - if (!scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - if (auto & prewhere_node = query_node_typed.getPrewhere()) - { - resolveExpressionNode(prewhere_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** Expressions in PREWHERE with JOIN should not change their type. - * Example: SELECT * FROM t1 JOIN t2 USING (a) PREWHERE a = 1 - * Column `a` in PREWHERE should be resolved from the left table - * and should not change its type to Nullable or to the supertype of `a` from t1 and t2. - * Here's a more complicated example where the column is somewhere inside an expression: - * SELECT a + 1 as b FROM t1 JOIN t2 USING (id) PREWHERE b = 1 - * The expression `a + 1 as b` in the projection and in PREWHERE should have different `a`. - */ - prewhere_node = prewhere_node->clone(); - ReplaceColumnsVisitor replace_visitor(scope.join_columns_with_changed_types, scope.context); - replace_visitor.visit(prewhere_node); - } - - if (query_node_typed.getWhere()) - resolveExpressionNode(query_node_typed.getWhere(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasGroupBy()) - resolveGroupByNode(query_node_typed, scope); - - if (scope.group_by_use_nulls) - { - resolved_expressions.clear(); - /// Clone is needed cause aliases share subtrees. - /// If not clone, the same (shared) subtree could be resolved again with different (Nullable) type - /// See 03023_group_by_use_nulls_analyzer_crashes - for (auto & [key, node] : scope.aliases.alias_name_to_expression_node_before_group_by) - scope.aliases.alias_name_to_expression_node_after_group_by[key] = node->clone(); - - scope.aliases.alias_name_to_expression_node = &scope.aliases.alias_name_to_expression_node_after_group_by; - } - - if (query_node_typed.hasHaving()) - resolveExpressionNode(query_node_typed.getHaving(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasWindow()) - resolveWindowNodeList(query_node_typed.getWindowNode(), scope); - - if (query_node_typed.hasQualify()) - resolveExpressionNode(query_node_typed.getQualify(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasOrderBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getOrderByNode(), query_node_typed.getProjection().getNodes(), scope); - - const auto & settings = scope.context->getSettingsRef(); - - expandOrderByAll(query_node_typed, settings); - resolveSortNodeList(query_node_typed.getOrderByNode(), scope); - } - - if (query_node_typed.hasInterpolate()) - resolveInterpolateColumnsNodeList(query_node_typed.getInterpolate(), scope); - - if (query_node_typed.hasLimitByLimit()) - { - resolveExpressionNode(query_node_typed.getLimitByLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByLimit(), "LIMIT BY LIMIT", scope); - } - - if (query_node_typed.hasLimitByOffset()) - { - resolveExpressionNode(query_node_typed.getLimitByOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByOffset(), "LIMIT BY OFFSET", scope); - } - - if (query_node_typed.hasLimitBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getLimitByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getLimitByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - - if (query_node_typed.hasLimit()) - { - resolveExpressionNode(query_node_typed.getLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimit(), "LIMIT", scope); - } - - if (query_node_typed.hasOffset()) - { - resolveExpressionNode(query_node_typed.getOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getOffset(), "OFFSET", scope); - } - - if (scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - /** Resolve nodes with duplicate aliases. - * Table expressions cannot have duplicate aliases. - * - * Such nodes during scope aliases collection are placed into duplicated array. - * After scope nodes are resolved, we can compare node with duplicate alias with - * node from scope alias table. - */ - for (const auto & node_with_duplicated_alias : scope.aliases.cloned_nodes_with_duplicated_aliases) - { - auto node = node_with_duplicated_alias; - auto node_alias = node->getAlias(); - - /// Add current alias to non cached set, because in case of cyclic alias identifier should not be substituted from cache. - /// See 02896_cyclic_aliases_crash. - resolveExpressionNode(node, scope, true /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool has_node_in_alias_table = false; - - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - if (!has_node_in_alias_table) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node {} with duplicate alias {} does not exist in alias table. In scope {}", - node->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - - node->removeAlias(); - } - - expandGroupByAll(query_node_typed); - - validateFilters(query_node); - validateAggregates(query_node, { .group_by_use_nulls = scope.group_by_use_nulls }); - - for (const auto & column : projection_columns) - { - if (isNotCreatable(column.type)) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Invalid projection column with type {}. In scope {}", - column.type->getName(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** WINDOW section can be safely removed, because WINDOW section can only provide window definition to window functions. - * - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - */ - query_node_typed.getWindow().getNodes().clear(); - - /// Remove aliases from expression and lambda nodes - - for (auto & [_, node] : *scope.aliases.alias_name_to_expression_node) - node->removeAlias(); - - for (auto & [_, node] : scope.aliases.alias_name_to_lambda_node) - node->removeAlias(); - - query_node_typed.resolveProjectionColumns(std::move(projection_columns)); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.erase(query_node_typed.getCTEName()); -} - -void QueryAnalyzer::resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope) -{ - auto & union_node_typed = union_node->as(); - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.insert(union_node_typed.getCTEName()); - - auto & queries_nodes = union_node_typed.getQueries().getNodes(); - - std::optional recursive_cte_table; - TableNodePtr recursive_cte_table_node; - - if (union_node_typed.isCTE() && union_node_typed.isRecursiveCTE()) - { - auto & non_recursive_query = queries_nodes[0]; - bool non_recursive_query_is_query_node = non_recursive_query->getNodeType() == QueryTreeNodeType::QUERY; - auto & non_recursive_query_mutable_context = non_recursive_query_is_query_node ? non_recursive_query->as().getMutableContext() - : non_recursive_query->as().getMutableContext(); - - IdentifierResolveScope non_recursive_subquery_scope(non_recursive_query, &scope /*parent_scope*/); - non_recursive_subquery_scope.subquery_depth = scope.subquery_depth + 1; - - if (non_recursive_query_is_query_node) - resolveQuery(non_recursive_query, non_recursive_subquery_scope); - else - resolveUnion(non_recursive_query, non_recursive_subquery_scope); - - auto temporary_table_columns = non_recursive_query_is_query_node - ? non_recursive_query->as().getProjectionColumns() - : non_recursive_query->as().computeProjectionColumns(); - - auto temporary_table_holder = std::make_shared( - non_recursive_query_mutable_context, - ColumnsDescription{NamesAndTypesList{temporary_table_columns.begin(), temporary_table_columns.end()}}, - ConstraintsDescription{}, - nullptr /*query*/, - true /*create_for_global_subquery*/); - auto temporary_table_storage = temporary_table_holder->getTable(); - - recursive_cte_table_node = std::make_shared(temporary_table_storage, non_recursive_query_mutable_context); - recursive_cte_table_node->setTemporaryTableName(union_node_typed.getCTEName()); - - recursive_cte_table.emplace(std::move(temporary_table_holder), std::move(temporary_table_storage), std::move(temporary_table_columns)); - } - - size_t queries_nodes_size = queries_nodes.size(); - for (size_t i = recursive_cte_table.has_value(); i < queries_nodes_size; ++i) - { - auto & query_node = queries_nodes[i]; - - IdentifierResolveScope subquery_scope(query_node, &scope /*parent_scope*/); - - if (recursive_cte_table_node) - subquery_scope.expression_argument_name_to_node[union_node_typed.getCTEName()] = recursive_cte_table_node; - - auto query_node_type = query_node->getNodeType(); - - if (query_node_type == QueryTreeNodeType::QUERY) - { - resolveQuery(query_node, subquery_scope); - } - else if (query_node_type == QueryTreeNodeType::UNION) - { - resolveUnion(query_node, subquery_scope); - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "UNION unsupported node {}. In scope {}", - query_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (recursive_cte_table && isStorageUsedInTree(recursive_cte_table->storage, union_node.get())) - { - if (union_node_typed.getUnionMode() != SelectUnionMode::UNION_ALL) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive CTE subquery {} with {} union mode is unsupported, only UNION ALL union mode is supported", - union_node_typed.formatASTForErrorMessage(), - toString(union_node_typed.getUnionMode())); - - union_node_typed.setRecursiveCTETable(std::move(*recursive_cte_table)); - } - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.erase(union_node_typed.getCTEName()); -} - -} - -QueryAnalysisPass::QueryAnalysisPass(QueryTreeNodePtr table_expression_, bool only_analyze_) - : table_expression(std::move(table_expression_)) - , only_analyze(only_analyze_) -{} - -QueryAnalysisPass::QueryAnalysisPass(bool only_analyze_) : only_analyze(only_analyze_) {} - -void QueryAnalysisPass::run(QueryTreeNodePtr & query_tree_node, ContextPtr context) -{ - QueryAnalyzer analyzer(only_analyze); - analyzer.resolve(query_tree_node, table_expression, context); - createUniqueTableAliases(query_tree_node, table_expression, context); -} - } diff --git a/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp b/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp index 3fca66e6eb8..041e0d1fefb 100644 --- a/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp +++ b/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp @@ -1,791 +1,12 @@ -#include +#include -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include #include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include -#include -#include -#include -#include -#include -#include - -namespace ProfileEvents -{ - extern const Event ScalarSubqueriesGlobalCacheHit; - extern const Event ScalarSubqueriesLocalCacheHit; - extern const Event ScalarSubqueriesCacheMiss; -} namespace DB { - -namespace ErrorCodes -{ - extern const int UNSUPPORTED_METHOD; - extern const int UNKNOWN_IDENTIFIER; - extern const int UNKNOWN_FUNCTION; - extern const int LOGICAL_ERROR; - extern const int CYCLIC_ALIASES; - extern const int INCORRECT_RESULT_OF_SCALAR_SUBQUERY; - extern const int BAD_ARGUMENTS; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int MULTIPLE_EXPRESSIONS_FOR_ALIAS; - extern const int TYPE_MISMATCH; - extern const int AMBIGUOUS_IDENTIFIER; - extern const int INVALID_WITH_FILL_EXPRESSION; - extern const int INVALID_LIMIT_EXPRESSION; - extern const int EMPTY_LIST_OF_COLUMNS_QUERIED; - extern const int TOO_DEEP_SUBQUERIES; - extern const int UNKNOWN_AGGREGATE_FUNCTION; - extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION; - extern const int TOO_MANY_ARGUMENTS_FOR_FUNCTION; - extern const int ILLEGAL_FINAL; - extern const int SAMPLING_NOT_SUPPORTED; - extern const int NO_COMMON_TYPE; - extern const int NOT_IMPLEMENTED; - extern const int ALIAS_REQUIRED; - extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; - extern const int UNKNOWN_TABLE; - extern const int ILLEGAL_COLUMN; - extern const int NUMBER_OF_COLUMNS_DOESNT_MATCH; - extern const int FUNCTION_CANNOT_HAVE_PARAMETERS; - extern const int SYNTAX_ERROR; - extern const int UNEXPECTED_EXPRESSION; - extern const int INVALID_IDENTIFIER; -} - -/** Query analyzer implementation overview. Please check documentation in QueryAnalysisPass.h first. - * And additional documentation for each method, where special cases are described in detail. - * - * Each node in query must be resolved. For each query tree node resolved state is specific. - * - * For constant node no resolve process exists, it is resolved during construction. - * - * For table node no resolve process exists, it is resolved during construction. - * - * For function node to be resolved parameters and arguments must be resolved, function node must be initialized with concrete aggregate or - * non aggregate function and with result type. - * - * For lambda node there can be 2 different cases. - * 1. Standalone: WITH (x -> x + 1) AS lambda SELECT lambda(1); Such lambdas are inlined in query tree during query analysis pass. - * 2. Function arguments: WITH (x -> x + 1) AS lambda SELECT arrayMap(lambda, [1, 2, 3]); For such lambda resolution must - * set concrete lambda arguments (initially they are identifier nodes) and resolve lambda expression body. - * - * For query node resolve process must resolve all its inner nodes. - * - * For matcher node resolve process must replace it with matched nodes. - * - * For identifier node resolve process must replace it with concrete non identifier node. This part is most complex because - * for identifier resolution scopes and identifier lookup context play important part. - * - * ClickHouse SQL support lexical scoping for identifier resolution. Scope can be defined by query node or by expression node. - * Expression nodes that can define scope are lambdas and table ALIAS columns. - * - * Identifier lookup context can be expression, function, table. - * - * Examples: WITH (x -> x + 1) as func SELECT func() FROM func; During function `func` resolution identifier lookup is performed - * in function context. - * - * If there are no information of identifier context rules are following: - * 1. Try to resolve identifier in expression context. - * 2. Try to resolve identifier in function context, if it is allowed. Example: SELECT func(arguments); Here func identifier cannot be resolved in function context - * because query projection does not support that. - * 3. Try to resolve identifier in table context, if it is allowed. Example: SELECT table; Here table identifier cannot be resolved in function context - * because query projection does not support that. - * - * TODO: This does not supported properly before, because matchers could not be resolved from aliases. - * - * Identifiers are resolved with following rules: - * Resolution starts with current scope. - * 1. Try to resolve identifier from expression scope arguments. Lambda expression arguments are greatest priority. - * 2. Try to resolve identifier from aliases. - * 3. Try to resolve identifier from join tree if scope is query, or if there are registered table columns in scope. - * Steps 2 and 3 can be changed using prefer_column_name_to_alias setting. - * 4. If it is table lookup, try to resolve identifier from CTE. - * If identifier could not be resolved in current scope, resolution must be continued in parent scopes. - * 5. Try to resolve identifier from parent scopes. - * - * Additional rules about aliases and scopes. - * 1. Parent scope cannot refer alias from child scope. - * 2. Child scope can refer to alias in parent scope. - * - * Example: SELECT arrayMap(x -> x + 1 AS a, [1,2,3]), a; Identifier a is unknown in parent scope. - * Example: SELECT a FROM (SELECT 1 as a); Here we do not refer to alias a from child query scope. But we query it projection result, similar to tables. - * Example: WITH 1 as a SELECT (SELECT a) as b; Here in child scope identifier a is resolved using alias from parent scope. - * - * Additional rules about identifier binding. - * Bind for identifier to entity means that identifier first part match some node during analysis. - * If other parts of identifier cannot be resolved in that node, exception must be thrown. - * - * Example: - * CREATE TABLE test_table (id UInt64, compound_value Tuple(value UInt64)) ENGINE=TinyLog; - * SELECT compound_value.value, 1 AS compound_value FROM test_table; - * Identifier first part compound_value bound to entity with alias compound_value, but nested identifier part cannot be resolved from entity, - * lookup should not be continued, and exception must be thrown because if lookup continues that way identifier can be resolved from join tree. - * - * TODO: This was not supported properly before analyzer because nested identifier could not be resolved from alias. - * - * More complex example: - * CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; - * WITH cast(('Value'), 'Tuple (value UInt64') AS value SELECT (SELECT value FROM test_table); - * Identifier first part value bound to test_table column value, but nested identifier part cannot be resolved from it, - * lookup should not be continued, and exception must be thrown because if lookup continues identifier can be resolved from parent scope. - * - * TODO: Update exception messages - * TODO: Table identifiers with optional UUID. - * TODO: Lookup functions arrayReduce(sum, [1, 2, 3]); - * TODO: Support function identifier resolve from parent query scope, if lambda in parent scope does not capture any columns. - */ - -namespace -{ - -/// Identifier lookup context -enum class IdentifierLookupContext : uint8_t -{ - EXPRESSION = 0, - FUNCTION, - TABLE_EXPRESSION, -}; - -const char * toString(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "EXPRESSION"; - case IdentifierLookupContext::FUNCTION: return "FUNCTION"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "TABLE_EXPRESSION"; - } -} - -const char * toStringLowercase(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "expression"; - case IdentifierLookupContext::FUNCTION: return "function"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "table expression"; - } -} - -/** Structure that represent identifier lookup during query analysis. - * Lookup can be in query expression, function, table context. - */ -struct IdentifierLookup -{ - Identifier identifier; - IdentifierLookupContext lookup_context; - - bool isExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::EXPRESSION; - } - - bool isFunctionLookup() const - { - return lookup_context == IdentifierLookupContext::FUNCTION; - } - - bool isTableExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::TABLE_EXPRESSION; - } - - String dump() const - { - return identifier.getFullName() + ' ' + toString(lookup_context); - } -}; - -inline bool operator==(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return lhs.identifier.getFullName() == rhs.identifier.getFullName() && lhs.lookup_context == rhs.lookup_context; -} - -[[maybe_unused]] inline bool operator!=(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return !(lhs == rhs); -} - -struct IdentifierLookupHash -{ - size_t operator()(const IdentifierLookup & identifier_lookup) const - { - return std::hash()(identifier_lookup.identifier.getFullName()) ^ static_cast(identifier_lookup.lookup_context); - } -}; - -enum class IdentifierResolvePlace : UInt8 -{ - NONE = 0, - EXPRESSION_ARGUMENTS, - ALIASES, - JOIN_TREE, - /// Valid only for table lookup - CTE, - /// Valid only for table lookup - DATABASE_CATALOG -}; - -const char * toString(IdentifierResolvePlace resolved_identifier_place) -{ - switch (resolved_identifier_place) - { - case IdentifierResolvePlace::NONE: return "NONE"; - case IdentifierResolvePlace::EXPRESSION_ARGUMENTS: return "EXPRESSION_ARGUMENTS"; - case IdentifierResolvePlace::ALIASES: return "ALIASES"; - case IdentifierResolvePlace::JOIN_TREE: return "JOIN_TREE"; - case IdentifierResolvePlace::CTE: return "CTE"; - case IdentifierResolvePlace::DATABASE_CATALOG: return "DATABASE_CATALOG"; - } -} - -struct IdentifierResolveResult -{ - IdentifierResolveResult() = default; - - QueryTreeNodePtr resolved_identifier; - IdentifierResolvePlace resolve_place = IdentifierResolvePlace::NONE; - bool resolved_from_parent_scopes = false; - - [[maybe_unused]] bool isResolved() const - { - return resolve_place != IdentifierResolvePlace::NONE; - } - - [[maybe_unused]] bool isResolvedFromParentScopes() const - { - return resolved_from_parent_scopes; - } - - [[maybe_unused]] bool isResolvedFromExpressionArguments() const - { - return resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - } - - [[maybe_unused]] bool isResolvedFromAliases() const - { - return resolve_place == IdentifierResolvePlace::ALIASES; - } - - [[maybe_unused]] bool isResolvedFromJoinTree() const - { - return resolve_place == IdentifierResolvePlace::JOIN_TREE; - } - - [[maybe_unused]] bool isResolvedFromCTEs() const - { - return resolve_place == IdentifierResolvePlace::CTE; - } - - void dump(WriteBuffer & buffer) const - { - if (!resolved_identifier) - { - buffer << "unresolved"; - return; - } - - buffer << resolved_identifier->formatASTForErrorMessage() << " place " << toString(resolve_place) << " resolved from parent scopes " << resolved_from_parent_scopes; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -struct IdentifierResolveState -{ - IdentifierResolveResult resolve_result; - bool cyclic_identifier_resolve = false; -}; - -struct IdentifierResolveSettings -{ - /// Allow to check join tree during identifier resolution - bool allow_to_check_join_tree = true; - - /// Allow to check CTEs during table identifier resolution - bool allow_to_check_cte = true; - - /// Allow to check parent scopes during identifier resolution - bool allow_to_check_parent_scopes = true; - - /// Allow to check database catalog during table identifier resolution - bool allow_to_check_database_catalog = true; - - /// Allow to resolve subquery during identifier resolution - bool allow_to_resolve_subquery_during_identifier_resolution = true; -}; - -struct StringTransparentHash -{ - using is_transparent = void; - using hash = std::hash; - - [[maybe_unused]] size_t operator()(const char * data) const - { - return hash()(data); - } - - size_t operator()(std::string_view data) const - { - return hash()(data); - } - - size_t operator()(const std::string & data) const - { - return hash()(data); - } -}; - -using ColumnNameToColumnNodeMap = std::unordered_map>; - -struct TableExpressionData -{ - std::string table_expression_name; - std::string table_expression_description; - std::string database_name; - std::string table_name; - bool should_qualify_columns = true; - NamesAndTypes column_names_and_types; - ColumnNameToColumnNodeMap column_name_to_column_node; - std::unordered_set subcolumn_names; /// Subset columns that are subcolumns of other columns - std::unordered_set> column_identifier_first_parts; - - bool hasFullIdentifierName(IdentifierView identifier_view) const - { - return column_name_to_column_node.contains(identifier_view.getFullName()); - } - - bool canBindIdentifier(IdentifierView identifier_view) const - { - return column_identifier_first_parts.contains(identifier_view.at(0)); - } - - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Table expression name " << table_expression_name; - - if (!table_expression_description.empty()) - buffer << " table expression description " << table_expression_description; - - if (!database_name.empty()) - buffer << " database name " << database_name; - - if (!table_name.empty()) - buffer << " table name " << table_name; - - buffer << " should qualify columns " << should_qualify_columns; - buffer << " columns size " << column_name_to_column_node.size() << '\n'; - - for (const auto & [column_name, column_node] : column_name_to_column_node) - buffer << "Column name " << column_name << " column node " << column_node->dumpTree() << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -class ExpressionsStack -{ -public: - void push(const QueryTreeNodePtr & node) - { - if (node->hasAlias()) - { - const auto & node_alias = node->getAlias(); - alias_name_to_expressions[node_alias].push_back(node); - } - - if (const auto * function = node->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - ++aggregate_functions_counter; - } - - expressions.emplace_back(node); - } - - void pop() - { - const auto & top_expression = expressions.back(); - const auto & top_expression_alias = top_expression->getAlias(); - - if (!top_expression_alias.empty()) - { - auto it = alias_name_to_expressions.find(top_expression_alias); - auto & alias_expressions = it->second; - alias_expressions.pop_back(); - - if (alias_expressions.empty()) - alias_name_to_expressions.erase(it); - } - - if (const auto * function = top_expression->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - --aggregate_functions_counter; - } - - expressions.pop_back(); - } - - [[maybe_unused]] const QueryTreeNodePtr & getRoot() const - { - return expressions.front(); - } - - const QueryTreeNodePtr & getTop() const - { - return expressions.back(); - } - - [[maybe_unused]] bool hasExpressionWithAlias(const std::string & alias) const - { - return alias_name_to_expressions.contains(alias); - } - - bool hasAggregateFunction() const - { - return aggregate_functions_counter > 0; - } - - QueryTreeNodePtr getExpressionWithAlias(const std::string & alias) const - { - auto expression_it = alias_name_to_expressions.find(alias); - if (expression_it == alias_name_to_expressions.end()) - return {}; - - return expression_it->second.front(); - } - - [[maybe_unused]] size_t size() const - { - return expressions.size(); - } - - bool empty() const - { - return expressions.empty(); - } - - void dump(WriteBuffer & buffer) const - { - buffer << expressions.size() << '\n'; - - for (const auto & expression : expressions) - { - buffer << "Expression "; - buffer << expression->formatASTForErrorMessage(); - - const auto & alias = expression->getAlias(); - if (!alias.empty()) - buffer << " alias " << alias; - - buffer << '\n'; - } - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } - -private: - QueryTreeNodes expressions; - size_t aggregate_functions_counter = 0; - std::unordered_map alias_name_to_expressions; -}; - -struct ScopeAliases -{ - /// Alias name to query expression node - std::unordered_map alias_name_to_expression_node_before_group_by; - std::unordered_map alias_name_to_expression_node_after_group_by; - - std::unordered_map * alias_name_to_expression_node = nullptr; - - /// Alias name to lambda node - std::unordered_map alias_name_to_lambda_node; - - /// Alias name to table expression node - std::unordered_map alias_name_to_table_expression_node; - - /// Expressions like `x as y` where we can't say whether it's a function, expression or table. - std::unordered_map transitive_aliases; - - /// Nodes with duplicated aliases - std::unordered_set nodes_with_duplicated_aliases; - std::vector cloned_nodes_with_duplicated_aliases; - - /// Names which are aliases from ARRAY JOIN. - /// This is needed to properly qualify columns from matchers and avoid name collision. - std::unordered_set array_join_aliases; - - std::unordered_map & getAliasMap(IdentifierLookupContext lookup_context) - { - switch (lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return *alias_name_to_expression_node; - case IdentifierLookupContext::FUNCTION: return alias_name_to_lambda_node; - case IdentifierLookupContext::TABLE_EXPRESSION: return alias_name_to_table_expression_node; - } - } - - enum class FindOption - { - FIRST_NAME, - FULL_NAME, - }; - - const std::string & getKey(const Identifier & identifier, FindOption find_option) - { - switch (find_option) - { - case FindOption::FIRST_NAME: return identifier.front(); - case FindOption::FULL_NAME: return identifier.getFullName(); - } - } - - QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) - { - auto & alias_map = getAliasMap(lookup.lookup_context); - const std::string * key = &getKey(lookup.identifier, find_option); - - auto it = alias_map.find(*key); - - if (it != alias_map.end()) - return &it->second; - - if (lookup.lookup_context == IdentifierLookupContext::TABLE_EXPRESSION) - return {}; - - while (it == alias_map.end()) - { - auto jt = transitive_aliases.find(*key); - if (jt == transitive_aliases.end()) - return {}; - - key = &(getKey(jt->second, find_option)); - it = alias_map.find(*key); - } - - return &it->second; - } - - const QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) const - { - return const_cast(this)->find(lookup, find_option); - } -}; - - -/** Projection names is name of query tree node that is used in projection part of query node. - * Example: SELECT id FROM test_table; - * `id` is projection name of column node - * - * Example: SELECT id AS id_alias FROM test_table; - * `id_alias` is projection name of column node - * - * Calculation of projection names is done during expression nodes resolution. This is done this way - * because after identifier node is resolved we lose information about identifier name. We could - * potentially save this information in query tree node itself, but that would require to clone it in some cases. - * Example: SELECT big_scalar_subquery AS a, a AS b, b AS c; - * All 3 nodes in projection are the same big_scalar_subquery, but they have different projection names. - * If we want to save it in query tree node, we have to clone subquery node that could lead to performance degradation. - * - * Possible solution is to separate query node metadata and query node content. So only node metadata could be cloned - * if we want to change projection name. This solution does not seem to be easy for client of query tree because projection - * name will be part of interface. If we potentially could hide projection names calculation in analyzer without introducing additional - * changes in query tree structure that would be preferable. - * - * Currently each resolve method returns projection names array. Resolve method must compute projection names of node. - * If node is resolved as list node this is case for `untuple` function or `matcher` result projection names array must contain projection names - * for result nodes. - * If node is not resolved as list node, projection names array contain single projection name for node. - * - * Rules for projection names: - * 1. If node has alias. It is node projection name. - * Except scenario where `untuple` function has alias. Example: SELECT untuple(expr) AS alias, alias. - * - * 2. For constant it is constant value string representation. - * - * 3. For identifier: - * If identifier is resolved from JOIN TREE, we want to remove additional identifier qualifications. - * Example: SELECT default.test_table.id FROM test_table. - * Result projection name is `id`. - * - * Example: SELECT t1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In example both test_table_1, test_table_2 have `id` column. - * In such case projection name is `t1.id` because if additional qualification is removed then column projection name `id` will be ambiguous. - * - * Example: SELECT default.test_table_1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In such case projection name is `test_table_1.id` because we remove unnecessary database qualification, but table name qualification cannot be removed - * because otherwise column projection name `id` will be ambiguous. - * - * If identifier is not resolved from JOIN TREE. Identifier name is projection name. - * Except scenario where `untuple` function resolved using identifier. Example: SELECT untuple(expr) AS alias, alias. - * Example: SELECT sum(1, 1) AS value, value. - * In such case both nodes have `value` projection names. - * - * Example: SELECT id AS value, value FROM test_table. - * In such case both nodes have have `value` projection names. - * - * Special case is `untuple` function. If `untuple` function specified with alias, then result nodes will have alias.tuple_column_name projection names. - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value) AS a; - * Result projection names are `value`, `a.id`. - * - * If `untuple` function does not have alias then result nodes will have `tupleElement(untuple_expression_projection_name, 'tuple_column_name') projection names. - * - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value); - * Result projection names are `value`, `tupleElement(value, 'id')`; - * - * 4. For function: - * Projection name consists from function_name(parameters_projection_names)(arguments_projection_names). - * Additionally if function is window function. Window node projection name is used with OVER clause. - * Example: function_name (parameters_names)(argument_projection_names) OVER window_name; - * Example: function_name (parameters_names)(argument_projection_names) OVER (PARTITION BY id ORDER BY id). - * Example: function_name (parameters_names)(argument_projection_names) OVER (window_name ORDER BY id). - * - * 5. For lambda: - * If it is standalone lambda that returns single expression, function projection name is used. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(1). - * Projection name is `lambda(1)`. - * - * If is it standalone lambda that returns list, projection names of list nodes are used. - * Example: WITH (x -> *) AS lambda SELECT lambda(1) FROM test_table; - * If test_table has two columns `id`, `value`. Then result projection names are `id`, `value`. - * - * If lambda is argument of function. - * Then projection name consists from lambda(tuple(lambda_arguments)(lambda_body_projection_name)); - * - * 6. For matcher: - * Matched nodes projection names are used as matcher projection names. - * - * Matched nodes must be qualified if needed. - * Example: SELECT * FROM test_table_1 AS t1, test_table_2 AS t2. - * In example table test_table_1 and test_table_2 both have `id`, `value` columns. - * Matched nodes after unqualified matcher resolve must be qualified to avoid ambiguous projection names. - * Result projection names must be `t1.id`, `t1.value`, `t2.id`, `t2.value`. - * - * There are special cases - * 1. For lambda inside APPLY matcher transformer: - * Example: SELECT * APPLY x -> toString(x) FROM test_table. - * In such case lambda argument projection name `x` will be replaced by matched node projection name. - * If table has two columns `id` and `value`. Then result projection names are `toString(id)`, `toString(value)`; - * - * 2. For unqualified matcher when JOIN tree contains JOIN with USING. - * Example: SELECT * FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING(id); - * Result projection names must be `id`, `t1.value`, `t2.value`. - * - * 7. For subquery: - * For subquery projection name consists of `_subquery_` prefix and implementation specific unique number suffix. - * Example: SELECT (SELECT 1), (SELECT 1 UNION DISTINCT SELECT 1); - * Result projection name can be `_subquery_1`, `subquery_2`; - * - * 8. For table: - * Table node can be used in expression context only as right argument of IN function. In that case identifier is used - * as table node projection name. - * Example: SELECT id IN test_table FROM test_table; - * Result projection name is `in(id, test_table)`. - */ -using ProjectionName = String; -using ProjectionNames = std::vector; -constexpr auto PROJECTION_NAME_PLACEHOLDER = "__projection_name_placeholder"; - -struct IdentifierResolveScope -{ - /// Construct identifier resolve scope using scope node, and parent scope - IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) + IdentifierResolveScope::IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) : scope_node(std::move(scope_node_)) , parent_scope(parent_scope_) { @@ -817,87 +38,7 @@ struct IdentifierResolveScope aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; } - QueryTreeNodePtr scope_node; - - IdentifierResolveScope * parent_scope = nullptr; - - ContextPtr context; - - /// Identifier lookup to result - std::unordered_map identifier_lookup_to_resolve_state; - - /// Argument can be expression like constant, column, function or table expression - std::unordered_map expression_argument_name_to_node; - - ScopeAliases aliases; - - /// Table column name to column node. Valid only during table ALIAS columns resolve. - ColumnNameToColumnNodeMap column_name_to_column_node; - - /// CTE name to query node - std::unordered_map cte_name_to_query_node; - - /// Window name to window node - std::unordered_map window_name_to_window_node; - - /// Current scope expression in resolve process stack - ExpressionsStack expressions_in_resolve_process_stack; - - /// Table expressions in resolve process - std::unordered_set table_expressions_in_resolve_process; - - /// Current scope expression - std::unordered_set non_cached_identifier_lookups_during_expression_resolve; - - /// Table expression node to data - std::unordered_map table_expression_node_to_data; - - QueryTreeNodePtrWithHashIgnoreTypesSet nullable_group_by_keys; - /// Here we count the number of nullable GROUP BY keys we met resolving expression. - /// E.g. for a query `SELECT tuple(tuple(number)) FROM numbers(10) GROUP BY (number, tuple(number)) with cube` - /// both `number` and `tuple(number)` would be in nullable_group_by_keys. - /// But when we resolve `tuple(tuple(number))` we should figure out that `tuple(number)` is already a key, - /// and we should not convert `number` to nullable. - size_t found_nullable_group_by_key_in_scope = 0; - - /** It's possible that after a JOIN, a column in the projection has a type different from the column in the source table. - * (For example, after join_use_nulls or USING column casted to supertype) - * However, the column in the projection still refers to the table as its source. - * This map is used to revert these columns back to their original columns in the source table. - */ - QueryTreeNodePtrWithHashMap join_columns_with_changed_types; - - /// Use identifier lookup to result cache - bool use_identifier_lookup_to_result_cache = true; - - /// Apply nullability to aggregation keys - bool group_by_use_nulls = false; - /// Join retutns NULLs instead of default values - bool join_use_nulls = false; - - /// JOINs count - size_t joins_count = 0; - - /// Subquery depth - size_t subquery_depth = 0; - - /** Scope join tree node for expression. - * Valid only during analysis construction for single expression. - */ - QueryTreeNodePtr expression_join_tree_node; - - /// Node hash to mask id map - std::shared_ptr> projection_mask_map; - - struct ResolvedFunctionsCache - { - FunctionOverloadResolverPtr resolver; - FunctionBasePtr function_base; - }; - - std::map functions_cache; - - [[maybe_unused]] const IdentifierResolveScope * getNearestQueryScope() const + [[maybe_unused]] const IdentifierResolveScope * IdentifierResolveScope::getNearestQueryScope() const { const IdentifierResolveScope * scope_to_check = this; while (scope_to_check != nullptr) @@ -911,7 +52,7 @@ struct IdentifierResolveScope return scope_to_check; } - IdentifierResolveScope * getNearestQueryScope() + IdentifierResolveScope * IdentifierResolveScope::getNearestQueryScope() { IdentifierResolveScope * scope_to_check = this; while (scope_to_check != nullptr) @@ -925,7 +66,7 @@ struct IdentifierResolveScope return scope_to_check; } - TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) + AnalysisTableExpressionData & IdentifierResolveScope::getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) { auto it = table_expression_node_to_data.find(table_expression_node); if (it == table_expression_node_to_data.end()) @@ -939,7 +80,7 @@ struct IdentifierResolveScope return it->second; } - const TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const + const AnalysisTableExpressionData & IdentifierResolveScope::getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const { auto it = table_expression_node_to_data.find(table_expression_node); if (it == table_expression_node_to_data.end()) @@ -953,7 +94,7 @@ struct IdentifierResolveScope return it->second; } - void pushExpressionNode(const QueryTreeNodePtr & node) + void IdentifierResolveScope::pushExpressionNode(const QueryTreeNodePtr & node) { bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); expressions_in_resolve_process_stack.push(node); @@ -961,7 +102,7 @@ struct IdentifierResolveScope aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; } - void popExpressionNode() + void IdentifierResolveScope::popExpressionNode() { bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); expressions_in_resolve_process_stack.pop(); @@ -970,7 +111,7 @@ struct IdentifierResolveScope } /// Dump identifier resolve scope - [[maybe_unused]] void dump(WriteBuffer & buffer) const + [[maybe_unused]] void IdentifierResolveScope::dump(WriteBuffer & buffer) const { buffer << "Scope node " << scope_node->formatASTForErrorMessage() << '\n'; buffer << "Identifier lookup to resolve state " << identifier_lookup_to_resolve_state.size() << '\n'; @@ -1028,7452 +169,11 @@ struct IdentifierResolveScope buffer << "Subquery depth " << subquery_depth << '\n'; } - [[maybe_unused]] String dump() const + [[maybe_unused]] String IdentifierResolveScope::dump() const { WriteBufferFromOwnString buffer; dump(buffer); return buffer.str(); } -}; - - -/** Visitor that extracts expression and function aliases from node and initialize scope tables with it. - * Does not go into child lambdas and queries. - * - * Important: - * Identifier nodes with aliases are added both in alias to expression and alias to function map. - * - * These is necessary because identifier with alias can give alias name to any query tree node. - * - * Example: - * WITH (x -> x + 1) AS id, id AS value SELECT value(1); - * In this example id as value is identifier node that has alias, during scope initialization we cannot derive - * that id is actually lambda or expression. - * - * There are no easy solution here, without trying to make full featured expression resolution at this stage. - * Example: - * WITH (x -> x + 1) AS id, id AS id_1, id_1 AS id_2 SELECT id_2(1); - * Example: SELECT a, b AS a, b AS c, 1 AS c; - * - * It is client responsibility after resolving identifier node with alias, make following actions: - * 1. If identifier node was resolved in function scope, remove alias from scope expression map. - * 2. If identifier node was resolved in expression scope, remove alias from scope function map. - * - * That way we separate alias map initialization and expressions resolution. - */ -class QueryExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit QueryExpressionsAliasVisitor(ScopeAliases & aliases_) - : aliases(aliases_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node, false /*is_lambda_node*/); - } - - bool needChildVisit(const QueryTreeNodePtr &, const QueryTreeNodePtr & child) - { - if (auto * lambda_node = child->as()) - { - updateAliasesIfNeeded(child, true /*is_lambda_node*/); - return false; - } - else if (auto * query_tree_node = child->as()) - { - if (query_tree_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - else if (auto * union_node = child->as()) - { - if (union_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - - return true; - } -private: - void addDuplicatingAlias(const QueryTreeNodePtr & node) - { - aliases.nodes_with_duplicated_aliases.emplace(node); - auto cloned_node = node->clone(); - aliases.cloned_nodes_with_duplicated_aliases.emplace_back(cloned_node); - aliases.nodes_with_duplicated_aliases.emplace(cloned_node); - } - - void updateAliasesIfNeeded(const QueryTreeNodePtr & node, bool is_lambda_node) - { - if (!node->hasAlias()) - return; - - // We should not resolve expressions to WindowNode - if (node->getNodeType() == QueryTreeNodeType::WINDOW) - return; - - const auto & alias = node->getAlias(); - - if (is_lambda_node) - { - if (aliases.alias_name_to_expression_node->contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_lambda_node.insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - return; - } - - if (aliases.alias_name_to_lambda_node.contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_expression_node->insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - /// If node is identifier put it into transitive aliases map. - if (const auto * identifier = typeid_cast(node.get())) - aliases.transitive_aliases.insert(std::make_pair(alias, identifier->getIdentifier())); - } - - ScopeAliases & aliases; -}; - -class TableExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit TableExpressionsAliasVisitor(IdentifierResolveScope & scope_) - : scope(scope_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node); - } - - static bool needChildVisit(const QueryTreeNodePtr & node, const QueryTreeNodePtr & child) - { - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::ARRAY_JOIN: - { - const auto & array_join_node = node->as(); - return child.get() == array_join_node.getTableExpression().get(); - } - case QueryTreeNodeType::JOIN: - { - const auto & join_node = node->as(); - return child.get() == join_node.getLeftTableExpression().get() || child.get() == join_node.getRightTableExpression().get(); - } - default: - { - break; - } - } - - return false; - } - -private: - void updateAliasesIfNeeded(const QueryTreeNodePtr & node) - { - if (!node->hasAlias()) - return; - - const auto & node_alias = node->getAlias(); - auto [_, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(node_alias, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple table expressions with same alias {}. In scope {}", - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - IdentifierResolveScope & scope; -}; - -class QueryAnalyzer -{ -public: - explicit QueryAnalyzer(bool only_analyze_) : only_analyze(only_analyze_) {} - - void resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context) - { - IdentifierResolveScope scope(node, nullptr /*parent_scope*/); - - if (!scope.context) - scope.context = context; - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::QUERY: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For query analysis table expression must be empty"); - - resolveQuery(node, scope); - break; - } - case QueryTreeNodeType::UNION: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For union analysis table expression must be empty"); - - resolveUnion(node, scope); - break; - } - case QueryTreeNodeType::IDENTIFIER: - [[fallthrough]]; - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - [[fallthrough]]; - case QueryTreeNodeType::FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::LIST: - { - if (table_expression) - { - scope.expression_join_tree_node = table_expression; - validateTableExpressionModifiers(scope.expression_join_tree_node, scope); - initializeTableExpressionData(scope.expression_join_tree_node, scope); - } - - if (node_type == QueryTreeNodeType::LIST) - resolveExpressionNodeList(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - else - resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - QueryExpressionsAliasVisitor expressions_alias_visitor(scope.aliases); - resolveTableFunction(node, scope, expressions_alias_visitor, false /*nested_table_function*/); - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Node {} with type {} is not supported by query analyzer. " - "Supported nodes are query, union, identifier, constant, column, function, list.", - node->formatASTForErrorMessage(), - node->getNodeTypeName()); - } - } - } - -private: - /// Utility functions - - static bool isExpressionNodeType(QueryTreeNodeType node_type); - - static bool isFunctionExpressionNodeType(QueryTreeNodeType node_type); - - static bool isSubqueryNodeType(QueryTreeNodeType node_type); - - static bool isTableExpressionNodeType(QueryTreeNodeType node_type); - - static DataTypePtr getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node); - - static ProjectionName calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, - const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names); - - static ProjectionName calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name); - - static ProjectionName calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, - const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, - const ProjectionName & fill_to_expression_projection_name, - const ProjectionName & fill_step_expression_projection_name); - - static void collectCompoundExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result); - - static void collectTableExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result); - - static void collectScopeValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static void collectScopeWithParentScopesValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static std::vector collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers); - - static QueryTreeNodePtr wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path); - - QueryTreeNodePtr tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context); - - void evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & query_tree_node, IdentifierResolveScope & scope); - - static void mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope); - - void replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope); - - static void convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope); - - static void validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope); - - static std::pair recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into); - - static void expandGroupByAll(QueryNode & query_tree_node_typed); - - void expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings); - - static std::string - rewriteAggregateFunctionNameIfNeeded(const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context); - - static std::optional getColumnSideFromJoinTree(const QueryTreeNodePtr & resolved_identifier, const JoinNode & join_node) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - return {}; - - if (resolved_identifier->getNodeType() == QueryTreeNodeType::FUNCTION) - { - const auto & resolved_function = resolved_identifier->as(); - - const auto & argument_nodes = resolved_function.getArguments().getNodes(); - - std::optional result; - for (const auto & argument_node : argument_nodes) - { - auto table_side = getColumnSideFromJoinTree(argument_node, join_node); - if (table_side && result && *table_side != *result) - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Ambiguous identifier {}. In scope {}", - resolved_identifier->formatASTForErrorMessage(), - join_node.formatASTForErrorMessage()); - } - result = table_side; - } - return result; - } - - const auto * column_src = resolved_identifier->as().getColumnSource().get(); - - if (join_node.getLeftTableExpression().get() == column_src) - return JoinTableSide::Left; - if (join_node.getRightTableExpression().get() == column_src) - return JoinTableSide::Right; - return {}; - } - - static QueryTreeNodePtr convertJoinedColumnTypeToNullIfNeeded( - const QueryTreeNodePtr & resolved_identifier, - const JoinKind & join_kind, - std::optional resolved_side, - IdentifierResolveScope & scope) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && - JoinCommon::canBecomeNullable(resolved_identifier->getResultType()) && - (isFull(join_kind) || - (isLeft(join_kind) && resolved_side && *resolved_side == JoinTableSide::Right) || - (isRight(join_kind) && resolved_side && *resolved_side == JoinTableSide::Left))) - { - auto nullable_resolved_identifier = resolved_identifier->clone(); - auto & resolved_column = nullable_resolved_identifier->as(); - auto new_result_type = makeNullableOrLowCardinalityNullable(resolved_column.getColumnType()); - resolved_column.setColumnType(new_result_type); - if (resolved_column.hasExpression()) - { - auto & resolved_expression = resolved_column.getExpression(); - if (!resolved_expression->getResultType()->equals(*new_result_type)) - resolved_expression = buildCastFunction(resolved_expression, new_result_type, scope.context, true); - } - if (!nullable_resolved_identifier->isEqual(*resolved_identifier)) - scope.join_columns_with_changed_types[nullable_resolved_identifier] = resolved_identifier; - return nullable_resolved_identifier; - } - return nullptr; - } - - /// Resolve identifier functions - - static QueryTreeNodePtr tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context); - - QueryTreeNodePtr tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found = false); - - QueryTreeNodePtr tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings); - - QueryTreeNodePtr tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings = {}); - - QueryTreeNodePtr tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found = false); - - /// Resolve query tree nodes functions - - void qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static GetColumnsOptions buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context); - - using QueryTreeNodesWithNames = std::vector>; - - QueryTreeNodesWithNames getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope); - - void updateMatchedColumnsFromJoinUsing(QueryTreeNodesWithNames & result_matched_column_nodes_with_names, const QueryTreeNodePtr & source_table_expression, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionNames resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionName resolveWindow(QueryTreeNodePtr & window_node, IdentifierResolveScope & scope); - - ProjectionNames resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope); - - ProjectionNames resolveFunction(QueryTreeNodePtr & function_node, IdentifierResolveScope & scope); - - ProjectionNames resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias = false); - - ProjectionNames resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression); - - ProjectionNames resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope); - - void resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope); - - void resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope); - - void resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope); - - NamesAndTypes resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope); - - void initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope); - - void initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - void resolveTableFunction(QueryTreeNodePtr & table_function_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, bool nested_table_function); - - void resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope); - - void resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope); - - /// Lambdas that are currently in resolve process - std::unordered_set lambdas_in_resolve_process; - - /// CTEs that are currently in resolve process - std::unordered_set ctes_in_resolve_process; - - /// Function name to user defined lambda map - std::unordered_map function_name_to_user_defined_lambda; - - /// Array join expressions counter - size_t array_join_expressions_counter = 1; - - /// Subquery counter - size_t subquery_counter = 1; - - /// Global expression node to projection name map - std::unordered_map node_to_projection_name; - - /// Global resolve expression node to projection names map - std::unordered_map resolved_expressions; - - /// Global resolve expression node to tree size - std::unordered_map node_to_tree_size; - - /// Global scalar subquery to scalar value map - std::unordered_map scalar_subquery_to_scalar_value_local; - std::unordered_map scalar_subquery_to_scalar_value_global; - - const bool only_analyze; -}; - -/// Utility functions implementation - - -bool QueryAnalyzer::isExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::CONSTANT || node_type == QueryTreeNodeType::COLUMN || node_type == QueryTreeNodeType::FUNCTION - || node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isFunctionExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::LAMBDA; -} - -bool QueryAnalyzer::isSubqueryNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isTableExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::TABLE || node_type == QueryTreeNodeType::TABLE_FUNCTION || - isSubqueryNodeType(node_type); -} - -DataTypePtr QueryAnalyzer::getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node) -{ - auto node_type = query_tree_node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - { - return query_tree_node->getResultType(); - } - case QueryTreeNodeType::FUNCTION: - { - auto & function_node = query_tree_node->as(); - if (function_node.isResolved()) - return function_node.getResultType(); - break; - } - default: - { - break; - } - } - - return nullptr; -} - -ProjectionName QueryAnalyzer::calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names) -{ - const auto & function_node_typed = function_node->as(); - const auto & function_node_name = function_node_typed.getFunctionName(); - - bool is_array_function = function_node_name == "array"; - bool is_tuple_function = function_node_name == "tuple"; - - WriteBufferFromOwnString buffer; - - if (!is_array_function && !is_tuple_function) - buffer << function_node_name; - - if (!parameters_projection_names.empty()) - { - buffer << '('; - - size_t function_parameters_projection_names_size = parameters_projection_names.size(); - for (size_t i = 0; i < function_parameters_projection_names_size; ++i) - { - buffer << parameters_projection_names[i]; - - if (i + 1 != function_parameters_projection_names_size) - buffer << ", "; - } - - buffer << ')'; - } - - char open_bracket = '('; - char close_bracket = ')'; - - if (is_array_function) - { - open_bracket = '['; - close_bracket = ']'; - } - - buffer << open_bracket; - - size_t function_arguments_projection_names_size = arguments_projection_names.size(); - for (size_t i = 0; i < function_arguments_projection_names_size; ++i) - { - buffer << arguments_projection_names[i]; - - if (i + 1 != function_arguments_projection_names_size) - buffer << ", "; - } - - buffer << close_bracket; - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name) -{ - const auto & window_node_typed = window_node->as(); - const auto & window_frame = window_node_typed.getWindowFrame(); - - bool parent_window_node_has_partition_by = false; - bool parent_window_node_has_order_by = false; - - if (parent_window_node) - { - const auto & parent_window_node_typed = parent_window_node->as(); - parent_window_node_has_partition_by = parent_window_node_typed.hasPartitionBy(); - parent_window_node_has_order_by = parent_window_node_typed.hasOrderBy(); - } - - WriteBufferFromOwnString buffer; - - if (!parent_window_name.empty()) - buffer << parent_window_name; - - if (!partition_by_projection_names.empty() && !parent_window_node_has_partition_by) - { - if (!parent_window_name.empty()) - buffer << ' '; - - buffer << "PARTITION BY "; - - size_t partition_by_projection_names_size = partition_by_projection_names.size(); - for (size_t i = 0; i < partition_by_projection_names_size; ++i) - { - buffer << partition_by_projection_names[i]; - if (i + 1 != partition_by_projection_names_size) - buffer << ", "; - } - } - - if (!order_by_projection_names.empty() && !parent_window_node_has_order_by) - { - if (!partition_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << "ORDER BY "; - - size_t order_by_projection_names_size = order_by_projection_names.size(); - for (size_t i = 0; i < order_by_projection_names_size; ++i) - { - buffer << order_by_projection_names[i]; - if (i + 1 != order_by_projection_names_size) - buffer << ", "; - } - } - - if (!window_frame.is_default) - { - if (!partition_by_projection_names.empty() || !order_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << window_frame.type << " BETWEEN "; - if (window_frame.begin_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.begin_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_begin_offset_projection_name; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - - buffer << " AND "; - - if (window_frame.end_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.end_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_end_offset_projection_name; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - } - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, const ProjectionName & fill_to_expression_projection_name, const ProjectionName & fill_step_expression_projection_name) -{ - auto & sort_node_typed = sort_column_node->as(); - - WriteBufferFromOwnString sort_column_projection_name_buffer; - sort_column_projection_name_buffer << sort_expression_projection_name; - - auto sort_direction = sort_node_typed.getSortDirection(); - sort_column_projection_name_buffer << (sort_direction == SortDirection::ASCENDING ? " ASC" : " DESC"); - - auto nulls_sort_direction = sort_node_typed.getNullsSortDirection(); - - if (nulls_sort_direction) - sort_column_projection_name_buffer << " NULLS " << (nulls_sort_direction == sort_direction ? "LAST" : "FIRST"); - - if (auto collator = sort_node_typed.getCollator()) - sort_column_projection_name_buffer << " COLLATE " << collator->getLocale(); - - if (sort_node_typed.withFill()) - { - sort_column_projection_name_buffer << " WITH FILL"; - - if (sort_node_typed.hasFillFrom()) - sort_column_projection_name_buffer << " FROM " << fill_from_expression_projection_name; - - if (sort_node_typed.hasFillTo()) - sort_column_projection_name_buffer << " TO " << fill_to_expression_projection_name; - - if (sort_node_typed.hasFillStep()) - sort_column_projection_name_buffer << " STEP " << fill_step_expression_projection_name; - } - - return sort_column_projection_name_buffer.str(); -} - -/// Get valid identifiers for typo correction from compound expression -void QueryAnalyzer::collectCompoundExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result) -{ - IDataType::forEachSubcolumn([&](const auto &, const auto & name, const auto &) - { - Identifier subcolumn_indentifier(name); - size_t new_identifier_size = valid_identifier_prefix.getPartsSize() + subcolumn_indentifier.getPartsSize(); - - if (new_identifier_size == unresolved_identifier.getPartsSize()) - { - auto new_identifier = valid_identifier_prefix; - for (const auto & part : subcolumn_indentifier) - new_identifier.push_back(part); - - valid_identifiers_result.insert(std::move(new_identifier)); - } - }, ISerialization::SubstreamData(compound_expression_type->getDefaultSerialization())); -} - -/// Get valid identifiers for typo correction from table expression -void QueryAnalyzer::collectTableExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result) -{ - for (const auto & [column_name, column_node] : table_expression_data.column_name_to_column_node) - { - Identifier column_identifier(column_name); - if (unresolved_identifier.getPartsSize() == column_identifier.getPartsSize()) - valid_identifiers_result.insert(column_identifier); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier, - valid_identifiers_result); - - if (table_expression->hasAlias()) - { - Identifier column_identifier_with_alias({table_expression->getAlias()}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_alias.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_alias.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_alias); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_alias, - valid_identifiers_result); - } - - if (!table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name({table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name, - valid_identifiers_result); - } - - if (!table_expression_data.database_name.empty() && !table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name_and_database_name({table_expression_data.database_name, table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name_and_database_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name_and_database_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name_and_database_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name_and_database_name, - valid_identifiers_result); - } - } -} - -/// Get valid identifiers for typo correction from scope without looking at parent scopes -void QueryAnalyzer::collectScopeValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - bool identifier_is_short = unresolved_identifier.isShort(); - bool identifier_is_compound = unresolved_identifier.isCompound(); - - if (allow_expression_identifiers) - { - for (const auto & [name, expression] : *scope.aliases.alias_name_to_expression_node) - { - assert(expression); - auto expression_identifier = Identifier(name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - - for (const auto & [table_expression, table_expression_data] : scope.table_expression_node_to_data) - { - collectTableExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - table_expression, - table_expression_data, - valid_identifiers_result); - } - } - - if (identifier_is_short) - { - if (allow_function_identifiers) - { - for (const auto & [name, _] : *scope.aliases.alias_name_to_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - - if (allow_table_expression_identifiers) - { - for (const auto & [name, _] : scope.aliases.alias_name_to_table_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - } - - for (const auto & [argument_name, expression] : scope.expression_argument_name_to_node) - { - assert(expression); - auto expression_node_type = expression->getNodeType(); - - if (allow_expression_identifiers && isExpressionNodeType(expression_node_type)) - { - auto expression_identifier = Identifier(argument_name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - else if (identifier_is_short && allow_function_identifiers && isFunctionExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - else if (allow_table_expression_identifiers && isTableExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - } -} - -void QueryAnalyzer::collectScopeWithParentScopesValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - const IdentifierResolveScope * current_scope = &scope; - - while (current_scope) - { - collectScopeValidIdentifiersForTypoCorrection(unresolved_identifier, - *current_scope, - allow_expression_identifiers, - allow_function_identifiers, - allow_table_expression_identifiers, - valid_identifiers_result); - - current_scope = current_scope->parent_scope; - } -} - -std::vector QueryAnalyzer::collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers) -{ - std::vector prompting_strings; - prompting_strings.reserve(valid_identifiers.size()); - - for (const auto & valid_identifier : valid_identifiers) - prompting_strings.push_back(valid_identifier.getFullName()); - - return NamePrompter<1>::getHints(unresolved_identifier.getFullName(), prompting_strings); -} - -/** Wrap expression node in tuple element function calls for nested paths. - * Example: Expression node: compound_expression. Nested path: nested_path_1.nested_path_2. - * Result: tupleElement(tupleElement(compound_expression, 'nested_path_1'), 'nested_path_2'). - */ -QueryTreeNodePtr QueryAnalyzer::wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path) -{ - size_t nested_path_parts_size = nested_path.getPartsSize(); - for (size_t i = 0; i < nested_path_parts_size; ++i) - { - const auto & nested_path_part = nested_path[i]; - auto tuple_element_function = std::make_shared("tupleElement"); - - auto & tuple_element_function_arguments_nodes = tuple_element_function->getArguments().getNodes(); - tuple_element_function_arguments_nodes.reserve(2); - tuple_element_function_arguments_nodes.push_back(expression_node); - tuple_element_function_arguments_nodes.push_back(std::make_shared(nested_path_part)); - - expression_node = std::move(tuple_element_function); - } - - return expression_node; -} - -/** Try to get lambda node from sql user defined functions if sql user defined function with function name exists. - * Returns lambda node if function exists, nullptr otherwise. - */ -QueryTreeNodePtr QueryAnalyzer::tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context) -{ - auto user_defined_function = UserDefinedSQLFunctionFactory::instance().tryGet(function_name); - if (!user_defined_function) - return {}; - - auto it = function_name_to_user_defined_lambda.find(function_name); - if (it != function_name_to_user_defined_lambda.end()) - return it->second; - - const auto & create_function_query = user_defined_function->as(); - auto result_node = buildQueryTree(create_function_query->function_core, context); - if (result_node->getNodeType() != QueryTreeNodeType::LAMBDA) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "SQL user defined function {} must represent lambda expression. Actual {}", - function_name, - create_function_query->function_core->formatForErrorMessage()); - - function_name_to_user_defined_lambda.emplace(function_name, result_node); - - return result_node; -} - -bool subtreeHasViewSource(const IQueryTreeNode * node, const Context & context) -{ - if (!node) - return false; - - if (const auto * table_node = node->as()) - { - if (table_node->getStorageID().getFullNameNotQuoted() == context.getViewSource()->getStorageID().getFullNameNotQuoted()) - return true; - } - - for (const auto & child : node->getChildren()) - if (subtreeHasViewSource(child.get(), context)) - return true; - - return false; -} - -/// Evaluate scalar subquery and perform constant folding if scalar subquery does not have constant value -void QueryAnalyzer::evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - auto * query_node = node->as(); - auto * union_node = node->as(); - if (!query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node must have query or union type. Actual {} {}", - node->getNodeTypeName(), - node->formatASTForErrorMessage()); - - auto & context = scope.context; - - Block scalar_block; - - auto node_without_alias = node->clone(); - node_without_alias->removeAlias(); - - QueryTreeNodePtrWithHash node_with_hash(node_without_alias); - auto str_hash = DB::toString(node_with_hash.hash); - - bool can_use_global_scalars = !only_analyze && !(context->getViewSource() && subtreeHasViewSource(node_without_alias.get(), *context)); - - auto & scalars_cache = can_use_global_scalars ? scalar_subquery_to_scalar_value_global : scalar_subquery_to_scalar_value_local; - - if (scalars_cache.contains(node_with_hash)) - { - if (can_use_global_scalars) - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - else - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesLocalCacheHit); - - scalar_block = scalars_cache.at(node_with_hash); - } - else if (context->hasQueryContext() && can_use_global_scalars && context->getQueryContext()->hasScalar(str_hash)) - { - scalar_block = context->getQueryContext()->getScalar(str_hash); - scalar_subquery_to_scalar_value_global.emplace(node_with_hash, scalar_block); - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - } - else - { - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesCacheMiss); - auto subquery_context = Context::createCopy(context); - - Settings subquery_settings = context->getSettings(); - subquery_settings.max_result_rows = 1; - subquery_settings.extremes = false; - subquery_context->setSettings(subquery_settings); - /// When execute `INSERT INTO t WITH ... SELECT ...`, it may lead to `Unknown columns` - /// exception with this settings enabled(https://github.com/ClickHouse/ClickHouse/issues/52494). - subquery_context->setSetting("use_structure_from_insertion_table_in_table_functions", false); - - auto options = SelectQueryOptions(QueryProcessingStage::Complete, scope.subquery_depth, true /*is_subquery*/); - options.only_analyze = only_analyze; - auto interpreter = std::make_unique(node->toAST(), subquery_context, subquery_context->getViewSource(), options); - - if (only_analyze) - { - /// If query is only analyzed, then constants are not correct. - scalar_block = interpreter->getSampleBlock(); - for (auto & column : scalar_block) - { - if (column.column->empty()) - { - auto mut_col = column.column->cloneEmpty(); - mut_col->insertDefault(); - column.column = std::move(mut_col); - } - } - } - else - { - auto io = interpreter->execute(); - PullingAsyncPipelineExecutor executor(io.pipeline); - io.pipeline.setProgressCallback(context->getProgressCallback()); - io.pipeline.setProcessListElement(context->getProcessListElement()); - - Block block; - - while (block.rows() == 0 && executor.pull(block)) - { - } - - if (block.rows() == 0) - { - auto types = interpreter->getSampleBlock().getDataTypes(); - if (types.size() != 1) - types = {std::make_shared(types)}; - - auto & type = types[0]; - if (!type->isNullable()) - { - if (!type->canBeInsideNullable()) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, - "Scalar subquery returned empty result of type {} which cannot be Nullable", - type->getName()); - - type = makeNullable(type); - } - - auto scalar_column = type->createColumn(); - scalar_column->insert(Null()); - scalar_block.insert({std::move(scalar_column), type, "null"}); - } - else - { - if (block.rows() != 1) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - Block tmp_block; - while (tmp_block.rows() == 0 && executor.pull(tmp_block)) - { - } - - if (tmp_block.rows() != 0) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - block = materializeBlock(block); - size_t columns = block.columns(); - - if (columns == 1) - { - auto & column = block.getByPosition(0); - /// Here we wrap type to nullable if we can. - /// It is needed cause if subquery return no rows, it's result will be Null. - /// In case of many columns, do not check it cause tuple can't be nullable. - if (!column.type->isNullable() && column.type->canBeInsideNullable()) - { - column.type = makeNullable(column.type); - column.column = makeNullable(column.column); - } - - scalar_block = block; - } - else - { - /** Make unique column names for tuple. - * - * Example: SELECT (SELECT 2 AS x, x) - */ - makeUniqueColumnNamesInBlock(block); - - scalar_block.insert({ - ColumnTuple::create(block.getColumns()), - std::make_shared(block.getDataTypes(), block.getNames()), - "tuple"}); - } - } - } - - scalars_cache.emplace(node_with_hash, scalar_block); - if (can_use_global_scalars && context->hasQueryContext()) - context->getQueryContext()->addScalar(str_hash, scalar_block); - } - - const auto & scalar_column_with_type = scalar_block.safeGetByPosition(0); - const auto & scalar_type = scalar_column_with_type.type; - - Field scalar_value; - scalar_column_with_type.column->get(0, scalar_value); - - const auto * scalar_type_name = scalar_block.safeGetByPosition(0).type->getFamilyName(); - static const std::set useless_literal_types = {"Array", "Tuple", "AggregateFunction", "Function", "Set", "LowCardinality"}; - auto * nearest_query_scope = scope.getNearestQueryScope(); - - /// Always convert to literals when there is no query context - if (!context->getSettingsRef().enable_scalar_subquery_optimization || - !useless_literal_types.contains(scalar_type_name) || - !context->hasQueryContext() || - !nearest_query_scope) - { - auto constant_value = std::make_shared(std::move(scalar_value), scalar_type); - auto constant_node = std::make_shared(constant_value, node); - - if (constant_node->getValue().isNull()) - { - node = buildCastFunction(constant_node, constant_node->getResultType(), context); - node = std::make_shared(std::move(constant_value), node); - } - else - node = std::move(constant_node); - - return; - } - - auto & nearest_query_scope_query_node = nearest_query_scope->scope_node->as(); - auto & mutable_context = nearest_query_scope_query_node.getMutableContext(); - - auto scalar_query_hash_string = DB::toString(node_with_hash.hash) + (only_analyze ? "_analyze" : ""); - - if (mutable_context->hasQueryContext()) - mutable_context->getQueryContext()->addScalar(scalar_query_hash_string, scalar_block); - - mutable_context->addScalar(scalar_query_hash_string, scalar_block); - - std::string get_scalar_function_name = "__getScalar"; - - auto scalar_query_hash_constant_value = std::make_shared(std::move(scalar_query_hash_string), std::make_shared()); - auto scalar_query_hash_constant_node = std::make_shared(std::move(scalar_query_hash_constant_value)); - - auto get_scalar_function_node = std::make_shared(get_scalar_function_name); - get_scalar_function_node->getArguments().getNodes().push_back(std::move(scalar_query_hash_constant_node)); - - auto get_scalar_function = FunctionFactory::instance().get(get_scalar_function_name, mutable_context); - get_scalar_function_node->resolveAsFunction(get_scalar_function->build(get_scalar_function_node->getArgumentColumns())); - - node = std::move(get_scalar_function_node); -} - -void QueryAnalyzer::mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope) -{ - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - - auto & parent_window_node_typed = parent_window_node->as(); - - /** If an existing_window_name is specified it must refer to an earlier - * entry in the WINDOW list; the new window copies its partitioning clause - * from that entry, as well as its ordering clause if any. In this case - * the new window cannot specify its own PARTITION BY clause, and it can - * specify ORDER BY only if the copied window does not have one. The new - * window always uses its own frame clause; the copied window must not - * specify a frame clause. - * https://www.postgresql.org/docs/current/sql-select.html - */ - if (window_node_typed.hasPartitionBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override PARTITION BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (window_node_typed.hasOrderBy() && parent_window_node_typed.hasOrderBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override a non-empty ORDER BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (!parent_window_node_typed.getWindowFrame().is_default) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parent window '{}' is not allowed to define a frame: while processing derived window definition '{}'. In scope {}", - parent_window_name, - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - window_node_typed.getPartitionByNode() = parent_window_node_typed.getPartitionBy().clone(); - - if (parent_window_node_typed.hasOrderBy()) - window_node_typed.getOrderByNode() = parent_window_node_typed.getOrderBy().clone(); -} - -/** Replace nodes in node list with positional arguments. - * - * Example: SELECT id, value FROM test_table GROUP BY 1, 2; - * Example: SELECT id, value FROM test_table ORDER BY 1, 2; - * Example: SELECT id, value FROM test_table LIMIT 5 BY 1, 2; - */ -void QueryAnalyzer::replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope) -{ - const auto & settings = scope.context->getSettingsRef(); - if (!settings.enable_positional_arguments || scope.context->getClientInfo().query_kind != ClientInfo::QueryKind::INITIAL_QUERY) - return; - - auto & node_list_typed = node_list->as(); - - for (auto & node : node_list_typed.getNodes()) - { - auto * node_to_replace = &node; - - if (auto * sort_node = node->as()) - node_to_replace = &sort_node->getExpression(); - - auto * constant_node = (*node_to_replace)->as(); - - if (!constant_node - || (constant_node->getValue().getType() != Field::Types::UInt64 - && constant_node->getValue().getType() != Field::Types::Int64)) - continue; - - UInt64 pos; - if (constant_node->getValue().getType() == Field::Types::UInt64) - { - pos = constant_node->getValue().get(); - } - else // Int64 - { - auto value = constant_node->getValue().get(); - if (value > 0) - pos = value; - else - { - if (value < -static_cast(projection_nodes.size())) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Negative positional argument number {} is out of bounds. Expected in range [-{}, -1]. In scope {}", - value, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - pos = projection_nodes.size() + value + 1; - } - } - - if (!pos || pos > projection_nodes.size()) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Positional argument number {} is out of bounds. Expected in range [1, {}]. In scope {}", - pos, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - - --pos; - *node_to_replace = projection_nodes[pos]->clone(); - if (auto it = resolved_expressions.find(projection_nodes[pos]); it != resolved_expressions.end()) - { - resolved_expressions[*node_to_replace] = it->second; - } - } -} - -void QueryAnalyzer::convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope) -{ - const auto * limit_offset_constant_node = expression_node->as(); - if (!limit_offset_constant_node || !isNativeNumber(removeNullable(limit_offset_constant_node->getResultType()))) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} expression must be constant with numeric type. Actual {}. In scope {}", - expression_description, - expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - Field converted_value = convertFieldToType(limit_offset_constant_node->getValue(), DataTypeUInt64()); - if (converted_value.isNull()) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} numeric constant expression is not representable as UInt64", - expression_description); - - auto constant_value = std::make_shared(std::move(converted_value), std::make_shared()); - auto result_constant_node = std::make_shared(std::move(constant_value)); - result_constant_node->getSourceExpression() = limit_offset_constant_node->getSourceExpression(); - - expression_node = std::move(result_constant_node); -} - -void QueryAnalyzer::validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unexpected table expression. Expected table, table function, query or union node. Table node: {}, scope node: {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (table_node || table_function_node) - { - auto table_expression_modifiers = table_node ? table_node->getTableExpressionModifiers() : table_function_node->getTableExpressionModifiers(); - - if (table_expression_modifiers.has_value()) - { - const auto & storage = table_node ? table_node->getStorage() : table_function_node->getStorage(); - if (table_expression_modifiers->hasFinal() && !storage->supportsFinal()) - throw Exception(ErrorCodes::ILLEGAL_FINAL, - "Storage {} doesn't support FINAL", - storage->getName()); - - if (table_expression_modifiers->hasSampleSizeRatio() && !storage->supportsSampling()) - throw Exception(ErrorCodes::SAMPLING_NOT_SUPPORTED, - "Storage {} doesn't support sampling", - storage->getStorageID().getFullNameNotQuoted()); - } - } -} - -void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - bool table_expression_has_alias = table_expression_node->hasAlias(); - if (table_expression_has_alias) - return; - - if (join_node->as().getKind() == JoinKind::Paste) - return; - - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - if ((query_node && !query_node->getCTEName().empty()) || (union_node && !union_node->getCTEName().empty())) - return; - - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || - table_expression_node_type == QueryTreeNodeType::QUERY || - table_expression_node_type == QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::ALIAS_REQUIRED, - "JOIN {} no alias for subquery or table function {}. " - "In scope {} (set joined_subquery_requires_alias = 0 to disable restriction)", - join_node->formatASTForErrorMessage(), - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); -} - -std::pair QueryAnalyzer::recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into) -{ - checkStackSize(); - - if (node->as()) - { - into.push_back(node); - return {false, 1}; - } - - auto * function = node->as(); - - if (!function) - return {false, 0}; - - if (function->isAggregateFunction()) - return {true, 0}; - - UInt64 pushed_children = 0; - bool has_aggregate = false; - - for (auto & child : function->getArguments().getNodes()) - { - auto [child_has_aggregate, child_pushed_children] = recursivelyCollectMaxOrdinaryExpressions(child, into); - has_aggregate |= child_has_aggregate; - pushed_children += child_pushed_children; - } - - /// The current function is not aggregate function and there is no aggregate function in its arguments, - /// so use the current function to replace its arguments - if (!has_aggregate) - { - for (UInt64 i = 0; i < pushed_children; i++) - into.pop_back(); - - into.push_back(node); - pushed_children = 1; - } - - return {has_aggregate, pushed_children}; -} - -/** Expand GROUP BY ALL by extracting all the SELECT-ed expressions that are not aggregate functions. - * - * For a special case that if there is a function having both aggregate functions and other fields as its arguments, - * the `GROUP BY` keys will contain the maximum non-aggregate fields we can extract from it. - * - * Example: - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY ALL - * will expand as - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY substring(a, 4, 2), substring(a, 1, 2) - */ -void QueryAnalyzer::expandGroupByAll(QueryNode & query_tree_node_typed) -{ - if (!query_tree_node_typed.isGroupByAll()) - return; - - auto & group_by_nodes = query_tree_node_typed.getGroupBy().getNodes(); - auto & projection_list = query_tree_node_typed.getProjection(); - - for (auto & node : projection_list.getNodes()) - recursivelyCollectMaxOrdinaryExpressions(node, group_by_nodes); - query_tree_node_typed.setIsGroupByAll(false); -} - -void QueryAnalyzer::expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings) -{ - if (!settings.enable_order_by_all || !query_tree_node_typed.isOrderByAll()) - return; - - auto * all_node = query_tree_node_typed.getOrderBy().getNodes()[0]->as(); - if (!all_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Select analyze for not sort node."); - - auto & projection_nodes = query_tree_node_typed.getProjection().getNodes(); - auto list_node = std::make_shared(); - list_node->getNodes().reserve(projection_nodes.size()); - - for (auto & node : projection_nodes) - { - /// Detect and reject ambiguous statements: - /// E.g. for a table with columns "all", "a", "b": - /// - SELECT all, a, b ORDER BY all; -- should we sort by all columns in SELECT or by column "all"? - /// - SELECT a, b AS all ORDER BY all; -- like before but "all" as alias - /// - SELECT func(...) AS all ORDER BY all; -- like before but "all" as function - /// - SELECT a, b ORDER BY all; -- tricky in other way: does the user want to sort by columns in SELECT clause or by not SELECTed column "all"? - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - auto projection_names = resolved_expression_it->second; - if (projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected 1 projection names. Actual {}", - projection_names.size()); - if (boost::iequals(projection_names[0], "all")) - throw Exception(ErrorCodes::UNEXPECTED_EXPRESSION, - "Cannot use ORDER BY ALL to sort a column with name 'all', please disable setting `enable_order_by_all` and try again"); - } - - auto sort_node = std::make_shared(node, all_node->getSortDirection(), all_node->getNullsSortDirection()); - list_node->getNodes().push_back(sort_node); - } - - query_tree_node_typed.getOrderByNode() = list_node; - query_tree_node_typed.setIsOrderByAll(false); -} - -std::string QueryAnalyzer::rewriteAggregateFunctionNameIfNeeded( - const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context) -{ - std::string result_aggregate_function_name = aggregate_function_name; - auto aggregate_function_name_lowercase = Poco::toLower(aggregate_function_name); - - const auto & settings = context->getSettingsRef(); - - if (aggregate_function_name_lowercase == "countdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - } - else if (aggregate_function_name_lowercase == "countdistinctif" || aggregate_function_name_lowercase == "countifdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - result_aggregate_function_name += "If"; - } - - /// Replace aggregateFunctionIfDistinct into aggregateFunctionDistinctIf to make execution more optimal - if (result_aggregate_function_name.ends_with("ifdistinct")) - { - size_t prefix_length = result_aggregate_function_name.size() - strlen("ifdistinct"); - result_aggregate_function_name = result_aggregate_function_name.substr(0, prefix_length) + "DistinctIf"; - } - - bool need_add_or_null = settings.aggregate_functions_null_for_empty && !result_aggregate_function_name.ends_with("OrNull"); - if (need_add_or_null) - { - auto properties = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (!properties->returns_default_when_only_null) - result_aggregate_function_name += "OrNull"; - } - - /** Move -OrNull suffix ahead, this should execute after add -OrNull suffix. - * Used to rewrite aggregate functions with -OrNull suffix in some cases. - * Example: sumIfOrNull. - * Result: sumOrNullIf. - */ - if (result_aggregate_function_name.ends_with("OrNull")) - { - auto function_properies = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (function_properies && !function_properies->returns_default_when_only_null) - { - size_t function_name_size = result_aggregate_function_name.size(); - - static constexpr std::array suffixes_to_replace = {"MergeState", "Merge", "State", "If"}; - for (const auto & suffix : suffixes_to_replace) - { - auto suffix_string_value = String(suffix); - auto suffix_to_check = suffix_string_value + "OrNull"; - - if (!result_aggregate_function_name.ends_with(suffix_to_check)) - continue; - - result_aggregate_function_name = result_aggregate_function_name.substr(0, function_name_size - suffix_to_check.size()); - result_aggregate_function_name += "OrNull"; - result_aggregate_function_name += suffix_string_value; - - break; - } - } - } - - return result_aggregate_function_name; -} - -/// Resolve identifier functions implementation - -/// Try resolve table identifier from database catalog -QueryTreeNodePtr QueryAnalyzer::tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context) -{ - size_t parts_size = table_identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected table identifier to contain 1 or 2 parts. Actual '{}'", - table_identifier.getFullName()); - - std::string database_name; - std::string table_name; - - if (table_identifier.isCompound()) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - else - { - table_name = table_identifier[0]; - } - - StorageID storage_id(database_name, table_name); - storage_id = context->resolveStorageID(storage_id); - bool is_temporary_table = storage_id.getDatabaseName() == DatabaseCatalog::TEMPORARY_DATABASE; - - StoragePtr storage; - - if (is_temporary_table) - storage = DatabaseCatalog::instance().getTable(storage_id, context); - else - storage = DatabaseCatalog::instance().tryGetTable(storage_id, context); - - if (!storage) - return {}; - - auto storage_lock = storage->lockForShare(context->getInitialQueryId(), context->getSettingsRef().lock_acquire_timeout); - auto storage_snapshot = storage->getStorageSnapshot(storage->getInMemoryMetadataPtr(), context); - auto result = std::make_shared(std::move(storage), std::move(storage_lock), std::move(storage_snapshot)); - if (is_temporary_table) - result->setTemporaryTableName(table_name); - - return result; -} - -/// Resolve identifier from compound expression -/// If identifier cannot be resolved throw exception or return nullptr if can_be_not_found is true -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found) -{ - Identifier compound_expression_identifier; - for (size_t i = 0; i < identifier_bind_size; ++i) - compound_expression_identifier.push_back(expression_identifier[i]); - - IdentifierView nested_path(expression_identifier); - nested_path.popFirst(identifier_bind_size); - - auto expression_type = compound_expression->getResultType(); - - if (!expression_type->hasSubcolumn(nested_path.getFullName())) - { - if (auto * column = compound_expression->as()) - { - const DataTypePtr & column_type = column->getColumn().getTypeInStorage(); - if (column_type->getTypeId() == TypeIndex::Object) - { - const auto * object_type = checkAndGetDataType(column_type.get()); - if (object_type->getSchemaFormat() == "json" && object_type->hasNullableSubcolumns()) - { - QueryTreeNodePtr constant_node_null = std::make_shared(Field()); - return constant_node_null; - } - } - } - - if (can_be_not_found) - return {}; - - std::unordered_set valid_identifiers; - collectCompoundExpressionValidIdentifiersForTypoCorrection(expression_identifier, - expression_type, - compound_expression_identifier, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(expression_identifier, valid_identifiers); - - String compound_expression_from_error_message; - if (!compound_expression_source.empty()) - { - compound_expression_from_error_message += " from "; - compound_expression_from_error_message += compound_expression_source; - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier {} nested path {} cannot be resolved from type {}{}. In scope {}{}", - expression_identifier, - nested_path, - expression_type->getName(), - compound_expression_from_error_message, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - QueryTreeNodePtr get_subcolumn_function = std::make_shared("getSubcolumn"); - auto & get_subcolumn_function_arguments_nodes = get_subcolumn_function->as()->getArguments().getNodes(); - - get_subcolumn_function_arguments_nodes.reserve(2); - get_subcolumn_function_arguments_nodes.push_back(compound_expression); - get_subcolumn_function_arguments_nodes.push_back(std::make_shared(nested_path.getFullName())); - - resolveFunction(get_subcolumn_function, scope); - return get_subcolumn_function; -} - -/** Resolve identifier from expression arguments. - * - * Expression arguments can be initialized during lambda analysis or they could be provided externally. - * Expression arguments must be already resolved nodes. This is client responsibility to resolve them. - * - * Example: SELECT arrayMap(x -> x + 1, [1,2,3]); - * For lambda x -> x + 1, `x` is lambda expression argument. - * - * Resolve strategy: - * 1. Try to bind identifier to scope argument name to node map. - * 2. If identifier is binded but expression context and node type are incompatible return nullptr. - * - * It is important to support edge cases, where we lookup for table or function node, but argument has same name. - * Example: WITH (x -> x + 1) AS func, (func -> func(1) + func) AS lambda SELECT lambda(1); - * - * 3. If identifier is compound and identifier lookup is in expression context use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - auto it = scope.expression_argument_name_to_node.find(identifier_lookup.identifier.getFullName()); - bool resolve_full_identifier = it != scope.expression_argument_name_to_node.end(); - - if (!resolve_full_identifier) - { - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - it = scope.expression_argument_name_to_node.find(identifier_bind_part); - if (it == scope.expression_argument_name_to_node.end()) - return {}; - } - - auto node_type = it->second->getNodeType(); - if (identifier_lookup.isExpressionLookup() && !isExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isTableExpressionLookup() && !isTableExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isFunctionLookup() && !isFunctionExpressionNodeType(node_type)) - return {}; - - if (!resolve_full_identifier && identifier_lookup.identifier.isCompound() && identifier_lookup.isExpressionLookup()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return it->second; -} - -bool QueryAnalyzer::tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope) -{ - return scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME) != nullptr || scope.aliases.array_join_aliases.contains(identifier_lookup.identifier.front()); -} - -/** Resolve identifier from scope aliases. - * - * Resolve strategy: - * 1. If alias is registered in current expressions that are in resolve process and if top expression is not part of bottom expression with the same alias subtree - * throw cyclic aliases exception. - * Otherwise prevent cache usage for identifier lookup and return nullptr. - * - * This is special scenario where identifier has name the same as alias name in one of its parent expressions including itself. - * In such case we cannot resolve identifier from aliases because of recursion. It is client responsibility to register and deregister alias - * names during expressions resolve. - * - * We must prevent cache usage for lookup because lookup outside of expression is supposed to return other value. - * Example: SELECT (id + 1) AS id, id + 2. Lookup for id inside (id + 1) as id should return id from table, but lookup (id + 2) should return - * (id + 1) AS id. - * - * Below cases should work: - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * SELECT (id + 1) AS id FROM test_table; - * SELECT (1 + (1 + id)) AS id FROM test_table; - * - * Below cases should throw cyclic aliases exception: - * SELECT (id + b) AS id, id as b FROM test_table; - * SELECT (1 + b + 1 + id) AS id, b as c, id as b FROM test_table; - * - * 2. Depending on IdentifierLookupContext get alias name to node map from IdentifierResolveScope. - * 3. Try to bind identifier to alias name in map. If there are no such binding return nullptr. - * 4. If node in map is not resolved, resolve it. It is important in case of compound expressions. - * Example: SELECT value.a, cast('(1)', 'Tuple(a UInt64)') AS value; - * - * Special case if node is identifier node. - * Example: SELECT value, id AS value FROM test_table; - * - * Add node in current scope expressions in resolve process stack. - * Try to resolve identifier. - * If identifier is resolved, depending on lookup context, erase entry from expression or lambda map. Check QueryExpressionsAliasVisitor documentation. - * Pop node from current scope expressions in resolve process stack. - * - * 5. If identifier is compound and identifier lookup is in expression context, use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - auto * it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME); - if (it == nullptr) - return {}; - - QueryTreeNodePtr & alias_node = *it; - - if (!alias_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node with alias {} is not valid. In scope {}", - identifier_bind_part, - scope.scope_node->formatASTForErrorMessage()); - - if (auto root_expression_with_alias = scope.expressions_in_resolve_process_stack.getExpressionWithAlias(identifier_bind_part)) - { - const auto top_expression = scope.expressions_in_resolve_process_stack.getTop(); - - if (!isNodePartOfTree(top_expression.get(), root_expression_with_alias.get())) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - scope.non_cached_identifier_lookups_during_expression_resolve.insert(identifier_lookup); - return {}; - } - - auto node_type = alias_node->getNodeType(); - - /// Resolve expression if necessary - if (node_type == QueryTreeNodeType::IDENTIFIER) - { - scope.pushExpressionNode(alias_node); - - auto & alias_identifier_node = alias_node->as(); - auto identifier = alias_identifier_node.getIdentifier(); - auto lookup_result = tryResolveIdentifier(IdentifierLookup{identifier, identifier_lookup.lookup_context}, scope, identifier_resolve_settings); - if (!lookup_result.resolved_identifier) - { - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(identifier, scope, true, false, false, valid_identifiers); - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {} identifier '{}'. In scope {}{}", - toStringLowercase(identifier_lookup.lookup_context), - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - alias_node = lookup_result.resolved_identifier; - scope.popExpressionNode(); - } - else if (node_type == QueryTreeNodeType::FUNCTION) - { - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - else if (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION) - { - if (identifier_resolve_settings.allow_to_resolve_subquery_during_identifier_resolution) - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, identifier_lookup.isTableExpressionLookup() /*allow_table_expression*/); - } - - if (identifier_lookup.identifier.isCompound() && alias_node) - { - if (identifier_lookup.isExpressionLookup()) - { - return tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - 1 /*identifier_bind_size*/, - alias_node, - {} /* compound_expression_source */, - scope, - identifier_resolve_settings.allow_to_check_join_tree /* can_be_not_found */); - } - else if (identifier_lookup.isFunctionLookup() || identifier_lookup.isTableExpressionLookup()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Compound identifier '{}' cannot be resolved as {}. In scope {}", - identifier_lookup.identifier.getFullName(), - identifier_lookup.isFunctionLookup() ? "function" : "table expression", - scope.scope_node->formatASTForErrorMessage()); - } - } - - return alias_node; -} - -/** Resolve identifier from table columns. - * - * 1. If table column nodes are empty or identifier is not expression lookup return nullptr. - * 2. If identifier full name match table column use column. Save information that we resolve identifier using full name. - * 3. Else if identifier binds to table column, use column. - * 4. Try to resolve column ALIAS expression if it exists. - * 5. If identifier was compound and was not resolved using full name during step 1 use `tryResolveIdentifierFromCompoundExpression`. - * This can be the case with compound ALIAS columns. - * - * Example: - * CREATE TABLE test_table (id UInt64, value Tuple(id UInt64, value String), alias_value ALIAS value.id) ENGINE=TinyLog; - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - if (scope.column_name_to_column_node.empty() || !identifier_lookup.isExpressionLookup()) - return {}; - - const auto & identifier = identifier_lookup.identifier; - auto it = scope.column_name_to_column_node.find(identifier.getFullName()); - bool full_column_name_match = it != scope.column_name_to_column_node.end(); - - if (!full_column_name_match) - { - it = scope.column_name_to_column_node.find(identifier_lookup.identifier[0]); - if (it == scope.column_name_to_column_node.end()) - return {}; - } - - if (it->second->hasExpression()) - resolveExpressionNode(it->second->getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - QueryTreeNodePtr result = it->second; - - if (!full_column_name_match && identifier.isCompound()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return result; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - if (parts_size == 1 && path_start == table_name) - return true; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return true; - else - return false; - } - - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier)) || table_expression_data.canBindIdentifier(IdentifierView(identifier))) - return true; - - if (identifier.getPartsSize() == 1) - return false; - - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return true; - - if (identifier.getPartsSize() == 2) - return false; - - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return true; - - return false; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node_to_ignore, - const IdentifierResolveScope & scope) -{ - bool can_bind_identifier_to_table_expression = false; - - for (const auto & [table_expression_node, _] : scope.table_expression_node_to_data) - { - if (table_expression_node.get() == table_expression_node_to_ignore.get()) - continue; - - can_bind_identifier_to_table_expression = tryBindIdentifierToTableExpression(identifier_lookup, table_expression_node, scope); - if (can_bind_identifier_to_table_expression) - break; - } - - return can_bind_identifier_to_table_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found) -{ - auto identifier_without_column_qualifier = identifier; - identifier_without_column_qualifier.popFirst(identifier_column_qualifier_parts); - - /** Compound identifier cannot be resolved directly from storage if storage is not table. - * - * Example: SELECT test_table.id.value1.value2 FROM test_table; - * In table storage column test_table.id.value1.value2 will exists. - * - * Example: SELECT test_subquery.compound_expression.value FROM (SELECT compound_expression AS value) AS test_subquery; - * Here there is no column with name test_subquery.compound_expression.value, and additional wrap in tuple element is required. - */ - - QueryTreeNodePtr result_expression; - bool match_full_identifier = false; - - const auto & identifier_full_name = identifier_without_column_qualifier.getFullName(); - auto it = table_expression_data.column_name_to_column_node.find(identifier_full_name); - bool can_resolve_directly_from_storage = it != table_expression_data.column_name_to_column_node.end(); - if (can_resolve_directly_from_storage && table_expression_data.subcolumn_names.contains(identifier_full_name)) - { - /** In the case when we have an ARRAY JOIN, we should not resolve subcolumns directly from storage. - * For example, consider the following SQL query: - * SELECT ProfileEvents.Values FROM system.query_log ARRAY JOIN ProfileEvents - * In this case, ProfileEvents.Values should also be array joined, not directly resolved from storage. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - if (nearest_query_scope_query_node && nearest_query_scope_query_node->getJoinTree()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - can_resolve_directly_from_storage = false; - } - - if (can_resolve_directly_from_storage) - { - match_full_identifier = true; - result_expression = it->second; - } - else - { - it = table_expression_data.column_name_to_column_node.find(identifier_without_column_qualifier.at(0)); - if (it != table_expression_data.column_name_to_column_node.end()) - result_expression = it->second; - } - - bool clone_is_needed = true; - - String table_expression_source = table_expression_data.table_expression_description; - if (!table_expression_data.table_expression_name.empty()) - table_expression_source += " with name " + table_expression_data.table_expression_name; - - if (result_expression && !match_full_identifier && identifier_without_column_qualifier.isCompound()) - { - size_t identifier_bind_size = identifier_column_qualifier_parts + 1; - result_expression = tryResolveIdentifierFromCompoundExpression(identifier, - identifier_bind_size, - result_expression, - table_expression_source, - scope, - can_be_not_found); - if (can_be_not_found && !result_expression) - return {}; - clone_is_needed = false; - } - - if (!result_expression) - { - QueryTreeNodes nested_column_nodes; - DataTypes nested_types; - Array nested_names_array; - - for (const auto & [column_name, _] : table_expression_data.column_names_and_types) - { - Identifier column_name_identifier_without_last_part(column_name); - auto column_name_identifier_last_part = column_name_identifier_without_last_part.getParts().back(); - column_name_identifier_without_last_part.popLast(); - - if (identifier_without_column_qualifier.getFullName() != column_name_identifier_without_last_part.getFullName()) - continue; - - auto column_node_it = table_expression_data.column_name_to_column_node.find(column_name); - if (column_node_it == table_expression_data.column_name_to_column_node.end()) - continue; - - const auto & column_node = column_node_it->second; - const auto & column_type = column_node->getColumnType(); - const auto * column_type_array = typeid_cast(column_type.get()); - if (!column_type_array) - continue; - - nested_column_nodes.push_back(column_node); - nested_types.push_back(column_type_array->getNestedType()); - nested_names_array.push_back(Field(std::move(column_name_identifier_last_part))); - } - - if (!nested_types.empty()) - { - auto nested_function_node = std::make_shared("nested"); - auto & nested_function_node_arguments = nested_function_node->getArguments().getNodes(); - - auto nested_function_names_array_type = std::make_shared(std::make_shared()); - auto nested_function_names_constant_node = std::make_shared(std::move(nested_names_array), - std::move(nested_function_names_array_type)); - nested_function_node_arguments.push_back(std::move(nested_function_names_constant_node)); - nested_function_node_arguments.insert(nested_function_node_arguments.end(), - nested_column_nodes.begin(), - nested_column_nodes.end()); - - auto nested_function = FunctionFactory::instance().get(nested_function_node->getFunctionName(), scope.context); - nested_function_node->resolveAsFunction(nested_function->build(nested_function_node->getArgumentColumns())); - - clone_is_needed = false; - result_expression = std::move(nested_function_node); - } - } - - if (!result_expression) - { - if (can_be_not_found) - return {}; - std::unordered_set valid_identifiers; - collectTableExpressionValidIdentifiersForTypoCorrection(identifier, - table_expression_node, - table_expression_data, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Identifier '{}' cannot be resolved from {}. In scope {}{}", - identifier.getFullName(), - table_expression_source, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (clone_is_needed) - result_expression = result_expression->clone(); - - auto qualified_identifier = identifier; - - for (size_t i = 0; i < identifier_column_qualifier_parts; ++i) - { - auto qualified_identifier_with_removed_part = qualified_identifier; - qualified_identifier_with_removed_part.popFirst(); - - if (qualified_identifier_with_removed_part.empty()) - break; - - IdentifierLookup column_identifier_lookup = {qualified_identifier_with_removed_part, IdentifierLookupContext::EXPRESSION}; - if (tryBindIdentifierToAliases(column_identifier_lookup, scope)) - break; - - if (table_expression_data.should_qualify_columns && - tryBindIdentifierToTableExpressions(column_identifier_lookup, table_expression_node, scope)) - break; - - qualified_identifier = std::move(qualified_identifier_with_removed_part); - } - - auto qualified_identifier_full_name = qualified_identifier.getFullName(); - node_to_projection_name.emplace(result_expression, std::move(qualified_identifier_full_name)); - - return result_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (parts_size == 1 && path_start == table_name) - return table_expression_node; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return table_expression_node; - else - return {}; - } - - /** If identifier first part binds to some column start or table has full identifier name. Then we can try to find whole identifier in table. - * 1. Try to bind identifier first part to column in table, if true get full identifier from table or throw exception. - * 2. Try to bind identifier first part to table name or storage alias, if true remove first part and try to get full identifier from table or throw exception. - * Storage alias works for subquery, table function as well. - * 3. Try to bind identifier first parts to database name and table name, if true remove first two parts and try to get full identifier from table or throw exception. - */ - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier))) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/); - - if (table_expression_data.canBindIdentifier(IdentifierView(identifier))) - { - /** This check is insufficient to determine whether and identifier can be resolved from table expression. - * A further check will be performed in `tryResolveIdentifierFromStorage` to see if we have such a subcolumn. - * In cases where the subcolumn cannot be found we want to have `nullptr` instead of exception. - * So, we set `can_be_not_found = true` to have an attempt to resolve the identifier from another table expression. - * Example: `SELECT t.t from (SELECT 1 as t) AS a FULL JOIN (SELECT 1 as t) as t ON a.t = t.t;` - * Initially, we will try to resolve t.t from `a` because `t.` is bound to `1 as t`. However, as it is not a nested column, we will need to resolve it from the second table expression. - */ - auto resolved_identifier = tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/, true /*can_be_not_found*/); - if (resolved_identifier) - return resolved_identifier; - } - - if (identifier.getPartsSize() == 1) - return {}; - - const auto & table_name = table_expression_data.table_name; - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 1 /*identifier_column_qualifier_parts*/); - - if (identifier.getPartsSize() == 2) - return {}; - - const auto & database_name = table_expression_data.database_name; - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 2 /*identifier_column_qualifier_parts*/); - - return {}; -} - -QueryTreeNodePtr checkIsMissedObjectJSONSubcolumn(const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier) -{ - if (left_resolved_identifier && right_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT - && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL" && right_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (left_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (right_resolved_identifier && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & right_resolved_column = right_resolved_identifier->as(); - if (right_resolved_column.getValueStringRepresentation() == "NULL") - return right_resolved_identifier; - } - return {}; -} - -/// Used to replace columns that changed type because of JOIN to their original type -class ReplaceColumnsVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit ReplaceColumnsVisitor(const QueryTreeNodePtrWithHashMap & replacement_map_, const ContextPtr & context_) - : replacement_map(replacement_map_) - , context(context_) - {} - - /// Apply replacement transitively, because column may change it's type twice, one to have a supertype and then because of `joun_use_nulls` - static QueryTreeNodePtr findTransitiveReplacement(QueryTreeNodePtr node, const QueryTreeNodePtrWithHashMap & replacement_map_) - { - auto it = replacement_map_.find(node); - QueryTreeNodePtr result_node = nullptr; - for (; it != replacement_map_.end(); it = replacement_map_.find(result_node)) - { - if (result_node && result_node->isEqual(*it->second)) - { - Strings map_dump; - for (const auto & [k, v]: replacement_map_) - map_dump.push_back(fmt::format("{} -> {} (is_equals: {}, is_same: {})", - k.node->dumpTree(), v->dumpTree(), k.node->isEqual(*v), k.node == v)); - throw Exception(ErrorCodes::LOGICAL_ERROR, "Infinite loop in query tree replacement map: {}", fmt::join(map_dump, "; ")); - } - chassert(it->second); - - result_node = it->second; - } - return result_node; - } - - void visitImpl(QueryTreeNodePtr & node) - { - if (auto replacement_node = findTransitiveReplacement(node, replacement_map)) - node = replacement_node; - - if (auto * function_node = node->as(); function_node && function_node->isResolved()) - rerunFunctionResolve(function_node, context); - } - - /// We want to re-run resolve for function _after_ its arguments are replaced - bool shouldTraverseTopToBottom() const { return false; } - - bool needChildVisit(QueryTreeNodePtr & /* parent */, QueryTreeNodePtr & child) - { - /// Visit only expressions, but not subqueries - return child->getNodeType() == QueryTreeNodeType::IDENTIFIER - || child->getNodeType() == QueryTreeNodeType::LIST - || child->getNodeType() == QueryTreeNodeType::FUNCTION - || child->getNodeType() == QueryTreeNodeType::COLUMN; - } - -private: - const QueryTreeNodePtrWithHashMap & replacement_map; - const ContextPtr & context; -}; - -/// Compare resolved identifiers considering columns that become nullable after JOIN -bool resolvedIdenfiersFromJoinAreEquals( - const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier, - const IdentifierResolveScope & scope) -{ - auto left_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(left_resolved_identifier, scope.join_columns_with_changed_types); - const auto & left_resolved_to_compare = left_original_node ? left_original_node : left_resolved_identifier; - - auto right_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(right_resolved_identifier, scope.join_columns_with_changed_types); - const auto & right_resolved_to_compare = right_original_node ? right_original_node : right_resolved_identifier; - - return left_resolved_to_compare->isEqual(*right_resolved_to_compare, IQueryTreeNode::CompareOptions{.compare_aliases = false}); -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_join_node = table_expression_node->as(); - auto left_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getLeftTableExpression(), scope); - auto right_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getRightTableExpression(), scope); - - if (!identifier_lookup.isExpressionLookup()) - { - if (left_resolved_identifier && right_resolved_identifier) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.dump(), - scope.scope_node->formatASTForErrorMessage()); - - return left_resolved_identifier ? left_resolved_identifier : right_resolved_identifier; - } - - bool join_node_in_resolve_process = scope.table_expressions_in_resolve_process.contains(table_expression_node.get()); - - std::unordered_map join_using_column_name_to_column_node; - - if (!join_node_in_resolve_process && from_join_node.isUsingJoinExpression()) - { - auto & join_using_list = from_join_node.getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & column_node = join_using_node->as(); - join_using_column_name_to_column_node.emplace(column_node.getColumnName(), std::static_pointer_cast(join_using_node)); - } - } - - auto check_nested_column_not_in_using = [&join_using_column_name_to_column_node, &identifier_lookup](const QueryTreeNodePtr & node) - { - /** tldr: When an identifier is resolved into the function `nested` or `getSubcolumn`, and - * some column in its argument is in the USING list and its type has to be updated, we throw an error to avoid overcomplication. - * - * Identifiers can be resolved into functions in case of nested or subcolumns. - * For example `t.t.t` can be resolved into `getSubcolumn(t, 't.t')` function in case of `t` is `Tuple`. - * So, `t` in USING list is resolved from JOIN itself and has supertype of columns from left and right table. - * But `t` in `getSubcolumn` argument is still resolved from table and we need to update its type. - * - * Example: - * - * SELECT t.t FROM ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t UInt32, s1 String), s1 String) as t - * ) AS a FULL JOIN ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t Int32, s2 String), s2 String) as t - * ) AS b USING t; - * - * Result type of `t` is `Tuple(Tuple(Int64, String), String)` (different type and no names for subcolumns), - * so it may be tricky to have a correct type for `t.t` that is resolved into getSubcolumn(t, 't'). - * - * It can be more complicated in case of Nested subcolumns, in that case in query: - * SELECT t FROM ... JOIN ... USING (t.t) - * Here, `t` is resolved into function `nested(['t', 's'], t.t, t.s) so, `t.t` should be from JOIN and `t.s` should be from table. - * - * Updating type accordingly is pretty complicated, so just forbid such cases. - * - * While it still may work for storages that support selecting subcolumns directly without `getSubcolumn` function: - * SELECT t, t.t, toTypeName(t), toTypeName(t.t) FROM t1 AS a FULL JOIN t2 AS b USING t.t; - * We just support it as a best-effort: `t` will have original type from table, but `t.t` will have super-type from JOIN. - * Probably it's good to prohibit such cases as well, but it's not clear how to check it in general case. - */ - if (node->getNodeType() != QueryTreeNodeType::FUNCTION) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {}, expected function node", node->getNodeType()); - - const auto & function_argument_nodes = node->as().getArguments().getNodes(); - for (const auto & argument_node : function_argument_nodes) - { - if (argument_node->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_name = argument_node->as().getColumnName(); - if (join_using_column_name_to_column_node.contains(column_name)) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Cannot select subcolumn for identifier '{}' while joining using column '{}'", - identifier_lookup.identifier, column_name); - } - else if (argument_node->getNodeType() == QueryTreeNodeType::CONSTANT) - { - continue; - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {} for argument node in {}", - argument_node->getNodeType(), node->formatASTForErrorMessage()); - } - } - }; - - std::optional resolved_side; - QueryTreeNodePtr resolved_identifier; - - JoinKind join_kind = from_join_node.getKind(); - - /// If columns from left or right table were missed Object(Nullable('json')) subcolumns, they will be replaced - /// to ConstantNode(NULL), which can't be cast to ColumnNode, so we resolve it here. - if (auto missed_subcolumn_identifier = checkIsMissedObjectJSONSubcolumn(left_resolved_identifier, right_resolved_identifier)) - return missed_subcolumn_identifier; - - if (left_resolved_identifier && right_resolved_identifier) - { - auto using_column_node_it = join_using_column_name_to_column_node.end(); - if (left_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && right_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getColumnName() == right_resolved_column.getColumnName()) - using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - } - else - { - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(left_resolved_identifier); - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(right_resolved_identifier); - } - - if (using_column_node_it != join_using_column_name_to_column_node.end()) - { - JoinTableSide using_column_inner_column_table_side = isRight(join_kind) ? JoinTableSide::Right : JoinTableSide::Left; - auto & using_column_node = using_column_node_it->second->as(); - auto & using_expression_list = using_column_node.getExpression()->as(); - - size_t inner_column_node_index = using_column_inner_column_table_side == JoinTableSide::Left ? 0 : 1; - const auto & inner_column_node = using_expression_list.getNodes().at(inner_column_node_index); - - auto result_column_node = inner_column_node->clone(); - auto & result_column = result_column_node->as(); - result_column.setColumnType(using_column_node.getColumnType()); - - const auto & join_using_left_column = using_expression_list.getNodes().at(0); - if (!result_column_node->isEqual(*join_using_left_column)) - scope.join_columns_with_changed_types[result_column_node] = join_using_left_column; - - resolved_identifier = std::move(result_column_node); - } - else if (resolvedIdenfiersFromJoinAreEquals(left_resolved_identifier, right_resolved_identifier, scope)) - { - const auto & identifier_path_part = identifier_lookup.identifier.front(); - auto * left_resolved_identifier_column = left_resolved_identifier->as(); - auto * right_resolved_identifier_column = right_resolved_identifier->as(); - - if (left_resolved_identifier_column && right_resolved_identifier_column) - { - const auto & left_column_source_alias = left_resolved_identifier_column->getColumnSource()->getAlias(); - const auto & right_column_source_alias = right_resolved_identifier_column->getColumnSource()->getAlias(); - - /** If column from right table was resolved using alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one JOIN system.one AS A ON A.dummy = system.one.dummy; - * - * If alias is specified for left table, and alias is not specified for right table and identifier was resolved - * without using left table alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one AS A JOIN system.one ON A.dummy = system.one.dummy; - * - * Otherwise we prefer column from left table. - */ - bool column_resolved_using_right_alias = identifier_path_part == right_column_source_alias; - bool column_resolved_without_using_left_alias = !left_column_source_alias.empty() - && right_column_source_alias.empty() - && identifier_path_part != left_column_source_alias; - if (column_resolved_using_right_alias || column_resolved_without_using_left_alias) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else if (scope.joins_count == 1 && scope.context->getSettingsRef().single_join_prefer_left_table) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - else - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier '{}'. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - else if (left_resolved_identifier) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(left_resolved_identifier); - } - else - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*left_resolved_column.getColumnType())) - { - auto left_resolved_column_clone = std::static_pointer_cast(left_resolved_column.clone()); - left_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(left_resolved_column_clone); - - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - else if (right_resolved_identifier) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(right_resolved_identifier); - } - else - { - auto & right_resolved_column = right_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(right_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*right_resolved_column.getColumnType())) - { - auto right_resolved_column_clone = std::static_pointer_cast(right_resolved_column.clone()); - right_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(right_resolved_column_clone); - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - - if (join_node_in_resolve_process || !resolved_identifier) - return resolved_identifier; - - if (scope.join_use_nulls) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier); - auto nullable_resolved_identifier = convertJoinedColumnTypeToNullIfNeeded(resolved_identifier, join_kind, resolved_side, scope); - if (nullable_resolved_identifier) - { - resolved_identifier = nullable_resolved_identifier; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(resolved_identifier, projection_name_it->second); - } - } - } - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope) -{ - const auto * resolved_function = resolved_expression->as(); - if (!resolved_function || resolved_function->getFunctionName() != "getSubcolumn") - return {}; - - const auto * array_join_parent_column = array_join_column_inner_expression.get(); - - /** If both resolved and array-joined expressions are subcolumns, try to match them: - * For example, in `SELECT t.map.values FROM (SELECT * FROM tbl) ARRAY JOIN t.map` - * Identifier `t.map.values` is resolved into `getSubcolumn(t, 'map.values')` and t.map is resolved into `getSubcolumn(t, 'map')` - * Since we need to perform array join on `getSubcolumn(t, 'map')`, `t.map.values` should become `getSubcolumn(getSubcolumn(t, 'map'), 'values')` - * - * Note: It doesn't work when subcolumn in ARRAY JOIN is transformed by another expression, for example - * SELECT c.map, c.map.values FROM (SELECT * FROM tbl) ARRAY JOIN mapApply(x -> x, t.map); - */ - String array_join_subcolumn_prefix; - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "getSubcolumn") - { - const auto & argument_nodes = array_join_column_inner_expression_function->getArguments().getNodes(); - if (argument_nodes.size() == 2 && argument_nodes.at(1)->getNodeType() == QueryTreeNodeType::CONSTANT) - { - const auto & constant_node = argument_nodes.at(1)->as(); - const auto & constant_node_value = constant_node.getValue(); - if (constant_node_value.getType() == Field::Types::String) - { - array_join_subcolumn_prefix = constant_node_value.get() + "."; - array_join_parent_column = argument_nodes.at(0).get(); - } - } - } - - const auto & argument_nodes = resolved_function->getArguments().getNodes(); - if (argument_nodes.size() != 2 && !array_join_parent_column->isEqual(*argument_nodes.at(0))) - return {}; - - const auto * second_argument = argument_nodes.at(1)->as(); - if (!second_argument || second_argument->getValue().getType() != Field::Types::String) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected constant string as second argument of getSubcolumn function {}", resolved_function->dumpTree()); - - const auto & resolved_subcolumn_path = second_argument->getValue().get(); - if (!startsWith(resolved_subcolumn_path, array_join_subcolumn_prefix)) - return {}; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(array_join_column_expression_typed.getColumn(), array_join_column_expression_typed.getColumnSource())); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(resolved_subcolumn_path.substr(array_join_subcolumn_prefix.size()))); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - return function_query_node; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & array_join_node = table_expression_node->as(); - const auto & array_join_column_expressions_list = array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions_list.getNodes(); - - QueryTreeNodePtr array_join_resolved_expression; - - /** Special case when qualified or unqualified identifier point to array join expression without alias. - * - * CREATE TABLE test_table (id UInt64, value String, value_array Array(UInt8)) ENGINE=TinyLog; - * SELECT id, value, value_array, test_table.value_array, default.test_table.value_array FROM test_table ARRAY JOIN value_array; - * - * value_array, test_table.value_array, default.test_table.value_array must be resolved into array join expression. - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - if (array_join_column_expression_typed.hasAlias()) - continue; - - auto & array_join_column_inner_expression = array_join_column_expression_typed.getExpressionOrThrow(); - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "nested" && - array_join_column_inner_expression_function->getArguments().getNodes().size() > 1 && - isTuple(array_join_column_expression_typed.getResultType())) - { - const auto & nested_function_arguments = array_join_column_inner_expression_function->getArguments().getNodes(); - size_t nested_function_arguments_size = nested_function_arguments.size(); - - const auto & nested_keys_names_constant_node = nested_function_arguments[0]->as(); - const auto & nested_keys_names = nested_keys_names_constant_node.getValue().get(); - size_t nested_keys_names_size = nested_keys_names.size(); - - if (nested_keys_names_size == nested_function_arguments_size - 1) - { - for (size_t i = 1; i < nested_function_arguments_size; ++i) - { - if (!nested_function_arguments[i]->isEqual(*resolved_expression)) - continue; - - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - - const auto & nested_key_name = nested_keys_names[i - 1].get(); - Identifier nested_identifier = Identifier(nested_key_name); - auto tuple_element_function = wrapExpressionNodeInTupleElement(array_join_column, nested_identifier); - resolveFunction(tuple_element_function, scope); - - array_join_resolved_expression = std::move(tuple_element_function); - break; - } - } - } - - if (array_join_resolved_expression) - break; - - if (array_join_column_inner_expression->isEqual(*resolved_expression)) - { - array_join_resolved_expression = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - break; - } - - /// When we select subcolumn of array joined column it also should be array joined - array_join_resolved_expression = matchArrayJoinSubcolumns(array_join_column_inner_expression, array_join_column_expression_typed, resolved_expression, scope); - if (array_join_resolved_expression) - break; - } - return array_join_resolved_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_array_join_node = table_expression_node->as(); - auto resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_array_join_node.getTableExpression(), scope); - - if (scope.table_expressions_in_resolve_process.contains(table_expression_node.get()) || !identifier_lookup.isExpressionLookup()) - return resolved_identifier; - - const auto & array_join_column_expressions = from_array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions.getNodes(); - - /** Allow JOIN with USING with ARRAY JOIN. - * - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN [1,2,3] AS id INNER JOIN test_table_2 AS t2 USING (id); - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN t1.id AS id INNER JOIN test_table_2 AS t2 USING (id); - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - - IdentifierView identifier_view(identifier_lookup.identifier); - - if (identifier_view.isCompound() && from_array_join_node.hasAlias() && identifier_view.front() == from_array_join_node.getAlias()) - identifier_view.popFirst(); - - const auto & alias_or_name = array_join_column_expression_typed.hasAlias() - ? array_join_column_expression_typed.getAlias() - : array_join_column_expression_typed.getColumnName(); - - if (identifier_view.front() == alias_or_name) - identifier_view.popFirst(); - else if (identifier_view.getFullName() == alias_or_name) - identifier_view.popFirst(identifier_view.getPartsSize()); /// Clear - else - continue; - - if (identifier_view.empty()) - { - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - return array_join_column; - } - - auto compound_expr = tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - identifier_lookup.identifier.getPartsSize() - identifier_view.getPartsSize() /*identifier_bind_size*/, - array_join_column_expression, - {} /* compound_expression_source */, - scope, - true /* can_be_not_found */); - - if (compound_expr) - return compound_expr; - } - - if (!resolved_identifier) - return nullptr; - - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(resolved_identifier, table_expression_node, scope); - if (array_join_resolved_expression) - resolved_identifier = std::move(array_join_resolved_expression); - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope) -{ - auto join_tree_node_type = join_tree_node->getNodeType(); - - switch (join_tree_node_type) - { - case QueryTreeNodeType::JOIN: - return tryResolveIdentifierFromJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::ARRAY_JOIN: - return tryResolveIdentifierFromArrayJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - [[fallthrough]]; - case QueryTreeNodeType::TABLE: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - { - /** Edge case scenario when subquery in FROM node try to resolve identifier from parent scopes, when FROM is not resolved. - * SELECT subquery.b AS value FROM (SELECT value, 1 AS b) AS subquery; - * TODO: This can be supported - */ - if (scope.table_expressions_in_resolve_process.contains(join_tree_node.get())) - return {}; - - return tryResolveIdentifierFromTableExpression(identifier_lookup, join_tree_node, scope); - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Scope FROM section expected table, table function, query, union, join or array join. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } -} - -/** Resolve identifier from scope join tree. - * - * 1. If identifier is in function lookup context return nullptr. - * 2. Try to resolve identifier from table columns. - * 3. If there is no FROM section return nullptr. - * 4. If identifier is in table lookup context, check if it has 1 or 2 parts, otherwise throw exception. - * If identifier has 2 parts try to match it with database_name and table_name. - * If identifier has 1 part try to match it with table_name, then try to match it with table alias. - * 5. If identifier is in expression lookup context, we first need to bind identifier to some table column using identifier first part. - * Start with identifier first part, if it match some column name in table try to get column with full identifier name. - * TODO: Need to check if it is okay to throw exception if compound identifier first part bind to column but column is not valid. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope) -{ - if (identifier_lookup.isFunctionLookup()) - return {}; - - /// Try to resolve identifier from table columns - if (auto resolved_identifier = tryResolveIdentifierFromTableColumns(identifier_lookup, scope)) - return resolved_identifier; - - if (scope.expression_join_tree_node) - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, scope.expression_join_tree_node, scope); - - auto * query_scope_node = scope.scope_node->as(); - if (!query_scope_node || !query_scope_node->getJoinTree()) - return {}; - - const auto & join_tree_node = query_scope_node->getJoinTree(); - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_tree_node, scope); -} - -/** Try resolve identifier in current scope parent scopes. - * - * TODO: If column is matched, throw exception that nested subqueries are not supported. - * - * If initial scope is expression. Then try to resolve identifier in parent scopes until query scope is hit. - * For query scope resolve strategy is same as if initial scope if query. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - bool initial_scope_is_query = scope.scope_node->getNodeType() == QueryTreeNodeType::QUERY; - bool initial_scope_is_expression = !initial_scope_is_query; - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_parent_scopes = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - IdentifierResolveScope * scope_to_check = scope.parent_scope; - - if (initial_scope_is_expression) - { - while (scope_to_check != nullptr) - { - auto resolve_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - if (resolve_result.resolved_identifier) - return resolve_result; - - bool scope_was_query = scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY; - scope_to_check = scope_to_check->parent_scope; - - if (scope_was_query) - break; - } - } - - if (!scope.context->getSettingsRef().enable_global_with_statement) - return {}; - - /** Nested subqueries cannot access outer subqueries table expressions from JOIN tree because - * that can prevent resolution of table expression from CTE. - * - * Example: WITH a AS (SELECT number FROM numbers(1)), b AS (SELECT number FROM a) SELECT * FROM a as l, b as r; - */ - if (identifier_lookup.isTableExpressionLookup()) - identifier_resolve_settings.allow_to_check_join_tree = false; - - while (scope_to_check != nullptr) - { - auto lookup_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - const auto & resolved_identifier = lookup_result.resolved_identifier; - - scope_to_check = scope_to_check->parent_scope; - - if (resolved_identifier) - { - auto * subquery_node = resolved_identifier->as(); - auto * union_node = resolved_identifier->as(); - - bool is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - bool is_table_from_expression_arguments = lookup_result.resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS && - resolved_identifier->getNodeType() == QueryTreeNodeType::TABLE; - bool is_valid_table_expression = is_cte || is_table_from_expression_arguments; - - /** From parent scopes we can resolve table identifiers only as CTE. - * Example: SELECT (SELECT 1 FROM a) FROM test_table AS a; - * - * During child scope table identifier resolve a, table node test_table with alias a from parent scope - * is invalid. - */ - if (identifier_lookup.isTableExpressionLookup() && !is_valid_table_expression) - continue; - - if (is_valid_table_expression || resolved_identifier->as()) - { - return lookup_result; - } - else if (auto * resolved_function = resolved_identifier->as()) - { - /// Special case: scalar subquery was executed and replaced by __getScalar function. - /// Handle it as a constant. - if (resolved_function->getFunctionName() == "__getScalar") - return lookup_result; - } - - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Resolve identifier '{}' from parent scope only supported for constants and CTE. Actual {} node type {}. In scope {}", - identifier_lookup.identifier.getFullName(), - resolved_identifier->formatASTForErrorMessage(), - resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - return {}; -} - -/** Resolve identifier in scope. - * - * If identifier was resolved resolve identified lookup status will be updated. - * - * Steps: - * 1. Register identifier lookup in scope identifier lookup to resolve status table. - * If entry is already registered and is not resolved, that means that we have cyclic aliases for identifier. - * Example: SELECT a AS b, b AS a; - * Try resolve identifier in current scope: - * 3. Try resolve identifier from expression arguments. - * - * If prefer_column_name_to_alias = true. - * 4. Try to resolve identifier from join tree. - * 5. Try to resolve identifier from aliases. - * Otherwise. - * 4. Try to resolve identifier from aliases. - * 5. Try to resolve identifier from join tree. - * - * 6. If it is table identifier lookup try to lookup identifier in current scope CTEs. - * - * 7. If identifier is not resolved in current scope, try to resolve it in parent scopes. - * 8. If identifier is not resolved from parent scopes and it is table identifier lookup try to lookup identifier - * in database catalog. - * - * Same is not done for functions because function resolution is more complex, and in case of aggregate functions requires not only name - * but also argument types, it is responsibility of resolve function method to handle resolution of function name. - * - * 9. If identifier was not resolved, or identifier caching was disabled remove it from identifier lookup to resolve status table. - * - * It is okay for identifier to be not resolved, in case we want first try to lookup identifier in one context, - * then if there is no identifier in this context, try to lookup in another context. - * Example: Try to lookup identifier as expression, if it is not found, lookup as function. - * Example: Try to lookup identifier as expression, if it is not found, lookup as table. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - auto it = scope.identifier_lookup_to_resolve_state.find(identifier_lookup); - if (it != scope.identifier_lookup_to_resolve_state.end()) - { - if (it->second.cyclic_identifier_resolve) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (!it->second.resolve_result.isResolved()) - it->second.cyclic_identifier_resolve = true; - - if (it->second.resolve_result.isResolved() && - scope.use_identifier_lookup_to_result_cache && - !scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) && - (!it->second.resolve_result.isResolvedFromCTEs() || !ctes_in_resolve_process.contains(identifier_lookup.identifier.getFullName()))) - return it->second.resolve_result; - } - else - { - auto [insert_it, _] = scope.identifier_lookup_to_resolve_state.insert({identifier_lookup, IdentifierResolveState()}); - it = insert_it; - } - - /// Resolve identifier from current scope - - IdentifierResolveResult resolve_result; - resolve_result.resolved_identifier = tryResolveIdentifierFromExpressionArguments(identifier_lookup, scope); - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - - if (!resolve_result.resolved_identifier) - { - bool prefer_column_name_to_alias = scope.context->getSettingsRef().prefer_column_name_to_alias; - - if (identifier_lookup.isExpressionLookup()) - { - /* For aliases from ARRAY JOIN we prefer column from join tree: - * SELECT id FROM ( SELECT ... ) AS subquery ARRAY JOIN [0] AS id INNER JOIN second_table USING (id) - * In the example, identifier `id` should be resolved into one from USING (id) column. - */ - - auto * alias_it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FULL_NAME); - if (alias_it && (*alias_it)->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_node = (*alias_it)->as(); - if (column_node.getColumnSource()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - prefer_column_name_to_alias = true; - } - } - - if (unlikely(prefer_column_name_to_alias)) - { - if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - - if (!resolve_result.resolved_identifier) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - } - else - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - { - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - else if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - } - } - - if (!resolve_result.resolved_identifier && identifier_lookup.isTableExpressionLookup()) - { - auto full_name = identifier_lookup.identifier.getFullName(); - auto cte_query_node_it = scope.cte_name_to_query_node.find(full_name); - - /// CTE may reference table expressions with the same name, e.g.: - /// - /// WITH test1 AS (SELECT * FROM test1) SELECT * FROM test1; - /// - /// Since we don't support recursive CTEs, `test1` identifier inside of CTE - /// references to table .test1. - /// This means that the example above is equivalent to the following query: - /// - /// SELECT * FROM test1; - /// - /// To accomplish this behaviour it's not allowed to resolve identifiers to - /// CTE that is being resolved. - if (cte_query_node_it != scope.cte_name_to_query_node.end() - && !ctes_in_resolve_process.contains(full_name)) - { - resolve_result.resolved_identifier = cte_query_node_it->second; - resolve_result.resolve_place = IdentifierResolvePlace::CTE; - } - } - - /// Try to resolve identifier from parent scopes - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_parent_scopes) - { - resolve_result = tryResolveIdentifierInParentScopes(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolved_from_parent_scopes = true; - } - - /// Try to resolve table identifier from database catalog - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_database_catalog && identifier_lookup.isTableExpressionLookup()) - { - resolve_result.resolved_identifier = tryResolveTableIdentifierFromDatabaseCatalog(identifier_lookup.identifier, scope.context); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::DATABASE_CATALOG; - } - - bool was_cyclic_identifier_resolve = it->second.cyclic_identifier_resolve; - if (!was_cyclic_identifier_resolve) - it->second.resolve_result = resolve_result; - it->second.cyclic_identifier_resolve = false; - - /** If identifier was not resolved, or during expression resolution identifier was explicitly added into non cached set, - * or identifier caching was disabled in resolve scope we remove identifier lookup result from identifier lookup to result table. - */ - if (!was_cyclic_identifier_resolve && (!resolve_result.resolved_identifier || - scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) || - !scope.use_identifier_lookup_to_result_cache)) - scope.identifier_lookup_to_resolve_state.erase(it); - - return resolve_result; -} - -/// Resolve query tree nodes functions implementation - -/** Qualify column nodes with projection names. - * - * Example: SELECT * FROM test_table AS t1, test_table AS t2; - */ -void QueryAnalyzer::qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - /// Build additional column qualification parts array - std::vector additional_column_qualification_parts; - - if (table_expression_node->hasAlias()) - additional_column_qualification_parts = {table_expression_node->getAlias()}; - else if (auto * table_node = table_expression_node->as()) - additional_column_qualification_parts = {table_node->getStorageID().getDatabaseName(), table_node->getStorageID().getTableName()}; - - size_t additional_column_qualification_parts_size = additional_column_qualification_parts.size(); - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - /** For each matched column node iterate over additional column qualifications and apply them if column needs to be qualified. - * To check if column needs to be qualified we check if column name can bind to any other table expression in scope or to scope aliases. - */ - std::vector column_qualified_identifier_parts; - - for (const auto & column_node : column_nodes) - { - const auto & column_name = column_node->as().getColumnName(); - column_qualified_identifier_parts = Identifier(column_name).getParts(); - - /// Iterate over additional column qualifications and apply them if needed - for (size_t i = 0; i < additional_column_qualification_parts_size; ++i) - { - auto identifier_to_check = Identifier(column_qualified_identifier_parts); - IdentifierLookup identifier_lookup{identifier_to_check, IdentifierLookupContext::EXPRESSION}; - bool need_to_qualify = table_expression_data.should_qualify_columns; - if (need_to_qualify) - need_to_qualify = tryBindIdentifierToTableExpressions(identifier_lookup, table_expression_node, scope); - - if (tryBindIdentifierToAliases(identifier_lookup, scope)) - need_to_qualify = true; - - if (need_to_qualify) - { - /** Add last qualification part that was not used into column qualified identifier. - * If additional column qualification parts consists from [database_name, table_name]. - * On first iteration if column is needed to be qualified to qualify it with table_name. - * On second iteration if column is needed to be qualified to qualify it with database_name. - */ - size_t part_index_to_use_for_qualification = additional_column_qualification_parts_size - i - 1; - const auto & part_to_use = additional_column_qualification_parts[part_index_to_use_for_qualification]; - column_qualified_identifier_parts.insert(column_qualified_identifier_parts.begin(), part_to_use); - } - else - { - break; - } - } - - auto qualified_node_name = Identifier(column_qualified_identifier_parts).getFullName(); - node_to_projection_name.emplace(column_node, qualified_node_name); - } -} - -/// Build get columns options for matcher -GetColumnsOptions QueryAnalyzer::buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context) -{ - auto & matcher_node_typed = matcher_node->as(); - UInt8 get_columns_options_kind = GetColumnsOptions::AllPhysicalAndAliases; - - if (matcher_node_typed.isAsteriskMatcher()) - { - get_columns_options_kind = GetColumnsOptions::Ordinary; - - const auto & settings = context->getSettingsRef(); - - if (settings.asterisk_include_alias_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Aliases; - - if (settings.asterisk_include_materialized_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Materialized; - } - - return GetColumnsOptions(static_cast(get_columns_options_kind)); -} - -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - /** Use resolved columns from table expression data in nearest query scope if available. - * It is important for ALIAS columns to use column nodes with resolved ALIAS expression. - */ - const TableExpressionData * table_expression_data = nullptr; - const auto * nearest_query_scope = scope.getNearestQueryScope(); - if (nearest_query_scope) - table_expression_data = &nearest_query_scope->getTableExpressionDataOrThrow(table_expression_node); - - QueryTreeNodes matched_column_nodes; - - for (const auto & column : matched_columns) - { - const auto & column_name = column.name; - if (!matcher_node_typed.isMatchingColumn(column_name)) - continue; - - if (table_expression_data) - { - auto column_node_it = table_expression_data->column_name_to_column_node.find(column_name); - if (column_node_it != table_expression_data->column_name_to_column_node.end()) - { - matched_column_nodes.emplace_back(column_node_it->second); - continue; - } - } - - matched_column_nodes.emplace_back(std::make_shared(column, table_expression_node)); - } - - const auto & qualify_matched_column_nodes_scope = nearest_query_scope ? *nearest_query_scope : scope; - qualifyColumnNodesWithProjectionNames(matched_column_nodes, table_expression_node, qualify_matched_column_nodes_scope); - - QueryAnalyzer::QueryTreeNodesWithNames matched_column_nodes_with_names; - matched_column_nodes_with_names.reserve(matched_column_nodes.size()); - - for (auto && matched_column_node : matched_column_nodes) - { - auto column_name = matched_column_node->as().getColumnName(); - matched_column_nodes_with_names.emplace_back(std::move(matched_column_node), std::move(column_name)); - } - - return matched_column_nodes_with_names; -} - -bool hasTableExpressionInJoinTree(const QueryTreeNodePtr & join_tree_node, const QueryTreeNodePtr & table_expression) -{ - QueryTreeNodes nodes_to_process; - nodes_to_process.push_back(join_tree_node); - - while (!nodes_to_process.empty()) - { - auto node_to_process = std::move(nodes_to_process.back()); - nodes_to_process.pop_back(); - if (node_to_process == table_expression) - return true; - - if (node_to_process->getNodeType() == QueryTreeNodeType::JOIN) - { - const auto & join_node = node_to_process->as(); - nodes_to_process.push_back(join_node.getLeftTableExpression()); - nodes_to_process.push_back(join_node.getRightTableExpression()); - } - } - return false; -} - -/// Columns that resolved from matcher can also match columns from JOIN USING. -/// In that case we update type to type of column in USING section. -/// TODO: It's not completely correct for qualified matchers, so t1.* should be resolved to left table column type. -/// But in planner we do not distinguish such cases. -void QueryAnalyzer::updateMatchedColumnsFromJoinUsing( - QueryTreeNodesWithNames & result_matched_column_nodes_with_names, - const QueryTreeNodePtr & source_table_expression, - IdentifierResolveScope & scope) -{ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "There are no table sources. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - const auto & join_tree = nearest_query_scope_query_node->getJoinTree(); - - const auto * join_node = join_tree->as(); - if (join_node && join_node->isUsingJoinExpression()) - { - const auto & join_using_list = join_node->getJoinExpression()->as(); - const auto & join_using_nodes = join_using_list.getNodes(); - - for (auto & [matched_column_node, _] : result_matched_column_nodes_with_names) - { - auto & matched_column_node_typed = matched_column_node->as(); - const auto & matched_column_name = matched_column_node_typed.getColumnName(); - - for (const auto & join_using_node : join_using_nodes) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (matched_column_name != join_using_column_name) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - auto it = node_to_projection_name.find(matched_column_node); - - if (hasTableExpressionInJoinTree(join_node->getLeftTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(0); - else if (hasTableExpressionInJoinTree(join_node->getRightTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(1); - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Cannot find column {} in JOIN USING section {}", - matched_column_node->dumpTree(), join_node->dumpTree()); - - matched_column_node = matched_column_node->clone(); - if (it != node_to_projection_name.end()) - node_to_projection_name.emplace(matched_column_node, it->second); - - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - } - } - } -} - -/** Resolve qualified tree matcher. - * - * First try to match qualified identifier to expression. If qualified identifier matched expression node then - * if expression is compound match it column names using matcher `isMatchingColumn` method, if expression is not compound, throw exception. - * If qualified identifier did not match expression in query tree, try to lookup qualified identifier in table context. - */ -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isQualified()); - - auto expression_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::EXPRESSION}; - auto expression_identifier_resolve_result = tryResolveIdentifier(expression_identifier_lookup, scope); - auto expression_query_tree_node = expression_identifier_resolve_result.resolved_identifier; - - /// Try to resolve unqualified matcher for query expression - - if (expression_query_tree_node) - { - auto result_type = expression_query_tree_node->getResultType(); - - while (true) - { - if (const auto * array_type = typeid_cast(result_type.get())) - result_type = array_type->getNestedType(); - else if (const auto * map_type = typeid_cast(result_type.get())) - result_type = map_type->getNestedType(); - else - break; - } - - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Qualified matcher {} find non compound expression {} with type {}. Expected tuple or array of tuples. In scope {}", - matcher_node->formatASTForErrorMessage(), - expression_query_tree_node->formatASTForErrorMessage(), - expression_query_tree_node->getResultType()->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - auto qualified_matcher_element_identifier = matcher_node_typed.getQualifiedIdentifier(); - for (const auto & element_name : element_names) - { - if (!matcher_node_typed.isMatchingColumn(element_name)) - continue; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back(expression_query_tree_node); - get_subcolumn_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - qualified_matcher_element_identifier.push_back(element_name); - node_to_projection_name.emplace(function_query_node, qualified_matcher_element_identifier.getFullName()); - qualified_matcher_element_identifier.pop_back(); - - matched_expression_nodes_with_column_names.emplace_back(std::move(function_query_node), element_name); - } - - return matched_expression_nodes_with_column_names; - } - - /// Try to resolve qualified matcher for table expression - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_cte = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - auto table_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, identifier_resolve_settings); - auto table_expression_node = table_identifier_resolve_result.resolved_identifier; - - if (!table_expression_node) - { - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Qualified matcher {} does not find table. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - NamesAndTypes matched_columns; - - auto * table_expression_query_node = table_expression_node->as(); - auto * table_expression_union_node = table_expression_node->as(); - auto * table_expression_table_node = table_expression_node->as(); - auto * table_expression_table_function_node = table_expression_node->as(); - - if (table_expression_query_node || table_expression_union_node) - { - matched_columns = table_expression_query_node ? table_expression_query_node->getProjectionColumns() - : table_expression_union_node->computeProjectionColumns(); - } - else if (table_expression_table_node || table_expression_table_function_node) - { - const auto & storage_snapshot = table_expression_table_node ? table_expression_table_node->getStorageSnapshot() - : table_expression_table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - matched_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Invalid table expression node {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto result_matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression_node, - matched_columns, - scope); - - updateMatchedColumnsFromJoinUsing(result_matched_column_nodes_with_names, table_expression_node, scope); - - return result_matched_column_nodes_with_names; -} - -/// Resolve non qualified matcher, using scope join tree node. -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isUnqualified()); - - /** There can be edge case if matcher is inside lambda expression. - * Try to find parent query expression using parent scopes. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unqualified matcher {} cannot be resolved. There are no table sources. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** For unqualifited matcher resolve we build table expressions stack from JOIN tree and then process it. - * For table, table function, query, union table expressions add matched columns into table expressions columns stack. - * For array join continue processing. - * For join node combine last left and right table expressions columns on stack together. It is important that if JOIN has USING - * we must add USING columns before combining left and right table expressions columns. Columns from left and right table - * expressions that have same names as columns in USING clause must be skipped. - */ - - auto table_expressions_stack = buildTableExpressionsStack(nearest_query_scope_query_node->getJoinTree()); - std::vector table_expressions_column_nodes_with_names_stack; - - std::unordered_set table_expression_column_names_to_skip; - - QueryTreeNodesWithNames result; - - if (matcher_node_typed.getMatcherType() == MatcherNodeType::COLUMNS_LIST) - { - auto identifiers = matcher_node_typed.getColumnsIdentifiers(); - result.reserve(identifiers.size()); - - for (const auto & identifier : identifiers) - { - auto resolve_result = tryResolveIdentifier(IdentifierLookup{identifier, IdentifierLookupContext::EXPRESSION}, scope); - if (!resolve_result.isResolved()) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Unknown identifier '{}' inside COLUMNS matcher. In scope {}", - identifier.getFullName(), scope.dump()); - - // TODO: Introduce IdentifierLookupContext::COLUMN and get rid of this check - auto * resolved_column = resolve_result.resolved_identifier->as(); - if (!resolved_column) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier '{}' inside COLUMNS matcher must resolve into a column, but got {}. In scope {}", - identifier.getFullName(), - resolve_result.resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - result.emplace_back(resolve_result.resolved_identifier, resolved_column->getColumnName()); - } - return result; - } - - result.resize(matcher_node_typed.getColumnsIdentifiers().size()); - - for (auto & table_expression : table_expressions_stack) - { - bool table_expression_in_resolve_process = nearest_query_scope->table_expressions_in_resolve_process.contains(table_expression.get()); - - if (auto * array_join_node = table_expression->as()) - { - if (table_expressions_column_nodes_with_names_stack.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 1 table expressions on stack before ARRAY JOIN processing"); - - if (table_expression_in_resolve_process) - continue; - - auto & table_expression_column_nodes_with_names = table_expressions_column_nodes_with_names_stack.back(); - - for (auto & [table_expression_column_node, _] : table_expression_column_nodes_with_names) - { - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(table_expression_column_node, - table_expression, - scope); - if (array_join_resolved_expression) - table_expression_column_node = std::move(array_join_resolved_expression); - } - - continue; - } - - auto * join_node = table_expression->as(); - - if (join_node) - { - size_t table_expressions_column_nodes_with_names_stack_size = table_expressions_column_nodes_with_names_stack.size(); - if (table_expressions_column_nodes_with_names_stack_size < 2) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 2 table expressions on stack before JOIN processing. Actual {}", - table_expressions_column_nodes_with_names_stack_size); - - auto right_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - auto left_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - table_expression_column_names_to_skip.clear(); - - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - /** If there is JOIN with USING we need to match only single USING column and do not use left table expression - * and right table expression column with same name. - * - * Example: SELECT id FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING (id); - */ - if (!table_expression_in_resolve_process && join_node->isUsingJoinExpression()) - { - auto & join_using_list = join_node->getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (!matcher_node_typed.isMatchingColumn(join_using_column_name)) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - /** If column doesn't exists in the table, then do not match column from USING clause. - * Example: SELECT a + 1 AS id, * FROM (SELECT 1 AS a) AS t1 JOIN (SELECT 2 AS id) AS t2 USING (id); - * In this case `id` is not present in the left table expression, - * so asterisk should return `id` from the right table expression. - */ - auto is_column_from_parent_scope = [&scope](const QueryTreeNodePtr & using_node_from_table) - { - const auto & using_column_from_table = using_node_from_table->as(); - auto table_expression_data_it = scope.table_expression_node_to_data.find(using_column_from_table.getColumnSource()); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - { - const auto & table_expression_data = table_expression_data_it->second; - const auto & column_name = using_column_from_table.getColumnName(); - return !table_expression_data.column_name_to_column_node.contains(column_name); - } - return false; - }; - - if (is_column_from_parent_scope(join_using_column_nodes.at(0)) || - is_column_from_parent_scope(join_using_column_nodes.at(1))) - continue; - - QueryTreeNodePtr matched_column_node; - - if (isRight(join_node->getKind())) - matched_column_node = join_using_column_nodes.at(1); - else - matched_column_node = join_using_column_nodes.at(0); - - matched_column_node = matched_column_node->clone(); - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - - table_expression_column_names_to_skip.insert(join_using_column_name); - matched_expression_nodes_with_column_names.emplace_back(std::move(matched_column_node), join_using_column_name); - } - } - - for (auto && left_table_column_with_name : left_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(left_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(left_table_column_with_name)); - } - - for (auto && right_table_column_with_name : right_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(right_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(right_table_column_with_name)); - } - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_expression_nodes_with_column_names)); - continue; - } - - if (table_expression_in_resolve_process) - { - table_expressions_column_nodes_with_names_stack.emplace_back(); - continue; - } - - auto * table_node = table_expression->as(); - auto * table_function_node = table_expression->as(); - auto * query_node = table_expression->as(); - auto * union_node = table_expression->as(); - - NamesAndTypes table_expression_columns; - - if (query_node || union_node) - { - table_expression_columns = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - } - else if (table_node || table_function_node) - { - const auto & storage_snapshot - = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - table_expression_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unqualified matcher {} resolve unexpected table expression. In scope {}", - matcher_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression, - table_expression_columns, - scope); - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_column_nodes_with_names)); - } - - for (auto & table_expression_column_nodes_with_names : table_expressions_column_nodes_with_names_stack) - { - for (auto && table_expression_column_node_with_name : table_expression_column_nodes_with_names) - result.push_back(std::move(table_expression_column_node_with_name)); - } - - return result; -} - - -/** Resolve query tree matcher. Check MatcherNode.h for detailed matcher description. Check ColumnTransformers.h for detailed transformers description. - * - * 1. Populate matched expression nodes resolving qualified or unqualified matcher. - * 2. Apply column transformers to matched expression nodes. For strict column transformers save used column names. - * 3. Validate strict column transformers. - */ -ProjectionNames QueryAnalyzer::resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - QueryTreeNodesWithNames matched_expression_nodes_with_names; - - if (matcher_node_typed.isQualified()) - matched_expression_nodes_with_names = resolveQualifiedMatcher(matcher_node, scope); - else - matched_expression_nodes_with_names = resolveUnqualifiedMatcher(matcher_node, scope); - - if (scope.join_use_nulls) - { - /** If we are resolving matcher came from the result of JOIN and `join_use_nulls` is set, - * we need to convert joined column type to Nullable. - * We are taking the nearest JoinNode to check to which table column belongs, - * because for LEFT/RIGHT join, we convert only the corresponding side. - */ - const auto * nearest_query_scope = scope.getNearestQueryScope(); - const QueryNode * nearest_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - const QueryTreeNodePtr & nearest_scope_join_tree = nearest_scope_query_node ? nearest_scope_query_node->getJoinTree() : nullptr; - const JoinNode * nearest_scope_join_node = nearest_scope_join_tree ? nearest_scope_join_tree->as() : nullptr; - if (nearest_scope_join_node) - { - for (auto & [node, node_name] : matched_expression_nodes_with_names) - { - auto join_identifier_side = getColumnSideFromJoinTree(node, *nearest_scope_join_node); - auto projection_name_it = node_to_projection_name.find(node); - auto nullable_node = convertJoinedColumnTypeToNullIfNeeded(node, nearest_scope_join_node->getKind(), join_identifier_side, scope); - if (nullable_node) - { - node = nullable_node; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(node, projection_name_it->second); - } - } - } - } - } - - if (!scope.expressions_in_resolve_process_stack.hasAggregateFunction()) - { - for (auto & [node, _] : matched_expression_nodes_with_names) - { - auto it = scope.nullable_group_by_keys.find(node); - if (it != scope.nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - } - } - } - - std::unordered_map> strict_transformer_to_used_column_names; - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - auto * except_transformer = transformer->as(); - auto * replace_transformer = transformer->as(); - - if (except_transformer && except_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(except_transformer, std::unordered_set()); - else if (replace_transformer && replace_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(replace_transformer, std::unordered_set()); - } - - ListNodePtr list = std::make_shared(); - ProjectionNames result_projection_names; - ProjectionNames node_projection_names; - - for (auto & [node, column_name] : matched_expression_nodes_with_names) - { - bool apply_transformer_was_used = false; - bool replace_transformer_was_used = false; - bool execute_apply_transformer = false; - bool execute_replace_transformer = false; - - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - else - result_projection_names.push_back(column_name); - - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - if (auto * apply_transformer = transformer->as()) - { - const auto & expression_node = apply_transformer->getExpressionNode(); - apply_transformer_was_used = true; - - if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::LAMBDA) - { - auto lambda_expression_to_resolve = expression_node->clone(); - IdentifierResolveScope lambda_scope(expression_node, &scope /*parent_scope*/); - node_projection_names = resolveLambda(expression_node, lambda_expression_to_resolve, {node}, lambda_scope); - auto & lambda_expression_to_resolve_typed = lambda_expression_to_resolve->as(); - node = lambda_expression_to_resolve_typed.getExpression(); - } - else if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::FUNCTION) - { - auto function_to_resolve_untyped = expression_node->clone(); - auto & function_to_resolve_typed = function_to_resolve_untyped->as(); - function_to_resolve_typed.getArguments().getNodes().push_back(node); - node_projection_names = resolveFunction(function_to_resolve_untyped, scope); - node = function_to_resolve_untyped; - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unsupported apply matcher expression type. Expected lambda or function apply transformer. Actual {}. In scope {}", - transformer->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - execute_apply_transformer = true; - } - else if (auto * except_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - if (except_transformer->isColumnMatching(column_name)) - { - if (except_transformer->isStrict()) - strict_transformer_to_used_column_names[except_transformer].insert(column_name); - - node = {}; - break; - } - } - else if (auto * replace_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - auto replace_expression = replace_transformer->findReplacementExpression(column_name); - if (!replace_expression) - continue; - - replace_transformer_was_used = true; - - if (replace_transformer->isStrict()) - strict_transformer_to_used_column_names[replace_transformer].insert(column_name); - - node = replace_expression->clone(); - node_projection_names = resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** If replace expression resolved as single node, we want to use replace column name as result projection name, instead - * of using replace expression projection name. - * - * Example: SELECT * REPLACE id + 5 AS id FROM test_table; - */ - if (node_projection_names.size() == 1) - node_projection_names[0] = column_name; - - execute_replace_transformer = true; - } - - if (execute_apply_transformer || execute_replace_transformer) - { - if (auto * node_list = node->as()) - { - auto & node_list_nodes = node_list->getNodes(); - size_t node_list_nodes_size = node_list_nodes.size(); - - if (node_list_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "{} transformer {} resolved as list node with size {}. Expected 1. In scope {}", - execute_apply_transformer ? "APPLY" : "REPLACE", - transformer->formatASTForErrorMessage(), - node_list_nodes_size, - scope.scope_node->formatASTForErrorMessage()); - - node = node_list_nodes[0]; - } - - if (node_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Matcher node expected 1 projection name. Actual {}", node_projection_names.size()); - - result_projection_names.back() = std::move(node_projection_names[0]); - node_to_projection_name.emplace(node, result_projection_names.back()); - node_projection_names.clear(); - } - } - - if (node) - list->getNodes().push_back(node); - else - result_projection_names.pop_back(); - } - - for (auto & [strict_transformer, used_column_names] : strict_transformer_to_used_column_names) - { - auto strict_transformer_type = strict_transformer->getTransformerType(); - const Names * strict_transformer_column_names = nullptr; - - switch (strict_transformer_type) - { - case ColumnTransfomerType::EXCEPT: - { - const auto * except_transformer = static_cast(strict_transformer); - const auto & except_names = except_transformer->getExceptColumnNames(); - - if (except_names.size() != used_column_names.size()) - strict_transformer_column_names = &except_transformer->getExceptColumnNames(); - - break; - } - case ColumnTransfomerType::REPLACE: - { - const auto * replace_transformer = static_cast(strict_transformer); - const auto & replacement_names = replace_transformer->getReplacementsNames(); - - if (replacement_names.size() != used_column_names.size()) - strict_transformer_column_names = &replace_transformer->getReplacementsNames(); - - break; - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected strict EXCEPT or REPLACE column transformer. Actual type {}. In scope {}", - toString(strict_transformer_type), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (!strict_transformer_column_names) - continue; - - Names non_matched_column_names; - size_t strict_transformer_column_names_size = strict_transformer_column_names->size(); - for (size_t i = 0; i < strict_transformer_column_names_size; ++i) - { - const auto & column_name = (*strict_transformer_column_names)[i]; - if (used_column_names.find(column_name) == used_column_names.end()) - non_matched_column_names.push_back(column_name); - } - - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Strict {} column transformer {} expects following column(s) : {}. In scope {}", - toString(strict_transformer_type), - strict_transformer->formatASTForErrorMessage(), - fmt::join(non_matched_column_names, ", "), - scope.scope_node->formatASTForErrorMessage()); - } - - auto original_ast = matcher_node->getOriginalAST(); - matcher_node = std::move(list); - if (original_ast) - matcher_node->setOriginalAST(original_ast); - - return result_projection_names; -} - -/** Resolve window function window node. - * - * Node can be identifier or window node. - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - * Example: SELECT count(*) OVER (PARTITION BY id); - * - * If node has parent window name specified, then parent window definition is searched in nearest query scope WINDOW section. - * If node is identifier, than node is replaced with window definition. - * If node is window, that window node is merged with parent window node. - * - * Window node PARTITION BY and ORDER BY parts are resolved. - * If window node has frame begin OFFSET or frame end OFFSET specified, they are resolved, and window node frame constants are updated. - * Window node frame is validated. - */ -ProjectionName QueryAnalyzer::resolveWindow(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - std::string parent_window_name; - auto * identifier_node = node->as(); - - ProjectionName result_projection_name; - QueryTreeNodePtr parent_window_node; - - if (identifier_node) - parent_window_name = identifier_node->getIdentifier().getFullName(); - else if (auto * window_node = node->as()) - parent_window_name = window_node->getParentWindowName(); - - if (!parent_window_name.empty()) - { - auto * nearest_query_scope = scope.getNearestQueryScope(); - - if (!nearest_query_scope) - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Window '{}' does not exist.", parent_window_name); - - auto & scope_window_name_to_window_node = nearest_query_scope->window_name_to_window_node; - - auto window_node_it = scope_window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope_window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - nearest_query_scope->scope_node->formatASTForErrorMessage()); - - parent_window_node = window_node_it->second; - - if (identifier_node) - { - node = parent_window_node->clone(); - result_projection_name = parent_window_name; - } - else - { - mergeWindowWithParentWindow(node, parent_window_node, scope); - } - } - - auto & window_node = node->as(); - window_node.setParentWindowName({}); - - ProjectionNames partition_by_projection_names = resolveExpressionNodeList(window_node.getPartitionByNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - ProjectionNames order_by_projection_names = resolveSortNodeList(window_node.getOrderByNode(), scope); - - ProjectionNames frame_begin_offset_projection_names; - ProjectionNames frame_end_offset_projection_names; - - if (window_node.hasFrameBeginOffset()) - { - frame_begin_offset_projection_names = resolveExpressionNode(window_node.getFrameBeginOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_begin_constant_node = window_node.getFrameBeginOffsetNode()->as(); - if (!window_frame_begin_constant_node || !isNativeNumber(removeNullable(window_frame_begin_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameBeginOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().begin_offset = window_frame_begin_constant_node->getValue(); - if (frame_begin_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_begin_offset_projection_names.size()); - } - - if (window_node.hasFrameEndOffset()) - { - frame_end_offset_projection_names = resolveExpressionNode(window_node.getFrameEndOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_end_constant_node = window_node.getFrameEndOffsetNode()->as(); - if (!window_frame_end_constant_node || !isNativeNumber(removeNullable(window_frame_end_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameEndOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().end_offset = window_frame_end_constant_node->getValue(); - if (frame_end_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_end_offset_projection_names.size()); - } - - window_node.getWindowFrame().checkValid(); - - if (result_projection_name.empty()) - { - result_projection_name = calculateWindowProjectionName(node, - parent_window_node, - parent_window_name, - partition_by_projection_names, - order_by_projection_names, - frame_begin_offset_projection_names.empty() ? "" : frame_begin_offset_projection_names.front(), - frame_end_offset_projection_names.empty() ? "" : frame_end_offset_projection_names.front()); - } - - return result_projection_name; -} - -/** Resolve lambda function. - * This function modified lambda_node during resolve. It is caller responsibility to clone lambda before resolve - * if it is needed for later use. - * - * Lambda body expression result projection names is used as lambda projection names. - * - * Lambda expression can be resolved into list node. It is caller responsibility to handle it properly. - * - * lambda_node - node that must have LambdaNode type. - * lambda_node_to_resolve - lambda node to resolve that must have LambdaNode type. - * arguments - lambda arguments. - * scope - lambda scope. It is client responsibility to create it. - * - * Resolve steps: - * 1. Validate arguments. - * 2. Register lambda node in lambdas in resolve process. This is necessary to prevent recursive lambda resolving. - * 3. Initialize scope with lambda aliases. - * 4. Validate lambda argument names, and scope expressions. - * 5. Resolve lambda body expression. - * 6. Deregister lambda node from lambdas in resolve process. - */ -ProjectionNames QueryAnalyzer::resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope) -{ - auto & lambda_to_resolve = lambda_node_to_resolve->as(); - auto & lambda_arguments_nodes = lambda_to_resolve.getArguments().getNodes(); - size_t lambda_arguments_nodes_size = lambda_arguments_nodes.size(); - - /** Register lambda as being resolved, to prevent recursive lambdas resolution. - * Example: WITH (x -> x + lambda_2(x)) AS lambda_1, (x -> x + lambda_1(x)) AS lambda_2 SELECT 1; - */ - auto it = lambdas_in_resolve_process.find(lambda_node.get()); - if (it != lambdas_in_resolve_process.end()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive lambda {}. In scope {}", - lambda_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - lambdas_in_resolve_process.emplace(lambda_node.get()); - - size_t arguments_size = lambda_arguments.size(); - if (lambda_arguments_nodes_size != arguments_size) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} expect {} arguments. Actual {}. In scope {}", - lambda_to_resolve.formatASTForErrorMessage(), - lambda_arguments_nodes_size, - arguments_size, - scope.scope_node->formatASTForErrorMessage()); - - /// Initialize aliases in lambda scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - visitor.visit(lambda_to_resolve.getExpression()); - - /** Replace lambda arguments with new arguments. - * Additionally validate that there are no aliases with same name as lambda arguments. - * Arguments are registered in current scope expression_argument_name_to_node map. - */ - QueryTreeNodes lambda_new_arguments_nodes; - lambda_new_arguments_nodes.reserve(lambda_arguments_nodes_size); - - for (size_t i = 0; i < lambda_arguments_nodes_size; ++i) - { - auto & lambda_argument_node = lambda_arguments_nodes[i]; - const auto * lambda_argument_identifier = lambda_argument_node->as(); - const auto * lambda_argument_column = lambda_argument_node->as(); - if (!lambda_argument_identifier && !lambda_argument_column) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected IDENTIFIER or COLUMN as lambda argument, got {}", lambda_node->dumpTree()); - const auto & lambda_argument_name = lambda_argument_identifier ? lambda_argument_identifier->getIdentifier().getFullName() - : lambda_argument_column->getColumnName(); - - bool has_expression_node = scope.aliases.alias_name_to_expression_node->contains(lambda_argument_name); - bool has_alias_node = scope.aliases.alias_name_to_lambda_node.contains(lambda_argument_name); - - if (has_expression_node || has_alias_node) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Alias name '{}' inside lambda {} cannot have same name as lambda argument. In scope {}", - lambda_argument_name, - lambda_argument_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - scope.expression_argument_name_to_node.emplace(lambda_argument_name, lambda_arguments[i]); - lambda_new_arguments_nodes.push_back(lambda_arguments[i]); - } - - lambda_to_resolve.getArguments().getNodes() = std::move(lambda_new_arguments_nodes); - - /// Lambda body expression is resolved as standard query expression node. - auto result_projection_names = resolveExpressionNode(lambda_to_resolve.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - lambdas_in_resolve_process.erase(lambda_node.get()); - - return result_projection_names; -} - -namespace -{ -void checkFunctionNodeHasEmptyNullsAction(FunctionNode const & node) -{ - if (node.getNullsAction() != NullsAction::EMPTY) - throw Exception( - ErrorCodes::SYNTAX_ERROR, - "Function with name '{}' cannot use {} NULLS", - node.getFunctionName(), - node.getNullsAction() == NullsAction::IGNORE_NULLS ? "IGNORE" : "RESPECT"); -} -} - -/** Resolve function node in scope. - * During function node resolve, function node can be replaced with another expression (if it match lambda or sql user defined function), - * with constant (if it allow constant folding), or with expression list. It is caller responsibility to handle such cases appropriately. - * - * Steps: - * 1. Resolve function parameters. Validate that each function parameter must be constant node. - * 2. Try to lookup function as lambda in current scope. If it is lambda we can skip `in` and `count` special handling. - * 3. If function is count function, that take unqualified ASTERISK matcher, remove it from its arguments. Example: SELECT count(*) FROM test_table; - * 4. If function is `IN` function, then right part of `IN` function is replaced as subquery. - * 5. Resolve function arguments list, lambda expressions are allowed as function arguments. - * For `IN` function table expressions are allowed as function arguments. - * 6. Initialize argument_columns, argument_types, function_lambda_arguments_indexes arrays from function arguments. - * 7. If function name identifier was not resolved as function in current scope, try to lookup lambda from sql user defined functions factory. - * 8. If function was resolve as lambda from step 2 or 7, then resolve lambda using function arguments and replace function node with lambda result. - * After than function node is resolved. - * 9. If function was not resolved during step 6 as lambda, then try to resolve function as window function or executable user defined function - * or ordinary function or aggregate function. - * - * If function is resolved as window function or executable user defined function or aggregate function, function node is resolved - * no additional special handling is required. - * - * 8. If function was resolved as non aggregate function. Then if some of function arguments are lambda expressions, their result types need to be initialized and - * they must be resolved. - * 9. If function is suitable for constant folding, try to perform constant folding for function node. - */ -ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - FunctionNodePtr function_node_ptr = std::static_pointer_cast(node); - auto function_name = function_node_ptr->getFunctionName(); - - /// Resolve function parameters - - auto parameters_projection_names = resolveExpressionNodeList(function_node_ptr->getParametersNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - /// Convert function parameters into constant parameters array - - Array parameters; - - auto & parameters_nodes = function_node_ptr->getParameters().getNodes(); - parameters.reserve(parameters_nodes.size()); - - for (auto & parameter_node : parameters_nodes) - { - const auto * constant_node = parameter_node->as(); - if (!constant_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parameter for function '{}' expected to have constant value. Actual {}. In scope {}", - function_name, - parameter_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - parameters.push_back(constant_node->getValue()); - } - - //// If function node is not window function try to lookup function node name as lambda identifier. - QueryTreeNodePtr lambda_expression_untyped; - if (!function_node_ptr->isWindowFunction()) - { - auto function_lookup_result = tryResolveIdentifier({Identifier{function_name}, IdentifierLookupContext::FUNCTION}, scope); - lambda_expression_untyped = function_lookup_result.resolved_identifier; - } - - bool is_special_function_in = false; - bool is_special_function_dict_get = false; - bool is_special_function_join_get = false; - bool is_special_function_exists = false; - bool is_special_function_if = false; - - if (!lambda_expression_untyped) - { - is_special_function_in = isNameOfInFunction(function_name); - is_special_function_dict_get = functionIsDictGet(function_name); - is_special_function_join_get = functionIsJoinGet(function_name); - is_special_function_exists = function_name == "exists"; - is_special_function_if = function_name == "if"; - - auto function_name_lowercase = Poco::toLower(function_name); - - /** Special handling for count and countState functions. - * - * Example: SELECT count(*) FROM test_table - * Example: SELECT countState(*) FROM test_table; - */ - if (function_node_ptr->getArguments().getNodes().size() == 1 && - (function_name_lowercase == "count" || function_name_lowercase == "countstate")) - { - auto * matcher_node = function_node_ptr->getArguments().getNodes().front()->as(); - if (matcher_node && matcher_node->isUnqualified()) - function_node_ptr->getArguments().getNodes().clear(); - } - } - - /** Special functions dictGet and its variations and joinGet can be executed when first argument is identifier. - * Example: SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Try to resolve identifier as expression identifier and if it is resolved use it. - * Example: WITH 'dict_name' AS identifier SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Otherwise replace identifier with identifier full name constant. - * Validation that dictionary exists or table exists will be performed during function `getReturnType` method call. - */ - if ((is_special_function_dict_get || is_special_function_join_get) && - !function_node_ptr->getArguments().getNodes().empty() && - function_node_ptr->getArguments().getNodes()[0]->getNodeType() == QueryTreeNodeType::IDENTIFIER) - { - auto & first_argument = function_node_ptr->getArguments().getNodes()[0]; - auto & first_argument_identifier = first_argument->as(); - auto identifier = first_argument_identifier.getIdentifier(); - - IdentifierLookup identifier_lookup{identifier, IdentifierLookupContext::EXPRESSION}; - auto resolve_result = tryResolveIdentifier(identifier_lookup, scope); - - if (resolve_result.isResolved()) - { - first_argument = std::move(resolve_result.resolved_identifier); - } - else - { - size_t parts_size = identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected {} function first argument identifier to contain 1 or 2 parts. Actual '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_special_function_dict_get) - { - scope.context->getExternalDictionariesLoader().assertDictionaryStructureExists(identifier.getFullName(), scope.context); - } - else - { - auto table_node = tryResolveTableIdentifierFromDatabaseCatalog(identifier, scope.context); - if (!table_node) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} first argument expected table identifier '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node_typed = table_node->as(); - if (!std::dynamic_pointer_cast(table_node_typed.getStorage())) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} table '{}' should have engine StorageJoin. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - first_argument = std::make_shared(identifier.getFullName()); - } - } - - if (is_special_function_exists) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /// Rewrite EXISTS (subquery) into 1 IN (SELECT 1 FROM (subquery) LIMIT 1). - auto & exists_subquery_argument = function_node_ptr->getArguments().getNodes().at(0); - - auto constant_data_type = std::make_shared(); - - auto in_subquery = std::make_shared(Context::createCopy(scope.context)); - in_subquery->setIsSubquery(true); - in_subquery->getProjection().getNodes().push_back(std::make_shared(1UL, constant_data_type)); - in_subquery->getJoinTree() = exists_subquery_argument; - in_subquery->getLimit() = std::make_shared(1UL, constant_data_type); - - function_node_ptr = std::make_shared("in"); - function_node_ptr->getArguments().getNodes() = {std::make_shared(1UL, constant_data_type), in_subquery}; - node = function_node_ptr; - function_name = "in"; - is_special_function_in = true; - } - - if (is_special_function_if && !function_node_ptr->getArguments().getNodes().empty()) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /** Handle special case with constant If function, even if some of the arguments are invalid. - * - * SELECT if(hasColumnInTable('system', 'numbers', 'not_existing_column'), not_existing_column, 5) FROM system.numbers; - */ - auto & if_function_arguments = function_node_ptr->getArguments().getNodes(); - auto if_function_condition = if_function_arguments[0]; - resolveExpressionNode(if_function_condition, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto constant_condition = tryExtractConstantFromConditionNode(if_function_condition); - - if (constant_condition.has_value() && if_function_arguments.size() == 3) - { - QueryTreeNodePtr constant_if_result_node; - QueryTreeNodePtr possibly_invalid_argument_node; - - if (*constant_condition) - { - possibly_invalid_argument_node = if_function_arguments[2]; - constant_if_result_node = if_function_arguments[1]; - } - else - { - possibly_invalid_argument_node = if_function_arguments[1]; - constant_if_result_node = if_function_arguments[2]; - } - - bool apply_constant_if_optimization = false; - - try - { - resolveExpressionNode(possibly_invalid_argument_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - } - catch (...) - { - apply_constant_if_optimization = true; - } - - if (apply_constant_if_optimization) - { - auto result_projection_names = resolveExpressionNode(constant_if_result_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - node = std::move(constant_if_result_node); - return result_projection_names; - } - } - } - - /// Resolve function arguments - bool allow_table_expressions = is_special_function_in; - auto arguments_projection_names = resolveExpressionNodeList(function_node_ptr->getArgumentsNode(), - scope, - true /*allow_lambda_expression*/, - allow_table_expressions /*allow_table_expression*/); - - /// Mask arguments if needed - if (!scope.context->getSettingsRef().format_display_secrets_in_show_and_select) - { - if (FunctionSecretArgumentsFinder::Result secret_arguments = FunctionSecretArgumentsFinderTreeNode(*function_node_ptr).getResult(); secret_arguments.count) - { - auto & argument_nodes = function_node_ptr->getArgumentsNode()->as().getNodes(); - - for (size_t n = secret_arguments.start; n < secret_arguments.start + secret_arguments.count; ++n) - { - if (auto * constant = argument_nodes[n]->as()) - { - auto mask = scope.projection_mask_map->insert({constant->getTreeHash(), scope.projection_mask_map->size() + 1}).first->second; - constant->setMaskId(mask); - arguments_projection_names[n] = "[HIDDEN id: " + std::to_string(mask) + "]"; - } - } - } - } - - auto & function_node = *function_node_ptr; - - /// Replace right IN function argument if it is table or table function with subquery that read ordinary columns - if (is_special_function_in) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - if (scope.context->getSettingsRef().transform_null_in) - { - static constexpr std::array, 4> in_function_to_replace_null_in_function_map = - {{ - {"in", "nullIn"}, - {"notIn", "notNullIn"}, - {"globalIn", "globalNullIn"}, - {"globalNotIn", "globalNotNullIn"}, - }}; - - for (const auto & [in_function_name, in_function_name_to_replace] : in_function_to_replace_null_in_function_map) - { - if (function_name == in_function_name) - { - function_name = in_function_name_to_replace; - break; - } - } - } - - auto & function_in_arguments_nodes = function_node.getArguments().getNodes(); - if (function_in_arguments_nodes.size() != 2) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function '{}' expects 2 arguments", function_name); - - auto & in_second_argument = function_in_arguments_nodes[1]; - auto * table_node = in_second_argument->as(); - auto * table_function_node = in_second_argument->as(); - - if (table_node) - { - /// If table is already prepared set, we do not replace it with subquery. - /// If table is not a StorageSet, we'll create plan to build set in the Planner. - } - else if (table_function_node) - { - const auto & storage_snapshot = table_function_node->getStorageSnapshot(); - auto columns_to_select = storage_snapshot->getColumns(GetColumnsOptions(GetColumnsOptions::Ordinary)); - - size_t columns_to_select_size = columns_to_select.size(); - - auto column_nodes_to_select = std::make_shared(); - column_nodes_to_select->getNodes().reserve(columns_to_select_size); - - NamesAndTypes projection_columns; - projection_columns.reserve(columns_to_select_size); - - for (auto & column : columns_to_select) - { - column_nodes_to_select->getNodes().emplace_back(std::make_shared(column, in_second_argument)); - projection_columns.emplace_back(column.name, column.type); - } - - auto in_second_argument_query_node = std::make_shared(Context::createCopy(scope.context)); - in_second_argument_query_node->setIsSubquery(true); - in_second_argument_query_node->getProjectionNode() = std::move(column_nodes_to_select); - in_second_argument_query_node->getJoinTree() = std::move(in_second_argument); - in_second_argument_query_node->resolveProjectionColumns(std::move(projection_columns)); - - in_second_argument = std::move(in_second_argument_query_node); - } - else - { - /// Replace storage with values storage of insertion block - if (StoragePtr storage = scope.context->getViewSource()) - { - QueryTreeNodePtr table_expression; - /// Process possibly nested sub-selects - for (auto * query_node = in_second_argument->as(); query_node; query_node = table_expression->as()) - table_expression = extractLeftTableExpression(query_node->getJoinTree()); - - if (table_expression) - { - if (auto * query_table_node = table_expression->as()) - { - if (query_table_node->getStorageID().getFullNameNotQuoted() == storage->getStorageID().getFullNameNotQuoted()) - { - auto replacement_table_expression = std::make_shared(storage, scope.context); - if (std::optional table_expression_modifiers = query_table_node->getTableExpressionModifiers()) - replacement_table_expression->setTableExpressionModifiers(*table_expression_modifiers); - in_second_argument = in_second_argument->cloneAndReplace(table_expression, std::move(replacement_table_expression)); - } - } - } - } - - resolveExpressionNode(in_second_argument, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - } - } - - /// Initialize function argument columns - - ColumnsWithTypeAndName argument_columns; - DataTypes argument_types; - bool all_arguments_constants = true; - std::vector function_lambda_arguments_indexes; - - auto & function_arguments = function_node.getArguments().getNodes(); - size_t function_arguments_size = function_arguments.size(); - - for (size_t function_argument_index = 0; function_argument_index < function_arguments_size; ++function_argument_index) - { - auto & function_argument = function_arguments[function_argument_index]; - - ColumnWithTypeAndName argument_column; - argument_column.name = arguments_projection_names[function_argument_index]; - - /** If function argument is lambda, save lambda argument index and initialize argument type as DataTypeFunction - * where function argument types are initialized with empty array of lambda arguments size. - */ - if (const auto * lambda_node = function_argument->as()) - { - size_t lambda_arguments_size = lambda_node->getArguments().getNodes().size(); - argument_column.type = std::make_shared(DataTypes(lambda_arguments_size, nullptr), nullptr); - function_lambda_arguments_indexes.push_back(function_argument_index); - } - else if (is_special_function_in && function_argument_index == 1) - { - argument_column.type = std::make_shared(); - } - else - { - argument_column.type = function_argument->getResultType(); - } - - if (!argument_column.type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' argument is not resolved. In scope {}", - function_name, - scope.scope_node->formatASTForErrorMessage()); - - bool argument_is_constant = false; - const auto * constant_node = function_argument->as(); - if (constant_node) - { - argument_column.column = constant_node->getResultType()->createColumnConst(1, constant_node->getValue()); - argument_column.type = constant_node->getResultType(); - argument_is_constant = true; - } - else if (const auto * get_scalar_function_node = function_argument->as(); - get_scalar_function_node && get_scalar_function_node->getFunctionName() == "__getScalar") - { - /// Allow constant folding through getScalar - const auto * get_scalar_const_arg = get_scalar_function_node->getArguments().getNodes().at(0)->as(); - if (get_scalar_const_arg && scope.context->hasQueryContext()) - { - auto query_context = scope.context->getQueryContext(); - auto scalar_string = toString(get_scalar_const_arg->getValue()); - if (query_context->hasScalar(scalar_string)) - { - auto scalar = query_context->getScalar(scalar_string); - argument_column.column = ColumnConst::create(scalar.getByPosition(0).column, 1); - argument_column.type = get_scalar_function_node->getResultType(); - argument_is_constant = true; - } - } - } - - all_arguments_constants &= argument_is_constant; - - argument_types.push_back(argument_column.type); - argument_columns.emplace_back(std::move(argument_column)); - } - - /// Calculate function projection name - ProjectionNames result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - - /** Try to resolve function as - * 1. Lambda function in current scope. Example: WITH (x -> x + 1) AS lambda SELECT lambda(1); - * 2. Lambda function from sql user defined functions. - * 3. Special `untuple` function. - * 4. Special `grouping` function. - * 5. Window function. - * 6. Executable user defined function. - * 7. Ordinary function. - * 8. Aggregate function. - * - * TODO: Provide better error hints. - */ - if (!function_node.isWindowFunction()) - { - if (!lambda_expression_untyped) - lambda_expression_untyped = tryGetLambdaFromSQLUserDefinedFunctions(function_node.getFunctionName(), scope.context); - - /** If function is resolved as lambda. - * Clone lambda before resolve. - * Initialize lambda arguments as function arguments. - * Resolve lambda and then replace function node with resolved lambda expression body. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(value) FROM test_table; - * Result: SELECT value + 1 FROM test_table; - */ - if (lambda_expression_untyped) - { - auto * lambda_expression = lambda_expression_untyped->as(); - if (!lambda_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function identifier '{}' must be resolved as lambda. Actual {}. In scope {}", - function_node.getFunctionName(), - lambda_expression_untyped->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - if (!parameters.empty()) - { - throw Exception( - ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_node.formatASTForErrorMessage()); - } - - auto lambda_expression_clone = lambda_expression_untyped->clone(); - - IdentifierResolveScope lambda_scope(lambda_expression_clone, &scope /*parent_scope*/); - ProjectionNames lambda_projection_names = resolveLambda(lambda_expression_untyped, lambda_expression_clone, function_arguments, lambda_scope); - - auto & resolved_lambda = lambda_expression_clone->as(); - node = resolved_lambda.getExpression(); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(lambda_projection_names); - - return result_projection_names; - } - - if (function_name == "untuple") - { - /// Special handling of `untuple` function - - if (function_arguments.size() != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' must have 1 argument. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - const auto & untuple_argument = function_arguments[0]; - /// Handle this special case first as `getResultType()` might return nullptr - if (untuple_argument->as()) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Function untuple can't have lambda-expressions as arguments"); - - auto result_type = untuple_argument->getResultType(); - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' argument must have compound type. Actual type {}. In scope {}", - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - - auto result_list = std::make_shared(); - result_list->getNodes().reserve(element_names.size()); - - for (const auto & element_name : element_names) - { - auto tuple_element_function = std::make_shared("tupleElement"); - tuple_element_function->getArguments().getNodes().push_back(untuple_argument); - tuple_element_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = tuple_element_function; - resolveFunction(function_query_node, scope); - - result_list->getNodes().push_back(std::move(function_query_node)); - } - - auto untuple_argument_projection_name = arguments_projection_names.at(0); - result_projection_names.clear(); - - for (const auto & element_name : element_names) - { - if (node->hasAlias()) - result_projection_names.push_back(node->getAlias() + '.' + element_name); - else - result_projection_names.push_back(fmt::format("tupleElement({}, '{}')", untuple_argument_projection_name, element_name)); - } - - node = std::move(result_list); - return result_projection_names; - } - else if (function_name == "grouping") - { - /// It is responsibility of planner to perform additional handling of grouping function - if (function_arguments_size == 0) - throw Exception(ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING expects at least one argument"); - else if (function_arguments_size > 64) - throw Exception(ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING can have up to 64 arguments, but {} provided", - function_arguments_size); - checkFunctionNodeHasEmptyNullsAction(function_node); - - bool force_grouping_standard_compatibility = scope.context->getSettingsRef().force_grouping_standard_compatibility; - auto grouping_function = std::make_shared(force_grouping_standard_compatibility); - auto grouping_function_adaptor = std::make_shared(std::move(grouping_function)); - function_node.resolveAsFunction(grouping_function_adaptor->build(argument_columns)); - - return result_projection_names; - } - } - - if (function_node.isWindowFunction()) - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - throw Exception(ErrorCodes::UNKNOWN_AGGREGATE_FUNCTION, "Aggregate function with name '{}' does not exist. In scope {}{}", - function_name, scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(AggregateFunctionFactory::instance().getHints(function_name))); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Window function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsWindowFunction(std::move(aggregate_function)); - - bool window_node_is_identifier = function_node.getWindowNode()->getNodeType() == QueryTreeNodeType::IDENTIFIER; - ProjectionName window_projection_name = resolveWindow(function_node.getWindowNode(), scope); - - if (window_node_is_identifier) - result_projection_names[0] += " OVER " + window_projection_name; - else - result_projection_names[0] += " OVER (" + window_projection_name + ')'; - - return result_projection_names; - } - - FunctionOverloadResolverPtr function = UserDefinedExecutableFunctionFactory::instance().tryGet(function_name, scope.context, parameters); /// NOLINT(readability-static-accessed-through-instance) - bool is_executable_udf = true; - - IdentifierResolveScope::ResolvedFunctionsCache * function_cache = nullptr; - - if (!function) - { - /// This is a hack to allow a query like `select randConstant(), randConstant(), randConstant()`. - /// Function randConstant() would return the same value for the same arguments (in scope). - - auto hash = function_node_ptr->getTreeHash(); - function_cache = &scope.functions_cache[hash]; - if (!function_cache->resolver) - function_cache->resolver = FunctionFactory::instance().tryGet(function_name, scope.context); - - function = function_cache->resolver; - - is_executable_udf = false; - } - - if (function) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - } - else - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - std::vector possible_function_names; - - auto function_names = UserDefinedExecutableFunctionFactory::instance().getRegisteredNames(scope.context); /// NOLINT(readability-static-accessed-through-instance) - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = UserDefinedSQLFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = FunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = AggregateFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - for (auto & [name, lambda_node] : scope.aliases.alias_name_to_lambda_node) - { - if (lambda_node->getNodeType() == QueryTreeNodeType::LAMBDA) - possible_function_names.push_back(name); - } - - auto hints = NamePrompter<2>::getHints(function_name, possible_function_names); - - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Function with name '{}' does not exist. In scope {}{}", - function_name, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Aggregate function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsAggregateFunction(std::move(aggregate_function)); - - return result_projection_names; - } - - /// Executable UDFs may have parameters. They are checked in UserDefinedExecutableFunctionFactory. - if (!parameters.empty() && !is_executable_udf) - { - throw Exception(ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_name); - } - - /** For lambda arguments we need to initialize lambda argument types DataTypeFunction using `getLambdaArgumentTypes` function. - * Then each lambda arguments are initialized with columns, where column source is lambda. - * This information is important for later steps of query processing. - * Example: SELECT arrayMap(x -> x + 1, [1, 2, 3]). - * lambda node x -> x + 1 identifier x is resolved as column where source is lambda node. - */ - bool has_lambda_arguments = !function_lambda_arguments_indexes.empty(); - if (has_lambda_arguments) - { - function->getLambdaArgumentTypes(argument_types); - - ProjectionNames lambda_projection_names; - for (auto & function_lambda_argument_index : function_lambda_arguments_indexes) - { - auto & lambda_argument = function_arguments[function_lambda_argument_index]; - auto lambda_to_resolve = lambda_argument->clone(); - auto & lambda_to_resolve_typed = lambda_to_resolve->as(); - - const auto & lambda_argument_names = lambda_to_resolve_typed.getArgumentNames(); - size_t lambda_arguments_size = lambda_to_resolve_typed.getArguments().getNodes().size(); - - const auto * function_data_type = typeid_cast(argument_types[function_lambda_argument_index].get()); - if (!function_data_type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' expected function data type for lambda argument with index {}. Actual {}. In scope {}", - function_name, - function_lambda_argument_index, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & function_data_type_argument_types = function_data_type->getArgumentTypes(); - size_t function_data_type_arguments_size = function_data_type_argument_types.size(); - if (function_data_type_arguments_size != lambda_arguments_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}" - "' function data type for lambda argument with index {} arguments size mismatch. " - "Actual {}. Expected {}. In scope {}", - function_name, - function_data_type_arguments_size, - lambda_arguments_size, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - QueryTreeNodes lambda_arguments; - lambda_arguments.reserve(lambda_arguments_size); - - for (size_t i = 0; i < lambda_arguments_size; ++i) - { - const auto & argument_type = function_data_type_argument_types[i]; - auto column_name_and_type = NameAndTypePair{lambda_argument_names[i], argument_type}; - lambda_arguments.push_back(std::make_shared(std::move(column_name_and_type), lambda_to_resolve)); - } - - IdentifierResolveScope lambda_scope(lambda_to_resolve, &scope /*parent_scope*/); - lambda_projection_names = resolveLambda(lambda_argument, lambda_to_resolve, lambda_arguments, lambda_scope); - - if (auto * lambda_list_node_result = lambda_to_resolve_typed.getExpression()->as()) - { - size_t lambda_list_node_result_nodes_size = lambda_list_node_result->getNodes().size(); - - if (lambda_list_node_result_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Lambda as function argument resolved as list node with size {}. Expected 1. In scope {}", - lambda_list_node_result_nodes_size, - lambda_to_resolve->formatASTForErrorMessage()); - - lambda_to_resolve_typed.getExpression() = lambda_list_node_result->getNodes().front(); - } - - if (arguments_projection_names.at(function_lambda_argument_index) == PROJECTION_NAME_PLACEHOLDER) - { - size_t lambda_projection_names_size =lambda_projection_names.size(); - if (lambda_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Lambda argument inside function expected to have 1 projection name. Actual {}", - lambda_projection_names_size); - - WriteBufferFromOwnString lambda_argument_projection_name_buffer; - lambda_argument_projection_name_buffer << "lambda("; - lambda_argument_projection_name_buffer << "tuple("; - - size_t lambda_argument_names_size = lambda_argument_names.size(); - - for (size_t i = 0; i < lambda_argument_names_size; ++i) - { - const auto & lambda_argument_name = lambda_argument_names[i]; - lambda_argument_projection_name_buffer << lambda_argument_name; - - if (i + 1 != lambda_argument_names_size) - lambda_argument_projection_name_buffer << ", "; - } - - lambda_argument_projection_name_buffer << "), "; - lambda_argument_projection_name_buffer << lambda_projection_names[0]; - lambda_argument_projection_name_buffer << ")"; - - lambda_projection_names.clear(); - - arguments_projection_names[function_lambda_argument_index] = lambda_argument_projection_name_buffer.str(); - } - - auto lambda_resolved_type = std::make_shared(function_data_type_argument_types, lambda_to_resolve_typed.getExpression()->getResultType()); - lambda_to_resolve_typed.resolve(lambda_resolved_type); - - argument_types[function_lambda_argument_index] = lambda_resolved_type; - argument_columns[function_lambda_argument_index].type = lambda_resolved_type; - function_arguments[function_lambda_argument_index] = std::move(lambda_to_resolve); - } - - /// Recalculate function projection name after lambda resolution - result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - } - - /** Create SET column for special function IN to allow constant folding - * if left and right arguments are constants. - * - * Example: SELECT * FROM test_table LIMIT 1 IN 1; - */ - if (is_special_function_in) - { - const auto * first_argument_constant_node = function_arguments[0]->as(); - const auto * second_argument_constant_node = function_arguments[1]->as(); - - if (first_argument_constant_node && second_argument_constant_node) - { - const auto & first_argument_constant_type = first_argument_constant_node->getResultType(); - const auto & second_argument_constant_literal = second_argument_constant_node->getValue(); - const auto & second_argument_constant_type = second_argument_constant_node->getResultType(); - - const auto & settings = scope.context->getSettingsRef(); - - auto result_block = getSetElementsForConstantValue(first_argument_constant_type, - second_argument_constant_literal, - second_argument_constant_type, - settings.transform_null_in); - - SizeLimits size_limits_for_set = {settings.max_rows_in_set, settings.max_bytes_in_set, settings.set_overflow_mode}; - - auto set = std::make_shared(size_limits_for_set, 0, settings.transform_null_in); - - set->setHeader(result_block.cloneEmpty().getColumnsWithTypeAndName()); - set->insertFromBlock(result_block.getColumnsWithTypeAndName()); - set->finishInsert(); - - auto future_set = std::make_shared(std::move(set)); - - /// Create constant set column for constant folding - - auto column_set = ColumnSet::create(1, std::move(future_set)); - argument_columns[1].column = ColumnConst::create(std::move(column_set), 1); - } - - argument_columns[1].type = std::make_shared(); - } - - std::shared_ptr constant_value; - - try - { - FunctionBasePtr function_base; - if (function_cache) - { - auto & cached_function = function_cache->function_base; - if (!cached_function) - cached_function = function->build(argument_columns); - - function_base = cached_function; - } - else - function_base = function->build(argument_columns); - - /// Do not constant fold get scalar functions - bool disable_constant_folding = function_name == "__getScalar" || function_name == "shardNum" || - function_name == "shardCount" || function_name == "hostName" || function_name == "tcpPort"; - - /** If function is suitable for constant folding try to convert it to constant. - * Example: SELECT plus(1, 1); - * Result: SELECT 2; - */ - if (function_base->isSuitableForConstantFolding() && !disable_constant_folding) - { - auto result_type = function_base->getResultType(); - auto executable_function = function_base->prepare(argument_columns); - - ColumnPtr column; - - if (all_arguments_constants) - { - size_t num_rows = function_arguments.empty() ? 0 : argument_columns.front().column->size(); - column = executable_function->execute(argument_columns, result_type, num_rows, true); - } - else - { - column = function_base->getConstantResultForNonConstArguments(argument_columns, result_type); - } - - if (column && column->getDataType() != result_type->getColumnType()) - throw Exception( - ErrorCodes::LOGICAL_ERROR, - "Unexpected return type from {}. Expected {}. Got {}", - function->getName(), - result_type->getColumnType(), - column->getDataType()); - - /** Do not perform constant folding if there are aggregate or arrayJoin functions inside function. - * Example: SELECT toTypeName(sum(number)) FROM numbers(10); - */ - if (column && isColumnConst(*column) && !typeid_cast(column.get())->getDataColumn().isDummy() && - !hasAggregateFunctionNodes(node) && !hasFunctionNode(node, "arrayJoin") && - /// Sanity check: do not convert large columns to constants - column->byteSize() < 1_MiB) - { - /// Replace function node with result constant node - Field column_constant_value; - column->get(0, column_constant_value); - constant_value = std::make_shared(std::move(column_constant_value), result_type); - } - } - - function_node.resolveAsFunction(std::move(function_base)); - } - catch (Exception & e) - { - e.addMessage("In scope {}", scope.scope_node->formatASTForErrorMessage()); - throw; - } - - if (constant_value) - node = std::make_shared(std::move(constant_value), node); - - return result_projection_names; -} - -/** Resolve expression node. - * Argument node can be replaced with different node, or even with list node in case of matcher resolution. - * Example: SELECT * FROM test_table; - * * - is matcher node, and it can be resolved into ListNode. - * - * Steps: - * 1. If node has alias, replace node with its value in scope alias map. Register alias in expression_aliases_in_resolve_process, to prevent resolving identifier - * which can bind to expression alias name. Check tryResolveIdentifierFromAliases documentation for additional explanation. - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * - * 2. Call specific resolve method depending on node type. - * - * If allow_table_expression = true and node is query node, then it is not evaluated as scalar subquery. - * Although if node is identifier that is resolved into query node that query is evaluated as scalar subquery. - * SELECT id, (SELECT 1) AS c FROM test_table WHERE a IN c; - * SELECT id, FROM test_table WHERE a IN (SELECT 1); - * - * 3. Special case identifier node. - * Try resolve it as expression identifier. - * Then if allow_lambda_expression = true try to resolve it as function. - * Then if allow_table_expression = true try to resolve it as table expression. - * - * 4. If node has alias, update its value in scope alias map. Deregister alias from expression_aliases_in_resolve_process. - */ -ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias) -{ - checkStackSize(); - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - /** There can be edge case, when subquery for IN function is resolved multiple times in different context. - * SELECT id IN (subquery AS value), value FROM test_table; - * When we start to resolve `value` identifier, subquery is already resolved but constant folding is not performed. - */ - auto node_type = node->getNodeType(); - if (!allow_table_expression && (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION)) - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - } - - return resolved_expression_it->second; - } - - String node_alias = node->getAlias(); - ProjectionNames result_projection_names; - - if (node_alias.empty()) - { - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - else - { - result_projection_names.push_back(node_alias); - } - - bool is_duplicated_alias = scope.aliases.nodes_with_duplicated_aliases.contains(node); - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.insert({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - /** Do not use alias table if node has alias same as some other node. - * Example: WITH x -> x + 1 AS lambda SELECT 1 AS lambda; - * During 1 AS lambda resolve if we use alias table we replace node with x -> x + 1 AS lambda. - * - * Do not use alias table if allow_table_expression = true and we resolve query node directly. - * Example: SELECT a FROM test_table WHERE id IN (SELECT 1) AS a; - * To support both (SELECT 1) AS expression in projection and (SELECT 1) as subquery in IN, do not use - * alias table because in alias table subquery could be evaluated as scalar. - */ - bool use_alias_table = !ignore_alias; - if (is_duplicated_alias || (allow_table_expression && isSubqueryNodeType(node->getNodeType()))) - use_alias_table = false; - - if (!node_alias.empty() && use_alias_table) - { - /** Node could be potentially resolved by resolving other nodes. - * SELECT b, a as b FROM test_table; - * - * To resolve b we need to resolve a. - */ - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - node = it->second; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - node = it->second; - } - } - - scope.pushExpressionNode(node); - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & identifier_node = node->as(); - auto unresolved_identifier = identifier_node.getIdentifier(); - auto resolve_identifier_expression_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier_node = resolve_identifier_expression_result.resolved_identifier; - - if (resolved_identifier_node && result_projection_names.empty() && - (resolve_identifier_expression_result.isResolvedFromJoinTree() || resolve_identifier_expression_result.isResolvedFromExpressionArguments())) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier_node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - - if (!resolved_identifier_node && allow_lambda_expression) - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::FUNCTION}, scope).resolved_identifier; - - if (!resolved_identifier_node && allow_table_expression) - { - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::TABLE_EXPRESSION}, scope).resolved_identifier; - - if (resolved_identifier_node) - { - /// If table identifier is resolved as CTE clone it and resolve - auto * subquery_node = resolved_identifier_node->as(); - auto * union_node = resolved_identifier_node->as(); - bool resolved_as_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - - if (resolved_as_cte) - { - resolved_identifier_node = resolved_identifier_node->clone(); - subquery_node = resolved_identifier_node->as(); - union_node = resolved_identifier_node->as(); - - std::string_view cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - if (subquery_node) - subquery_node->setIsCTE(false); - else - union_node->setIsCTE(false); - - IdentifierResolveScope subquery_scope(resolved_identifier_node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - /// CTE is being resolved, it's required to forbid to resolve to it again - /// because recursive CTEs are not supported, e.g.: - /// - /// WITH test1 AS (SELECT i + 1, j + 1 FROM test1) SELECT toInt64(4) i, toInt64(5) j FROM numbers(3) WHERE (i, j) IN test1; - /// - /// In this example argument of function `in` is being resolve here. If CTE `test1` is not forbidden, - /// `test1` is resolved to CTE (not to the table) in `initializeQueryJoinTreeNode` function. - ctes_in_resolve_process.insert(cte_name); - - if (subquery_node) - resolveQuery(resolved_identifier_node, subquery_scope); - else - resolveUnion(resolved_identifier_node, subquery_scope); - - ctes_in_resolve_process.erase(cte_name); - } - } - } - - if (!resolved_identifier_node) - { - std::string message_clarification; - if (allow_lambda_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::FUNCTION); - - if (allow_table_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::TABLE_EXPRESSION); - - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(unresolved_identifier, - scope, - true, - allow_lambda_expression, - allow_table_expression, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(unresolved_identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {}{} identifier '{}' in scope {}{}", - toStringLowercase(IdentifierLookupContext::EXPRESSION), - message_clarification, - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - node = std::move(resolved_identifier_node); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - { - result_projection_names.clear(); - resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - return resolved_expression_it->second; - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier '{}' resolve into list node and list node projection names are not initialized. In scope {}", - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_projection_names.empty()) - result_projection_names.push_back(unresolved_identifier.getFullName()); - - break; - } - case QueryTreeNodeType::MATCHER: - { - result_projection_names = resolveMatcher(node, scope); - break; - } - case QueryTreeNodeType::LIST: - { - /** Edge case if list expression has alias. - * Matchers cannot have aliases, but `untuple` function can. - * Example: SELECT a, untuple(CAST(('hello', 1) AS Tuple(name String, count UInt32))) AS a; - * During resolveFunction `untuple` function is replaced by list of 2 constants 'hello', 1. - */ - result_projection_names = resolveExpressionNodeList(node, scope, allow_lambda_expression, allow_lambda_expression); - break; - } - case QueryTreeNodeType::CONSTANT: - { - if (result_projection_names.empty()) - { - const auto & constant_node = node->as(); - result_projection_names.push_back(constant_node.getValueStringRepresentation()); - } - - /// Already resolved - break; - } - case QueryTreeNodeType::COLUMN: - { - auto & column_node = node->as(); - if (column_node.hasExpression()) - resolveExpressionNode(column_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (result_projection_names.empty()) - result_projection_names.push_back(column_node.getColumnName()); - - break; - } - case QueryTreeNodeType::FUNCTION: - { - auto function_projection_names = resolveFunction(node, scope); - - if (result_projection_names.empty() || node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(function_projection_names); - - break; - } - case QueryTreeNodeType::LAMBDA: - { - if (!allow_lambda_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (result_projection_names.empty()) - result_projection_names.push_back(PROJECTION_NAME_PLACEHOLDER); - - /// Lambda must be resolved by caller - break; - } - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - std::string projection_name = "_subquery_" + std::to_string(subquery_counter); - ++subquery_counter; - - if (node_type == QueryTreeNodeType::QUERY) - resolveQuery(node, subquery_scope); - else - resolveUnion(node, subquery_scope); - - if (!allow_table_expression) - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - - if (result_projection_names.empty()) - result_projection_names.push_back(std::move(projection_name)); - - break; - } - case QueryTreeNodeType::TABLE: - { - if (!allow_table_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Table {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node = node->as(); - result_projection_names.push_back(table_node.getStorageID().getFullNameNotQuoted()); - - break; - } - case QueryTreeNodeType::TRANSFORMER: - [[fallthrough]]; - case QueryTreeNodeType::SORT: - [[fallthrough]]; - case QueryTreeNodeType::INTERPOLATE: - [[fallthrough]]; - case QueryTreeNodeType::WINDOW: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::ARRAY_JOIN: - [[fallthrough]]; - case QueryTreeNodeType::JOIN: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "{} {} is not allowed in expression context. In scope {}", - node->getNodeType(), - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - validateTreeSize(node, scope.context->getSettingsRef().max_expanded_ast_elements, node_to_tree_size); - - /// Lambda can be inside the aggregate function, so we should check parent scopes. - /// Most likely only the root scope can have an arrgegate function, but let's check all just in case. - bool in_aggregate_function_scope = false; - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - in_aggregate_function_scope = in_aggregate_function_scope || scope_ptr->expressions_in_resolve_process_stack.hasAggregateFunction(); - - if (!in_aggregate_function_scope) - { - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - { - auto it = scope_ptr->nullable_group_by_keys.find(node); - if (it != scope_ptr->nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - break; - } - } - } - - /** Update aliases after expression node was resolved. - * Do not update node in alias table if we resolve it for duplicate alias. - */ - if (!node_alias.empty() && use_alias_table && !scope.group_by_use_nulls) - { - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - it->second = node; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - it->second = node; - } - } - - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.erase({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - if (!ignore_alias) - resolved_expressions.emplace(node, result_projection_names); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - return result_projection_names; -} - -/** Resolve expression node list. - * If expression is CTE subquery node it is skipped. - * If expression is resolved in list, it is flattened into initial node list. - * - * Such examples must work: - * Example: CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; SELECT plus(*) FROM test_table; - * Example: SELECT *** FROM system.one; - */ -ProjectionNames QueryAnalyzer::resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression) -{ - auto & node_list_typed = node_list->as(); - size_t node_list_size = node_list_typed.getNodes().size(); - - QueryTreeNodes result_nodes; - result_nodes.reserve(node_list_size); - - ProjectionNames result_projection_names; - - for (auto & node : node_list_typed.getNodes()) - { - auto node_to_resolve = node; - auto expression_node_projection_names = resolveExpressionNode(node_to_resolve, scope, allow_lambda_expression, allow_table_expression); - size_t expected_projection_names_size = 1; - if (auto * expression_list = node_to_resolve->as()) - { - expected_projection_names_size = expression_list->getNodes().size(); - for (auto & expression_list_node : expression_list->getNodes()) - result_nodes.push_back(expression_list_node); - } - else - { - result_nodes.push_back(std::move(node_to_resolve)); - } - - if (expression_node_projection_names.size() != expected_projection_names_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected {} projection names. Actual {}", - expected_projection_names_size, - expression_node_projection_names.size()); - - result_projection_names.insert(result_projection_names.end(), expression_node_projection_names.begin(), expression_node_projection_names.end()); - expression_node_projection_names.clear(); - } - - node_list_typed.getNodes() = std::move(result_nodes); - - return result_projection_names; -} - -/** Resolve sort columns nodes list. - */ -ProjectionNames QueryAnalyzer::resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames result_projection_names; - ProjectionNames sort_expression_projection_names; - ProjectionNames fill_from_expression_projection_names; - ProjectionNames fill_to_expression_projection_names; - ProjectionNames fill_step_expression_projection_names; - - auto & sort_node_list_typed = sort_node_list->as(); - for (auto & node : sort_node_list_typed.getNodes()) - { - auto & sort_node = node->as(); - sort_expression_projection_names = resolveExpressionNode(sort_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (auto * sort_column_list_node = sort_node.getExpression()->as()) - { - size_t sort_column_list_node_size = sort_column_list_node->getNodes().size(); - if (sort_column_list_node_size != 1) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Sort column node expression resolved into list with size {}. Expected 1. In scope {}", - sort_column_list_node_size, - scope.scope_node->formatASTForErrorMessage()); - } - - sort_node.getExpression() = sort_column_list_node->getNodes().front(); - } - - size_t sort_expression_projection_names_size = sort_expression_projection_names.size(); - if (sort_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort expression expected 1 projection name. Actual {}", - sort_expression_projection_names_size); - - if (sort_node.hasFillFrom()) - { - fill_from_expression_projection_names = resolveExpressionNode(sort_node.getFillFrom(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillFrom()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL FROM expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_from_expression_projection_names_size = fill_from_expression_projection_names.size(); - if (fill_from_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL FROM expression expected 1 projection name. Actual {}", - fill_from_expression_projection_names_size); - } - - if (sort_node.hasFillTo()) - { - fill_to_expression_projection_names = resolveExpressionNode(sort_node.getFillTo(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillTo()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL TO expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_to_expression_projection_names_size = fill_to_expression_projection_names.size(); - if (fill_to_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL TO expression expected 1 projection name. Actual {}", - fill_to_expression_projection_names_size); - } - - if (sort_node.hasFillStep()) - { - fill_step_expression_projection_names = resolveExpressionNode(sort_node.getFillStep(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillStep()->as(); - if (!constant_node) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - bool is_number = isColumnedAsNumber(constant_node->getResultType()); - bool is_interval = WhichDataType(constant_node->getResultType()).isInterval(); - if (!is_number && !is_interval) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_step_expression_projection_names_size = fill_step_expression_projection_names.size(); - if (fill_step_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort FILL STEP expression expected 1 projection name. Actual {}", - fill_step_expression_projection_names_size); - } - - auto sort_column_projection_name = calculateSortColumnProjectionName(node, - sort_expression_projection_names[0], - fill_from_expression_projection_names.empty() ? "" : fill_from_expression_projection_names.front(), - fill_to_expression_projection_names.empty() ? "" : fill_to_expression_projection_names.front(), - fill_step_expression_projection_names.empty() ? "" : fill_step_expression_projection_names.front()); - - result_projection_names.push_back(std::move(sort_column_projection_name)); - - sort_expression_projection_names.clear(); - fill_from_expression_projection_names.clear(); - fill_to_expression_projection_names.clear(); - fill_step_expression_projection_names.clear(); - } - - return result_projection_names; -} - -namespace -{ - -void expandTuplesInList(QueryTreeNodes & key_list) -{ - QueryTreeNodes expanded_keys; - expanded_keys.reserve(key_list.size()); - for (auto const & key : key_list) - { - if (auto * function = key->as(); function != nullptr && function->getFunctionName() == "tuple") - { - std::copy(function->getArguments().begin(), function->getArguments().end(), std::back_inserter(expanded_keys)); - } - else - expanded_keys.push_back(key); - } - key_list = std::move(expanded_keys); -} - -} - -/** Resolve GROUP BY clause. - */ -void QueryAnalyzer::resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope) -{ - if (query_node_typed.isGroupByWithGroupingSets()) - { - for (auto & grouping_sets_keys_list_node : query_node_typed.getGroupBy().getNodes()) - { - replaceNodesWithPositionalArguments(grouping_sets_keys_list_node, query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(grouping_sets_keys_list_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = grouping_sets_keys_list_node->as().getNodes(); - expandTuplesInList(group_by_list); - } - - if (scope.group_by_use_nulls) - { - for (const auto & grouping_set : query_node_typed.getGroupBy().getNodes()) - { - for (const auto & group_by_elem : grouping_set->as()->getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } - } - else - { - replaceNodesWithPositionalArguments(query_node_typed.getGroupByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getGroupByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = query_node_typed.getGroupBy().getNodes(); - expandTuplesInList(group_by_list); - - if (scope.group_by_use_nulls) - { - for (const auto & group_by_elem : query_node_typed.getGroupBy().getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } -} - -/** Resolve interpolate columns nodes list. - */ -void QueryAnalyzer::resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope) -{ - auto & interpolate_node_list_typed = interpolate_node_list->as(); - - for (auto & interpolate_node : interpolate_node_list_typed.getNodes()) - { - auto & interpolate_node_typed = interpolate_node->as(); - - auto * column_to_interpolate = interpolate_node_typed.getExpression()->as(); - if (!column_to_interpolate) - throw Exception(ErrorCodes::LOGICAL_ERROR, "INTERPOLATE can work only for indentifiers, but {} is found", - interpolate_node_typed.getExpression()->formatASTForErrorMessage()); - auto column_to_interpolate_name = column_to_interpolate->getIdentifier().getFullName(); - - resolveExpressionNode(interpolate_node_typed.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool is_column_constant = interpolate_node_typed.getExpression()->getNodeType() == QueryTreeNodeType::CONSTANT; - - auto & interpolation_to_resolve = interpolate_node_typed.getInterpolateExpression(); - IdentifierResolveScope interpolate_scope(interpolation_to_resolve, &scope /*parent_scope*/); - - auto fake_column_node = std::make_shared(NameAndTypePair(column_to_interpolate_name, interpolate_node_typed.getExpression()->getResultType()), interpolate_node_typed.getExpression()); - if (is_column_constant) - interpolate_scope.expression_argument_name_to_node.emplace(column_to_interpolate_name, fake_column_node); - - resolveExpressionNode(interpolation_to_resolve, interpolate_scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (is_column_constant) - interpolation_to_resolve = interpolation_to_resolve->cloneAndReplace(fake_column_node, interpolate_node_typed.getExpression()); - } -} - -/** Resolve window nodes list. - */ -void QueryAnalyzer::resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope) -{ - auto & window_node_list_typed = window_node_list->as(); - for (auto & node : window_node_list_typed.getNodes()) - resolveWindow(node, scope); -} - -NamesAndTypes QueryAnalyzer::resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames projection_names = resolveExpressionNodeList(projection_node_list, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto projection_nodes = projection_node_list->as().getNodes(); - size_t projection_nodes_size = projection_nodes.size(); - - NamesAndTypes projection_columns; - projection_columns.reserve(projection_nodes_size); - - for (size_t i = 0; i < projection_nodes_size; ++i) - { - auto projection_node = projection_nodes[i]; - - if (!isExpressionNodeType(projection_node->getNodeType())) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Projection node must be constant, function, column, query or union"); - - projection_columns.emplace_back(projection_names[i], projection_node->getResultType()); - } - - return projection_columns; -} - -/** Initialize query join tree node. - * - * 1. Resolve identifiers. - * 2. Register table, table function, query, union, join, array join nodes in scope table expressions in resolve process. - */ -void QueryAnalyzer::initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope) -{ - std::deque join_tree_node_ptrs_to_process_queue; - join_tree_node_ptrs_to_process_queue.push_back(&join_tree_node); - - while (!join_tree_node_ptrs_to_process_queue.empty()) - { - auto * current_join_tree_node_ptr = join_tree_node_ptrs_to_process_queue.front(); - join_tree_node_ptrs_to_process_queue.pop_front(); - - auto & current_join_tree_node = *current_join_tree_node_ptr; - auto current_join_tree_node_type = current_join_tree_node->getNodeType(); - - switch (current_join_tree_node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & from_table_identifier = current_join_tree_node->as(); - auto table_identifier_lookup = IdentifierLookup{from_table_identifier.getIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - - auto from_table_identifier_alias = from_table_identifier.getAlias(); - - IdentifierResolveSettings resolve_settings; - /// In join tree initialization ignore join tree as identifier lookup source - resolve_settings.allow_to_check_join_tree = false; - /** Disable resolve of subquery during identifier resolution. - * Example: SELECT * FROM (SELECT 1) AS t1, t1; - * During `t1` identifier resolution we resolve it into subquery SELECT 1, but we want to disable - * subquery resolution at this stage, because JOIN TREE of parent query is not resolved. - */ - resolve_settings.allow_to_resolve_subquery_during_identifier_resolution = false; - - scope.pushExpressionNode(current_join_tree_node); - - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, resolve_settings); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - auto resolved_identifier = table_identifier_resolve_result.resolved_identifier; - - if (!resolved_identifier) - throw Exception(ErrorCodes::UNKNOWN_TABLE, - "Unknown table expression identifier '{}' in scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - resolved_identifier = resolved_identifier->clone(); - - /// Update alias name to table expression map - auto table_expression_it = scope.aliases.alias_name_to_table_expression_node.find(from_table_identifier_alias); - if (table_expression_it != scope.aliases.alias_name_to_table_expression_node.end()) - table_expression_it->second = resolved_identifier; - - auto table_expression_modifiers = from_table_identifier.getTableExpressionModifiers(); - - auto * resolved_identifier_query_node = resolved_identifier->as(); - auto * resolved_identifier_union_node = resolved_identifier->as(); - - if (resolved_identifier_query_node || resolved_identifier_union_node) - { - if (table_expression_modifiers.has_value()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Table expression modifiers {} are not supported for subquery {}", - table_expression_modifiers->formatForErrorMessage(), - resolved_identifier->formatASTForErrorMessage()); - } - } - else if (auto * resolved_identifier_table_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else if (auto * resolved_identifier_table_function_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_function_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier in JOIN TREE '{}' resolved into unexpected table expression. In scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto current_join_tree_node_alias = current_join_tree_node->getAlias(); - resolved_identifier->setAlias(current_join_tree_node_alias); - current_join_tree_node = resolved_identifier; - - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::QUERY: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::UNION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - auto & array_join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&array_join.getTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::JOIN: - { - auto & join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&join.getLeftTableExpression()); - join_tree_node_ptrs_to_process_queue.push_back(&join.getRightTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - ++scope.joins_count; - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, UNION, ARRAY JOIN or JOIN. Actual {} {}. In scope {}", - current_join_tree_node->getNodeTypeName(), - current_join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - } -} - -/// Initialize table expression data for table expression node -void QueryAnalyzer::initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto table_expression_data_it = scope.table_expression_node_to_data.find(table_expression_node); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - return; - - TableExpressionData table_expression_data; - - if (table_node) - { - if (!table_node->getTemporaryTableName().empty()) - { - table_expression_data.table_name = table_node->getTemporaryTableName(); - table_expression_data.table_expression_name = table_node->getTemporaryTableName(); - } - else - { - const auto & table_storage_id = table_node->getStorageID(); - table_expression_data.database_name = table_storage_id.database_name; - table_expression_data.table_name = table_storage_id.table_name; - table_expression_data.table_expression_name = table_storage_id.getFullNameNotQuoted(); - } - - table_expression_data.table_expression_description = "table"; - } - else if (query_node || union_node) - { - table_expression_data.table_name = query_node ? query_node->getCTEName() : union_node->getCTEName(); - table_expression_data.table_expression_description = "subquery"; - } - else if (table_function_node) - { - table_expression_data.table_expression_description = "table_function"; - } - - if (table_expression_node->hasAlias()) - table_expression_data.table_expression_name = table_expression_node->getAlias(); - - if (table_node || table_function_node) - { - const auto & storage_snapshot = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - - auto get_column_options = GetColumnsOptions(GetColumnsOptions::All).withExtendedObjects().withVirtuals(); - if (storage_snapshot->storage.supportsSubcolumns()) - get_column_options.withSubcolumns(); - - auto column_names_and_types = storage_snapshot->getColumns(get_column_options); - table_expression_data.column_names_and_types = NamesAndTypes(column_names_and_types.begin(), column_names_and_types.end()); - - const auto & columns_description = storage_snapshot->metadata->getColumns(); - - std::vector> alias_columns_to_resolve; - ColumnNameToColumnNodeMap column_name_to_column_node; - column_name_to_column_node.reserve(column_names_and_types.size()); - - /** For ALIAS columns in table we must additionally analyze ALIAS expressions. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + 5); - * - * To do that we collect alias columns and build table column name to column node map. - * For each alias column we build identifier resolve scope, initialize it with table column name to node map - * and resolve alias column. - */ - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - for (const auto & subcolumn : columns_description.getSubcolumns(column_name_and_type.name)) - table_expression_data.subcolumn_names.insert(subcolumn.name); - const auto & column_default = columns_description.getDefault(column_name_and_type.name); - - if (column_default && column_default->kind == ColumnDefaultKind::Alias) - { - auto alias_expression = buildQueryTree(column_default->expression, scope.context); - auto column_node = std::make_shared(column_name_and_type, std::move(alias_expression), table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - alias_columns_to_resolve.emplace_back(column_name_and_type.name, column_node); - } - else - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - for (auto & [alias_column_to_resolve_name, alias_column_to_resolve] : alias_columns_to_resolve) - { - /** Alias column could be potentially resolved during resolve of other ALIAS column. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + alias_value_2, alias_value_2 ALIAS id + 5) ENGINE=TinyLog; - * - * During resolve of alias_value_1, alias_value_2 column will be resolved. - */ - alias_column_to_resolve = column_name_to_column_node[alias_column_to_resolve_name]; - - IdentifierResolveScope alias_column_resolve_scope(alias_column_to_resolve, nullptr /*parent_scope*/); - alias_column_resolve_scope.column_name_to_column_node = std::move(column_name_to_column_node); - alias_column_resolve_scope.context = scope.context; - - /// Initialize aliases in alias column scope - QueryExpressionsAliasVisitor visitor(alias_column_resolve_scope.aliases); - visitor.visit(alias_column_to_resolve->getExpression()); - - resolveExpressionNode(alias_column_resolve_scope.scope_node, - alias_column_resolve_scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - auto & resolved_expression = alias_column_to_resolve->getExpression(); - if (!resolved_expression->getResultType()->equals(*alias_column_to_resolve->getResultType())) - resolved_expression = buildCastFunction(resolved_expression, alias_column_to_resolve->getResultType(), scope.context, true); - column_name_to_column_node = std::move(alias_column_resolve_scope.column_name_to_column_node); - column_name_to_column_node[alias_column_to_resolve_name] = alias_column_to_resolve; - } - - table_expression_data.column_name_to_column_node = std::move(column_name_to_column_node); - } - else if (query_node || union_node) - { - table_expression_data.column_names_and_types = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - table_expression_data.column_name_to_column_node.reserve(table_expression_data.column_names_and_types.size()); - - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - table_expression_data.column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - table_expression_data.column_identifier_first_parts.reserve(table_expression_data.column_name_to_column_node.size()); - - for (auto & [column_name, _] : table_expression_data.column_name_to_column_node) - { - Identifier column_name_identifier(column_name); - table_expression_data.column_identifier_first_parts.insert(column_name_identifier.at(0)); - } - - if (auto * scope_query_node = scope.scope_node->as()) - { - auto left_table_expression = extractLeftTableExpression(scope_query_node->getJoinTree()); - if (table_expression_node.get() == left_table_expression.get() && - scope.joins_count == 1 && - scope.context->getSettingsRef().single_join_prefer_left_table) - table_expression_data.should_qualify_columns = false; - } - - scope.table_expression_node_to_data.emplace(table_expression_node, std::move(table_expression_data)); -} - -bool findIdentifier(const FunctionNode & function) -{ - for (const auto & argument : function.getArguments()) - { - if (argument->as()) - return true; - if (const auto * f = argument->as(); f && findIdentifier(*f)) - return true; - } - return false; -} - -/// Resolve table function node in scope -void QueryAnalyzer::resolveTableFunction(QueryTreeNodePtr & table_function_node, - IdentifierResolveScope & scope, - QueryExpressionsAliasVisitor & expressions_visitor, - bool nested_table_function) -{ - auto & table_function_node_typed = table_function_node->as(); - - if (!nested_table_function) - expressions_visitor.visit(table_function_node_typed.getArgumentsNode()); - - const auto & table_function_name = table_function_node_typed.getTableFunctionName(); - - auto & scope_context = scope.context; - - TableFunctionPtr table_function_ptr = TableFunctionFactory::instance().tryGet(table_function_name, scope_context); - if (!table_function_ptr) - { - String database_name = scope_context->getCurrentDatabase(); - String table_name; - - auto function_ast = table_function_node->toAST(); - Identifier table_identifier{table_function_name}; - if (table_identifier.getPartsSize() == 1) - { - table_name = table_identifier[0]; - } - else if (table_identifier.getPartsSize() == 2) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - - auto parametrized_view_storage = scope_context->getQueryContext()->buildParametrizedViewStorage(function_ast, database_name, table_name); - if (parametrized_view_storage) - { - auto fake_table_node = std::make_shared(parametrized_view_storage, scope_context); - fake_table_node->setAlias(table_function_node->getAlias()); - table_function_node = fake_table_node; - return; - } - - auto hints = TableFunctionFactory::instance().getHints(table_function_name); - if (!hints.empty()) - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}. Maybe you meant: {}", - table_function_name, - DB::toString(hints)); - else - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}", - table_function_name); - } - - QueryTreeNodes result_table_function_arguments; - - auto skip_analysis_arguments_indexes = table_function_ptr->skipAnalysisForArguments(table_function_node, scope_context); - - auto & table_function_arguments = table_function_node_typed.getArguments().getNodes(); - size_t table_function_arguments_size = table_function_arguments.size(); - - for (size_t table_function_argument_index = 0; table_function_argument_index < table_function_arguments_size; ++table_function_argument_index) - { - auto & table_function_argument = table_function_arguments[table_function_argument_index]; - - auto skip_argument_index_it = std::find(skip_analysis_arguments_indexes.begin(), - skip_analysis_arguments_indexes.end(), - table_function_argument_index); - if (skip_argument_index_it != skip_analysis_arguments_indexes.end()) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - if (auto * identifier_node = table_function_argument->as()) - { - const auto & unresolved_identifier = identifier_node->getIdentifier(); - auto identifier_resolve_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier = std::move(identifier_resolve_result.resolved_identifier); - - if (resolved_identifier && resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - result_table_function_arguments.push_back(std::move(resolved_identifier)); - else - result_table_function_arguments.push_back(table_function_argument); - - continue; - } - else if (auto * table_function_argument_function = table_function_argument->as()) - { - const auto & table_function_argument_function_name = table_function_argument_function->getFunctionName(); - if (TableFunctionFactory::instance().isTableFunctionName(table_function_argument_function_name)) - { - auto table_function_node_to_resolve_typed = std::make_shared(table_function_argument_function_name); - table_function_node_to_resolve_typed->getArgumentsNode() = table_function_argument_function->getArgumentsNode(); - - QueryTreeNodePtr table_function_node_to_resolve = std::move(table_function_node_to_resolve_typed); - resolveTableFunction(table_function_node_to_resolve, scope, expressions_visitor, true /*nested_table_function*/); - - result_table_function_arguments.push_back(std::move(table_function_node_to_resolve)); - continue; - } - } - - /** Table functions arguments can contain expressions with invalid identifiers. - * We cannot skip analysis for such arguments, because some table functions cannot provide - * information if analysis for argument should be skipped until other arguments will be resolved. - * - * Example: SELECT key from remote('127.0.0.{1,2}', view(select number AS key from numbers(2)), cityHash64(key)); - * Example: SELECT id from remote('127.0.0.{1,2}', 'default', 'test_table', cityHash64(id)); - */ - try - { - resolveExpressionNode(table_function_argument, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - catch (const Exception & exception) - { - if (exception.code() == ErrorCodes::UNKNOWN_IDENTIFIER) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - throw; - } - - if (auto * expression_list = table_function_argument->as()) - { - for (auto & expression_list_node : expression_list->getNodes()) - result_table_function_arguments.push_back(expression_list_node); - } - else - { - result_table_function_arguments.push_back(table_function_argument); - } - } - - table_function_node_typed.getArguments().getNodes() = std::move(result_table_function_arguments); - - auto table_function_ast = table_function_node_typed.toAST(); - table_function_ptr->parseArguments(table_function_ast, scope_context); - - - uint64_t use_structure_from_insertion_table_in_table_functions = scope_context->getSettingsRef().use_structure_from_insertion_table_in_table_functions; - if (!nested_table_function && - use_structure_from_insertion_table_in_table_functions && - scope_context->hasInsertionTable() && - table_function_ptr->needStructureHint()) - { - const auto & insertion_table = scope_context->getInsertionTable(); - if (!insertion_table.empty()) - { - const auto & insert_columns = DatabaseCatalog::instance() - .getTable(insertion_table, scope_context) - ->getInMemoryMetadataPtr() - ->getColumns(); - const auto & insert_column_names = scope_context->hasInsertionTableColumnNames() ? *scope_context->getInsertionTableColumnNames() : insert_columns.getOrdinary().getNames(); - DB::ColumnsDescription structure_hint; - - bool use_columns_from_insert_query = true; - - /// Insert table matches columns against SELECT expression by position, so we want to map - /// insert table columns to table function columns through names from SELECT expression. - - auto insert_column_name_it = insert_column_names.begin(); - auto insert_column_names_end = insert_column_names.end(); /// end iterator of the range covered by possible asterisk - auto virtual_column_names = table_function_ptr->getVirtualsToCheckBeforeUsingStructureHint(); - bool asterisk = false; - const auto & expression_list = scope.scope_node->as().getProjection(); - auto expression = expression_list.begin(); - - /// We want to go through SELECT expression list and correspond each expression to column in insert table - /// which type will be used as a hint for the file structure inference. - for (; expression != expression_list.end() && insert_column_name_it != insert_column_names_end; ++expression) - { - if (auto * identifier_node = (*expression)->as()) - { - - if (!virtual_column_names.contains(identifier_node->getIdentifier().getFullName())) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - ColumnDescription column = insert_columns.get(*insert_column_name_it); - column.name = identifier_node->getIdentifier().getFullName(); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else if (auto * matcher_node = (*expression)->as(); matcher_node && matcher_node->getMatcherType() == MatcherNodeType::ASTERISK) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Only one asterisk can be used in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - if (!structure_hint.empty()) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - asterisk = true; - } - else if (auto * function = (*expression)->as()) - { - if (use_structure_from_insertion_table_in_table_functions == 2 && findIdentifier(*function)) - { - use_columns_from_insert_query = false; - break; - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else - { - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - } - - if (use_structure_from_insertion_table_in_table_functions == 2 && !asterisk) - { - /// For input function we should check if input format supports reading subset of columns. - if (table_function_ptr->getName() == "input") - use_columns_from_insert_query = FormatFactory::instance().checkIfFormatSupportsSubsetOfColumns(scope.context->getInsertFormat(), scope.context); - else - use_columns_from_insert_query = table_function_ptr->supportsReadingSubsetOfColumns(scope.context); - } - - if (use_columns_from_insert_query) - { - if (expression == expression_list.end()) - { - /// Append tail of insert structure to the hint - if (asterisk) - { - for (; insert_column_name_it != insert_column_names_end; ++insert_column_name_it) - { - ColumnDescription column = insert_columns.get(*insert_column_name_it); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - } - - if (!structure_hint.empty()) - table_function_ptr->setStructureHint(structure_hint); - - } else if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::NUMBER_OF_COLUMNS_DOESNT_MATCH, "Number of columns in insert table less than required by SELECT expression."); - } - } - } - - auto table_function_storage = scope_context->getQueryContext()->executeTableFunction(table_function_ast, table_function_ptr); - table_function_node_typed.resolve(std::move(table_function_ptr), std::move(table_function_storage), scope_context, std::move(skip_analysis_arguments_indexes)); -} - -/// Resolve array join node in scope -void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & array_join_node_typed = array_join_node->as(); - resolveQueryJoinTreeNode(array_join_node_typed.getTableExpression(), scope, expressions_visitor); - - std::unordered_set array_join_column_names; - - /// Wrap array join expressions into column nodes, where array join expression is inner expression - - auto & array_join_nodes = array_join_node_typed.getJoinExpressions().getNodes(); - size_t array_join_nodes_size = array_join_nodes.size(); - - if (array_join_nodes_size == 0) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, - "ARRAY JOIN requires at least single expression"); - - std::vector array_join_column_expressions; - array_join_column_expressions.reserve(array_join_nodes_size); - - for (auto & array_join_expression : array_join_nodes) - { - auto array_join_expression_alias = array_join_expression->getAlias(); - - for (const auto & elem : array_join_nodes) - { - if (elem->hasAlias()) - scope.aliases.array_join_aliases.insert(elem->getAlias()); - - for (auto & child : elem->getChildren()) - { - if (child) - expressions_visitor.visit(child); - } - } - - std::string identifier_full_name; - - if (auto * identifier_node = array_join_expression->as()) - identifier_full_name = identifier_node->getIdentifier().getFullName(); - - resolveExpressionNode(array_join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/, true /*ignore_alias*/); - - auto process_array_join_expression = [&](QueryTreeNodePtr & expression) - { - auto result_type = expression->getResultType(); - bool is_array_type = isArray(result_type); - bool is_map_type = isMap(result_type); - - if (!is_array_type && !is_map_type) - throw Exception(ErrorCodes::TYPE_MISMATCH, - "ARRAY JOIN {} requires expression {} with Array or Map type. Actual {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - expression->formatASTForErrorMessage(), - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_map_type) - result_type = assert_cast(*result_type).getNestedType(); - - result_type = assert_cast(*result_type).getNestedType(); - - String array_join_column_name; - - if (!array_join_expression_alias.empty()) - { - array_join_column_name = array_join_expression_alias; - } - else if (auto * array_join_expression_inner_column = array_join_expression->as()) - { - array_join_column_name = array_join_expression_inner_column->getColumnName(); - } - else if (!identifier_full_name.empty()) - { - array_join_column_name = identifier_full_name; - } - else - { - array_join_column_name = "__array_join_expression_" + std::to_string(array_join_expressions_counter); - ++array_join_expressions_counter; - } - - if (array_join_column_names.contains(array_join_column_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "ARRAY JOIN {} multiple columns with name {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - array_join_column_name, - scope.scope_node->formatASTForErrorMessage()); - array_join_column_names.emplace(array_join_column_name); - - NameAndTypePair array_join_column(array_join_column_name, result_type); - auto array_join_column_node = std::make_shared(std::move(array_join_column), expression, array_join_node); - array_join_column_node->setAlias(array_join_expression_alias); - array_join_column_expressions.push_back(std::move(array_join_column_node)); - }; - - // Support ARRAY JOIN COLUMNS(...). COLUMNS transformer is resolved to list of columns. - if (auto * columns_list = array_join_expression->as()) - { - for (auto & array_join_subexpression : columns_list->getNodes()) - process_array_join_expression(array_join_subexpression); - } - else - { - process_array_join_expression(array_join_expression); - } - } - - array_join_nodes = std::move(array_join_column_expressions); -} - -void QueryAnalyzer::checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope) -{ - Names column_names; - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - if (join_node->as().getKind() != JoinKind::Paste) - return; - - auto * left_node = left_table_expr->as(); - auto * right_node = right_table_expr->as(); - - if (!left_node && !right_node) - return; - - if (left_node) - for (const auto & name_and_type : left_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - if (right_node) - for (const auto & name_and_type : right_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - - if (column_names.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of projection columns cannot be empty"); - - std::sort(column_names.begin(), column_names.end()); - for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is no any duplicates because it will lead to broken result - if (column_names[i] == column_names[i+1]) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add/change aliases to avoid duplication)" - "While processing '{}'", join_node->formatASTForErrorMessage()); -} - -/// Resolve join node in scope -void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & join_node_typed = join_node->as(); - - resolveQueryJoinTreeNode(join_node_typed.getLeftTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getLeftTableExpression(), scope); - - resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); - - if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) - checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope); - - if (join_node_typed.isOnJoinExpression()) - { - expressions_visitor.visit(join_node_typed.getJoinExpression()); - auto join_expression = join_node_typed.getJoinExpression(); - resolveExpressionNode(join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - join_node_typed.getJoinExpression() = std::move(join_expression); - } - else if (join_node_typed.isUsingJoinExpression()) - { - auto & join_using_list = join_node_typed.getJoinExpression()->as(); - std::unordered_set join_using_identifiers; - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto * identifier_node = join_using_node->as(); - if (!identifier_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} USING clause expected identifier. Actual {}", - join_node_typed.formatASTForErrorMessage(), - join_using_node->formatASTForErrorMessage()); - - const auto & identifier_full_name = identifier_node->getIdentifier().getFullName(); - - if (join_using_identifiers.contains(identifier_full_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} identifier '{}' appears more than once in USING clause", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name); - - join_using_identifiers.insert(identifier_full_name); - - const auto & settings = scope.context->getSettingsRef(); - - /** While resolving JOIN USING identifier, try to resolve identifier from parent subquery projection. - * Example: SELECT a + 1 AS b FROM (SELECT 1 AS a) t1 JOIN (SELECT 2 AS b) USING b - * In this case `b` is not in the left table expression, but it is in the parent subquery projection. - */ - auto try_resolve_identifier_from_query_projection = [this](const String & identifier_full_name_, - const QueryTreeNodePtr & left_table_expression, - const IdentifierResolveScope & scope_) -> QueryTreeNodePtr - { - const QueryNode * query_node = scope_.scope_node ? scope_.scope_node->as() : nullptr; - if (!query_node) - return nullptr; - - const auto & projection_list = query_node->getProjection(); - for (const auto & projection_node : projection_list.getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name_ == projection_node->getAlias()) - { - auto left_subquery = std::make_shared(query_node->getMutableContext()); - left_subquery->getProjection().getNodes().push_back(projection_node->clone()); - left_subquery->getJoinTree() = left_table_expression; - - IdentifierResolveScope left_subquery_scope(left_subquery, nullptr /*parent_scope*/); - resolveQuery(left_subquery, left_subquery_scope); - - const auto & resolved_nodes = left_subquery->getProjection().getNodes(); - if (resolved_nodes.size() == 1) - { - /// Create ColumnNode with expression from parent projection - return std::make_shared( - NameAndTypePair{identifier_full_name_, resolved_nodes.front()->getResultType()}, - resolved_nodes.front(), left_table_expression); - } - } - } - return nullptr; - }; - - QueryTreeNodePtr result_left_table_expression = nullptr; - /** With `analyzer_compatibility_join_using_top_level_identifier` alias in projection has higher priority than column from left table. - * But if aliased expression cannot be resolved from left table, we get UNKNOW_IDENTIFIER error, - * despite the fact that column from USING could be resolved from left table. - * It's compatibility with a default behavior for old analyzer. - */ - if (settings.analyzer_compatibility_join_using_top_level_identifier) - result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - IdentifierLookup identifier_lookup{identifier_node->getIdentifier(), IdentifierLookupContext::EXPRESSION}; - if (!result_left_table_expression) - result_left_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getLeftTableExpression(), scope); - - /** Here we may try to resolve identifier from projection in case it's not resolved from left table expression - * and analyzer_compatibility_join_using_top_level_identifier is disabled. - * For now we do not do this, because not all corner cases are clear. - * But let's at least mention it in error message - */ - /// if (!settings.analyzer_compatibility_join_using_top_level_identifier && !result_left_table_expression) - /// result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - if (!result_left_table_expression) - { - String extra_message; - const QueryNode * query_node = scope.scope_node ? scope.scope_node->as() : nullptr; - if (settings.analyzer_compatibility_join_using_top_level_identifier && query_node) - { - for (const auto & projection_node : query_node->getProjection().getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name == projection_node->getAlias()) - { - extra_message = fmt::format( - ", but alias '{}' is present in SELECT list." - " You may try to SET analyzer_compatibility_join_using_top_level_identifier = 1, to allow to use it in USING clause", - projection_node->formatASTForErrorMessage()); - break; - } - } - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from left table expression{}. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - extra_message, - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_left_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from left table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto result_right_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getRightTableExpression(), scope); - if (!result_right_table_expression) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - if (result_right_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto expression_types = DataTypes{result_left_table_expression->getResultType(), result_right_table_expression->getResultType()}; - DataTypePtr common_type = tryGetLeastSupertype(expression_types); - - if (!common_type) - throw Exception(ErrorCodes::NO_COMMON_TYPE, - "JOIN {} cannot infer common type for {} and {} in USING for identifier '{}'. In scope {}", - join_node_typed.formatASTForErrorMessage(), - result_left_table_expression->getResultType()->getName(), - result_right_table_expression->getResultType()->getName(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - NameAndTypePair join_using_column(identifier_full_name, common_type); - ListNodePtr join_using_expression = std::make_shared(QueryTreeNodes{result_left_table_expression, result_right_table_expression}); - auto join_using_column_node = std::make_shared(std::move(join_using_column), std::move(join_using_expression), join_node); - join_using_node = std::move(join_using_column_node); - } - } -} - -/** Resolve query join tree. - * - * Query join tree must be initialized before calling this function. - */ -void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto from_node_type = join_tree_node->getNodeType(); - - switch (from_node_type) - { - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - resolveExpressionNode(join_tree_node, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - resolveTableFunction(join_tree_node, scope, expressions_visitor, false /*nested_table_function*/); - break; - } - case QueryTreeNodeType::TABLE: - { - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - resolveArrayJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::JOIN: - { - resolveJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::IDENTIFIER: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifiers in FROM section must be already resolved. Node {}, scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, ARRAY JOIN or JOIN. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - auto join_tree_node_type = join_tree_node->getNodeType(); - if (isTableExpressionNodeType(join_tree_node_type)) - { - validateTableExpressionModifiers(join_tree_node, scope); - initializeTableExpressionData(join_tree_node, scope); - - auto & query_node = scope.scope_node->as(); - auto & mutable_context = query_node.getMutableContext(); - - if (!mutable_context->isDistributed()) - { - bool is_distributed = false; - - if (auto * table_node = join_tree_node->as()) - is_distributed = table_node->getStorage()->isRemote(); - else if (auto * table_function_node = join_tree_node->as()) - is_distributed = table_function_node->getStorage()->isRemote(); - - mutable_context->setDistributed(is_distributed); - } - } - - auto add_table_expression_alias_into_scope = [&](const QueryTreeNodePtr & table_expression_node) - { - const auto & alias_name = table_expression_node->getAlias(); - if (alias_name.empty()) - return; - - auto [it, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(alias_name, table_expression_node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Duplicate aliases {} for table expressions in FROM section are not allowed. Try to register {}. Already registered {}.", - alias_name, - table_expression_node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage()); - }; - - add_table_expression_alias_into_scope(join_tree_node); - scope.table_expressions_in_resolve_process.erase(join_tree_node.get()); -} - -/** Resolve query. - * This function modifies query node during resolve. It is caller responsibility to clone query node before resolve - * if it is needed for later use. - * - * query_node - query_tree_node that must have QueryNode type. - * scope - query scope. It is caller responsibility to create it. - * - * Resolve steps: - * 1. Validate subqueries depth, perform GROUP BY validation that does not depend on information about aggregate functions. - * 2. Initialize query scope with aliases. - * 3. Register CTE subqueries from WITH section in scope and remove them from WITH section. - * 4. Resolve JOIN TREE. - * 5. Resolve projection columns. - * 6. Resolve expressions in other query parts. - * 7. Validate nodes with duplicate aliases. - * 8. Validate aggregate functions, GROUPING function, window functions. - * 9. Remove WITH and WINDOW sections from query. - * 10. Remove aliases from expression and lambda nodes. - * 11. Resolve query tree node with projection columns. - */ -void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope) -{ - size_t max_subquery_depth = scope.context->getSettingsRef().max_subquery_depth; - if (max_subquery_depth && scope.subquery_depth > max_subquery_depth) - throw Exception(ErrorCodes::TOO_DEEP_SUBQUERIES, - "Too deep subqueries. Maximum: {}", - max_subquery_depth); - - auto & query_node_typed = query_node->as(); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.insert(query_node_typed.getCTEName()); - - bool is_rollup_or_cube = query_node_typed.isGroupByWithRollup() || query_node_typed.isGroupByWithCube(); - - if (query_node_typed.isGroupByWithGroupingSets() - && query_node_typed.isGroupByWithTotals() - && query_node_typed.getGroupBy().getNodes().size() != 1) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and GROUPING SETS are not supported together"); - - if (query_node_typed.isGroupByWithGroupingSets() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "GROUPING SETS are not supported together with ROLLUP and CUBE"); - - if (query_node_typed.isGroupByWithRollup() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithCube())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "ROLLUP is not supported together with GROUPING SETS and CUBE"); - - if (query_node_typed.isGroupByWithCube() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithRollup())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "CUBE is not supported together with GROUPING SETS and ROLLUP"); - - if (query_node_typed.hasHaving() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of HAVING"); - - if (query_node_typed.hasQualify() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of QUALIFY"); - - /// Initialize aliases in query node scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - - if (query_node_typed.hasWith()) - visitor.visit(query_node_typed.getWithNode()); - - if (!query_node_typed.getProjection().getNodes().empty()) - visitor.visit(query_node_typed.getProjectionNode()); - - if (query_node_typed.getPrewhere()) - visitor.visit(query_node_typed.getPrewhere()); - - if (query_node_typed.getWhere()) - visitor.visit(query_node_typed.getWhere()); - - if (query_node_typed.hasGroupBy()) - visitor.visit(query_node_typed.getGroupByNode()); - - if (query_node_typed.hasHaving()) - visitor.visit(query_node_typed.getHaving()); - - if (query_node_typed.hasWindow()) - visitor.visit(query_node_typed.getWindowNode()); - - if (query_node_typed.hasQualify()) - visitor.visit(query_node_typed.getQualify()); - - if (query_node_typed.hasOrderBy()) - visitor.visit(query_node_typed.getOrderByNode()); - - if (query_node_typed.hasInterpolate()) - visitor.visit(query_node_typed.getInterpolate()); - - if (query_node_typed.hasLimitByLimit()) - visitor.visit(query_node_typed.getLimitByLimit()); - - if (query_node_typed.hasLimitByOffset()) - visitor.visit(query_node_typed.getLimitByOffset()); - - if (query_node_typed.hasLimitBy()) - visitor.visit(query_node_typed.getLimitByNode()); - - if (query_node_typed.hasLimit()) - visitor.visit(query_node_typed.getLimit()); - - if (query_node_typed.hasOffset()) - visitor.visit(query_node_typed.getOffset()); - - /// Register CTE subqueries and remove them from WITH section - - auto & with_nodes = query_node_typed.getWith().getNodes(); - - for (auto & node : with_nodes) - { - auto * subquery_node = node->as(); - auto * union_node = node->as(); - - bool subquery_is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - if (!subquery_is_cte) - continue; - - const auto & cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - auto [_, inserted] = scope.cte_name_to_query_node.emplace(cte_name, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "CTE with name {} already exists. In scope {}", - cte_name, - scope.scope_node->formatASTForErrorMessage()); - } - - /** WITH section can be safely removed, because WITH section only can provide aliases to query expressions - * and CTE for other sections to use. - * - * Example: WITH 1 AS constant, (x -> x + 1) AS lambda, a AS (SELECT * FROM test_table); - */ - query_node_typed.getWith().getNodes().clear(); - - for (auto & window_node : query_node_typed.getWindow().getNodes()) - { - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - if (!parent_window_name.empty()) - { - auto window_node_it = scope.window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope.window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - scope.scope_node->formatASTForErrorMessage()); - - mergeWindowWithParentWindow(window_node, window_node_it->second, scope); - window_node_typed.setParentWindowName({}); - } - - auto [_, inserted] = scope.window_name_to_window_node.emplace(window_node_typed.getAlias(), window_node); - if (!inserted) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' is already defined. In scope {}", - window_node_typed.getAlias(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** Disable identifier cache during JOIN TREE resolve. - * Depending on JOIN expression section, identifier with same name - * can be resolved in different columns. - * - * Example: SELECT id FROM test_table AS t1 INNER JOIN test_table AS t2 ON t1.id = t2.id INNER JOIN test_table AS t3 ON t1.id = t3.id - * In first join expression ON t1.id = t2.id t1.id is resolved into test_table.id column. - * In second join expression ON t1.id = t3.id t1.id must be resolved into test_table.id column after first JOIN. - */ - scope.use_identifier_lookup_to_result_cache = false; - - if (query_node_typed.getJoinTree()) - { - TableExpressionsAliasVisitor table_expressions_visitor(scope); - table_expressions_visitor.visit(query_node_typed.getJoinTree()); - - initializeQueryJoinTreeNode(query_node_typed.getJoinTree(), scope); - scope.aliases.alias_name_to_table_expression_node.clear(); - - resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor); - } - - if (!scope.group_by_use_nulls) - scope.use_identifier_lookup_to_result_cache = true; - - /// Resolve query node sections. - - NamesAndTypes projection_columns; - - if (!scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - if (auto & prewhere_node = query_node_typed.getPrewhere()) - { - resolveExpressionNode(prewhere_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** Expressions in PREWHERE with JOIN should not change their type. - * Example: SELECT * FROM t1 JOIN t2 USING (a) PREWHERE a = 1 - * Column `a` in PREWHERE should be resolved from the left table - * and should not change its type to Nullable or to the supertype of `a` from t1 and t2. - * Here's a more complicated example where the column is somewhere inside an expression: - * SELECT a + 1 as b FROM t1 JOIN t2 USING (id) PREWHERE b = 1 - * The expression `a + 1 as b` in the projection and in PREWHERE should have different `a`. - */ - prewhere_node = prewhere_node->clone(); - ReplaceColumnsVisitor replace_visitor(scope.join_columns_with_changed_types, scope.context); - replace_visitor.visit(prewhere_node); - } - - if (query_node_typed.getWhere()) - resolveExpressionNode(query_node_typed.getWhere(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasGroupBy()) - resolveGroupByNode(query_node_typed, scope); - - if (scope.group_by_use_nulls) - { - resolved_expressions.clear(); - /// Clone is needed cause aliases share subtrees. - /// If not clone, the same (shared) subtree could be resolved again with different (Nullable) type - /// See 03023_group_by_use_nulls_analyzer_crashes - for (auto & [key, node] : scope.aliases.alias_name_to_expression_node_before_group_by) - scope.aliases.alias_name_to_expression_node_after_group_by[key] = node->clone(); - - scope.aliases.alias_name_to_expression_node = &scope.aliases.alias_name_to_expression_node_after_group_by; - } - - if (query_node_typed.hasHaving()) - resolveExpressionNode(query_node_typed.getHaving(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasWindow()) - resolveWindowNodeList(query_node_typed.getWindowNode(), scope); - - if (query_node_typed.hasQualify()) - resolveExpressionNode(query_node_typed.getQualify(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasOrderBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getOrderByNode(), query_node_typed.getProjection().getNodes(), scope); - - const auto & settings = scope.context->getSettingsRef(); - - expandOrderByAll(query_node_typed, settings); - resolveSortNodeList(query_node_typed.getOrderByNode(), scope); - } - - if (query_node_typed.hasInterpolate()) - resolveInterpolateColumnsNodeList(query_node_typed.getInterpolate(), scope); - - if (query_node_typed.hasLimitByLimit()) - { - resolveExpressionNode(query_node_typed.getLimitByLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByLimit(), "LIMIT BY LIMIT", scope); - } - - if (query_node_typed.hasLimitByOffset()) - { - resolveExpressionNode(query_node_typed.getLimitByOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByOffset(), "LIMIT BY OFFSET", scope); - } - - if (query_node_typed.hasLimitBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getLimitByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getLimitByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - - if (query_node_typed.hasLimit()) - { - resolveExpressionNode(query_node_typed.getLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimit(), "LIMIT", scope); - } - - if (query_node_typed.hasOffset()) - { - resolveExpressionNode(query_node_typed.getOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getOffset(), "OFFSET", scope); - } - - if (scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - /** Resolve nodes with duplicate aliases. - * Table expressions cannot have duplicate aliases. - * - * Such nodes during scope aliases collection are placed into duplicated array. - * After scope nodes are resolved, we can compare node with duplicate alias with - * node from scope alias table. - */ - for (const auto & node_with_duplicated_alias : scope.aliases.cloned_nodes_with_duplicated_aliases) - { - auto node = node_with_duplicated_alias; - auto node_alias = node->getAlias(); - - /// Add current alias to non cached set, because in case of cyclic alias identifier should not be substituted from cache. - /// See 02896_cyclic_aliases_crash. - resolveExpressionNode(node, scope, true /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool has_node_in_alias_table = false; - - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - if (!has_node_in_alias_table) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node {} with duplicate alias {} does not exist in alias table. In scope {}", - node->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - - node->removeAlias(); - } - - expandGroupByAll(query_node_typed); - - validateFilters(query_node); - validateAggregates(query_node, { .group_by_use_nulls = scope.group_by_use_nulls }); - - for (const auto & column : projection_columns) - { - if (isNotCreatable(column.type)) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Invalid projection column with type {}. In scope {}", - column.type->getName(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** WINDOW section can be safely removed, because WINDOW section can only provide window definition to window functions. - * - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - */ - query_node_typed.getWindow().getNodes().clear(); - - /// Remove aliases from expression and lambda nodes - - for (auto & [_, node] : *scope.aliases.alias_name_to_expression_node) - node->removeAlias(); - - for (auto & [_, node] : scope.aliases.alias_name_to_lambda_node) - node->removeAlias(); - - query_node_typed.resolveProjectionColumns(std::move(projection_columns)); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.erase(query_node_typed.getCTEName()); -} - -void QueryAnalyzer::resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope) -{ - auto & union_node_typed = union_node->as(); - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.insert(union_node_typed.getCTEName()); - - auto & queries_nodes = union_node_typed.getQueries().getNodes(); - - std::optional recursive_cte_table; - TableNodePtr recursive_cte_table_node; - - if (union_node_typed.isCTE() && union_node_typed.isRecursiveCTE()) - { - auto & non_recursive_query = queries_nodes[0]; - bool non_recursive_query_is_query_node = non_recursive_query->getNodeType() == QueryTreeNodeType::QUERY; - auto & non_recursive_query_mutable_context = non_recursive_query_is_query_node ? non_recursive_query->as().getMutableContext() - : non_recursive_query->as().getMutableContext(); - - IdentifierResolveScope non_recursive_subquery_scope(non_recursive_query, &scope /*parent_scope*/); - non_recursive_subquery_scope.subquery_depth = scope.subquery_depth + 1; - - if (non_recursive_query_is_query_node) - resolveQuery(non_recursive_query, non_recursive_subquery_scope); - else - resolveUnion(non_recursive_query, non_recursive_subquery_scope); - - auto temporary_table_columns = non_recursive_query_is_query_node - ? non_recursive_query->as().getProjectionColumns() - : non_recursive_query->as().computeProjectionColumns(); - - auto temporary_table_holder = std::make_shared( - non_recursive_query_mutable_context, - ColumnsDescription{NamesAndTypesList{temporary_table_columns.begin(), temporary_table_columns.end()}}, - ConstraintsDescription{}, - nullptr /*query*/, - true /*create_for_global_subquery*/); - auto temporary_table_storage = temporary_table_holder->getTable(); - - recursive_cte_table_node = std::make_shared(temporary_table_storage, non_recursive_query_mutable_context); - recursive_cte_table_node->setTemporaryTableName(union_node_typed.getCTEName()); - - recursive_cte_table.emplace(std::move(temporary_table_holder), std::move(temporary_table_storage), std::move(temporary_table_columns)); - } - - size_t queries_nodes_size = queries_nodes.size(); - for (size_t i = recursive_cte_table.has_value(); i < queries_nodes_size; ++i) - { - auto & query_node = queries_nodes[i]; - - IdentifierResolveScope subquery_scope(query_node, &scope /*parent_scope*/); - - if (recursive_cte_table_node) - subquery_scope.expression_argument_name_to_node[union_node_typed.getCTEName()] = recursive_cte_table_node; - - auto query_node_type = query_node->getNodeType(); - - if (query_node_type == QueryTreeNodeType::QUERY) - { - resolveQuery(query_node, subquery_scope); - } - else if (query_node_type == QueryTreeNodeType::UNION) - { - resolveUnion(query_node, subquery_scope); - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "UNION unsupported node {}. In scope {}", - query_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (recursive_cte_table && isStorageUsedInTree(recursive_cte_table->storage, union_node.get())) - { - if (union_node_typed.getUnionMode() != SelectUnionMode::UNION_ALL) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive CTE subquery {} with {} union mode is unsupported, only UNION ALL union mode is supported", - union_node_typed.formatASTForErrorMessage(), - toString(union_node_typed.getUnionMode())); - - union_node_typed.setRecursiveCTETable(std::move(*recursive_cte_table)); - } - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.erase(union_node_typed.getCTEName()); -} - -} - -QueryAnalysisPass::QueryAnalysisPass(QueryTreeNodePtr table_expression_, bool only_analyze_) - : table_expression(std::move(table_expression_)) - , only_analyze(only_analyze_) -{} - -QueryAnalysisPass::QueryAnalysisPass(bool only_analyze_) : only_analyze(only_analyze_) {} - -void QueryAnalysisPass::run(QueryTreeNodePtr & query_tree_node, ContextPtr context) -{ - QueryAnalyzer analyzer(only_analyze); - analyzer.resolve(query_tree_node, table_expression, context); - createUniqueTableAliases(query_tree_node, table_expression, context); -} - } diff --git a/src/Analyzer/QueryAnalysis/IdentifierResolveScope.h b/src/Analyzer/QueryAnalysis/IdentifierResolveScope.h index 3fca66e6eb8..661d75014e7 100644 --- a/src/Analyzer/QueryAnalysis/IdentifierResolveScope.h +++ b/src/Analyzer/QueryAnalysis/IdentifierResolveScope.h @@ -1,674 +1,17 @@ -#include +#pragma once -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -namespace ProfileEvents -{ - extern const Event ScalarSubqueriesGlobalCacheHit; - extern const Event ScalarSubqueriesLocalCacheHit; - extern const Event ScalarSubqueriesCacheMiss; -} +#include +#include +#include +#include namespace DB { -namespace ErrorCodes -{ - extern const int UNSUPPORTED_METHOD; - extern const int UNKNOWN_IDENTIFIER; - extern const int UNKNOWN_FUNCTION; - extern const int LOGICAL_ERROR; - extern const int CYCLIC_ALIASES; - extern const int INCORRECT_RESULT_OF_SCALAR_SUBQUERY; - extern const int BAD_ARGUMENTS; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int MULTIPLE_EXPRESSIONS_FOR_ALIAS; - extern const int TYPE_MISMATCH; - extern const int AMBIGUOUS_IDENTIFIER; - extern const int INVALID_WITH_FILL_EXPRESSION; - extern const int INVALID_LIMIT_EXPRESSION; - extern const int EMPTY_LIST_OF_COLUMNS_QUERIED; - extern const int TOO_DEEP_SUBQUERIES; - extern const int UNKNOWN_AGGREGATE_FUNCTION; - extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION; - extern const int TOO_MANY_ARGUMENTS_FOR_FUNCTION; - extern const int ILLEGAL_FINAL; - extern const int SAMPLING_NOT_SUPPORTED; - extern const int NO_COMMON_TYPE; - extern const int NOT_IMPLEMENTED; - extern const int ALIAS_REQUIRED; - extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; - extern const int UNKNOWN_TABLE; - extern const int ILLEGAL_COLUMN; - extern const int NUMBER_OF_COLUMNS_DOESNT_MATCH; - extern const int FUNCTION_CANNOT_HAVE_PARAMETERS; - extern const int SYNTAX_ERROR; - extern const int UNEXPECTED_EXPRESSION; - extern const int INVALID_IDENTIFIER; -} - -/** Query analyzer implementation overview. Please check documentation in QueryAnalysisPass.h first. - * And additional documentation for each method, where special cases are described in detail. - * - * Each node in query must be resolved. For each query tree node resolved state is specific. - * - * For constant node no resolve process exists, it is resolved during construction. - * - * For table node no resolve process exists, it is resolved during construction. - * - * For function node to be resolved parameters and arguments must be resolved, function node must be initialized with concrete aggregate or - * non aggregate function and with result type. - * - * For lambda node there can be 2 different cases. - * 1. Standalone: WITH (x -> x + 1) AS lambda SELECT lambda(1); Such lambdas are inlined in query tree during query analysis pass. - * 2. Function arguments: WITH (x -> x + 1) AS lambda SELECT arrayMap(lambda, [1, 2, 3]); For such lambda resolution must - * set concrete lambda arguments (initially they are identifier nodes) and resolve lambda expression body. - * - * For query node resolve process must resolve all its inner nodes. - * - * For matcher node resolve process must replace it with matched nodes. - * - * For identifier node resolve process must replace it with concrete non identifier node. This part is most complex because - * for identifier resolution scopes and identifier lookup context play important part. - * - * ClickHouse SQL support lexical scoping for identifier resolution. Scope can be defined by query node or by expression node. - * Expression nodes that can define scope are lambdas and table ALIAS columns. - * - * Identifier lookup context can be expression, function, table. - * - * Examples: WITH (x -> x + 1) as func SELECT func() FROM func; During function `func` resolution identifier lookup is performed - * in function context. - * - * If there are no information of identifier context rules are following: - * 1. Try to resolve identifier in expression context. - * 2. Try to resolve identifier in function context, if it is allowed. Example: SELECT func(arguments); Here func identifier cannot be resolved in function context - * because query projection does not support that. - * 3. Try to resolve identifier in table context, if it is allowed. Example: SELECT table; Here table identifier cannot be resolved in function context - * because query projection does not support that. - * - * TODO: This does not supported properly before, because matchers could not be resolved from aliases. - * - * Identifiers are resolved with following rules: - * Resolution starts with current scope. - * 1. Try to resolve identifier from expression scope arguments. Lambda expression arguments are greatest priority. - * 2. Try to resolve identifier from aliases. - * 3. Try to resolve identifier from join tree if scope is query, or if there are registered table columns in scope. - * Steps 2 and 3 can be changed using prefer_column_name_to_alias setting. - * 4. If it is table lookup, try to resolve identifier from CTE. - * If identifier could not be resolved in current scope, resolution must be continued in parent scopes. - * 5. Try to resolve identifier from parent scopes. - * - * Additional rules about aliases and scopes. - * 1. Parent scope cannot refer alias from child scope. - * 2. Child scope can refer to alias in parent scope. - * - * Example: SELECT arrayMap(x -> x + 1 AS a, [1,2,3]), a; Identifier a is unknown in parent scope. - * Example: SELECT a FROM (SELECT 1 as a); Here we do not refer to alias a from child query scope. But we query it projection result, similar to tables. - * Example: WITH 1 as a SELECT (SELECT a) as b; Here in child scope identifier a is resolved using alias from parent scope. - * - * Additional rules about identifier binding. - * Bind for identifier to entity means that identifier first part match some node during analysis. - * If other parts of identifier cannot be resolved in that node, exception must be thrown. - * - * Example: - * CREATE TABLE test_table (id UInt64, compound_value Tuple(value UInt64)) ENGINE=TinyLog; - * SELECT compound_value.value, 1 AS compound_value FROM test_table; - * Identifier first part compound_value bound to entity with alias compound_value, but nested identifier part cannot be resolved from entity, - * lookup should not be continued, and exception must be thrown because if lookup continues that way identifier can be resolved from join tree. - * - * TODO: This was not supported properly before analyzer because nested identifier could not be resolved from alias. - * - * More complex example: - * CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; - * WITH cast(('Value'), 'Tuple (value UInt64') AS value SELECT (SELECT value FROM test_table); - * Identifier first part value bound to test_table column value, but nested identifier part cannot be resolved from it, - * lookup should not be continued, and exception must be thrown because if lookup continues identifier can be resolved from parent scope. - * - * TODO: Update exception messages - * TODO: Table identifiers with optional UUID. - * TODO: Lookup functions arrayReduce(sum, [1, 2, 3]); - * TODO: Support function identifier resolve from parent query scope, if lambda in parent scope does not capture any columns. - */ - -namespace -{ - -/// Identifier lookup context -enum class IdentifierLookupContext : uint8_t -{ - EXPRESSION = 0, - FUNCTION, - TABLE_EXPRESSION, -}; - -const char * toString(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "EXPRESSION"; - case IdentifierLookupContext::FUNCTION: return "FUNCTION"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "TABLE_EXPRESSION"; - } -} - -const char * toStringLowercase(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "expression"; - case IdentifierLookupContext::FUNCTION: return "function"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "table expression"; - } -} - -/** Structure that represent identifier lookup during query analysis. - * Lookup can be in query expression, function, table context. - */ -struct IdentifierLookup -{ - Identifier identifier; - IdentifierLookupContext lookup_context; - - bool isExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::EXPRESSION; - } - - bool isFunctionLookup() const - { - return lookup_context == IdentifierLookupContext::FUNCTION; - } - - bool isTableExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::TABLE_EXPRESSION; - } - - String dump() const - { - return identifier.getFullName() + ' ' + toString(lookup_context); - } -}; - -inline bool operator==(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return lhs.identifier.getFullName() == rhs.identifier.getFullName() && lhs.lookup_context == rhs.lookup_context; -} - -[[maybe_unused]] inline bool operator!=(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return !(lhs == rhs); -} - -struct IdentifierLookupHash -{ - size_t operator()(const IdentifierLookup & identifier_lookup) const - { - return std::hash()(identifier_lookup.identifier.getFullName()) ^ static_cast(identifier_lookup.lookup_context); - } -}; - -enum class IdentifierResolvePlace : UInt8 -{ - NONE = 0, - EXPRESSION_ARGUMENTS, - ALIASES, - JOIN_TREE, - /// Valid only for table lookup - CTE, - /// Valid only for table lookup - DATABASE_CATALOG -}; - -const char * toString(IdentifierResolvePlace resolved_identifier_place) -{ - switch (resolved_identifier_place) - { - case IdentifierResolvePlace::NONE: return "NONE"; - case IdentifierResolvePlace::EXPRESSION_ARGUMENTS: return "EXPRESSION_ARGUMENTS"; - case IdentifierResolvePlace::ALIASES: return "ALIASES"; - case IdentifierResolvePlace::JOIN_TREE: return "JOIN_TREE"; - case IdentifierResolvePlace::CTE: return "CTE"; - case IdentifierResolvePlace::DATABASE_CATALOG: return "DATABASE_CATALOG"; - } -} - -struct IdentifierResolveResult -{ - IdentifierResolveResult() = default; - - QueryTreeNodePtr resolved_identifier; - IdentifierResolvePlace resolve_place = IdentifierResolvePlace::NONE; - bool resolved_from_parent_scopes = false; - - [[maybe_unused]] bool isResolved() const - { - return resolve_place != IdentifierResolvePlace::NONE; - } - - [[maybe_unused]] bool isResolvedFromParentScopes() const - { - return resolved_from_parent_scopes; - } - - [[maybe_unused]] bool isResolvedFromExpressionArguments() const - { - return resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - } - - [[maybe_unused]] bool isResolvedFromAliases() const - { - return resolve_place == IdentifierResolvePlace::ALIASES; - } - - [[maybe_unused]] bool isResolvedFromJoinTree() const - { - return resolve_place == IdentifierResolvePlace::JOIN_TREE; - } - - [[maybe_unused]] bool isResolvedFromCTEs() const - { - return resolve_place == IdentifierResolvePlace::CTE; - } - - void dump(WriteBuffer & buffer) const - { - if (!resolved_identifier) - { - buffer << "unresolved"; - return; - } - - buffer << resolved_identifier->formatASTForErrorMessage() << " place " << toString(resolve_place) << " resolved from parent scopes " << resolved_from_parent_scopes; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -struct IdentifierResolveState -{ - IdentifierResolveResult resolve_result; - bool cyclic_identifier_resolve = false; -}; - -struct IdentifierResolveSettings -{ - /// Allow to check join tree during identifier resolution - bool allow_to_check_join_tree = true; - - /// Allow to check CTEs during table identifier resolution - bool allow_to_check_cte = true; - - /// Allow to check parent scopes during identifier resolution - bool allow_to_check_parent_scopes = true; - - /// Allow to check database catalog during table identifier resolution - bool allow_to_check_database_catalog = true; - - /// Allow to resolve subquery during identifier resolution - bool allow_to_resolve_subquery_during_identifier_resolution = true; -}; - -struct StringTransparentHash -{ - using is_transparent = void; - using hash = std::hash; - - [[maybe_unused]] size_t operator()(const char * data) const - { - return hash()(data); - } - - size_t operator()(std::string_view data) const - { - return hash()(data); - } - - size_t operator()(const std::string & data) const - { - return hash()(data); - } -}; - -using ColumnNameToColumnNodeMap = std::unordered_map>; - -struct TableExpressionData -{ - std::string table_expression_name; - std::string table_expression_description; - std::string database_name; - std::string table_name; - bool should_qualify_columns = true; - NamesAndTypes column_names_and_types; - ColumnNameToColumnNodeMap column_name_to_column_node; - std::unordered_set subcolumn_names; /// Subset columns that are subcolumns of other columns - std::unordered_set> column_identifier_first_parts; - - bool hasFullIdentifierName(IdentifierView identifier_view) const - { - return column_name_to_column_node.contains(identifier_view.getFullName()); - } - - bool canBindIdentifier(IdentifierView identifier_view) const - { - return column_identifier_first_parts.contains(identifier_view.at(0)); - } - - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Table expression name " << table_expression_name; - - if (!table_expression_description.empty()) - buffer << " table expression description " << table_expression_description; - - if (!database_name.empty()) - buffer << " database name " << database_name; - - if (!table_name.empty()) - buffer << " table name " << table_name; - - buffer << " should qualify columns " << should_qualify_columns; - buffer << " columns size " << column_name_to_column_node.size() << '\n'; - - for (const auto & [column_name, column_node] : column_name_to_column_node) - buffer << "Column name " << column_name << " column node " << column_node->dumpTree() << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -class ExpressionsStack -{ -public: - void push(const QueryTreeNodePtr & node) - { - if (node->hasAlias()) - { - const auto & node_alias = node->getAlias(); - alias_name_to_expressions[node_alias].push_back(node); - } - - if (const auto * function = node->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - ++aggregate_functions_counter; - } - - expressions.emplace_back(node); - } - - void pop() - { - const auto & top_expression = expressions.back(); - const auto & top_expression_alias = top_expression->getAlias(); - - if (!top_expression_alias.empty()) - { - auto it = alias_name_to_expressions.find(top_expression_alias); - auto & alias_expressions = it->second; - alias_expressions.pop_back(); - - if (alias_expressions.empty()) - alias_name_to_expressions.erase(it); - } - - if (const auto * function = top_expression->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - --aggregate_functions_counter; - } - - expressions.pop_back(); - } - - [[maybe_unused]] const QueryTreeNodePtr & getRoot() const - { - return expressions.front(); - } - - const QueryTreeNodePtr & getTop() const - { - return expressions.back(); - } - - [[maybe_unused]] bool hasExpressionWithAlias(const std::string & alias) const - { - return alias_name_to_expressions.contains(alias); - } - - bool hasAggregateFunction() const - { - return aggregate_functions_counter > 0; - } - - QueryTreeNodePtr getExpressionWithAlias(const std::string & alias) const - { - auto expression_it = alias_name_to_expressions.find(alias); - if (expression_it == alias_name_to_expressions.end()) - return {}; - - return expression_it->second.front(); - } - - [[maybe_unused]] size_t size() const - { - return expressions.size(); - } - - bool empty() const - { - return expressions.empty(); - } - - void dump(WriteBuffer & buffer) const - { - buffer << expressions.size() << '\n'; - - for (const auto & expression : expressions) - { - buffer << "Expression "; - buffer << expression->formatASTForErrorMessage(); - - const auto & alias = expression->getAlias(); - if (!alias.empty()) - buffer << " alias " << alias; - - buffer << '\n'; - } - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } - -private: - QueryTreeNodes expressions; - size_t aggregate_functions_counter = 0; - std::unordered_map alias_name_to_expressions; -}; - -struct ScopeAliases -{ - /// Alias name to query expression node - std::unordered_map alias_name_to_expression_node_before_group_by; - std::unordered_map alias_name_to_expression_node_after_group_by; - - std::unordered_map * alias_name_to_expression_node = nullptr; - - /// Alias name to lambda node - std::unordered_map alias_name_to_lambda_node; - - /// Alias name to table expression node - std::unordered_map alias_name_to_table_expression_node; - - /// Expressions like `x as y` where we can't say whether it's a function, expression or table. - std::unordered_map transitive_aliases; - - /// Nodes with duplicated aliases - std::unordered_set nodes_with_duplicated_aliases; - std::vector cloned_nodes_with_duplicated_aliases; - - /// Names which are aliases from ARRAY JOIN. - /// This is needed to properly qualify columns from matchers and avoid name collision. - std::unordered_set array_join_aliases; - - std::unordered_map & getAliasMap(IdentifierLookupContext lookup_context) - { - switch (lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return *alias_name_to_expression_node; - case IdentifierLookupContext::FUNCTION: return alias_name_to_lambda_node; - case IdentifierLookupContext::TABLE_EXPRESSION: return alias_name_to_table_expression_node; - } - } - - enum class FindOption - { - FIRST_NAME, - FULL_NAME, - }; - - const std::string & getKey(const Identifier & identifier, FindOption find_option) - { - switch (find_option) - { - case FindOption::FIRST_NAME: return identifier.front(); - case FindOption::FULL_NAME: return identifier.getFullName(); - } - } - - QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) - { - auto & alias_map = getAliasMap(lookup.lookup_context); - const std::string * key = &getKey(lookup.identifier, find_option); - - auto it = alias_map.find(*key); - - if (it != alias_map.end()) - return &it->second; - - if (lookup.lookup_context == IdentifierLookupContext::TABLE_EXPRESSION) - return {}; - - while (it == alias_map.end()) - { - auto jt = transitive_aliases.find(*key); - if (jt == transitive_aliases.end()) - return {}; - - key = &(getKey(jt->second, find_option)); - it = alias_map.find(*key); - } - - return &it->second; - } - - const QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) const - { - return const_cast(this)->find(lookup, find_option); - } -}; - - /** Projection names is name of query tree node that is used in projection part of query node. * Example: SELECT id FROM test_table; * `id` is projection name of column node @@ -785,37 +128,7 @@ constexpr auto PROJECTION_NAME_PLACEHOLDER = "__projection_name_placeholder"; struct IdentifierResolveScope { /// Construct identifier resolve scope using scope node, and parent scope - IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) - : scope_node(std::move(scope_node_)) - , parent_scope(parent_scope_) - { - if (parent_scope) - { - subquery_depth = parent_scope->subquery_depth; - context = parent_scope->context; - projection_mask_map = parent_scope->projection_mask_map; - } - else - projection_mask_map = std::make_shared>(); - - if (auto * union_node = scope_node->as()) - { - context = union_node->getContext(); - } - else if (auto * query_node = scope_node->as()) - { - context = query_node->getContext(); - group_by_use_nulls = context->getSettingsRef().group_by_use_nulls && - (query_node->isGroupByWithGroupingSets() || query_node->isGroupByWithRollup() || query_node->isGroupByWithCube()); - } - - if (context) - join_use_nulls = context->getSettingsRef().join_use_nulls; - else if (parent_scope) - join_use_nulls = parent_scope->join_use_nulls; - - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } + IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_); QueryTreeNodePtr scope_node; @@ -850,7 +163,7 @@ struct IdentifierResolveScope std::unordered_set non_cached_identifier_lookups_during_expression_resolve; /// Table expression node to data - std::unordered_map table_expression_node_to_data; + std::unordered_map table_expression_node_to_data; QueryTreeNodePtrWithHashIgnoreTypesSet nullable_group_by_keys; /// Here we count the number of nullable GROUP BY keys we met resolving expression. @@ -897,7583 +210,22 @@ struct IdentifierResolveScope std::map functions_cache; - [[maybe_unused]] const IdentifierResolveScope * getNearestQueryScope() const - { - const IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; + [[maybe_unused]] const IdentifierResolveScope * getNearestQueryScope() const; - scope_to_check = scope_to_check->parent_scope; - } + IdentifierResolveScope * getNearestQueryScope(); - return scope_to_check; - } + AnalysisTableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node); - IdentifierResolveScope * getNearestQueryScope() - { - IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; + const AnalysisTableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const; - scope_to_check = scope_to_check->parent_scope; - } + void pushExpressionNode(const QueryTreeNodePtr & node); - return scope_to_check; - } - - TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - const TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - void pushExpressionNode(const QueryTreeNodePtr & node) - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.push(node); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - void popExpressionNode() - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.pop(); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_after_group_by; - } + void popExpressionNode(); /// Dump identifier resolve scope - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Scope node " << scope_node->formatASTForErrorMessage() << '\n'; - buffer << "Identifier lookup to resolve state " << identifier_lookup_to_resolve_state.size() << '\n'; - for (const auto & [identifier, state] : identifier_lookup_to_resolve_state) - { - buffer << "Identifier " << identifier.dump() << " resolve result "; - state.resolve_result.dump(buffer); - buffer << '\n'; - } + [[maybe_unused]] void dump(WriteBuffer & buffer) const; - buffer << "Expression argument name to node " << expression_argument_name_to_node.size() << '\n'; - for (const auto & [alias_name, node] : expression_argument_name_to_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to expression node table size " << aliases.alias_name_to_expression_node->size() << '\n'; - for (const auto & [alias_name, node] : *aliases.alias_name_to_expression_node) - buffer << "Alias name " << alias_name << " expression node " << node->dumpTree() << '\n'; - - buffer << "Alias name to function node table size " << aliases.alias_name_to_lambda_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_lambda_node) - buffer << "Alias name " << alias_name << " lambda node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to table expression node table size " << aliases.alias_name_to_table_expression_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_table_expression_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "CTE name to query node table size " << cte_name_to_query_node.size() << '\n'; - for (const auto & [cte_name, node] : cte_name_to_query_node) - buffer << "CTE name " << cte_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "WINDOW name to window node table size " << window_name_to_window_node.size() << '\n'; - for (const auto & [window_name, node] : window_name_to_window_node) - buffer << "CTE name " << window_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Nodes with duplicated aliases size " << aliases.nodes_with_duplicated_aliases.size() << '\n'; - for (const auto & node : aliases.nodes_with_duplicated_aliases) - buffer << "Alias name " << node->getAlias() << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Expression resolve process stack " << '\n'; - expressions_in_resolve_process_stack.dump(buffer); - - buffer << "Table expressions in resolve process size " << table_expressions_in_resolve_process.size() << '\n'; - for (const auto & node : table_expressions_in_resolve_process) - buffer << "Table expression " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Non cached identifier lookups during expression resolve " << non_cached_identifier_lookups_during_expression_resolve.size() << '\n'; - for (const auto & identifier_lookup : non_cached_identifier_lookups_during_expression_resolve) - buffer << "Identifier lookup " << identifier_lookup.dump() << '\n'; - - buffer << "Table expression node to data " << table_expression_node_to_data.size() << '\n'; - for (const auto & [table_expression_node, table_expression_data] : table_expression_node_to_data) - buffer << "Table expression node " << table_expression_node->formatASTForErrorMessage() << " data " << table_expression_data.dump() << '\n'; - - buffer << "Use identifier lookup to result cache " << use_identifier_lookup_to_result_cache << '\n'; - buffer << "Subquery depth " << subquery_depth << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } + [[maybe_unused]] String dump() const; }; - -/** Visitor that extracts expression and function aliases from node and initialize scope tables with it. - * Does not go into child lambdas and queries. - * - * Important: - * Identifier nodes with aliases are added both in alias to expression and alias to function map. - * - * These is necessary because identifier with alias can give alias name to any query tree node. - * - * Example: - * WITH (x -> x + 1) AS id, id AS value SELECT value(1); - * In this example id as value is identifier node that has alias, during scope initialization we cannot derive - * that id is actually lambda or expression. - * - * There are no easy solution here, without trying to make full featured expression resolution at this stage. - * Example: - * WITH (x -> x + 1) AS id, id AS id_1, id_1 AS id_2 SELECT id_2(1); - * Example: SELECT a, b AS a, b AS c, 1 AS c; - * - * It is client responsibility after resolving identifier node with alias, make following actions: - * 1. If identifier node was resolved in function scope, remove alias from scope expression map. - * 2. If identifier node was resolved in expression scope, remove alias from scope function map. - * - * That way we separate alias map initialization and expressions resolution. - */ -class QueryExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit QueryExpressionsAliasVisitor(ScopeAliases & aliases_) - : aliases(aliases_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node, false /*is_lambda_node*/); - } - - bool needChildVisit(const QueryTreeNodePtr &, const QueryTreeNodePtr & child) - { - if (auto * lambda_node = child->as()) - { - updateAliasesIfNeeded(child, true /*is_lambda_node*/); - return false; - } - else if (auto * query_tree_node = child->as()) - { - if (query_tree_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - else if (auto * union_node = child->as()) - { - if (union_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - - return true; - } -private: - void addDuplicatingAlias(const QueryTreeNodePtr & node) - { - aliases.nodes_with_duplicated_aliases.emplace(node); - auto cloned_node = node->clone(); - aliases.cloned_nodes_with_duplicated_aliases.emplace_back(cloned_node); - aliases.nodes_with_duplicated_aliases.emplace(cloned_node); - } - - void updateAliasesIfNeeded(const QueryTreeNodePtr & node, bool is_lambda_node) - { - if (!node->hasAlias()) - return; - - // We should not resolve expressions to WindowNode - if (node->getNodeType() == QueryTreeNodeType::WINDOW) - return; - - const auto & alias = node->getAlias(); - - if (is_lambda_node) - { - if (aliases.alias_name_to_expression_node->contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_lambda_node.insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - return; - } - - if (aliases.alias_name_to_lambda_node.contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_expression_node->insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - /// If node is identifier put it into transitive aliases map. - if (const auto * identifier = typeid_cast(node.get())) - aliases.transitive_aliases.insert(std::make_pair(alias, identifier->getIdentifier())); - } - - ScopeAliases & aliases; -}; - -class TableExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit TableExpressionsAliasVisitor(IdentifierResolveScope & scope_) - : scope(scope_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node); - } - - static bool needChildVisit(const QueryTreeNodePtr & node, const QueryTreeNodePtr & child) - { - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::ARRAY_JOIN: - { - const auto & array_join_node = node->as(); - return child.get() == array_join_node.getTableExpression().get(); - } - case QueryTreeNodeType::JOIN: - { - const auto & join_node = node->as(); - return child.get() == join_node.getLeftTableExpression().get() || child.get() == join_node.getRightTableExpression().get(); - } - default: - { - break; - } - } - - return false; - } - -private: - void updateAliasesIfNeeded(const QueryTreeNodePtr & node) - { - if (!node->hasAlias()) - return; - - const auto & node_alias = node->getAlias(); - auto [_, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(node_alias, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple table expressions with same alias {}. In scope {}", - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - IdentifierResolveScope & scope; -}; - -class QueryAnalyzer -{ -public: - explicit QueryAnalyzer(bool only_analyze_) : only_analyze(only_analyze_) {} - - void resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context) - { - IdentifierResolveScope scope(node, nullptr /*parent_scope*/); - - if (!scope.context) - scope.context = context; - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::QUERY: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For query analysis table expression must be empty"); - - resolveQuery(node, scope); - break; - } - case QueryTreeNodeType::UNION: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For union analysis table expression must be empty"); - - resolveUnion(node, scope); - break; - } - case QueryTreeNodeType::IDENTIFIER: - [[fallthrough]]; - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - [[fallthrough]]; - case QueryTreeNodeType::FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::LIST: - { - if (table_expression) - { - scope.expression_join_tree_node = table_expression; - validateTableExpressionModifiers(scope.expression_join_tree_node, scope); - initializeTableExpressionData(scope.expression_join_tree_node, scope); - } - - if (node_type == QueryTreeNodeType::LIST) - resolveExpressionNodeList(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - else - resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - QueryExpressionsAliasVisitor expressions_alias_visitor(scope.aliases); - resolveTableFunction(node, scope, expressions_alias_visitor, false /*nested_table_function*/); - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Node {} with type {} is not supported by query analyzer. " - "Supported nodes are query, union, identifier, constant, column, function, list.", - node->formatASTForErrorMessage(), - node->getNodeTypeName()); - } - } - } - -private: - /// Utility functions - - static bool isExpressionNodeType(QueryTreeNodeType node_type); - - static bool isFunctionExpressionNodeType(QueryTreeNodeType node_type); - - static bool isSubqueryNodeType(QueryTreeNodeType node_type); - - static bool isTableExpressionNodeType(QueryTreeNodeType node_type); - - static DataTypePtr getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node); - - static ProjectionName calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, - const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names); - - static ProjectionName calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name); - - static ProjectionName calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, - const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, - const ProjectionName & fill_to_expression_projection_name, - const ProjectionName & fill_step_expression_projection_name); - - static void collectCompoundExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result); - - static void collectTableExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result); - - static void collectScopeValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static void collectScopeWithParentScopesValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static std::vector collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers); - - static QueryTreeNodePtr wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path); - - QueryTreeNodePtr tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context); - - void evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & query_tree_node, IdentifierResolveScope & scope); - - static void mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope); - - void replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope); - - static void convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope); - - static void validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope); - - static std::pair recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into); - - static void expandGroupByAll(QueryNode & query_tree_node_typed); - - void expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings); - - static std::string - rewriteAggregateFunctionNameIfNeeded(const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context); - - static std::optional getColumnSideFromJoinTree(const QueryTreeNodePtr & resolved_identifier, const JoinNode & join_node) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - return {}; - - if (resolved_identifier->getNodeType() == QueryTreeNodeType::FUNCTION) - { - const auto & resolved_function = resolved_identifier->as(); - - const auto & argument_nodes = resolved_function.getArguments().getNodes(); - - std::optional result; - for (const auto & argument_node : argument_nodes) - { - auto table_side = getColumnSideFromJoinTree(argument_node, join_node); - if (table_side && result && *table_side != *result) - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Ambiguous identifier {}. In scope {}", - resolved_identifier->formatASTForErrorMessage(), - join_node.formatASTForErrorMessage()); - } - result = table_side; - } - return result; - } - - const auto * column_src = resolved_identifier->as().getColumnSource().get(); - - if (join_node.getLeftTableExpression().get() == column_src) - return JoinTableSide::Left; - if (join_node.getRightTableExpression().get() == column_src) - return JoinTableSide::Right; - return {}; - } - - static QueryTreeNodePtr convertJoinedColumnTypeToNullIfNeeded( - const QueryTreeNodePtr & resolved_identifier, - const JoinKind & join_kind, - std::optional resolved_side, - IdentifierResolveScope & scope) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && - JoinCommon::canBecomeNullable(resolved_identifier->getResultType()) && - (isFull(join_kind) || - (isLeft(join_kind) && resolved_side && *resolved_side == JoinTableSide::Right) || - (isRight(join_kind) && resolved_side && *resolved_side == JoinTableSide::Left))) - { - auto nullable_resolved_identifier = resolved_identifier->clone(); - auto & resolved_column = nullable_resolved_identifier->as(); - auto new_result_type = makeNullableOrLowCardinalityNullable(resolved_column.getColumnType()); - resolved_column.setColumnType(new_result_type); - if (resolved_column.hasExpression()) - { - auto & resolved_expression = resolved_column.getExpression(); - if (!resolved_expression->getResultType()->equals(*new_result_type)) - resolved_expression = buildCastFunction(resolved_expression, new_result_type, scope.context, true); - } - if (!nullable_resolved_identifier->isEqual(*resolved_identifier)) - scope.join_columns_with_changed_types[nullable_resolved_identifier] = resolved_identifier; - return nullable_resolved_identifier; - } - return nullptr; - } - - /// Resolve identifier functions - - static QueryTreeNodePtr tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context); - - QueryTreeNodePtr tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found = false); - - QueryTreeNodePtr tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings); - - QueryTreeNodePtr tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings = {}); - - QueryTreeNodePtr tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found = false); - - /// Resolve query tree nodes functions - - void qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static GetColumnsOptions buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context); - - using QueryTreeNodesWithNames = std::vector>; - - QueryTreeNodesWithNames getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope); - - void updateMatchedColumnsFromJoinUsing(QueryTreeNodesWithNames & result_matched_column_nodes_with_names, const QueryTreeNodePtr & source_table_expression, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionNames resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionName resolveWindow(QueryTreeNodePtr & window_node, IdentifierResolveScope & scope); - - ProjectionNames resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope); - - ProjectionNames resolveFunction(QueryTreeNodePtr & function_node, IdentifierResolveScope & scope); - - ProjectionNames resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias = false); - - ProjectionNames resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression); - - ProjectionNames resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope); - - void resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope); - - void resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope); - - void resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope); - - NamesAndTypes resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope); - - void initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope); - - void initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - void resolveTableFunction(QueryTreeNodePtr & table_function_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, bool nested_table_function); - - void resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope); - - void resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope); - - /// Lambdas that are currently in resolve process - std::unordered_set lambdas_in_resolve_process; - - /// CTEs that are currently in resolve process - std::unordered_set ctes_in_resolve_process; - - /// Function name to user defined lambda map - std::unordered_map function_name_to_user_defined_lambda; - - /// Array join expressions counter - size_t array_join_expressions_counter = 1; - - /// Subquery counter - size_t subquery_counter = 1; - - /// Global expression node to projection name map - std::unordered_map node_to_projection_name; - - /// Global resolve expression node to projection names map - std::unordered_map resolved_expressions; - - /// Global resolve expression node to tree size - std::unordered_map node_to_tree_size; - - /// Global scalar subquery to scalar value map - std::unordered_map scalar_subquery_to_scalar_value_local; - std::unordered_map scalar_subquery_to_scalar_value_global; - - const bool only_analyze; -}; - -/// Utility functions implementation - - -bool QueryAnalyzer::isExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::CONSTANT || node_type == QueryTreeNodeType::COLUMN || node_type == QueryTreeNodeType::FUNCTION - || node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isFunctionExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::LAMBDA; -} - -bool QueryAnalyzer::isSubqueryNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isTableExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::TABLE || node_type == QueryTreeNodeType::TABLE_FUNCTION || - isSubqueryNodeType(node_type); -} - -DataTypePtr QueryAnalyzer::getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node) -{ - auto node_type = query_tree_node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - { - return query_tree_node->getResultType(); - } - case QueryTreeNodeType::FUNCTION: - { - auto & function_node = query_tree_node->as(); - if (function_node.isResolved()) - return function_node.getResultType(); - break; - } - default: - { - break; - } - } - - return nullptr; -} - -ProjectionName QueryAnalyzer::calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names) -{ - const auto & function_node_typed = function_node->as(); - const auto & function_node_name = function_node_typed.getFunctionName(); - - bool is_array_function = function_node_name == "array"; - bool is_tuple_function = function_node_name == "tuple"; - - WriteBufferFromOwnString buffer; - - if (!is_array_function && !is_tuple_function) - buffer << function_node_name; - - if (!parameters_projection_names.empty()) - { - buffer << '('; - - size_t function_parameters_projection_names_size = parameters_projection_names.size(); - for (size_t i = 0; i < function_parameters_projection_names_size; ++i) - { - buffer << parameters_projection_names[i]; - - if (i + 1 != function_parameters_projection_names_size) - buffer << ", "; - } - - buffer << ')'; - } - - char open_bracket = '('; - char close_bracket = ')'; - - if (is_array_function) - { - open_bracket = '['; - close_bracket = ']'; - } - - buffer << open_bracket; - - size_t function_arguments_projection_names_size = arguments_projection_names.size(); - for (size_t i = 0; i < function_arguments_projection_names_size; ++i) - { - buffer << arguments_projection_names[i]; - - if (i + 1 != function_arguments_projection_names_size) - buffer << ", "; - } - - buffer << close_bracket; - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name) -{ - const auto & window_node_typed = window_node->as(); - const auto & window_frame = window_node_typed.getWindowFrame(); - - bool parent_window_node_has_partition_by = false; - bool parent_window_node_has_order_by = false; - - if (parent_window_node) - { - const auto & parent_window_node_typed = parent_window_node->as(); - parent_window_node_has_partition_by = parent_window_node_typed.hasPartitionBy(); - parent_window_node_has_order_by = parent_window_node_typed.hasOrderBy(); - } - - WriteBufferFromOwnString buffer; - - if (!parent_window_name.empty()) - buffer << parent_window_name; - - if (!partition_by_projection_names.empty() && !parent_window_node_has_partition_by) - { - if (!parent_window_name.empty()) - buffer << ' '; - - buffer << "PARTITION BY "; - - size_t partition_by_projection_names_size = partition_by_projection_names.size(); - for (size_t i = 0; i < partition_by_projection_names_size; ++i) - { - buffer << partition_by_projection_names[i]; - if (i + 1 != partition_by_projection_names_size) - buffer << ", "; - } - } - - if (!order_by_projection_names.empty() && !parent_window_node_has_order_by) - { - if (!partition_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << "ORDER BY "; - - size_t order_by_projection_names_size = order_by_projection_names.size(); - for (size_t i = 0; i < order_by_projection_names_size; ++i) - { - buffer << order_by_projection_names[i]; - if (i + 1 != order_by_projection_names_size) - buffer << ", "; - } - } - - if (!window_frame.is_default) - { - if (!partition_by_projection_names.empty() || !order_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << window_frame.type << " BETWEEN "; - if (window_frame.begin_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.begin_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_begin_offset_projection_name; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - - buffer << " AND "; - - if (window_frame.end_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.end_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_end_offset_projection_name; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - } - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, const ProjectionName & fill_to_expression_projection_name, const ProjectionName & fill_step_expression_projection_name) -{ - auto & sort_node_typed = sort_column_node->as(); - - WriteBufferFromOwnString sort_column_projection_name_buffer; - sort_column_projection_name_buffer << sort_expression_projection_name; - - auto sort_direction = sort_node_typed.getSortDirection(); - sort_column_projection_name_buffer << (sort_direction == SortDirection::ASCENDING ? " ASC" : " DESC"); - - auto nulls_sort_direction = sort_node_typed.getNullsSortDirection(); - - if (nulls_sort_direction) - sort_column_projection_name_buffer << " NULLS " << (nulls_sort_direction == sort_direction ? "LAST" : "FIRST"); - - if (auto collator = sort_node_typed.getCollator()) - sort_column_projection_name_buffer << " COLLATE " << collator->getLocale(); - - if (sort_node_typed.withFill()) - { - sort_column_projection_name_buffer << " WITH FILL"; - - if (sort_node_typed.hasFillFrom()) - sort_column_projection_name_buffer << " FROM " << fill_from_expression_projection_name; - - if (sort_node_typed.hasFillTo()) - sort_column_projection_name_buffer << " TO " << fill_to_expression_projection_name; - - if (sort_node_typed.hasFillStep()) - sort_column_projection_name_buffer << " STEP " << fill_step_expression_projection_name; - } - - return sort_column_projection_name_buffer.str(); -} - -/// Get valid identifiers for typo correction from compound expression -void QueryAnalyzer::collectCompoundExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result) -{ - IDataType::forEachSubcolumn([&](const auto &, const auto & name, const auto &) - { - Identifier subcolumn_indentifier(name); - size_t new_identifier_size = valid_identifier_prefix.getPartsSize() + subcolumn_indentifier.getPartsSize(); - - if (new_identifier_size == unresolved_identifier.getPartsSize()) - { - auto new_identifier = valid_identifier_prefix; - for (const auto & part : subcolumn_indentifier) - new_identifier.push_back(part); - - valid_identifiers_result.insert(std::move(new_identifier)); - } - }, ISerialization::SubstreamData(compound_expression_type->getDefaultSerialization())); -} - -/// Get valid identifiers for typo correction from table expression -void QueryAnalyzer::collectTableExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result) -{ - for (const auto & [column_name, column_node] : table_expression_data.column_name_to_column_node) - { - Identifier column_identifier(column_name); - if (unresolved_identifier.getPartsSize() == column_identifier.getPartsSize()) - valid_identifiers_result.insert(column_identifier); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier, - valid_identifiers_result); - - if (table_expression->hasAlias()) - { - Identifier column_identifier_with_alias({table_expression->getAlias()}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_alias.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_alias.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_alias); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_alias, - valid_identifiers_result); - } - - if (!table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name({table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name, - valid_identifiers_result); - } - - if (!table_expression_data.database_name.empty() && !table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name_and_database_name({table_expression_data.database_name, table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name_and_database_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name_and_database_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name_and_database_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name_and_database_name, - valid_identifiers_result); - } - } -} - -/// Get valid identifiers for typo correction from scope without looking at parent scopes -void QueryAnalyzer::collectScopeValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - bool identifier_is_short = unresolved_identifier.isShort(); - bool identifier_is_compound = unresolved_identifier.isCompound(); - - if (allow_expression_identifiers) - { - for (const auto & [name, expression] : *scope.aliases.alias_name_to_expression_node) - { - assert(expression); - auto expression_identifier = Identifier(name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - - for (const auto & [table_expression, table_expression_data] : scope.table_expression_node_to_data) - { - collectTableExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - table_expression, - table_expression_data, - valid_identifiers_result); - } - } - - if (identifier_is_short) - { - if (allow_function_identifiers) - { - for (const auto & [name, _] : *scope.aliases.alias_name_to_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - - if (allow_table_expression_identifiers) - { - for (const auto & [name, _] : scope.aliases.alias_name_to_table_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - } - - for (const auto & [argument_name, expression] : scope.expression_argument_name_to_node) - { - assert(expression); - auto expression_node_type = expression->getNodeType(); - - if (allow_expression_identifiers && isExpressionNodeType(expression_node_type)) - { - auto expression_identifier = Identifier(argument_name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - else if (identifier_is_short && allow_function_identifiers && isFunctionExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - else if (allow_table_expression_identifiers && isTableExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - } -} - -void QueryAnalyzer::collectScopeWithParentScopesValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - const IdentifierResolveScope * current_scope = &scope; - - while (current_scope) - { - collectScopeValidIdentifiersForTypoCorrection(unresolved_identifier, - *current_scope, - allow_expression_identifiers, - allow_function_identifiers, - allow_table_expression_identifiers, - valid_identifiers_result); - - current_scope = current_scope->parent_scope; - } -} - -std::vector QueryAnalyzer::collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers) -{ - std::vector prompting_strings; - prompting_strings.reserve(valid_identifiers.size()); - - for (const auto & valid_identifier : valid_identifiers) - prompting_strings.push_back(valid_identifier.getFullName()); - - return NamePrompter<1>::getHints(unresolved_identifier.getFullName(), prompting_strings); -} - -/** Wrap expression node in tuple element function calls for nested paths. - * Example: Expression node: compound_expression. Nested path: nested_path_1.nested_path_2. - * Result: tupleElement(tupleElement(compound_expression, 'nested_path_1'), 'nested_path_2'). - */ -QueryTreeNodePtr QueryAnalyzer::wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path) -{ - size_t nested_path_parts_size = nested_path.getPartsSize(); - for (size_t i = 0; i < nested_path_parts_size; ++i) - { - const auto & nested_path_part = nested_path[i]; - auto tuple_element_function = std::make_shared("tupleElement"); - - auto & tuple_element_function_arguments_nodes = tuple_element_function->getArguments().getNodes(); - tuple_element_function_arguments_nodes.reserve(2); - tuple_element_function_arguments_nodes.push_back(expression_node); - tuple_element_function_arguments_nodes.push_back(std::make_shared(nested_path_part)); - - expression_node = std::move(tuple_element_function); - } - - return expression_node; -} - -/** Try to get lambda node from sql user defined functions if sql user defined function with function name exists. - * Returns lambda node if function exists, nullptr otherwise. - */ -QueryTreeNodePtr QueryAnalyzer::tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context) -{ - auto user_defined_function = UserDefinedSQLFunctionFactory::instance().tryGet(function_name); - if (!user_defined_function) - return {}; - - auto it = function_name_to_user_defined_lambda.find(function_name); - if (it != function_name_to_user_defined_lambda.end()) - return it->second; - - const auto & create_function_query = user_defined_function->as(); - auto result_node = buildQueryTree(create_function_query->function_core, context); - if (result_node->getNodeType() != QueryTreeNodeType::LAMBDA) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "SQL user defined function {} must represent lambda expression. Actual {}", - function_name, - create_function_query->function_core->formatForErrorMessage()); - - function_name_to_user_defined_lambda.emplace(function_name, result_node); - - return result_node; -} - -bool subtreeHasViewSource(const IQueryTreeNode * node, const Context & context) -{ - if (!node) - return false; - - if (const auto * table_node = node->as()) - { - if (table_node->getStorageID().getFullNameNotQuoted() == context.getViewSource()->getStorageID().getFullNameNotQuoted()) - return true; - } - - for (const auto & child : node->getChildren()) - if (subtreeHasViewSource(child.get(), context)) - return true; - - return false; -} - -/// Evaluate scalar subquery and perform constant folding if scalar subquery does not have constant value -void QueryAnalyzer::evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - auto * query_node = node->as(); - auto * union_node = node->as(); - if (!query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node must have query or union type. Actual {} {}", - node->getNodeTypeName(), - node->formatASTForErrorMessage()); - - auto & context = scope.context; - - Block scalar_block; - - auto node_without_alias = node->clone(); - node_without_alias->removeAlias(); - - QueryTreeNodePtrWithHash node_with_hash(node_without_alias); - auto str_hash = DB::toString(node_with_hash.hash); - - bool can_use_global_scalars = !only_analyze && !(context->getViewSource() && subtreeHasViewSource(node_without_alias.get(), *context)); - - auto & scalars_cache = can_use_global_scalars ? scalar_subquery_to_scalar_value_global : scalar_subquery_to_scalar_value_local; - - if (scalars_cache.contains(node_with_hash)) - { - if (can_use_global_scalars) - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - else - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesLocalCacheHit); - - scalar_block = scalars_cache.at(node_with_hash); - } - else if (context->hasQueryContext() && can_use_global_scalars && context->getQueryContext()->hasScalar(str_hash)) - { - scalar_block = context->getQueryContext()->getScalar(str_hash); - scalar_subquery_to_scalar_value_global.emplace(node_with_hash, scalar_block); - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - } - else - { - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesCacheMiss); - auto subquery_context = Context::createCopy(context); - - Settings subquery_settings = context->getSettings(); - subquery_settings.max_result_rows = 1; - subquery_settings.extremes = false; - subquery_context->setSettings(subquery_settings); - /// When execute `INSERT INTO t WITH ... SELECT ...`, it may lead to `Unknown columns` - /// exception with this settings enabled(https://github.com/ClickHouse/ClickHouse/issues/52494). - subquery_context->setSetting("use_structure_from_insertion_table_in_table_functions", false); - - auto options = SelectQueryOptions(QueryProcessingStage::Complete, scope.subquery_depth, true /*is_subquery*/); - options.only_analyze = only_analyze; - auto interpreter = std::make_unique(node->toAST(), subquery_context, subquery_context->getViewSource(), options); - - if (only_analyze) - { - /// If query is only analyzed, then constants are not correct. - scalar_block = interpreter->getSampleBlock(); - for (auto & column : scalar_block) - { - if (column.column->empty()) - { - auto mut_col = column.column->cloneEmpty(); - mut_col->insertDefault(); - column.column = std::move(mut_col); - } - } - } - else - { - auto io = interpreter->execute(); - PullingAsyncPipelineExecutor executor(io.pipeline); - io.pipeline.setProgressCallback(context->getProgressCallback()); - io.pipeline.setProcessListElement(context->getProcessListElement()); - - Block block; - - while (block.rows() == 0 && executor.pull(block)) - { - } - - if (block.rows() == 0) - { - auto types = interpreter->getSampleBlock().getDataTypes(); - if (types.size() != 1) - types = {std::make_shared(types)}; - - auto & type = types[0]; - if (!type->isNullable()) - { - if (!type->canBeInsideNullable()) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, - "Scalar subquery returned empty result of type {} which cannot be Nullable", - type->getName()); - - type = makeNullable(type); - } - - auto scalar_column = type->createColumn(); - scalar_column->insert(Null()); - scalar_block.insert({std::move(scalar_column), type, "null"}); - } - else - { - if (block.rows() != 1) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - Block tmp_block; - while (tmp_block.rows() == 0 && executor.pull(tmp_block)) - { - } - - if (tmp_block.rows() != 0) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - block = materializeBlock(block); - size_t columns = block.columns(); - - if (columns == 1) - { - auto & column = block.getByPosition(0); - /// Here we wrap type to nullable if we can. - /// It is needed cause if subquery return no rows, it's result will be Null. - /// In case of many columns, do not check it cause tuple can't be nullable. - if (!column.type->isNullable() && column.type->canBeInsideNullable()) - { - column.type = makeNullable(column.type); - column.column = makeNullable(column.column); - } - - scalar_block = block; - } - else - { - /** Make unique column names for tuple. - * - * Example: SELECT (SELECT 2 AS x, x) - */ - makeUniqueColumnNamesInBlock(block); - - scalar_block.insert({ - ColumnTuple::create(block.getColumns()), - std::make_shared(block.getDataTypes(), block.getNames()), - "tuple"}); - } - } - } - - scalars_cache.emplace(node_with_hash, scalar_block); - if (can_use_global_scalars && context->hasQueryContext()) - context->getQueryContext()->addScalar(str_hash, scalar_block); - } - - const auto & scalar_column_with_type = scalar_block.safeGetByPosition(0); - const auto & scalar_type = scalar_column_with_type.type; - - Field scalar_value; - scalar_column_with_type.column->get(0, scalar_value); - - const auto * scalar_type_name = scalar_block.safeGetByPosition(0).type->getFamilyName(); - static const std::set useless_literal_types = {"Array", "Tuple", "AggregateFunction", "Function", "Set", "LowCardinality"}; - auto * nearest_query_scope = scope.getNearestQueryScope(); - - /// Always convert to literals when there is no query context - if (!context->getSettingsRef().enable_scalar_subquery_optimization || - !useless_literal_types.contains(scalar_type_name) || - !context->hasQueryContext() || - !nearest_query_scope) - { - auto constant_value = std::make_shared(std::move(scalar_value), scalar_type); - auto constant_node = std::make_shared(constant_value, node); - - if (constant_node->getValue().isNull()) - { - node = buildCastFunction(constant_node, constant_node->getResultType(), context); - node = std::make_shared(std::move(constant_value), node); - } - else - node = std::move(constant_node); - - return; - } - - auto & nearest_query_scope_query_node = nearest_query_scope->scope_node->as(); - auto & mutable_context = nearest_query_scope_query_node.getMutableContext(); - - auto scalar_query_hash_string = DB::toString(node_with_hash.hash) + (only_analyze ? "_analyze" : ""); - - if (mutable_context->hasQueryContext()) - mutable_context->getQueryContext()->addScalar(scalar_query_hash_string, scalar_block); - - mutable_context->addScalar(scalar_query_hash_string, scalar_block); - - std::string get_scalar_function_name = "__getScalar"; - - auto scalar_query_hash_constant_value = std::make_shared(std::move(scalar_query_hash_string), std::make_shared()); - auto scalar_query_hash_constant_node = std::make_shared(std::move(scalar_query_hash_constant_value)); - - auto get_scalar_function_node = std::make_shared(get_scalar_function_name); - get_scalar_function_node->getArguments().getNodes().push_back(std::move(scalar_query_hash_constant_node)); - - auto get_scalar_function = FunctionFactory::instance().get(get_scalar_function_name, mutable_context); - get_scalar_function_node->resolveAsFunction(get_scalar_function->build(get_scalar_function_node->getArgumentColumns())); - - node = std::move(get_scalar_function_node); -} - -void QueryAnalyzer::mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope) -{ - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - - auto & parent_window_node_typed = parent_window_node->as(); - - /** If an existing_window_name is specified it must refer to an earlier - * entry in the WINDOW list; the new window copies its partitioning clause - * from that entry, as well as its ordering clause if any. In this case - * the new window cannot specify its own PARTITION BY clause, and it can - * specify ORDER BY only if the copied window does not have one. The new - * window always uses its own frame clause; the copied window must not - * specify a frame clause. - * https://www.postgresql.org/docs/current/sql-select.html - */ - if (window_node_typed.hasPartitionBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override PARTITION BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (window_node_typed.hasOrderBy() && parent_window_node_typed.hasOrderBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override a non-empty ORDER BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (!parent_window_node_typed.getWindowFrame().is_default) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parent window '{}' is not allowed to define a frame: while processing derived window definition '{}'. In scope {}", - parent_window_name, - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - window_node_typed.getPartitionByNode() = parent_window_node_typed.getPartitionBy().clone(); - - if (parent_window_node_typed.hasOrderBy()) - window_node_typed.getOrderByNode() = parent_window_node_typed.getOrderBy().clone(); -} - -/** Replace nodes in node list with positional arguments. - * - * Example: SELECT id, value FROM test_table GROUP BY 1, 2; - * Example: SELECT id, value FROM test_table ORDER BY 1, 2; - * Example: SELECT id, value FROM test_table LIMIT 5 BY 1, 2; - */ -void QueryAnalyzer::replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope) -{ - const auto & settings = scope.context->getSettingsRef(); - if (!settings.enable_positional_arguments || scope.context->getClientInfo().query_kind != ClientInfo::QueryKind::INITIAL_QUERY) - return; - - auto & node_list_typed = node_list->as(); - - for (auto & node : node_list_typed.getNodes()) - { - auto * node_to_replace = &node; - - if (auto * sort_node = node->as()) - node_to_replace = &sort_node->getExpression(); - - auto * constant_node = (*node_to_replace)->as(); - - if (!constant_node - || (constant_node->getValue().getType() != Field::Types::UInt64 - && constant_node->getValue().getType() != Field::Types::Int64)) - continue; - - UInt64 pos; - if (constant_node->getValue().getType() == Field::Types::UInt64) - { - pos = constant_node->getValue().get(); - } - else // Int64 - { - auto value = constant_node->getValue().get(); - if (value > 0) - pos = value; - else - { - if (value < -static_cast(projection_nodes.size())) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Negative positional argument number {} is out of bounds. Expected in range [-{}, -1]. In scope {}", - value, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - pos = projection_nodes.size() + value + 1; - } - } - - if (!pos || pos > projection_nodes.size()) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Positional argument number {} is out of bounds. Expected in range [1, {}]. In scope {}", - pos, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - - --pos; - *node_to_replace = projection_nodes[pos]->clone(); - if (auto it = resolved_expressions.find(projection_nodes[pos]); it != resolved_expressions.end()) - { - resolved_expressions[*node_to_replace] = it->second; - } - } -} - -void QueryAnalyzer::convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope) -{ - const auto * limit_offset_constant_node = expression_node->as(); - if (!limit_offset_constant_node || !isNativeNumber(removeNullable(limit_offset_constant_node->getResultType()))) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} expression must be constant with numeric type. Actual {}. In scope {}", - expression_description, - expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - Field converted_value = convertFieldToType(limit_offset_constant_node->getValue(), DataTypeUInt64()); - if (converted_value.isNull()) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} numeric constant expression is not representable as UInt64", - expression_description); - - auto constant_value = std::make_shared(std::move(converted_value), std::make_shared()); - auto result_constant_node = std::make_shared(std::move(constant_value)); - result_constant_node->getSourceExpression() = limit_offset_constant_node->getSourceExpression(); - - expression_node = std::move(result_constant_node); -} - -void QueryAnalyzer::validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unexpected table expression. Expected table, table function, query or union node. Table node: {}, scope node: {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (table_node || table_function_node) - { - auto table_expression_modifiers = table_node ? table_node->getTableExpressionModifiers() : table_function_node->getTableExpressionModifiers(); - - if (table_expression_modifiers.has_value()) - { - const auto & storage = table_node ? table_node->getStorage() : table_function_node->getStorage(); - if (table_expression_modifiers->hasFinal() && !storage->supportsFinal()) - throw Exception(ErrorCodes::ILLEGAL_FINAL, - "Storage {} doesn't support FINAL", - storage->getName()); - - if (table_expression_modifiers->hasSampleSizeRatio() && !storage->supportsSampling()) - throw Exception(ErrorCodes::SAMPLING_NOT_SUPPORTED, - "Storage {} doesn't support sampling", - storage->getStorageID().getFullNameNotQuoted()); - } - } -} - -void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - bool table_expression_has_alias = table_expression_node->hasAlias(); - if (table_expression_has_alias) - return; - - if (join_node->as().getKind() == JoinKind::Paste) - return; - - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - if ((query_node && !query_node->getCTEName().empty()) || (union_node && !union_node->getCTEName().empty())) - return; - - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || - table_expression_node_type == QueryTreeNodeType::QUERY || - table_expression_node_type == QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::ALIAS_REQUIRED, - "JOIN {} no alias for subquery or table function {}. " - "In scope {} (set joined_subquery_requires_alias = 0 to disable restriction)", - join_node->formatASTForErrorMessage(), - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); -} - -std::pair QueryAnalyzer::recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into) -{ - checkStackSize(); - - if (node->as()) - { - into.push_back(node); - return {false, 1}; - } - - auto * function = node->as(); - - if (!function) - return {false, 0}; - - if (function->isAggregateFunction()) - return {true, 0}; - - UInt64 pushed_children = 0; - bool has_aggregate = false; - - for (auto & child : function->getArguments().getNodes()) - { - auto [child_has_aggregate, child_pushed_children] = recursivelyCollectMaxOrdinaryExpressions(child, into); - has_aggregate |= child_has_aggregate; - pushed_children += child_pushed_children; - } - - /// The current function is not aggregate function and there is no aggregate function in its arguments, - /// so use the current function to replace its arguments - if (!has_aggregate) - { - for (UInt64 i = 0; i < pushed_children; i++) - into.pop_back(); - - into.push_back(node); - pushed_children = 1; - } - - return {has_aggregate, pushed_children}; -} - -/** Expand GROUP BY ALL by extracting all the SELECT-ed expressions that are not aggregate functions. - * - * For a special case that if there is a function having both aggregate functions and other fields as its arguments, - * the `GROUP BY` keys will contain the maximum non-aggregate fields we can extract from it. - * - * Example: - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY ALL - * will expand as - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY substring(a, 4, 2), substring(a, 1, 2) - */ -void QueryAnalyzer::expandGroupByAll(QueryNode & query_tree_node_typed) -{ - if (!query_tree_node_typed.isGroupByAll()) - return; - - auto & group_by_nodes = query_tree_node_typed.getGroupBy().getNodes(); - auto & projection_list = query_tree_node_typed.getProjection(); - - for (auto & node : projection_list.getNodes()) - recursivelyCollectMaxOrdinaryExpressions(node, group_by_nodes); - query_tree_node_typed.setIsGroupByAll(false); -} - -void QueryAnalyzer::expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings) -{ - if (!settings.enable_order_by_all || !query_tree_node_typed.isOrderByAll()) - return; - - auto * all_node = query_tree_node_typed.getOrderBy().getNodes()[0]->as(); - if (!all_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Select analyze for not sort node."); - - auto & projection_nodes = query_tree_node_typed.getProjection().getNodes(); - auto list_node = std::make_shared(); - list_node->getNodes().reserve(projection_nodes.size()); - - for (auto & node : projection_nodes) - { - /// Detect and reject ambiguous statements: - /// E.g. for a table with columns "all", "a", "b": - /// - SELECT all, a, b ORDER BY all; -- should we sort by all columns in SELECT or by column "all"? - /// - SELECT a, b AS all ORDER BY all; -- like before but "all" as alias - /// - SELECT func(...) AS all ORDER BY all; -- like before but "all" as function - /// - SELECT a, b ORDER BY all; -- tricky in other way: does the user want to sort by columns in SELECT clause or by not SELECTed column "all"? - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - auto projection_names = resolved_expression_it->second; - if (projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected 1 projection names. Actual {}", - projection_names.size()); - if (boost::iequals(projection_names[0], "all")) - throw Exception(ErrorCodes::UNEXPECTED_EXPRESSION, - "Cannot use ORDER BY ALL to sort a column with name 'all', please disable setting `enable_order_by_all` and try again"); - } - - auto sort_node = std::make_shared(node, all_node->getSortDirection(), all_node->getNullsSortDirection()); - list_node->getNodes().push_back(sort_node); - } - - query_tree_node_typed.getOrderByNode() = list_node; - query_tree_node_typed.setIsOrderByAll(false); -} - -std::string QueryAnalyzer::rewriteAggregateFunctionNameIfNeeded( - const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context) -{ - std::string result_aggregate_function_name = aggregate_function_name; - auto aggregate_function_name_lowercase = Poco::toLower(aggregate_function_name); - - const auto & settings = context->getSettingsRef(); - - if (aggregate_function_name_lowercase == "countdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - } - else if (aggregate_function_name_lowercase == "countdistinctif" || aggregate_function_name_lowercase == "countifdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - result_aggregate_function_name += "If"; - } - - /// Replace aggregateFunctionIfDistinct into aggregateFunctionDistinctIf to make execution more optimal - if (result_aggregate_function_name.ends_with("ifdistinct")) - { - size_t prefix_length = result_aggregate_function_name.size() - strlen("ifdistinct"); - result_aggregate_function_name = result_aggregate_function_name.substr(0, prefix_length) + "DistinctIf"; - } - - bool need_add_or_null = settings.aggregate_functions_null_for_empty && !result_aggregate_function_name.ends_with("OrNull"); - if (need_add_or_null) - { - auto properties = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (!properties->returns_default_when_only_null) - result_aggregate_function_name += "OrNull"; - } - - /** Move -OrNull suffix ahead, this should execute after add -OrNull suffix. - * Used to rewrite aggregate functions with -OrNull suffix in some cases. - * Example: sumIfOrNull. - * Result: sumOrNullIf. - */ - if (result_aggregate_function_name.ends_with("OrNull")) - { - auto function_properies = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (function_properies && !function_properies->returns_default_when_only_null) - { - size_t function_name_size = result_aggregate_function_name.size(); - - static constexpr std::array suffixes_to_replace = {"MergeState", "Merge", "State", "If"}; - for (const auto & suffix : suffixes_to_replace) - { - auto suffix_string_value = String(suffix); - auto suffix_to_check = suffix_string_value + "OrNull"; - - if (!result_aggregate_function_name.ends_with(suffix_to_check)) - continue; - - result_aggregate_function_name = result_aggregate_function_name.substr(0, function_name_size - suffix_to_check.size()); - result_aggregate_function_name += "OrNull"; - result_aggregate_function_name += suffix_string_value; - - break; - } - } - } - - return result_aggregate_function_name; -} - -/// Resolve identifier functions implementation - -/// Try resolve table identifier from database catalog -QueryTreeNodePtr QueryAnalyzer::tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context) -{ - size_t parts_size = table_identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected table identifier to contain 1 or 2 parts. Actual '{}'", - table_identifier.getFullName()); - - std::string database_name; - std::string table_name; - - if (table_identifier.isCompound()) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - else - { - table_name = table_identifier[0]; - } - - StorageID storage_id(database_name, table_name); - storage_id = context->resolveStorageID(storage_id); - bool is_temporary_table = storage_id.getDatabaseName() == DatabaseCatalog::TEMPORARY_DATABASE; - - StoragePtr storage; - - if (is_temporary_table) - storage = DatabaseCatalog::instance().getTable(storage_id, context); - else - storage = DatabaseCatalog::instance().tryGetTable(storage_id, context); - - if (!storage) - return {}; - - auto storage_lock = storage->lockForShare(context->getInitialQueryId(), context->getSettingsRef().lock_acquire_timeout); - auto storage_snapshot = storage->getStorageSnapshot(storage->getInMemoryMetadataPtr(), context); - auto result = std::make_shared(std::move(storage), std::move(storage_lock), std::move(storage_snapshot)); - if (is_temporary_table) - result->setTemporaryTableName(table_name); - - return result; -} - -/// Resolve identifier from compound expression -/// If identifier cannot be resolved throw exception or return nullptr if can_be_not_found is true -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found) -{ - Identifier compound_expression_identifier; - for (size_t i = 0; i < identifier_bind_size; ++i) - compound_expression_identifier.push_back(expression_identifier[i]); - - IdentifierView nested_path(expression_identifier); - nested_path.popFirst(identifier_bind_size); - - auto expression_type = compound_expression->getResultType(); - - if (!expression_type->hasSubcolumn(nested_path.getFullName())) - { - if (auto * column = compound_expression->as()) - { - const DataTypePtr & column_type = column->getColumn().getTypeInStorage(); - if (column_type->getTypeId() == TypeIndex::Object) - { - const auto * object_type = checkAndGetDataType(column_type.get()); - if (object_type->getSchemaFormat() == "json" && object_type->hasNullableSubcolumns()) - { - QueryTreeNodePtr constant_node_null = std::make_shared(Field()); - return constant_node_null; - } - } - } - - if (can_be_not_found) - return {}; - - std::unordered_set valid_identifiers; - collectCompoundExpressionValidIdentifiersForTypoCorrection(expression_identifier, - expression_type, - compound_expression_identifier, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(expression_identifier, valid_identifiers); - - String compound_expression_from_error_message; - if (!compound_expression_source.empty()) - { - compound_expression_from_error_message += " from "; - compound_expression_from_error_message += compound_expression_source; - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier {} nested path {} cannot be resolved from type {}{}. In scope {}{}", - expression_identifier, - nested_path, - expression_type->getName(), - compound_expression_from_error_message, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - QueryTreeNodePtr get_subcolumn_function = std::make_shared("getSubcolumn"); - auto & get_subcolumn_function_arguments_nodes = get_subcolumn_function->as()->getArguments().getNodes(); - - get_subcolumn_function_arguments_nodes.reserve(2); - get_subcolumn_function_arguments_nodes.push_back(compound_expression); - get_subcolumn_function_arguments_nodes.push_back(std::make_shared(nested_path.getFullName())); - - resolveFunction(get_subcolumn_function, scope); - return get_subcolumn_function; -} - -/** Resolve identifier from expression arguments. - * - * Expression arguments can be initialized during lambda analysis or they could be provided externally. - * Expression arguments must be already resolved nodes. This is client responsibility to resolve them. - * - * Example: SELECT arrayMap(x -> x + 1, [1,2,3]); - * For lambda x -> x + 1, `x` is lambda expression argument. - * - * Resolve strategy: - * 1. Try to bind identifier to scope argument name to node map. - * 2. If identifier is binded but expression context and node type are incompatible return nullptr. - * - * It is important to support edge cases, where we lookup for table or function node, but argument has same name. - * Example: WITH (x -> x + 1) AS func, (func -> func(1) + func) AS lambda SELECT lambda(1); - * - * 3. If identifier is compound and identifier lookup is in expression context use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - auto it = scope.expression_argument_name_to_node.find(identifier_lookup.identifier.getFullName()); - bool resolve_full_identifier = it != scope.expression_argument_name_to_node.end(); - - if (!resolve_full_identifier) - { - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - it = scope.expression_argument_name_to_node.find(identifier_bind_part); - if (it == scope.expression_argument_name_to_node.end()) - return {}; - } - - auto node_type = it->second->getNodeType(); - if (identifier_lookup.isExpressionLookup() && !isExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isTableExpressionLookup() && !isTableExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isFunctionLookup() && !isFunctionExpressionNodeType(node_type)) - return {}; - - if (!resolve_full_identifier && identifier_lookup.identifier.isCompound() && identifier_lookup.isExpressionLookup()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return it->second; -} - -bool QueryAnalyzer::tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope) -{ - return scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME) != nullptr || scope.aliases.array_join_aliases.contains(identifier_lookup.identifier.front()); -} - -/** Resolve identifier from scope aliases. - * - * Resolve strategy: - * 1. If alias is registered in current expressions that are in resolve process and if top expression is not part of bottom expression with the same alias subtree - * throw cyclic aliases exception. - * Otherwise prevent cache usage for identifier lookup and return nullptr. - * - * This is special scenario where identifier has name the same as alias name in one of its parent expressions including itself. - * In such case we cannot resolve identifier from aliases because of recursion. It is client responsibility to register and deregister alias - * names during expressions resolve. - * - * We must prevent cache usage for lookup because lookup outside of expression is supposed to return other value. - * Example: SELECT (id + 1) AS id, id + 2. Lookup for id inside (id + 1) as id should return id from table, but lookup (id + 2) should return - * (id + 1) AS id. - * - * Below cases should work: - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * SELECT (id + 1) AS id FROM test_table; - * SELECT (1 + (1 + id)) AS id FROM test_table; - * - * Below cases should throw cyclic aliases exception: - * SELECT (id + b) AS id, id as b FROM test_table; - * SELECT (1 + b + 1 + id) AS id, b as c, id as b FROM test_table; - * - * 2. Depending on IdentifierLookupContext get alias name to node map from IdentifierResolveScope. - * 3. Try to bind identifier to alias name in map. If there are no such binding return nullptr. - * 4. If node in map is not resolved, resolve it. It is important in case of compound expressions. - * Example: SELECT value.a, cast('(1)', 'Tuple(a UInt64)') AS value; - * - * Special case if node is identifier node. - * Example: SELECT value, id AS value FROM test_table; - * - * Add node in current scope expressions in resolve process stack. - * Try to resolve identifier. - * If identifier is resolved, depending on lookup context, erase entry from expression or lambda map. Check QueryExpressionsAliasVisitor documentation. - * Pop node from current scope expressions in resolve process stack. - * - * 5. If identifier is compound and identifier lookup is in expression context, use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - auto * it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME); - if (it == nullptr) - return {}; - - QueryTreeNodePtr & alias_node = *it; - - if (!alias_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node with alias {} is not valid. In scope {}", - identifier_bind_part, - scope.scope_node->formatASTForErrorMessage()); - - if (auto root_expression_with_alias = scope.expressions_in_resolve_process_stack.getExpressionWithAlias(identifier_bind_part)) - { - const auto top_expression = scope.expressions_in_resolve_process_stack.getTop(); - - if (!isNodePartOfTree(top_expression.get(), root_expression_with_alias.get())) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - scope.non_cached_identifier_lookups_during_expression_resolve.insert(identifier_lookup); - return {}; - } - - auto node_type = alias_node->getNodeType(); - - /// Resolve expression if necessary - if (node_type == QueryTreeNodeType::IDENTIFIER) - { - scope.pushExpressionNode(alias_node); - - auto & alias_identifier_node = alias_node->as(); - auto identifier = alias_identifier_node.getIdentifier(); - auto lookup_result = tryResolveIdentifier(IdentifierLookup{identifier, identifier_lookup.lookup_context}, scope, identifier_resolve_settings); - if (!lookup_result.resolved_identifier) - { - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(identifier, scope, true, false, false, valid_identifiers); - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {} identifier '{}'. In scope {}{}", - toStringLowercase(identifier_lookup.lookup_context), - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - alias_node = lookup_result.resolved_identifier; - scope.popExpressionNode(); - } - else if (node_type == QueryTreeNodeType::FUNCTION) - { - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - else if (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION) - { - if (identifier_resolve_settings.allow_to_resolve_subquery_during_identifier_resolution) - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, identifier_lookup.isTableExpressionLookup() /*allow_table_expression*/); - } - - if (identifier_lookup.identifier.isCompound() && alias_node) - { - if (identifier_lookup.isExpressionLookup()) - { - return tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - 1 /*identifier_bind_size*/, - alias_node, - {} /* compound_expression_source */, - scope, - identifier_resolve_settings.allow_to_check_join_tree /* can_be_not_found */); - } - else if (identifier_lookup.isFunctionLookup() || identifier_lookup.isTableExpressionLookup()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Compound identifier '{}' cannot be resolved as {}. In scope {}", - identifier_lookup.identifier.getFullName(), - identifier_lookup.isFunctionLookup() ? "function" : "table expression", - scope.scope_node->formatASTForErrorMessage()); - } - } - - return alias_node; -} - -/** Resolve identifier from table columns. - * - * 1. If table column nodes are empty or identifier is not expression lookup return nullptr. - * 2. If identifier full name match table column use column. Save information that we resolve identifier using full name. - * 3. Else if identifier binds to table column, use column. - * 4. Try to resolve column ALIAS expression if it exists. - * 5. If identifier was compound and was not resolved using full name during step 1 use `tryResolveIdentifierFromCompoundExpression`. - * This can be the case with compound ALIAS columns. - * - * Example: - * CREATE TABLE test_table (id UInt64, value Tuple(id UInt64, value String), alias_value ALIAS value.id) ENGINE=TinyLog; - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - if (scope.column_name_to_column_node.empty() || !identifier_lookup.isExpressionLookup()) - return {}; - - const auto & identifier = identifier_lookup.identifier; - auto it = scope.column_name_to_column_node.find(identifier.getFullName()); - bool full_column_name_match = it != scope.column_name_to_column_node.end(); - - if (!full_column_name_match) - { - it = scope.column_name_to_column_node.find(identifier_lookup.identifier[0]); - if (it == scope.column_name_to_column_node.end()) - return {}; - } - - if (it->second->hasExpression()) - resolveExpressionNode(it->second->getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - QueryTreeNodePtr result = it->second; - - if (!full_column_name_match && identifier.isCompound()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return result; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - if (parts_size == 1 && path_start == table_name) - return true; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return true; - else - return false; - } - - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier)) || table_expression_data.canBindIdentifier(IdentifierView(identifier))) - return true; - - if (identifier.getPartsSize() == 1) - return false; - - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return true; - - if (identifier.getPartsSize() == 2) - return false; - - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return true; - - return false; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node_to_ignore, - const IdentifierResolveScope & scope) -{ - bool can_bind_identifier_to_table_expression = false; - - for (const auto & [table_expression_node, _] : scope.table_expression_node_to_data) - { - if (table_expression_node.get() == table_expression_node_to_ignore.get()) - continue; - - can_bind_identifier_to_table_expression = tryBindIdentifierToTableExpression(identifier_lookup, table_expression_node, scope); - if (can_bind_identifier_to_table_expression) - break; - } - - return can_bind_identifier_to_table_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found) -{ - auto identifier_without_column_qualifier = identifier; - identifier_without_column_qualifier.popFirst(identifier_column_qualifier_parts); - - /** Compound identifier cannot be resolved directly from storage if storage is not table. - * - * Example: SELECT test_table.id.value1.value2 FROM test_table; - * In table storage column test_table.id.value1.value2 will exists. - * - * Example: SELECT test_subquery.compound_expression.value FROM (SELECT compound_expression AS value) AS test_subquery; - * Here there is no column with name test_subquery.compound_expression.value, and additional wrap in tuple element is required. - */ - - QueryTreeNodePtr result_expression; - bool match_full_identifier = false; - - const auto & identifier_full_name = identifier_without_column_qualifier.getFullName(); - auto it = table_expression_data.column_name_to_column_node.find(identifier_full_name); - bool can_resolve_directly_from_storage = it != table_expression_data.column_name_to_column_node.end(); - if (can_resolve_directly_from_storage && table_expression_data.subcolumn_names.contains(identifier_full_name)) - { - /** In the case when we have an ARRAY JOIN, we should not resolve subcolumns directly from storage. - * For example, consider the following SQL query: - * SELECT ProfileEvents.Values FROM system.query_log ARRAY JOIN ProfileEvents - * In this case, ProfileEvents.Values should also be array joined, not directly resolved from storage. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - if (nearest_query_scope_query_node && nearest_query_scope_query_node->getJoinTree()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - can_resolve_directly_from_storage = false; - } - - if (can_resolve_directly_from_storage) - { - match_full_identifier = true; - result_expression = it->second; - } - else - { - it = table_expression_data.column_name_to_column_node.find(identifier_without_column_qualifier.at(0)); - if (it != table_expression_data.column_name_to_column_node.end()) - result_expression = it->second; - } - - bool clone_is_needed = true; - - String table_expression_source = table_expression_data.table_expression_description; - if (!table_expression_data.table_expression_name.empty()) - table_expression_source += " with name " + table_expression_data.table_expression_name; - - if (result_expression && !match_full_identifier && identifier_without_column_qualifier.isCompound()) - { - size_t identifier_bind_size = identifier_column_qualifier_parts + 1; - result_expression = tryResolveIdentifierFromCompoundExpression(identifier, - identifier_bind_size, - result_expression, - table_expression_source, - scope, - can_be_not_found); - if (can_be_not_found && !result_expression) - return {}; - clone_is_needed = false; - } - - if (!result_expression) - { - QueryTreeNodes nested_column_nodes; - DataTypes nested_types; - Array nested_names_array; - - for (const auto & [column_name, _] : table_expression_data.column_names_and_types) - { - Identifier column_name_identifier_without_last_part(column_name); - auto column_name_identifier_last_part = column_name_identifier_without_last_part.getParts().back(); - column_name_identifier_without_last_part.popLast(); - - if (identifier_without_column_qualifier.getFullName() != column_name_identifier_without_last_part.getFullName()) - continue; - - auto column_node_it = table_expression_data.column_name_to_column_node.find(column_name); - if (column_node_it == table_expression_data.column_name_to_column_node.end()) - continue; - - const auto & column_node = column_node_it->second; - const auto & column_type = column_node->getColumnType(); - const auto * column_type_array = typeid_cast(column_type.get()); - if (!column_type_array) - continue; - - nested_column_nodes.push_back(column_node); - nested_types.push_back(column_type_array->getNestedType()); - nested_names_array.push_back(Field(std::move(column_name_identifier_last_part))); - } - - if (!nested_types.empty()) - { - auto nested_function_node = std::make_shared("nested"); - auto & nested_function_node_arguments = nested_function_node->getArguments().getNodes(); - - auto nested_function_names_array_type = std::make_shared(std::make_shared()); - auto nested_function_names_constant_node = std::make_shared(std::move(nested_names_array), - std::move(nested_function_names_array_type)); - nested_function_node_arguments.push_back(std::move(nested_function_names_constant_node)); - nested_function_node_arguments.insert(nested_function_node_arguments.end(), - nested_column_nodes.begin(), - nested_column_nodes.end()); - - auto nested_function = FunctionFactory::instance().get(nested_function_node->getFunctionName(), scope.context); - nested_function_node->resolveAsFunction(nested_function->build(nested_function_node->getArgumentColumns())); - - clone_is_needed = false; - result_expression = std::move(nested_function_node); - } - } - - if (!result_expression) - { - if (can_be_not_found) - return {}; - std::unordered_set valid_identifiers; - collectTableExpressionValidIdentifiersForTypoCorrection(identifier, - table_expression_node, - table_expression_data, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Identifier '{}' cannot be resolved from {}. In scope {}{}", - identifier.getFullName(), - table_expression_source, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (clone_is_needed) - result_expression = result_expression->clone(); - - auto qualified_identifier = identifier; - - for (size_t i = 0; i < identifier_column_qualifier_parts; ++i) - { - auto qualified_identifier_with_removed_part = qualified_identifier; - qualified_identifier_with_removed_part.popFirst(); - - if (qualified_identifier_with_removed_part.empty()) - break; - - IdentifierLookup column_identifier_lookup = {qualified_identifier_with_removed_part, IdentifierLookupContext::EXPRESSION}; - if (tryBindIdentifierToAliases(column_identifier_lookup, scope)) - break; - - if (table_expression_data.should_qualify_columns && - tryBindIdentifierToTableExpressions(column_identifier_lookup, table_expression_node, scope)) - break; - - qualified_identifier = std::move(qualified_identifier_with_removed_part); - } - - auto qualified_identifier_full_name = qualified_identifier.getFullName(); - node_to_projection_name.emplace(result_expression, std::move(qualified_identifier_full_name)); - - return result_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (parts_size == 1 && path_start == table_name) - return table_expression_node; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return table_expression_node; - else - return {}; - } - - /** If identifier first part binds to some column start or table has full identifier name. Then we can try to find whole identifier in table. - * 1. Try to bind identifier first part to column in table, if true get full identifier from table or throw exception. - * 2. Try to bind identifier first part to table name or storage alias, if true remove first part and try to get full identifier from table or throw exception. - * Storage alias works for subquery, table function as well. - * 3. Try to bind identifier first parts to database name and table name, if true remove first two parts and try to get full identifier from table or throw exception. - */ - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier))) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/); - - if (table_expression_data.canBindIdentifier(IdentifierView(identifier))) - { - /** This check is insufficient to determine whether and identifier can be resolved from table expression. - * A further check will be performed in `tryResolveIdentifierFromStorage` to see if we have such a subcolumn. - * In cases where the subcolumn cannot be found we want to have `nullptr` instead of exception. - * So, we set `can_be_not_found = true` to have an attempt to resolve the identifier from another table expression. - * Example: `SELECT t.t from (SELECT 1 as t) AS a FULL JOIN (SELECT 1 as t) as t ON a.t = t.t;` - * Initially, we will try to resolve t.t from `a` because `t.` is bound to `1 as t`. However, as it is not a nested column, we will need to resolve it from the second table expression. - */ - auto resolved_identifier = tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/, true /*can_be_not_found*/); - if (resolved_identifier) - return resolved_identifier; - } - - if (identifier.getPartsSize() == 1) - return {}; - - const auto & table_name = table_expression_data.table_name; - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 1 /*identifier_column_qualifier_parts*/); - - if (identifier.getPartsSize() == 2) - return {}; - - const auto & database_name = table_expression_data.database_name; - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 2 /*identifier_column_qualifier_parts*/); - - return {}; -} - -QueryTreeNodePtr checkIsMissedObjectJSONSubcolumn(const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier) -{ - if (left_resolved_identifier && right_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT - && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL" && right_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (left_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (right_resolved_identifier && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & right_resolved_column = right_resolved_identifier->as(); - if (right_resolved_column.getValueStringRepresentation() == "NULL") - return right_resolved_identifier; - } - return {}; -} - -/// Used to replace columns that changed type because of JOIN to their original type -class ReplaceColumnsVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit ReplaceColumnsVisitor(const QueryTreeNodePtrWithHashMap & replacement_map_, const ContextPtr & context_) - : replacement_map(replacement_map_) - , context(context_) - {} - - /// Apply replacement transitively, because column may change it's type twice, one to have a supertype and then because of `joun_use_nulls` - static QueryTreeNodePtr findTransitiveReplacement(QueryTreeNodePtr node, const QueryTreeNodePtrWithHashMap & replacement_map_) - { - auto it = replacement_map_.find(node); - QueryTreeNodePtr result_node = nullptr; - for (; it != replacement_map_.end(); it = replacement_map_.find(result_node)) - { - if (result_node && result_node->isEqual(*it->second)) - { - Strings map_dump; - for (const auto & [k, v]: replacement_map_) - map_dump.push_back(fmt::format("{} -> {} (is_equals: {}, is_same: {})", - k.node->dumpTree(), v->dumpTree(), k.node->isEqual(*v), k.node == v)); - throw Exception(ErrorCodes::LOGICAL_ERROR, "Infinite loop in query tree replacement map: {}", fmt::join(map_dump, "; ")); - } - chassert(it->second); - - result_node = it->second; - } - return result_node; - } - - void visitImpl(QueryTreeNodePtr & node) - { - if (auto replacement_node = findTransitiveReplacement(node, replacement_map)) - node = replacement_node; - - if (auto * function_node = node->as(); function_node && function_node->isResolved()) - rerunFunctionResolve(function_node, context); - } - - /// We want to re-run resolve for function _after_ its arguments are replaced - bool shouldTraverseTopToBottom() const { return false; } - - bool needChildVisit(QueryTreeNodePtr & /* parent */, QueryTreeNodePtr & child) - { - /// Visit only expressions, but not subqueries - return child->getNodeType() == QueryTreeNodeType::IDENTIFIER - || child->getNodeType() == QueryTreeNodeType::LIST - || child->getNodeType() == QueryTreeNodeType::FUNCTION - || child->getNodeType() == QueryTreeNodeType::COLUMN; - } - -private: - const QueryTreeNodePtrWithHashMap & replacement_map; - const ContextPtr & context; -}; - -/// Compare resolved identifiers considering columns that become nullable after JOIN -bool resolvedIdenfiersFromJoinAreEquals( - const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier, - const IdentifierResolveScope & scope) -{ - auto left_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(left_resolved_identifier, scope.join_columns_with_changed_types); - const auto & left_resolved_to_compare = left_original_node ? left_original_node : left_resolved_identifier; - - auto right_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(right_resolved_identifier, scope.join_columns_with_changed_types); - const auto & right_resolved_to_compare = right_original_node ? right_original_node : right_resolved_identifier; - - return left_resolved_to_compare->isEqual(*right_resolved_to_compare, IQueryTreeNode::CompareOptions{.compare_aliases = false}); -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_join_node = table_expression_node->as(); - auto left_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getLeftTableExpression(), scope); - auto right_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getRightTableExpression(), scope); - - if (!identifier_lookup.isExpressionLookup()) - { - if (left_resolved_identifier && right_resolved_identifier) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.dump(), - scope.scope_node->formatASTForErrorMessage()); - - return left_resolved_identifier ? left_resolved_identifier : right_resolved_identifier; - } - - bool join_node_in_resolve_process = scope.table_expressions_in_resolve_process.contains(table_expression_node.get()); - - std::unordered_map join_using_column_name_to_column_node; - - if (!join_node_in_resolve_process && from_join_node.isUsingJoinExpression()) - { - auto & join_using_list = from_join_node.getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & column_node = join_using_node->as(); - join_using_column_name_to_column_node.emplace(column_node.getColumnName(), std::static_pointer_cast(join_using_node)); - } - } - - auto check_nested_column_not_in_using = [&join_using_column_name_to_column_node, &identifier_lookup](const QueryTreeNodePtr & node) - { - /** tldr: When an identifier is resolved into the function `nested` or `getSubcolumn`, and - * some column in its argument is in the USING list and its type has to be updated, we throw an error to avoid overcomplication. - * - * Identifiers can be resolved into functions in case of nested or subcolumns. - * For example `t.t.t` can be resolved into `getSubcolumn(t, 't.t')` function in case of `t` is `Tuple`. - * So, `t` in USING list is resolved from JOIN itself and has supertype of columns from left and right table. - * But `t` in `getSubcolumn` argument is still resolved from table and we need to update its type. - * - * Example: - * - * SELECT t.t FROM ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t UInt32, s1 String), s1 String) as t - * ) AS a FULL JOIN ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t Int32, s2 String), s2 String) as t - * ) AS b USING t; - * - * Result type of `t` is `Tuple(Tuple(Int64, String), String)` (different type and no names for subcolumns), - * so it may be tricky to have a correct type for `t.t` that is resolved into getSubcolumn(t, 't'). - * - * It can be more complicated in case of Nested subcolumns, in that case in query: - * SELECT t FROM ... JOIN ... USING (t.t) - * Here, `t` is resolved into function `nested(['t', 's'], t.t, t.s) so, `t.t` should be from JOIN and `t.s` should be from table. - * - * Updating type accordingly is pretty complicated, so just forbid such cases. - * - * While it still may work for storages that support selecting subcolumns directly without `getSubcolumn` function: - * SELECT t, t.t, toTypeName(t), toTypeName(t.t) FROM t1 AS a FULL JOIN t2 AS b USING t.t; - * We just support it as a best-effort: `t` will have original type from table, but `t.t` will have super-type from JOIN. - * Probably it's good to prohibit such cases as well, but it's not clear how to check it in general case. - */ - if (node->getNodeType() != QueryTreeNodeType::FUNCTION) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {}, expected function node", node->getNodeType()); - - const auto & function_argument_nodes = node->as().getArguments().getNodes(); - for (const auto & argument_node : function_argument_nodes) - { - if (argument_node->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_name = argument_node->as().getColumnName(); - if (join_using_column_name_to_column_node.contains(column_name)) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Cannot select subcolumn for identifier '{}' while joining using column '{}'", - identifier_lookup.identifier, column_name); - } - else if (argument_node->getNodeType() == QueryTreeNodeType::CONSTANT) - { - continue; - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {} for argument node in {}", - argument_node->getNodeType(), node->formatASTForErrorMessage()); - } - } - }; - - std::optional resolved_side; - QueryTreeNodePtr resolved_identifier; - - JoinKind join_kind = from_join_node.getKind(); - - /// If columns from left or right table were missed Object(Nullable('json')) subcolumns, they will be replaced - /// to ConstantNode(NULL), which can't be cast to ColumnNode, so we resolve it here. - if (auto missed_subcolumn_identifier = checkIsMissedObjectJSONSubcolumn(left_resolved_identifier, right_resolved_identifier)) - return missed_subcolumn_identifier; - - if (left_resolved_identifier && right_resolved_identifier) - { - auto using_column_node_it = join_using_column_name_to_column_node.end(); - if (left_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && right_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getColumnName() == right_resolved_column.getColumnName()) - using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - } - else - { - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(left_resolved_identifier); - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(right_resolved_identifier); - } - - if (using_column_node_it != join_using_column_name_to_column_node.end()) - { - JoinTableSide using_column_inner_column_table_side = isRight(join_kind) ? JoinTableSide::Right : JoinTableSide::Left; - auto & using_column_node = using_column_node_it->second->as(); - auto & using_expression_list = using_column_node.getExpression()->as(); - - size_t inner_column_node_index = using_column_inner_column_table_side == JoinTableSide::Left ? 0 : 1; - const auto & inner_column_node = using_expression_list.getNodes().at(inner_column_node_index); - - auto result_column_node = inner_column_node->clone(); - auto & result_column = result_column_node->as(); - result_column.setColumnType(using_column_node.getColumnType()); - - const auto & join_using_left_column = using_expression_list.getNodes().at(0); - if (!result_column_node->isEqual(*join_using_left_column)) - scope.join_columns_with_changed_types[result_column_node] = join_using_left_column; - - resolved_identifier = std::move(result_column_node); - } - else if (resolvedIdenfiersFromJoinAreEquals(left_resolved_identifier, right_resolved_identifier, scope)) - { - const auto & identifier_path_part = identifier_lookup.identifier.front(); - auto * left_resolved_identifier_column = left_resolved_identifier->as(); - auto * right_resolved_identifier_column = right_resolved_identifier->as(); - - if (left_resolved_identifier_column && right_resolved_identifier_column) - { - const auto & left_column_source_alias = left_resolved_identifier_column->getColumnSource()->getAlias(); - const auto & right_column_source_alias = right_resolved_identifier_column->getColumnSource()->getAlias(); - - /** If column from right table was resolved using alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one JOIN system.one AS A ON A.dummy = system.one.dummy; - * - * If alias is specified for left table, and alias is not specified for right table and identifier was resolved - * without using left table alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one AS A JOIN system.one ON A.dummy = system.one.dummy; - * - * Otherwise we prefer column from left table. - */ - bool column_resolved_using_right_alias = identifier_path_part == right_column_source_alias; - bool column_resolved_without_using_left_alias = !left_column_source_alias.empty() - && right_column_source_alias.empty() - && identifier_path_part != left_column_source_alias; - if (column_resolved_using_right_alias || column_resolved_without_using_left_alias) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else if (scope.joins_count == 1 && scope.context->getSettingsRef().single_join_prefer_left_table) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - else - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier '{}'. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - else if (left_resolved_identifier) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(left_resolved_identifier); - } - else - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*left_resolved_column.getColumnType())) - { - auto left_resolved_column_clone = std::static_pointer_cast(left_resolved_column.clone()); - left_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(left_resolved_column_clone); - - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - else if (right_resolved_identifier) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(right_resolved_identifier); - } - else - { - auto & right_resolved_column = right_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(right_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*right_resolved_column.getColumnType())) - { - auto right_resolved_column_clone = std::static_pointer_cast(right_resolved_column.clone()); - right_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(right_resolved_column_clone); - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - - if (join_node_in_resolve_process || !resolved_identifier) - return resolved_identifier; - - if (scope.join_use_nulls) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier); - auto nullable_resolved_identifier = convertJoinedColumnTypeToNullIfNeeded(resolved_identifier, join_kind, resolved_side, scope); - if (nullable_resolved_identifier) - { - resolved_identifier = nullable_resolved_identifier; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(resolved_identifier, projection_name_it->second); - } - } - } - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope) -{ - const auto * resolved_function = resolved_expression->as(); - if (!resolved_function || resolved_function->getFunctionName() != "getSubcolumn") - return {}; - - const auto * array_join_parent_column = array_join_column_inner_expression.get(); - - /** If both resolved and array-joined expressions are subcolumns, try to match them: - * For example, in `SELECT t.map.values FROM (SELECT * FROM tbl) ARRAY JOIN t.map` - * Identifier `t.map.values` is resolved into `getSubcolumn(t, 'map.values')` and t.map is resolved into `getSubcolumn(t, 'map')` - * Since we need to perform array join on `getSubcolumn(t, 'map')`, `t.map.values` should become `getSubcolumn(getSubcolumn(t, 'map'), 'values')` - * - * Note: It doesn't work when subcolumn in ARRAY JOIN is transformed by another expression, for example - * SELECT c.map, c.map.values FROM (SELECT * FROM tbl) ARRAY JOIN mapApply(x -> x, t.map); - */ - String array_join_subcolumn_prefix; - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "getSubcolumn") - { - const auto & argument_nodes = array_join_column_inner_expression_function->getArguments().getNodes(); - if (argument_nodes.size() == 2 && argument_nodes.at(1)->getNodeType() == QueryTreeNodeType::CONSTANT) - { - const auto & constant_node = argument_nodes.at(1)->as(); - const auto & constant_node_value = constant_node.getValue(); - if (constant_node_value.getType() == Field::Types::String) - { - array_join_subcolumn_prefix = constant_node_value.get() + "."; - array_join_parent_column = argument_nodes.at(0).get(); - } - } - } - - const auto & argument_nodes = resolved_function->getArguments().getNodes(); - if (argument_nodes.size() != 2 && !array_join_parent_column->isEqual(*argument_nodes.at(0))) - return {}; - - const auto * second_argument = argument_nodes.at(1)->as(); - if (!second_argument || second_argument->getValue().getType() != Field::Types::String) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected constant string as second argument of getSubcolumn function {}", resolved_function->dumpTree()); - - const auto & resolved_subcolumn_path = second_argument->getValue().get(); - if (!startsWith(resolved_subcolumn_path, array_join_subcolumn_prefix)) - return {}; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(array_join_column_expression_typed.getColumn(), array_join_column_expression_typed.getColumnSource())); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(resolved_subcolumn_path.substr(array_join_subcolumn_prefix.size()))); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - return function_query_node; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & array_join_node = table_expression_node->as(); - const auto & array_join_column_expressions_list = array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions_list.getNodes(); - - QueryTreeNodePtr array_join_resolved_expression; - - /** Special case when qualified or unqualified identifier point to array join expression without alias. - * - * CREATE TABLE test_table (id UInt64, value String, value_array Array(UInt8)) ENGINE=TinyLog; - * SELECT id, value, value_array, test_table.value_array, default.test_table.value_array FROM test_table ARRAY JOIN value_array; - * - * value_array, test_table.value_array, default.test_table.value_array must be resolved into array join expression. - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - if (array_join_column_expression_typed.hasAlias()) - continue; - - auto & array_join_column_inner_expression = array_join_column_expression_typed.getExpressionOrThrow(); - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "nested" && - array_join_column_inner_expression_function->getArguments().getNodes().size() > 1 && - isTuple(array_join_column_expression_typed.getResultType())) - { - const auto & nested_function_arguments = array_join_column_inner_expression_function->getArguments().getNodes(); - size_t nested_function_arguments_size = nested_function_arguments.size(); - - const auto & nested_keys_names_constant_node = nested_function_arguments[0]->as(); - const auto & nested_keys_names = nested_keys_names_constant_node.getValue().get(); - size_t nested_keys_names_size = nested_keys_names.size(); - - if (nested_keys_names_size == nested_function_arguments_size - 1) - { - for (size_t i = 1; i < nested_function_arguments_size; ++i) - { - if (!nested_function_arguments[i]->isEqual(*resolved_expression)) - continue; - - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - - const auto & nested_key_name = nested_keys_names[i - 1].get(); - Identifier nested_identifier = Identifier(nested_key_name); - auto tuple_element_function = wrapExpressionNodeInTupleElement(array_join_column, nested_identifier); - resolveFunction(tuple_element_function, scope); - - array_join_resolved_expression = std::move(tuple_element_function); - break; - } - } - } - - if (array_join_resolved_expression) - break; - - if (array_join_column_inner_expression->isEqual(*resolved_expression)) - { - array_join_resolved_expression = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - break; - } - - /// When we select subcolumn of array joined column it also should be array joined - array_join_resolved_expression = matchArrayJoinSubcolumns(array_join_column_inner_expression, array_join_column_expression_typed, resolved_expression, scope); - if (array_join_resolved_expression) - break; - } - return array_join_resolved_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_array_join_node = table_expression_node->as(); - auto resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_array_join_node.getTableExpression(), scope); - - if (scope.table_expressions_in_resolve_process.contains(table_expression_node.get()) || !identifier_lookup.isExpressionLookup()) - return resolved_identifier; - - const auto & array_join_column_expressions = from_array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions.getNodes(); - - /** Allow JOIN with USING with ARRAY JOIN. - * - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN [1,2,3] AS id INNER JOIN test_table_2 AS t2 USING (id); - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN t1.id AS id INNER JOIN test_table_2 AS t2 USING (id); - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - - IdentifierView identifier_view(identifier_lookup.identifier); - - if (identifier_view.isCompound() && from_array_join_node.hasAlias() && identifier_view.front() == from_array_join_node.getAlias()) - identifier_view.popFirst(); - - const auto & alias_or_name = array_join_column_expression_typed.hasAlias() - ? array_join_column_expression_typed.getAlias() - : array_join_column_expression_typed.getColumnName(); - - if (identifier_view.front() == alias_or_name) - identifier_view.popFirst(); - else if (identifier_view.getFullName() == alias_or_name) - identifier_view.popFirst(identifier_view.getPartsSize()); /// Clear - else - continue; - - if (identifier_view.empty()) - { - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - return array_join_column; - } - - auto compound_expr = tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - identifier_lookup.identifier.getPartsSize() - identifier_view.getPartsSize() /*identifier_bind_size*/, - array_join_column_expression, - {} /* compound_expression_source */, - scope, - true /* can_be_not_found */); - - if (compound_expr) - return compound_expr; - } - - if (!resolved_identifier) - return nullptr; - - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(resolved_identifier, table_expression_node, scope); - if (array_join_resolved_expression) - resolved_identifier = std::move(array_join_resolved_expression); - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope) -{ - auto join_tree_node_type = join_tree_node->getNodeType(); - - switch (join_tree_node_type) - { - case QueryTreeNodeType::JOIN: - return tryResolveIdentifierFromJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::ARRAY_JOIN: - return tryResolveIdentifierFromArrayJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - [[fallthrough]]; - case QueryTreeNodeType::TABLE: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - { - /** Edge case scenario when subquery in FROM node try to resolve identifier from parent scopes, when FROM is not resolved. - * SELECT subquery.b AS value FROM (SELECT value, 1 AS b) AS subquery; - * TODO: This can be supported - */ - if (scope.table_expressions_in_resolve_process.contains(join_tree_node.get())) - return {}; - - return tryResolveIdentifierFromTableExpression(identifier_lookup, join_tree_node, scope); - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Scope FROM section expected table, table function, query, union, join or array join. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } -} - -/** Resolve identifier from scope join tree. - * - * 1. If identifier is in function lookup context return nullptr. - * 2. Try to resolve identifier from table columns. - * 3. If there is no FROM section return nullptr. - * 4. If identifier is in table lookup context, check if it has 1 or 2 parts, otherwise throw exception. - * If identifier has 2 parts try to match it with database_name and table_name. - * If identifier has 1 part try to match it with table_name, then try to match it with table alias. - * 5. If identifier is in expression lookup context, we first need to bind identifier to some table column using identifier first part. - * Start with identifier first part, if it match some column name in table try to get column with full identifier name. - * TODO: Need to check if it is okay to throw exception if compound identifier first part bind to column but column is not valid. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope) -{ - if (identifier_lookup.isFunctionLookup()) - return {}; - - /// Try to resolve identifier from table columns - if (auto resolved_identifier = tryResolveIdentifierFromTableColumns(identifier_lookup, scope)) - return resolved_identifier; - - if (scope.expression_join_tree_node) - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, scope.expression_join_tree_node, scope); - - auto * query_scope_node = scope.scope_node->as(); - if (!query_scope_node || !query_scope_node->getJoinTree()) - return {}; - - const auto & join_tree_node = query_scope_node->getJoinTree(); - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_tree_node, scope); -} - -/** Try resolve identifier in current scope parent scopes. - * - * TODO: If column is matched, throw exception that nested subqueries are not supported. - * - * If initial scope is expression. Then try to resolve identifier in parent scopes until query scope is hit. - * For query scope resolve strategy is same as if initial scope if query. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - bool initial_scope_is_query = scope.scope_node->getNodeType() == QueryTreeNodeType::QUERY; - bool initial_scope_is_expression = !initial_scope_is_query; - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_parent_scopes = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - IdentifierResolveScope * scope_to_check = scope.parent_scope; - - if (initial_scope_is_expression) - { - while (scope_to_check != nullptr) - { - auto resolve_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - if (resolve_result.resolved_identifier) - return resolve_result; - - bool scope_was_query = scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY; - scope_to_check = scope_to_check->parent_scope; - - if (scope_was_query) - break; - } - } - - if (!scope.context->getSettingsRef().enable_global_with_statement) - return {}; - - /** Nested subqueries cannot access outer subqueries table expressions from JOIN tree because - * that can prevent resolution of table expression from CTE. - * - * Example: WITH a AS (SELECT number FROM numbers(1)), b AS (SELECT number FROM a) SELECT * FROM a as l, b as r; - */ - if (identifier_lookup.isTableExpressionLookup()) - identifier_resolve_settings.allow_to_check_join_tree = false; - - while (scope_to_check != nullptr) - { - auto lookup_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - const auto & resolved_identifier = lookup_result.resolved_identifier; - - scope_to_check = scope_to_check->parent_scope; - - if (resolved_identifier) - { - auto * subquery_node = resolved_identifier->as(); - auto * union_node = resolved_identifier->as(); - - bool is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - bool is_table_from_expression_arguments = lookup_result.resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS && - resolved_identifier->getNodeType() == QueryTreeNodeType::TABLE; - bool is_valid_table_expression = is_cte || is_table_from_expression_arguments; - - /** From parent scopes we can resolve table identifiers only as CTE. - * Example: SELECT (SELECT 1 FROM a) FROM test_table AS a; - * - * During child scope table identifier resolve a, table node test_table with alias a from parent scope - * is invalid. - */ - if (identifier_lookup.isTableExpressionLookup() && !is_valid_table_expression) - continue; - - if (is_valid_table_expression || resolved_identifier->as()) - { - return lookup_result; - } - else if (auto * resolved_function = resolved_identifier->as()) - { - /// Special case: scalar subquery was executed and replaced by __getScalar function. - /// Handle it as a constant. - if (resolved_function->getFunctionName() == "__getScalar") - return lookup_result; - } - - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Resolve identifier '{}' from parent scope only supported for constants and CTE. Actual {} node type {}. In scope {}", - identifier_lookup.identifier.getFullName(), - resolved_identifier->formatASTForErrorMessage(), - resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - return {}; -} - -/** Resolve identifier in scope. - * - * If identifier was resolved resolve identified lookup status will be updated. - * - * Steps: - * 1. Register identifier lookup in scope identifier lookup to resolve status table. - * If entry is already registered and is not resolved, that means that we have cyclic aliases for identifier. - * Example: SELECT a AS b, b AS a; - * Try resolve identifier in current scope: - * 3. Try resolve identifier from expression arguments. - * - * If prefer_column_name_to_alias = true. - * 4. Try to resolve identifier from join tree. - * 5. Try to resolve identifier from aliases. - * Otherwise. - * 4. Try to resolve identifier from aliases. - * 5. Try to resolve identifier from join tree. - * - * 6. If it is table identifier lookup try to lookup identifier in current scope CTEs. - * - * 7. If identifier is not resolved in current scope, try to resolve it in parent scopes. - * 8. If identifier is not resolved from parent scopes and it is table identifier lookup try to lookup identifier - * in database catalog. - * - * Same is not done for functions because function resolution is more complex, and in case of aggregate functions requires not only name - * but also argument types, it is responsibility of resolve function method to handle resolution of function name. - * - * 9. If identifier was not resolved, or identifier caching was disabled remove it from identifier lookup to resolve status table. - * - * It is okay for identifier to be not resolved, in case we want first try to lookup identifier in one context, - * then if there is no identifier in this context, try to lookup in another context. - * Example: Try to lookup identifier as expression, if it is not found, lookup as function. - * Example: Try to lookup identifier as expression, if it is not found, lookup as table. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - auto it = scope.identifier_lookup_to_resolve_state.find(identifier_lookup); - if (it != scope.identifier_lookup_to_resolve_state.end()) - { - if (it->second.cyclic_identifier_resolve) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (!it->second.resolve_result.isResolved()) - it->second.cyclic_identifier_resolve = true; - - if (it->second.resolve_result.isResolved() && - scope.use_identifier_lookup_to_result_cache && - !scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) && - (!it->second.resolve_result.isResolvedFromCTEs() || !ctes_in_resolve_process.contains(identifier_lookup.identifier.getFullName()))) - return it->second.resolve_result; - } - else - { - auto [insert_it, _] = scope.identifier_lookup_to_resolve_state.insert({identifier_lookup, IdentifierResolveState()}); - it = insert_it; - } - - /// Resolve identifier from current scope - - IdentifierResolveResult resolve_result; - resolve_result.resolved_identifier = tryResolveIdentifierFromExpressionArguments(identifier_lookup, scope); - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - - if (!resolve_result.resolved_identifier) - { - bool prefer_column_name_to_alias = scope.context->getSettingsRef().prefer_column_name_to_alias; - - if (identifier_lookup.isExpressionLookup()) - { - /* For aliases from ARRAY JOIN we prefer column from join tree: - * SELECT id FROM ( SELECT ... ) AS subquery ARRAY JOIN [0] AS id INNER JOIN second_table USING (id) - * In the example, identifier `id` should be resolved into one from USING (id) column. - */ - - auto * alias_it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FULL_NAME); - if (alias_it && (*alias_it)->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_node = (*alias_it)->as(); - if (column_node.getColumnSource()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - prefer_column_name_to_alias = true; - } - } - - if (unlikely(prefer_column_name_to_alias)) - { - if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - - if (!resolve_result.resolved_identifier) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - } - else - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - { - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - else if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - } - } - - if (!resolve_result.resolved_identifier && identifier_lookup.isTableExpressionLookup()) - { - auto full_name = identifier_lookup.identifier.getFullName(); - auto cte_query_node_it = scope.cte_name_to_query_node.find(full_name); - - /// CTE may reference table expressions with the same name, e.g.: - /// - /// WITH test1 AS (SELECT * FROM test1) SELECT * FROM test1; - /// - /// Since we don't support recursive CTEs, `test1` identifier inside of CTE - /// references to table .test1. - /// This means that the example above is equivalent to the following query: - /// - /// SELECT * FROM test1; - /// - /// To accomplish this behaviour it's not allowed to resolve identifiers to - /// CTE that is being resolved. - if (cte_query_node_it != scope.cte_name_to_query_node.end() - && !ctes_in_resolve_process.contains(full_name)) - { - resolve_result.resolved_identifier = cte_query_node_it->second; - resolve_result.resolve_place = IdentifierResolvePlace::CTE; - } - } - - /// Try to resolve identifier from parent scopes - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_parent_scopes) - { - resolve_result = tryResolveIdentifierInParentScopes(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolved_from_parent_scopes = true; - } - - /// Try to resolve table identifier from database catalog - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_database_catalog && identifier_lookup.isTableExpressionLookup()) - { - resolve_result.resolved_identifier = tryResolveTableIdentifierFromDatabaseCatalog(identifier_lookup.identifier, scope.context); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::DATABASE_CATALOG; - } - - bool was_cyclic_identifier_resolve = it->second.cyclic_identifier_resolve; - if (!was_cyclic_identifier_resolve) - it->second.resolve_result = resolve_result; - it->second.cyclic_identifier_resolve = false; - - /** If identifier was not resolved, or during expression resolution identifier was explicitly added into non cached set, - * or identifier caching was disabled in resolve scope we remove identifier lookup result from identifier lookup to result table. - */ - if (!was_cyclic_identifier_resolve && (!resolve_result.resolved_identifier || - scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) || - !scope.use_identifier_lookup_to_result_cache)) - scope.identifier_lookup_to_resolve_state.erase(it); - - return resolve_result; -} - -/// Resolve query tree nodes functions implementation - -/** Qualify column nodes with projection names. - * - * Example: SELECT * FROM test_table AS t1, test_table AS t2; - */ -void QueryAnalyzer::qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - /// Build additional column qualification parts array - std::vector additional_column_qualification_parts; - - if (table_expression_node->hasAlias()) - additional_column_qualification_parts = {table_expression_node->getAlias()}; - else if (auto * table_node = table_expression_node->as()) - additional_column_qualification_parts = {table_node->getStorageID().getDatabaseName(), table_node->getStorageID().getTableName()}; - - size_t additional_column_qualification_parts_size = additional_column_qualification_parts.size(); - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - /** For each matched column node iterate over additional column qualifications and apply them if column needs to be qualified. - * To check if column needs to be qualified we check if column name can bind to any other table expression in scope or to scope aliases. - */ - std::vector column_qualified_identifier_parts; - - for (const auto & column_node : column_nodes) - { - const auto & column_name = column_node->as().getColumnName(); - column_qualified_identifier_parts = Identifier(column_name).getParts(); - - /// Iterate over additional column qualifications and apply them if needed - for (size_t i = 0; i < additional_column_qualification_parts_size; ++i) - { - auto identifier_to_check = Identifier(column_qualified_identifier_parts); - IdentifierLookup identifier_lookup{identifier_to_check, IdentifierLookupContext::EXPRESSION}; - bool need_to_qualify = table_expression_data.should_qualify_columns; - if (need_to_qualify) - need_to_qualify = tryBindIdentifierToTableExpressions(identifier_lookup, table_expression_node, scope); - - if (tryBindIdentifierToAliases(identifier_lookup, scope)) - need_to_qualify = true; - - if (need_to_qualify) - { - /** Add last qualification part that was not used into column qualified identifier. - * If additional column qualification parts consists from [database_name, table_name]. - * On first iteration if column is needed to be qualified to qualify it with table_name. - * On second iteration if column is needed to be qualified to qualify it with database_name. - */ - size_t part_index_to_use_for_qualification = additional_column_qualification_parts_size - i - 1; - const auto & part_to_use = additional_column_qualification_parts[part_index_to_use_for_qualification]; - column_qualified_identifier_parts.insert(column_qualified_identifier_parts.begin(), part_to_use); - } - else - { - break; - } - } - - auto qualified_node_name = Identifier(column_qualified_identifier_parts).getFullName(); - node_to_projection_name.emplace(column_node, qualified_node_name); - } -} - -/// Build get columns options for matcher -GetColumnsOptions QueryAnalyzer::buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context) -{ - auto & matcher_node_typed = matcher_node->as(); - UInt8 get_columns_options_kind = GetColumnsOptions::AllPhysicalAndAliases; - - if (matcher_node_typed.isAsteriskMatcher()) - { - get_columns_options_kind = GetColumnsOptions::Ordinary; - - const auto & settings = context->getSettingsRef(); - - if (settings.asterisk_include_alias_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Aliases; - - if (settings.asterisk_include_materialized_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Materialized; - } - - return GetColumnsOptions(static_cast(get_columns_options_kind)); -} - -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - /** Use resolved columns from table expression data in nearest query scope if available. - * It is important for ALIAS columns to use column nodes with resolved ALIAS expression. - */ - const TableExpressionData * table_expression_data = nullptr; - const auto * nearest_query_scope = scope.getNearestQueryScope(); - if (nearest_query_scope) - table_expression_data = &nearest_query_scope->getTableExpressionDataOrThrow(table_expression_node); - - QueryTreeNodes matched_column_nodes; - - for (const auto & column : matched_columns) - { - const auto & column_name = column.name; - if (!matcher_node_typed.isMatchingColumn(column_name)) - continue; - - if (table_expression_data) - { - auto column_node_it = table_expression_data->column_name_to_column_node.find(column_name); - if (column_node_it != table_expression_data->column_name_to_column_node.end()) - { - matched_column_nodes.emplace_back(column_node_it->second); - continue; - } - } - - matched_column_nodes.emplace_back(std::make_shared(column, table_expression_node)); - } - - const auto & qualify_matched_column_nodes_scope = nearest_query_scope ? *nearest_query_scope : scope; - qualifyColumnNodesWithProjectionNames(matched_column_nodes, table_expression_node, qualify_matched_column_nodes_scope); - - QueryAnalyzer::QueryTreeNodesWithNames matched_column_nodes_with_names; - matched_column_nodes_with_names.reserve(matched_column_nodes.size()); - - for (auto && matched_column_node : matched_column_nodes) - { - auto column_name = matched_column_node->as().getColumnName(); - matched_column_nodes_with_names.emplace_back(std::move(matched_column_node), std::move(column_name)); - } - - return matched_column_nodes_with_names; -} - -bool hasTableExpressionInJoinTree(const QueryTreeNodePtr & join_tree_node, const QueryTreeNodePtr & table_expression) -{ - QueryTreeNodes nodes_to_process; - nodes_to_process.push_back(join_tree_node); - - while (!nodes_to_process.empty()) - { - auto node_to_process = std::move(nodes_to_process.back()); - nodes_to_process.pop_back(); - if (node_to_process == table_expression) - return true; - - if (node_to_process->getNodeType() == QueryTreeNodeType::JOIN) - { - const auto & join_node = node_to_process->as(); - nodes_to_process.push_back(join_node.getLeftTableExpression()); - nodes_to_process.push_back(join_node.getRightTableExpression()); - } - } - return false; -} - -/// Columns that resolved from matcher can also match columns from JOIN USING. -/// In that case we update type to type of column in USING section. -/// TODO: It's not completely correct for qualified matchers, so t1.* should be resolved to left table column type. -/// But in planner we do not distinguish such cases. -void QueryAnalyzer::updateMatchedColumnsFromJoinUsing( - QueryTreeNodesWithNames & result_matched_column_nodes_with_names, - const QueryTreeNodePtr & source_table_expression, - IdentifierResolveScope & scope) -{ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "There are no table sources. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - const auto & join_tree = nearest_query_scope_query_node->getJoinTree(); - - const auto * join_node = join_tree->as(); - if (join_node && join_node->isUsingJoinExpression()) - { - const auto & join_using_list = join_node->getJoinExpression()->as(); - const auto & join_using_nodes = join_using_list.getNodes(); - - for (auto & [matched_column_node, _] : result_matched_column_nodes_with_names) - { - auto & matched_column_node_typed = matched_column_node->as(); - const auto & matched_column_name = matched_column_node_typed.getColumnName(); - - for (const auto & join_using_node : join_using_nodes) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (matched_column_name != join_using_column_name) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - auto it = node_to_projection_name.find(matched_column_node); - - if (hasTableExpressionInJoinTree(join_node->getLeftTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(0); - else if (hasTableExpressionInJoinTree(join_node->getRightTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(1); - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Cannot find column {} in JOIN USING section {}", - matched_column_node->dumpTree(), join_node->dumpTree()); - - matched_column_node = matched_column_node->clone(); - if (it != node_to_projection_name.end()) - node_to_projection_name.emplace(matched_column_node, it->second); - - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - } - } - } -} - -/** Resolve qualified tree matcher. - * - * First try to match qualified identifier to expression. If qualified identifier matched expression node then - * if expression is compound match it column names using matcher `isMatchingColumn` method, if expression is not compound, throw exception. - * If qualified identifier did not match expression in query tree, try to lookup qualified identifier in table context. - */ -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isQualified()); - - auto expression_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::EXPRESSION}; - auto expression_identifier_resolve_result = tryResolveIdentifier(expression_identifier_lookup, scope); - auto expression_query_tree_node = expression_identifier_resolve_result.resolved_identifier; - - /// Try to resolve unqualified matcher for query expression - - if (expression_query_tree_node) - { - auto result_type = expression_query_tree_node->getResultType(); - - while (true) - { - if (const auto * array_type = typeid_cast(result_type.get())) - result_type = array_type->getNestedType(); - else if (const auto * map_type = typeid_cast(result_type.get())) - result_type = map_type->getNestedType(); - else - break; - } - - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Qualified matcher {} find non compound expression {} with type {}. Expected tuple or array of tuples. In scope {}", - matcher_node->formatASTForErrorMessage(), - expression_query_tree_node->formatASTForErrorMessage(), - expression_query_tree_node->getResultType()->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - auto qualified_matcher_element_identifier = matcher_node_typed.getQualifiedIdentifier(); - for (const auto & element_name : element_names) - { - if (!matcher_node_typed.isMatchingColumn(element_name)) - continue; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back(expression_query_tree_node); - get_subcolumn_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - qualified_matcher_element_identifier.push_back(element_name); - node_to_projection_name.emplace(function_query_node, qualified_matcher_element_identifier.getFullName()); - qualified_matcher_element_identifier.pop_back(); - - matched_expression_nodes_with_column_names.emplace_back(std::move(function_query_node), element_name); - } - - return matched_expression_nodes_with_column_names; - } - - /// Try to resolve qualified matcher for table expression - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_cte = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - auto table_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, identifier_resolve_settings); - auto table_expression_node = table_identifier_resolve_result.resolved_identifier; - - if (!table_expression_node) - { - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Qualified matcher {} does not find table. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - NamesAndTypes matched_columns; - - auto * table_expression_query_node = table_expression_node->as(); - auto * table_expression_union_node = table_expression_node->as(); - auto * table_expression_table_node = table_expression_node->as(); - auto * table_expression_table_function_node = table_expression_node->as(); - - if (table_expression_query_node || table_expression_union_node) - { - matched_columns = table_expression_query_node ? table_expression_query_node->getProjectionColumns() - : table_expression_union_node->computeProjectionColumns(); - } - else if (table_expression_table_node || table_expression_table_function_node) - { - const auto & storage_snapshot = table_expression_table_node ? table_expression_table_node->getStorageSnapshot() - : table_expression_table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - matched_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Invalid table expression node {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto result_matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression_node, - matched_columns, - scope); - - updateMatchedColumnsFromJoinUsing(result_matched_column_nodes_with_names, table_expression_node, scope); - - return result_matched_column_nodes_with_names; -} - -/// Resolve non qualified matcher, using scope join tree node. -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isUnqualified()); - - /** There can be edge case if matcher is inside lambda expression. - * Try to find parent query expression using parent scopes. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unqualified matcher {} cannot be resolved. There are no table sources. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** For unqualifited matcher resolve we build table expressions stack from JOIN tree and then process it. - * For table, table function, query, union table expressions add matched columns into table expressions columns stack. - * For array join continue processing. - * For join node combine last left and right table expressions columns on stack together. It is important that if JOIN has USING - * we must add USING columns before combining left and right table expressions columns. Columns from left and right table - * expressions that have same names as columns in USING clause must be skipped. - */ - - auto table_expressions_stack = buildTableExpressionsStack(nearest_query_scope_query_node->getJoinTree()); - std::vector table_expressions_column_nodes_with_names_stack; - - std::unordered_set table_expression_column_names_to_skip; - - QueryTreeNodesWithNames result; - - if (matcher_node_typed.getMatcherType() == MatcherNodeType::COLUMNS_LIST) - { - auto identifiers = matcher_node_typed.getColumnsIdentifiers(); - result.reserve(identifiers.size()); - - for (const auto & identifier : identifiers) - { - auto resolve_result = tryResolveIdentifier(IdentifierLookup{identifier, IdentifierLookupContext::EXPRESSION}, scope); - if (!resolve_result.isResolved()) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Unknown identifier '{}' inside COLUMNS matcher. In scope {}", - identifier.getFullName(), scope.dump()); - - // TODO: Introduce IdentifierLookupContext::COLUMN and get rid of this check - auto * resolved_column = resolve_result.resolved_identifier->as(); - if (!resolved_column) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier '{}' inside COLUMNS matcher must resolve into a column, but got {}. In scope {}", - identifier.getFullName(), - resolve_result.resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - result.emplace_back(resolve_result.resolved_identifier, resolved_column->getColumnName()); - } - return result; - } - - result.resize(matcher_node_typed.getColumnsIdentifiers().size()); - - for (auto & table_expression : table_expressions_stack) - { - bool table_expression_in_resolve_process = nearest_query_scope->table_expressions_in_resolve_process.contains(table_expression.get()); - - if (auto * array_join_node = table_expression->as()) - { - if (table_expressions_column_nodes_with_names_stack.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 1 table expressions on stack before ARRAY JOIN processing"); - - if (table_expression_in_resolve_process) - continue; - - auto & table_expression_column_nodes_with_names = table_expressions_column_nodes_with_names_stack.back(); - - for (auto & [table_expression_column_node, _] : table_expression_column_nodes_with_names) - { - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(table_expression_column_node, - table_expression, - scope); - if (array_join_resolved_expression) - table_expression_column_node = std::move(array_join_resolved_expression); - } - - continue; - } - - auto * join_node = table_expression->as(); - - if (join_node) - { - size_t table_expressions_column_nodes_with_names_stack_size = table_expressions_column_nodes_with_names_stack.size(); - if (table_expressions_column_nodes_with_names_stack_size < 2) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 2 table expressions on stack before JOIN processing. Actual {}", - table_expressions_column_nodes_with_names_stack_size); - - auto right_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - auto left_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - table_expression_column_names_to_skip.clear(); - - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - /** If there is JOIN with USING we need to match only single USING column and do not use left table expression - * and right table expression column with same name. - * - * Example: SELECT id FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING (id); - */ - if (!table_expression_in_resolve_process && join_node->isUsingJoinExpression()) - { - auto & join_using_list = join_node->getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (!matcher_node_typed.isMatchingColumn(join_using_column_name)) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - /** If column doesn't exists in the table, then do not match column from USING clause. - * Example: SELECT a + 1 AS id, * FROM (SELECT 1 AS a) AS t1 JOIN (SELECT 2 AS id) AS t2 USING (id); - * In this case `id` is not present in the left table expression, - * so asterisk should return `id` from the right table expression. - */ - auto is_column_from_parent_scope = [&scope](const QueryTreeNodePtr & using_node_from_table) - { - const auto & using_column_from_table = using_node_from_table->as(); - auto table_expression_data_it = scope.table_expression_node_to_data.find(using_column_from_table.getColumnSource()); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - { - const auto & table_expression_data = table_expression_data_it->second; - const auto & column_name = using_column_from_table.getColumnName(); - return !table_expression_data.column_name_to_column_node.contains(column_name); - } - return false; - }; - - if (is_column_from_parent_scope(join_using_column_nodes.at(0)) || - is_column_from_parent_scope(join_using_column_nodes.at(1))) - continue; - - QueryTreeNodePtr matched_column_node; - - if (isRight(join_node->getKind())) - matched_column_node = join_using_column_nodes.at(1); - else - matched_column_node = join_using_column_nodes.at(0); - - matched_column_node = matched_column_node->clone(); - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - - table_expression_column_names_to_skip.insert(join_using_column_name); - matched_expression_nodes_with_column_names.emplace_back(std::move(matched_column_node), join_using_column_name); - } - } - - for (auto && left_table_column_with_name : left_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(left_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(left_table_column_with_name)); - } - - for (auto && right_table_column_with_name : right_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(right_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(right_table_column_with_name)); - } - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_expression_nodes_with_column_names)); - continue; - } - - if (table_expression_in_resolve_process) - { - table_expressions_column_nodes_with_names_stack.emplace_back(); - continue; - } - - auto * table_node = table_expression->as(); - auto * table_function_node = table_expression->as(); - auto * query_node = table_expression->as(); - auto * union_node = table_expression->as(); - - NamesAndTypes table_expression_columns; - - if (query_node || union_node) - { - table_expression_columns = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - } - else if (table_node || table_function_node) - { - const auto & storage_snapshot - = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - table_expression_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unqualified matcher {} resolve unexpected table expression. In scope {}", - matcher_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression, - table_expression_columns, - scope); - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_column_nodes_with_names)); - } - - for (auto & table_expression_column_nodes_with_names : table_expressions_column_nodes_with_names_stack) - { - for (auto && table_expression_column_node_with_name : table_expression_column_nodes_with_names) - result.push_back(std::move(table_expression_column_node_with_name)); - } - - return result; -} - - -/** Resolve query tree matcher. Check MatcherNode.h for detailed matcher description. Check ColumnTransformers.h for detailed transformers description. - * - * 1. Populate matched expression nodes resolving qualified or unqualified matcher. - * 2. Apply column transformers to matched expression nodes. For strict column transformers save used column names. - * 3. Validate strict column transformers. - */ -ProjectionNames QueryAnalyzer::resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - QueryTreeNodesWithNames matched_expression_nodes_with_names; - - if (matcher_node_typed.isQualified()) - matched_expression_nodes_with_names = resolveQualifiedMatcher(matcher_node, scope); - else - matched_expression_nodes_with_names = resolveUnqualifiedMatcher(matcher_node, scope); - - if (scope.join_use_nulls) - { - /** If we are resolving matcher came from the result of JOIN and `join_use_nulls` is set, - * we need to convert joined column type to Nullable. - * We are taking the nearest JoinNode to check to which table column belongs, - * because for LEFT/RIGHT join, we convert only the corresponding side. - */ - const auto * nearest_query_scope = scope.getNearestQueryScope(); - const QueryNode * nearest_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - const QueryTreeNodePtr & nearest_scope_join_tree = nearest_scope_query_node ? nearest_scope_query_node->getJoinTree() : nullptr; - const JoinNode * nearest_scope_join_node = nearest_scope_join_tree ? nearest_scope_join_tree->as() : nullptr; - if (nearest_scope_join_node) - { - for (auto & [node, node_name] : matched_expression_nodes_with_names) - { - auto join_identifier_side = getColumnSideFromJoinTree(node, *nearest_scope_join_node); - auto projection_name_it = node_to_projection_name.find(node); - auto nullable_node = convertJoinedColumnTypeToNullIfNeeded(node, nearest_scope_join_node->getKind(), join_identifier_side, scope); - if (nullable_node) - { - node = nullable_node; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(node, projection_name_it->second); - } - } - } - } - } - - if (!scope.expressions_in_resolve_process_stack.hasAggregateFunction()) - { - for (auto & [node, _] : matched_expression_nodes_with_names) - { - auto it = scope.nullable_group_by_keys.find(node); - if (it != scope.nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - } - } - } - - std::unordered_map> strict_transformer_to_used_column_names; - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - auto * except_transformer = transformer->as(); - auto * replace_transformer = transformer->as(); - - if (except_transformer && except_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(except_transformer, std::unordered_set()); - else if (replace_transformer && replace_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(replace_transformer, std::unordered_set()); - } - - ListNodePtr list = std::make_shared(); - ProjectionNames result_projection_names; - ProjectionNames node_projection_names; - - for (auto & [node, column_name] : matched_expression_nodes_with_names) - { - bool apply_transformer_was_used = false; - bool replace_transformer_was_used = false; - bool execute_apply_transformer = false; - bool execute_replace_transformer = false; - - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - else - result_projection_names.push_back(column_name); - - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - if (auto * apply_transformer = transformer->as()) - { - const auto & expression_node = apply_transformer->getExpressionNode(); - apply_transformer_was_used = true; - - if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::LAMBDA) - { - auto lambda_expression_to_resolve = expression_node->clone(); - IdentifierResolveScope lambda_scope(expression_node, &scope /*parent_scope*/); - node_projection_names = resolveLambda(expression_node, lambda_expression_to_resolve, {node}, lambda_scope); - auto & lambda_expression_to_resolve_typed = lambda_expression_to_resolve->as(); - node = lambda_expression_to_resolve_typed.getExpression(); - } - else if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::FUNCTION) - { - auto function_to_resolve_untyped = expression_node->clone(); - auto & function_to_resolve_typed = function_to_resolve_untyped->as(); - function_to_resolve_typed.getArguments().getNodes().push_back(node); - node_projection_names = resolveFunction(function_to_resolve_untyped, scope); - node = function_to_resolve_untyped; - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unsupported apply matcher expression type. Expected lambda or function apply transformer. Actual {}. In scope {}", - transformer->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - execute_apply_transformer = true; - } - else if (auto * except_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - if (except_transformer->isColumnMatching(column_name)) - { - if (except_transformer->isStrict()) - strict_transformer_to_used_column_names[except_transformer].insert(column_name); - - node = {}; - break; - } - } - else if (auto * replace_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - auto replace_expression = replace_transformer->findReplacementExpression(column_name); - if (!replace_expression) - continue; - - replace_transformer_was_used = true; - - if (replace_transformer->isStrict()) - strict_transformer_to_used_column_names[replace_transformer].insert(column_name); - - node = replace_expression->clone(); - node_projection_names = resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** If replace expression resolved as single node, we want to use replace column name as result projection name, instead - * of using replace expression projection name. - * - * Example: SELECT * REPLACE id + 5 AS id FROM test_table; - */ - if (node_projection_names.size() == 1) - node_projection_names[0] = column_name; - - execute_replace_transformer = true; - } - - if (execute_apply_transformer || execute_replace_transformer) - { - if (auto * node_list = node->as()) - { - auto & node_list_nodes = node_list->getNodes(); - size_t node_list_nodes_size = node_list_nodes.size(); - - if (node_list_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "{} transformer {} resolved as list node with size {}. Expected 1. In scope {}", - execute_apply_transformer ? "APPLY" : "REPLACE", - transformer->formatASTForErrorMessage(), - node_list_nodes_size, - scope.scope_node->formatASTForErrorMessage()); - - node = node_list_nodes[0]; - } - - if (node_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Matcher node expected 1 projection name. Actual {}", node_projection_names.size()); - - result_projection_names.back() = std::move(node_projection_names[0]); - node_to_projection_name.emplace(node, result_projection_names.back()); - node_projection_names.clear(); - } - } - - if (node) - list->getNodes().push_back(node); - else - result_projection_names.pop_back(); - } - - for (auto & [strict_transformer, used_column_names] : strict_transformer_to_used_column_names) - { - auto strict_transformer_type = strict_transformer->getTransformerType(); - const Names * strict_transformer_column_names = nullptr; - - switch (strict_transformer_type) - { - case ColumnTransfomerType::EXCEPT: - { - const auto * except_transformer = static_cast(strict_transformer); - const auto & except_names = except_transformer->getExceptColumnNames(); - - if (except_names.size() != used_column_names.size()) - strict_transformer_column_names = &except_transformer->getExceptColumnNames(); - - break; - } - case ColumnTransfomerType::REPLACE: - { - const auto * replace_transformer = static_cast(strict_transformer); - const auto & replacement_names = replace_transformer->getReplacementsNames(); - - if (replacement_names.size() != used_column_names.size()) - strict_transformer_column_names = &replace_transformer->getReplacementsNames(); - - break; - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected strict EXCEPT or REPLACE column transformer. Actual type {}. In scope {}", - toString(strict_transformer_type), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (!strict_transformer_column_names) - continue; - - Names non_matched_column_names; - size_t strict_transformer_column_names_size = strict_transformer_column_names->size(); - for (size_t i = 0; i < strict_transformer_column_names_size; ++i) - { - const auto & column_name = (*strict_transformer_column_names)[i]; - if (used_column_names.find(column_name) == used_column_names.end()) - non_matched_column_names.push_back(column_name); - } - - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Strict {} column transformer {} expects following column(s) : {}. In scope {}", - toString(strict_transformer_type), - strict_transformer->formatASTForErrorMessage(), - fmt::join(non_matched_column_names, ", "), - scope.scope_node->formatASTForErrorMessage()); - } - - auto original_ast = matcher_node->getOriginalAST(); - matcher_node = std::move(list); - if (original_ast) - matcher_node->setOriginalAST(original_ast); - - return result_projection_names; -} - -/** Resolve window function window node. - * - * Node can be identifier or window node. - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - * Example: SELECT count(*) OVER (PARTITION BY id); - * - * If node has parent window name specified, then parent window definition is searched in nearest query scope WINDOW section. - * If node is identifier, than node is replaced with window definition. - * If node is window, that window node is merged with parent window node. - * - * Window node PARTITION BY and ORDER BY parts are resolved. - * If window node has frame begin OFFSET or frame end OFFSET specified, they are resolved, and window node frame constants are updated. - * Window node frame is validated. - */ -ProjectionName QueryAnalyzer::resolveWindow(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - std::string parent_window_name; - auto * identifier_node = node->as(); - - ProjectionName result_projection_name; - QueryTreeNodePtr parent_window_node; - - if (identifier_node) - parent_window_name = identifier_node->getIdentifier().getFullName(); - else if (auto * window_node = node->as()) - parent_window_name = window_node->getParentWindowName(); - - if (!parent_window_name.empty()) - { - auto * nearest_query_scope = scope.getNearestQueryScope(); - - if (!nearest_query_scope) - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Window '{}' does not exist.", parent_window_name); - - auto & scope_window_name_to_window_node = nearest_query_scope->window_name_to_window_node; - - auto window_node_it = scope_window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope_window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - nearest_query_scope->scope_node->formatASTForErrorMessage()); - - parent_window_node = window_node_it->second; - - if (identifier_node) - { - node = parent_window_node->clone(); - result_projection_name = parent_window_name; - } - else - { - mergeWindowWithParentWindow(node, parent_window_node, scope); - } - } - - auto & window_node = node->as(); - window_node.setParentWindowName({}); - - ProjectionNames partition_by_projection_names = resolveExpressionNodeList(window_node.getPartitionByNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - ProjectionNames order_by_projection_names = resolveSortNodeList(window_node.getOrderByNode(), scope); - - ProjectionNames frame_begin_offset_projection_names; - ProjectionNames frame_end_offset_projection_names; - - if (window_node.hasFrameBeginOffset()) - { - frame_begin_offset_projection_names = resolveExpressionNode(window_node.getFrameBeginOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_begin_constant_node = window_node.getFrameBeginOffsetNode()->as(); - if (!window_frame_begin_constant_node || !isNativeNumber(removeNullable(window_frame_begin_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameBeginOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().begin_offset = window_frame_begin_constant_node->getValue(); - if (frame_begin_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_begin_offset_projection_names.size()); - } - - if (window_node.hasFrameEndOffset()) - { - frame_end_offset_projection_names = resolveExpressionNode(window_node.getFrameEndOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_end_constant_node = window_node.getFrameEndOffsetNode()->as(); - if (!window_frame_end_constant_node || !isNativeNumber(removeNullable(window_frame_end_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameEndOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().end_offset = window_frame_end_constant_node->getValue(); - if (frame_end_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_end_offset_projection_names.size()); - } - - window_node.getWindowFrame().checkValid(); - - if (result_projection_name.empty()) - { - result_projection_name = calculateWindowProjectionName(node, - parent_window_node, - parent_window_name, - partition_by_projection_names, - order_by_projection_names, - frame_begin_offset_projection_names.empty() ? "" : frame_begin_offset_projection_names.front(), - frame_end_offset_projection_names.empty() ? "" : frame_end_offset_projection_names.front()); - } - - return result_projection_name; -} - -/** Resolve lambda function. - * This function modified lambda_node during resolve. It is caller responsibility to clone lambda before resolve - * if it is needed for later use. - * - * Lambda body expression result projection names is used as lambda projection names. - * - * Lambda expression can be resolved into list node. It is caller responsibility to handle it properly. - * - * lambda_node - node that must have LambdaNode type. - * lambda_node_to_resolve - lambda node to resolve that must have LambdaNode type. - * arguments - lambda arguments. - * scope - lambda scope. It is client responsibility to create it. - * - * Resolve steps: - * 1. Validate arguments. - * 2. Register lambda node in lambdas in resolve process. This is necessary to prevent recursive lambda resolving. - * 3. Initialize scope with lambda aliases. - * 4. Validate lambda argument names, and scope expressions. - * 5. Resolve lambda body expression. - * 6. Deregister lambda node from lambdas in resolve process. - */ -ProjectionNames QueryAnalyzer::resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope) -{ - auto & lambda_to_resolve = lambda_node_to_resolve->as(); - auto & lambda_arguments_nodes = lambda_to_resolve.getArguments().getNodes(); - size_t lambda_arguments_nodes_size = lambda_arguments_nodes.size(); - - /** Register lambda as being resolved, to prevent recursive lambdas resolution. - * Example: WITH (x -> x + lambda_2(x)) AS lambda_1, (x -> x + lambda_1(x)) AS lambda_2 SELECT 1; - */ - auto it = lambdas_in_resolve_process.find(lambda_node.get()); - if (it != lambdas_in_resolve_process.end()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive lambda {}. In scope {}", - lambda_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - lambdas_in_resolve_process.emplace(lambda_node.get()); - - size_t arguments_size = lambda_arguments.size(); - if (lambda_arguments_nodes_size != arguments_size) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} expect {} arguments. Actual {}. In scope {}", - lambda_to_resolve.formatASTForErrorMessage(), - lambda_arguments_nodes_size, - arguments_size, - scope.scope_node->formatASTForErrorMessage()); - - /// Initialize aliases in lambda scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - visitor.visit(lambda_to_resolve.getExpression()); - - /** Replace lambda arguments with new arguments. - * Additionally validate that there are no aliases with same name as lambda arguments. - * Arguments are registered in current scope expression_argument_name_to_node map. - */ - QueryTreeNodes lambda_new_arguments_nodes; - lambda_new_arguments_nodes.reserve(lambda_arguments_nodes_size); - - for (size_t i = 0; i < lambda_arguments_nodes_size; ++i) - { - auto & lambda_argument_node = lambda_arguments_nodes[i]; - const auto * lambda_argument_identifier = lambda_argument_node->as(); - const auto * lambda_argument_column = lambda_argument_node->as(); - if (!lambda_argument_identifier && !lambda_argument_column) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected IDENTIFIER or COLUMN as lambda argument, got {}", lambda_node->dumpTree()); - const auto & lambda_argument_name = lambda_argument_identifier ? lambda_argument_identifier->getIdentifier().getFullName() - : lambda_argument_column->getColumnName(); - - bool has_expression_node = scope.aliases.alias_name_to_expression_node->contains(lambda_argument_name); - bool has_alias_node = scope.aliases.alias_name_to_lambda_node.contains(lambda_argument_name); - - if (has_expression_node || has_alias_node) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Alias name '{}' inside lambda {} cannot have same name as lambda argument. In scope {}", - lambda_argument_name, - lambda_argument_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - scope.expression_argument_name_to_node.emplace(lambda_argument_name, lambda_arguments[i]); - lambda_new_arguments_nodes.push_back(lambda_arguments[i]); - } - - lambda_to_resolve.getArguments().getNodes() = std::move(lambda_new_arguments_nodes); - - /// Lambda body expression is resolved as standard query expression node. - auto result_projection_names = resolveExpressionNode(lambda_to_resolve.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - lambdas_in_resolve_process.erase(lambda_node.get()); - - return result_projection_names; -} - -namespace -{ -void checkFunctionNodeHasEmptyNullsAction(FunctionNode const & node) -{ - if (node.getNullsAction() != NullsAction::EMPTY) - throw Exception( - ErrorCodes::SYNTAX_ERROR, - "Function with name '{}' cannot use {} NULLS", - node.getFunctionName(), - node.getNullsAction() == NullsAction::IGNORE_NULLS ? "IGNORE" : "RESPECT"); -} -} - -/** Resolve function node in scope. - * During function node resolve, function node can be replaced with another expression (if it match lambda or sql user defined function), - * with constant (if it allow constant folding), or with expression list. It is caller responsibility to handle such cases appropriately. - * - * Steps: - * 1. Resolve function parameters. Validate that each function parameter must be constant node. - * 2. Try to lookup function as lambda in current scope. If it is lambda we can skip `in` and `count` special handling. - * 3. If function is count function, that take unqualified ASTERISK matcher, remove it from its arguments. Example: SELECT count(*) FROM test_table; - * 4. If function is `IN` function, then right part of `IN` function is replaced as subquery. - * 5. Resolve function arguments list, lambda expressions are allowed as function arguments. - * For `IN` function table expressions are allowed as function arguments. - * 6. Initialize argument_columns, argument_types, function_lambda_arguments_indexes arrays from function arguments. - * 7. If function name identifier was not resolved as function in current scope, try to lookup lambda from sql user defined functions factory. - * 8. If function was resolve as lambda from step 2 or 7, then resolve lambda using function arguments and replace function node with lambda result. - * After than function node is resolved. - * 9. If function was not resolved during step 6 as lambda, then try to resolve function as window function or executable user defined function - * or ordinary function or aggregate function. - * - * If function is resolved as window function or executable user defined function or aggregate function, function node is resolved - * no additional special handling is required. - * - * 8. If function was resolved as non aggregate function. Then if some of function arguments are lambda expressions, their result types need to be initialized and - * they must be resolved. - * 9. If function is suitable for constant folding, try to perform constant folding for function node. - */ -ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - FunctionNodePtr function_node_ptr = std::static_pointer_cast(node); - auto function_name = function_node_ptr->getFunctionName(); - - /// Resolve function parameters - - auto parameters_projection_names = resolveExpressionNodeList(function_node_ptr->getParametersNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - /// Convert function parameters into constant parameters array - - Array parameters; - - auto & parameters_nodes = function_node_ptr->getParameters().getNodes(); - parameters.reserve(parameters_nodes.size()); - - for (auto & parameter_node : parameters_nodes) - { - const auto * constant_node = parameter_node->as(); - if (!constant_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parameter for function '{}' expected to have constant value. Actual {}. In scope {}", - function_name, - parameter_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - parameters.push_back(constant_node->getValue()); - } - - //// If function node is not window function try to lookup function node name as lambda identifier. - QueryTreeNodePtr lambda_expression_untyped; - if (!function_node_ptr->isWindowFunction()) - { - auto function_lookup_result = tryResolveIdentifier({Identifier{function_name}, IdentifierLookupContext::FUNCTION}, scope); - lambda_expression_untyped = function_lookup_result.resolved_identifier; - } - - bool is_special_function_in = false; - bool is_special_function_dict_get = false; - bool is_special_function_join_get = false; - bool is_special_function_exists = false; - bool is_special_function_if = false; - - if (!lambda_expression_untyped) - { - is_special_function_in = isNameOfInFunction(function_name); - is_special_function_dict_get = functionIsDictGet(function_name); - is_special_function_join_get = functionIsJoinGet(function_name); - is_special_function_exists = function_name == "exists"; - is_special_function_if = function_name == "if"; - - auto function_name_lowercase = Poco::toLower(function_name); - - /** Special handling for count and countState functions. - * - * Example: SELECT count(*) FROM test_table - * Example: SELECT countState(*) FROM test_table; - */ - if (function_node_ptr->getArguments().getNodes().size() == 1 && - (function_name_lowercase == "count" || function_name_lowercase == "countstate")) - { - auto * matcher_node = function_node_ptr->getArguments().getNodes().front()->as(); - if (matcher_node && matcher_node->isUnqualified()) - function_node_ptr->getArguments().getNodes().clear(); - } - } - - /** Special functions dictGet and its variations and joinGet can be executed when first argument is identifier. - * Example: SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Try to resolve identifier as expression identifier and if it is resolved use it. - * Example: WITH 'dict_name' AS identifier SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Otherwise replace identifier with identifier full name constant. - * Validation that dictionary exists or table exists will be performed during function `getReturnType` method call. - */ - if ((is_special_function_dict_get || is_special_function_join_get) && - !function_node_ptr->getArguments().getNodes().empty() && - function_node_ptr->getArguments().getNodes()[0]->getNodeType() == QueryTreeNodeType::IDENTIFIER) - { - auto & first_argument = function_node_ptr->getArguments().getNodes()[0]; - auto & first_argument_identifier = first_argument->as(); - auto identifier = first_argument_identifier.getIdentifier(); - - IdentifierLookup identifier_lookup{identifier, IdentifierLookupContext::EXPRESSION}; - auto resolve_result = tryResolveIdentifier(identifier_lookup, scope); - - if (resolve_result.isResolved()) - { - first_argument = std::move(resolve_result.resolved_identifier); - } - else - { - size_t parts_size = identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected {} function first argument identifier to contain 1 or 2 parts. Actual '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_special_function_dict_get) - { - scope.context->getExternalDictionariesLoader().assertDictionaryStructureExists(identifier.getFullName(), scope.context); - } - else - { - auto table_node = tryResolveTableIdentifierFromDatabaseCatalog(identifier, scope.context); - if (!table_node) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} first argument expected table identifier '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node_typed = table_node->as(); - if (!std::dynamic_pointer_cast(table_node_typed.getStorage())) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} table '{}' should have engine StorageJoin. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - first_argument = std::make_shared(identifier.getFullName()); - } - } - - if (is_special_function_exists) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /// Rewrite EXISTS (subquery) into 1 IN (SELECT 1 FROM (subquery) LIMIT 1). - auto & exists_subquery_argument = function_node_ptr->getArguments().getNodes().at(0); - - auto constant_data_type = std::make_shared(); - - auto in_subquery = std::make_shared(Context::createCopy(scope.context)); - in_subquery->setIsSubquery(true); - in_subquery->getProjection().getNodes().push_back(std::make_shared(1UL, constant_data_type)); - in_subquery->getJoinTree() = exists_subquery_argument; - in_subquery->getLimit() = std::make_shared(1UL, constant_data_type); - - function_node_ptr = std::make_shared("in"); - function_node_ptr->getArguments().getNodes() = {std::make_shared(1UL, constant_data_type), in_subquery}; - node = function_node_ptr; - function_name = "in"; - is_special_function_in = true; - } - - if (is_special_function_if && !function_node_ptr->getArguments().getNodes().empty()) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /** Handle special case with constant If function, even if some of the arguments are invalid. - * - * SELECT if(hasColumnInTable('system', 'numbers', 'not_existing_column'), not_existing_column, 5) FROM system.numbers; - */ - auto & if_function_arguments = function_node_ptr->getArguments().getNodes(); - auto if_function_condition = if_function_arguments[0]; - resolveExpressionNode(if_function_condition, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto constant_condition = tryExtractConstantFromConditionNode(if_function_condition); - - if (constant_condition.has_value() && if_function_arguments.size() == 3) - { - QueryTreeNodePtr constant_if_result_node; - QueryTreeNodePtr possibly_invalid_argument_node; - - if (*constant_condition) - { - possibly_invalid_argument_node = if_function_arguments[2]; - constant_if_result_node = if_function_arguments[1]; - } - else - { - possibly_invalid_argument_node = if_function_arguments[1]; - constant_if_result_node = if_function_arguments[2]; - } - - bool apply_constant_if_optimization = false; - - try - { - resolveExpressionNode(possibly_invalid_argument_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - } - catch (...) - { - apply_constant_if_optimization = true; - } - - if (apply_constant_if_optimization) - { - auto result_projection_names = resolveExpressionNode(constant_if_result_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - node = std::move(constant_if_result_node); - return result_projection_names; - } - } - } - - /// Resolve function arguments - bool allow_table_expressions = is_special_function_in; - auto arguments_projection_names = resolveExpressionNodeList(function_node_ptr->getArgumentsNode(), - scope, - true /*allow_lambda_expression*/, - allow_table_expressions /*allow_table_expression*/); - - /// Mask arguments if needed - if (!scope.context->getSettingsRef().format_display_secrets_in_show_and_select) - { - if (FunctionSecretArgumentsFinder::Result secret_arguments = FunctionSecretArgumentsFinderTreeNode(*function_node_ptr).getResult(); secret_arguments.count) - { - auto & argument_nodes = function_node_ptr->getArgumentsNode()->as().getNodes(); - - for (size_t n = secret_arguments.start; n < secret_arguments.start + secret_arguments.count; ++n) - { - if (auto * constant = argument_nodes[n]->as()) - { - auto mask = scope.projection_mask_map->insert({constant->getTreeHash(), scope.projection_mask_map->size() + 1}).first->second; - constant->setMaskId(mask); - arguments_projection_names[n] = "[HIDDEN id: " + std::to_string(mask) + "]"; - } - } - } - } - - auto & function_node = *function_node_ptr; - - /// Replace right IN function argument if it is table or table function with subquery that read ordinary columns - if (is_special_function_in) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - if (scope.context->getSettingsRef().transform_null_in) - { - static constexpr std::array, 4> in_function_to_replace_null_in_function_map = - {{ - {"in", "nullIn"}, - {"notIn", "notNullIn"}, - {"globalIn", "globalNullIn"}, - {"globalNotIn", "globalNotNullIn"}, - }}; - - for (const auto & [in_function_name, in_function_name_to_replace] : in_function_to_replace_null_in_function_map) - { - if (function_name == in_function_name) - { - function_name = in_function_name_to_replace; - break; - } - } - } - - auto & function_in_arguments_nodes = function_node.getArguments().getNodes(); - if (function_in_arguments_nodes.size() != 2) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function '{}' expects 2 arguments", function_name); - - auto & in_second_argument = function_in_arguments_nodes[1]; - auto * table_node = in_second_argument->as(); - auto * table_function_node = in_second_argument->as(); - - if (table_node) - { - /// If table is already prepared set, we do not replace it with subquery. - /// If table is not a StorageSet, we'll create plan to build set in the Planner. - } - else if (table_function_node) - { - const auto & storage_snapshot = table_function_node->getStorageSnapshot(); - auto columns_to_select = storage_snapshot->getColumns(GetColumnsOptions(GetColumnsOptions::Ordinary)); - - size_t columns_to_select_size = columns_to_select.size(); - - auto column_nodes_to_select = std::make_shared(); - column_nodes_to_select->getNodes().reserve(columns_to_select_size); - - NamesAndTypes projection_columns; - projection_columns.reserve(columns_to_select_size); - - for (auto & column : columns_to_select) - { - column_nodes_to_select->getNodes().emplace_back(std::make_shared(column, in_second_argument)); - projection_columns.emplace_back(column.name, column.type); - } - - auto in_second_argument_query_node = std::make_shared(Context::createCopy(scope.context)); - in_second_argument_query_node->setIsSubquery(true); - in_second_argument_query_node->getProjectionNode() = std::move(column_nodes_to_select); - in_second_argument_query_node->getJoinTree() = std::move(in_second_argument); - in_second_argument_query_node->resolveProjectionColumns(std::move(projection_columns)); - - in_second_argument = std::move(in_second_argument_query_node); - } - else - { - /// Replace storage with values storage of insertion block - if (StoragePtr storage = scope.context->getViewSource()) - { - QueryTreeNodePtr table_expression; - /// Process possibly nested sub-selects - for (auto * query_node = in_second_argument->as(); query_node; query_node = table_expression->as()) - table_expression = extractLeftTableExpression(query_node->getJoinTree()); - - if (table_expression) - { - if (auto * query_table_node = table_expression->as()) - { - if (query_table_node->getStorageID().getFullNameNotQuoted() == storage->getStorageID().getFullNameNotQuoted()) - { - auto replacement_table_expression = std::make_shared(storage, scope.context); - if (std::optional table_expression_modifiers = query_table_node->getTableExpressionModifiers()) - replacement_table_expression->setTableExpressionModifiers(*table_expression_modifiers); - in_second_argument = in_second_argument->cloneAndReplace(table_expression, std::move(replacement_table_expression)); - } - } - } - } - - resolveExpressionNode(in_second_argument, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - } - } - - /// Initialize function argument columns - - ColumnsWithTypeAndName argument_columns; - DataTypes argument_types; - bool all_arguments_constants = true; - std::vector function_lambda_arguments_indexes; - - auto & function_arguments = function_node.getArguments().getNodes(); - size_t function_arguments_size = function_arguments.size(); - - for (size_t function_argument_index = 0; function_argument_index < function_arguments_size; ++function_argument_index) - { - auto & function_argument = function_arguments[function_argument_index]; - - ColumnWithTypeAndName argument_column; - argument_column.name = arguments_projection_names[function_argument_index]; - - /** If function argument is lambda, save lambda argument index and initialize argument type as DataTypeFunction - * where function argument types are initialized with empty array of lambda arguments size. - */ - if (const auto * lambda_node = function_argument->as()) - { - size_t lambda_arguments_size = lambda_node->getArguments().getNodes().size(); - argument_column.type = std::make_shared(DataTypes(lambda_arguments_size, nullptr), nullptr); - function_lambda_arguments_indexes.push_back(function_argument_index); - } - else if (is_special_function_in && function_argument_index == 1) - { - argument_column.type = std::make_shared(); - } - else - { - argument_column.type = function_argument->getResultType(); - } - - if (!argument_column.type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' argument is not resolved. In scope {}", - function_name, - scope.scope_node->formatASTForErrorMessage()); - - bool argument_is_constant = false; - const auto * constant_node = function_argument->as(); - if (constant_node) - { - argument_column.column = constant_node->getResultType()->createColumnConst(1, constant_node->getValue()); - argument_column.type = constant_node->getResultType(); - argument_is_constant = true; - } - else if (const auto * get_scalar_function_node = function_argument->as(); - get_scalar_function_node && get_scalar_function_node->getFunctionName() == "__getScalar") - { - /// Allow constant folding through getScalar - const auto * get_scalar_const_arg = get_scalar_function_node->getArguments().getNodes().at(0)->as(); - if (get_scalar_const_arg && scope.context->hasQueryContext()) - { - auto query_context = scope.context->getQueryContext(); - auto scalar_string = toString(get_scalar_const_arg->getValue()); - if (query_context->hasScalar(scalar_string)) - { - auto scalar = query_context->getScalar(scalar_string); - argument_column.column = ColumnConst::create(scalar.getByPosition(0).column, 1); - argument_column.type = get_scalar_function_node->getResultType(); - argument_is_constant = true; - } - } - } - - all_arguments_constants &= argument_is_constant; - - argument_types.push_back(argument_column.type); - argument_columns.emplace_back(std::move(argument_column)); - } - - /// Calculate function projection name - ProjectionNames result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - - /** Try to resolve function as - * 1. Lambda function in current scope. Example: WITH (x -> x + 1) AS lambda SELECT lambda(1); - * 2. Lambda function from sql user defined functions. - * 3. Special `untuple` function. - * 4. Special `grouping` function. - * 5. Window function. - * 6. Executable user defined function. - * 7. Ordinary function. - * 8. Aggregate function. - * - * TODO: Provide better error hints. - */ - if (!function_node.isWindowFunction()) - { - if (!lambda_expression_untyped) - lambda_expression_untyped = tryGetLambdaFromSQLUserDefinedFunctions(function_node.getFunctionName(), scope.context); - - /** If function is resolved as lambda. - * Clone lambda before resolve. - * Initialize lambda arguments as function arguments. - * Resolve lambda and then replace function node with resolved lambda expression body. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(value) FROM test_table; - * Result: SELECT value + 1 FROM test_table; - */ - if (lambda_expression_untyped) - { - auto * lambda_expression = lambda_expression_untyped->as(); - if (!lambda_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function identifier '{}' must be resolved as lambda. Actual {}. In scope {}", - function_node.getFunctionName(), - lambda_expression_untyped->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - if (!parameters.empty()) - { - throw Exception( - ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_node.formatASTForErrorMessage()); - } - - auto lambda_expression_clone = lambda_expression_untyped->clone(); - - IdentifierResolveScope lambda_scope(lambda_expression_clone, &scope /*parent_scope*/); - ProjectionNames lambda_projection_names = resolveLambda(lambda_expression_untyped, lambda_expression_clone, function_arguments, lambda_scope); - - auto & resolved_lambda = lambda_expression_clone->as(); - node = resolved_lambda.getExpression(); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(lambda_projection_names); - - return result_projection_names; - } - - if (function_name == "untuple") - { - /// Special handling of `untuple` function - - if (function_arguments.size() != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' must have 1 argument. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - const auto & untuple_argument = function_arguments[0]; - /// Handle this special case first as `getResultType()` might return nullptr - if (untuple_argument->as()) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Function untuple can't have lambda-expressions as arguments"); - - auto result_type = untuple_argument->getResultType(); - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' argument must have compound type. Actual type {}. In scope {}", - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - - auto result_list = std::make_shared(); - result_list->getNodes().reserve(element_names.size()); - - for (const auto & element_name : element_names) - { - auto tuple_element_function = std::make_shared("tupleElement"); - tuple_element_function->getArguments().getNodes().push_back(untuple_argument); - tuple_element_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = tuple_element_function; - resolveFunction(function_query_node, scope); - - result_list->getNodes().push_back(std::move(function_query_node)); - } - - auto untuple_argument_projection_name = arguments_projection_names.at(0); - result_projection_names.clear(); - - for (const auto & element_name : element_names) - { - if (node->hasAlias()) - result_projection_names.push_back(node->getAlias() + '.' + element_name); - else - result_projection_names.push_back(fmt::format("tupleElement({}, '{}')", untuple_argument_projection_name, element_name)); - } - - node = std::move(result_list); - return result_projection_names; - } - else if (function_name == "grouping") - { - /// It is responsibility of planner to perform additional handling of grouping function - if (function_arguments_size == 0) - throw Exception(ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING expects at least one argument"); - else if (function_arguments_size > 64) - throw Exception(ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING can have up to 64 arguments, but {} provided", - function_arguments_size); - checkFunctionNodeHasEmptyNullsAction(function_node); - - bool force_grouping_standard_compatibility = scope.context->getSettingsRef().force_grouping_standard_compatibility; - auto grouping_function = std::make_shared(force_grouping_standard_compatibility); - auto grouping_function_adaptor = std::make_shared(std::move(grouping_function)); - function_node.resolveAsFunction(grouping_function_adaptor->build(argument_columns)); - - return result_projection_names; - } - } - - if (function_node.isWindowFunction()) - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - throw Exception(ErrorCodes::UNKNOWN_AGGREGATE_FUNCTION, "Aggregate function with name '{}' does not exist. In scope {}{}", - function_name, scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(AggregateFunctionFactory::instance().getHints(function_name))); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Window function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsWindowFunction(std::move(aggregate_function)); - - bool window_node_is_identifier = function_node.getWindowNode()->getNodeType() == QueryTreeNodeType::IDENTIFIER; - ProjectionName window_projection_name = resolveWindow(function_node.getWindowNode(), scope); - - if (window_node_is_identifier) - result_projection_names[0] += " OVER " + window_projection_name; - else - result_projection_names[0] += " OVER (" + window_projection_name + ')'; - - return result_projection_names; - } - - FunctionOverloadResolverPtr function = UserDefinedExecutableFunctionFactory::instance().tryGet(function_name, scope.context, parameters); /// NOLINT(readability-static-accessed-through-instance) - bool is_executable_udf = true; - - IdentifierResolveScope::ResolvedFunctionsCache * function_cache = nullptr; - - if (!function) - { - /// This is a hack to allow a query like `select randConstant(), randConstant(), randConstant()`. - /// Function randConstant() would return the same value for the same arguments (in scope). - - auto hash = function_node_ptr->getTreeHash(); - function_cache = &scope.functions_cache[hash]; - if (!function_cache->resolver) - function_cache->resolver = FunctionFactory::instance().tryGet(function_name, scope.context); - - function = function_cache->resolver; - - is_executable_udf = false; - } - - if (function) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - } - else - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - std::vector possible_function_names; - - auto function_names = UserDefinedExecutableFunctionFactory::instance().getRegisteredNames(scope.context); /// NOLINT(readability-static-accessed-through-instance) - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = UserDefinedSQLFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = FunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = AggregateFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - for (auto & [name, lambda_node] : scope.aliases.alias_name_to_lambda_node) - { - if (lambda_node->getNodeType() == QueryTreeNodeType::LAMBDA) - possible_function_names.push_back(name); - } - - auto hints = NamePrompter<2>::getHints(function_name, possible_function_names); - - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Function with name '{}' does not exist. In scope {}{}", - function_name, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Aggregate function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsAggregateFunction(std::move(aggregate_function)); - - return result_projection_names; - } - - /// Executable UDFs may have parameters. They are checked in UserDefinedExecutableFunctionFactory. - if (!parameters.empty() && !is_executable_udf) - { - throw Exception(ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_name); - } - - /** For lambda arguments we need to initialize lambda argument types DataTypeFunction using `getLambdaArgumentTypes` function. - * Then each lambda arguments are initialized with columns, where column source is lambda. - * This information is important for later steps of query processing. - * Example: SELECT arrayMap(x -> x + 1, [1, 2, 3]). - * lambda node x -> x + 1 identifier x is resolved as column where source is lambda node. - */ - bool has_lambda_arguments = !function_lambda_arguments_indexes.empty(); - if (has_lambda_arguments) - { - function->getLambdaArgumentTypes(argument_types); - - ProjectionNames lambda_projection_names; - for (auto & function_lambda_argument_index : function_lambda_arguments_indexes) - { - auto & lambda_argument = function_arguments[function_lambda_argument_index]; - auto lambda_to_resolve = lambda_argument->clone(); - auto & lambda_to_resolve_typed = lambda_to_resolve->as(); - - const auto & lambda_argument_names = lambda_to_resolve_typed.getArgumentNames(); - size_t lambda_arguments_size = lambda_to_resolve_typed.getArguments().getNodes().size(); - - const auto * function_data_type = typeid_cast(argument_types[function_lambda_argument_index].get()); - if (!function_data_type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' expected function data type for lambda argument with index {}. Actual {}. In scope {}", - function_name, - function_lambda_argument_index, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & function_data_type_argument_types = function_data_type->getArgumentTypes(); - size_t function_data_type_arguments_size = function_data_type_argument_types.size(); - if (function_data_type_arguments_size != lambda_arguments_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}" - "' function data type for lambda argument with index {} arguments size mismatch. " - "Actual {}. Expected {}. In scope {}", - function_name, - function_data_type_arguments_size, - lambda_arguments_size, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - QueryTreeNodes lambda_arguments; - lambda_arguments.reserve(lambda_arguments_size); - - for (size_t i = 0; i < lambda_arguments_size; ++i) - { - const auto & argument_type = function_data_type_argument_types[i]; - auto column_name_and_type = NameAndTypePair{lambda_argument_names[i], argument_type}; - lambda_arguments.push_back(std::make_shared(std::move(column_name_and_type), lambda_to_resolve)); - } - - IdentifierResolveScope lambda_scope(lambda_to_resolve, &scope /*parent_scope*/); - lambda_projection_names = resolveLambda(lambda_argument, lambda_to_resolve, lambda_arguments, lambda_scope); - - if (auto * lambda_list_node_result = lambda_to_resolve_typed.getExpression()->as()) - { - size_t lambda_list_node_result_nodes_size = lambda_list_node_result->getNodes().size(); - - if (lambda_list_node_result_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Lambda as function argument resolved as list node with size {}. Expected 1. In scope {}", - lambda_list_node_result_nodes_size, - lambda_to_resolve->formatASTForErrorMessage()); - - lambda_to_resolve_typed.getExpression() = lambda_list_node_result->getNodes().front(); - } - - if (arguments_projection_names.at(function_lambda_argument_index) == PROJECTION_NAME_PLACEHOLDER) - { - size_t lambda_projection_names_size =lambda_projection_names.size(); - if (lambda_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Lambda argument inside function expected to have 1 projection name. Actual {}", - lambda_projection_names_size); - - WriteBufferFromOwnString lambda_argument_projection_name_buffer; - lambda_argument_projection_name_buffer << "lambda("; - lambda_argument_projection_name_buffer << "tuple("; - - size_t lambda_argument_names_size = lambda_argument_names.size(); - - for (size_t i = 0; i < lambda_argument_names_size; ++i) - { - const auto & lambda_argument_name = lambda_argument_names[i]; - lambda_argument_projection_name_buffer << lambda_argument_name; - - if (i + 1 != lambda_argument_names_size) - lambda_argument_projection_name_buffer << ", "; - } - - lambda_argument_projection_name_buffer << "), "; - lambda_argument_projection_name_buffer << lambda_projection_names[0]; - lambda_argument_projection_name_buffer << ")"; - - lambda_projection_names.clear(); - - arguments_projection_names[function_lambda_argument_index] = lambda_argument_projection_name_buffer.str(); - } - - auto lambda_resolved_type = std::make_shared(function_data_type_argument_types, lambda_to_resolve_typed.getExpression()->getResultType()); - lambda_to_resolve_typed.resolve(lambda_resolved_type); - - argument_types[function_lambda_argument_index] = lambda_resolved_type; - argument_columns[function_lambda_argument_index].type = lambda_resolved_type; - function_arguments[function_lambda_argument_index] = std::move(lambda_to_resolve); - } - - /// Recalculate function projection name after lambda resolution - result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - } - - /** Create SET column for special function IN to allow constant folding - * if left and right arguments are constants. - * - * Example: SELECT * FROM test_table LIMIT 1 IN 1; - */ - if (is_special_function_in) - { - const auto * first_argument_constant_node = function_arguments[0]->as(); - const auto * second_argument_constant_node = function_arguments[1]->as(); - - if (first_argument_constant_node && second_argument_constant_node) - { - const auto & first_argument_constant_type = first_argument_constant_node->getResultType(); - const auto & second_argument_constant_literal = second_argument_constant_node->getValue(); - const auto & second_argument_constant_type = second_argument_constant_node->getResultType(); - - const auto & settings = scope.context->getSettingsRef(); - - auto result_block = getSetElementsForConstantValue(first_argument_constant_type, - second_argument_constant_literal, - second_argument_constant_type, - settings.transform_null_in); - - SizeLimits size_limits_for_set = {settings.max_rows_in_set, settings.max_bytes_in_set, settings.set_overflow_mode}; - - auto set = std::make_shared(size_limits_for_set, 0, settings.transform_null_in); - - set->setHeader(result_block.cloneEmpty().getColumnsWithTypeAndName()); - set->insertFromBlock(result_block.getColumnsWithTypeAndName()); - set->finishInsert(); - - auto future_set = std::make_shared(std::move(set)); - - /// Create constant set column for constant folding - - auto column_set = ColumnSet::create(1, std::move(future_set)); - argument_columns[1].column = ColumnConst::create(std::move(column_set), 1); - } - - argument_columns[1].type = std::make_shared(); - } - - std::shared_ptr constant_value; - - try - { - FunctionBasePtr function_base; - if (function_cache) - { - auto & cached_function = function_cache->function_base; - if (!cached_function) - cached_function = function->build(argument_columns); - - function_base = cached_function; - } - else - function_base = function->build(argument_columns); - - /// Do not constant fold get scalar functions - bool disable_constant_folding = function_name == "__getScalar" || function_name == "shardNum" || - function_name == "shardCount" || function_name == "hostName" || function_name == "tcpPort"; - - /** If function is suitable for constant folding try to convert it to constant. - * Example: SELECT plus(1, 1); - * Result: SELECT 2; - */ - if (function_base->isSuitableForConstantFolding() && !disable_constant_folding) - { - auto result_type = function_base->getResultType(); - auto executable_function = function_base->prepare(argument_columns); - - ColumnPtr column; - - if (all_arguments_constants) - { - size_t num_rows = function_arguments.empty() ? 0 : argument_columns.front().column->size(); - column = executable_function->execute(argument_columns, result_type, num_rows, true); - } - else - { - column = function_base->getConstantResultForNonConstArguments(argument_columns, result_type); - } - - if (column && column->getDataType() != result_type->getColumnType()) - throw Exception( - ErrorCodes::LOGICAL_ERROR, - "Unexpected return type from {}. Expected {}. Got {}", - function->getName(), - result_type->getColumnType(), - column->getDataType()); - - /** Do not perform constant folding if there are aggregate or arrayJoin functions inside function. - * Example: SELECT toTypeName(sum(number)) FROM numbers(10); - */ - if (column && isColumnConst(*column) && !typeid_cast(column.get())->getDataColumn().isDummy() && - !hasAggregateFunctionNodes(node) && !hasFunctionNode(node, "arrayJoin") && - /// Sanity check: do not convert large columns to constants - column->byteSize() < 1_MiB) - { - /// Replace function node with result constant node - Field column_constant_value; - column->get(0, column_constant_value); - constant_value = std::make_shared(std::move(column_constant_value), result_type); - } - } - - function_node.resolveAsFunction(std::move(function_base)); - } - catch (Exception & e) - { - e.addMessage("In scope {}", scope.scope_node->formatASTForErrorMessage()); - throw; - } - - if (constant_value) - node = std::make_shared(std::move(constant_value), node); - - return result_projection_names; -} - -/** Resolve expression node. - * Argument node can be replaced with different node, or even with list node in case of matcher resolution. - * Example: SELECT * FROM test_table; - * * - is matcher node, and it can be resolved into ListNode. - * - * Steps: - * 1. If node has alias, replace node with its value in scope alias map. Register alias in expression_aliases_in_resolve_process, to prevent resolving identifier - * which can bind to expression alias name. Check tryResolveIdentifierFromAliases documentation for additional explanation. - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * - * 2. Call specific resolve method depending on node type. - * - * If allow_table_expression = true and node is query node, then it is not evaluated as scalar subquery. - * Although if node is identifier that is resolved into query node that query is evaluated as scalar subquery. - * SELECT id, (SELECT 1) AS c FROM test_table WHERE a IN c; - * SELECT id, FROM test_table WHERE a IN (SELECT 1); - * - * 3. Special case identifier node. - * Try resolve it as expression identifier. - * Then if allow_lambda_expression = true try to resolve it as function. - * Then if allow_table_expression = true try to resolve it as table expression. - * - * 4. If node has alias, update its value in scope alias map. Deregister alias from expression_aliases_in_resolve_process. - */ -ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias) -{ - checkStackSize(); - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - /** There can be edge case, when subquery for IN function is resolved multiple times in different context. - * SELECT id IN (subquery AS value), value FROM test_table; - * When we start to resolve `value` identifier, subquery is already resolved but constant folding is not performed. - */ - auto node_type = node->getNodeType(); - if (!allow_table_expression && (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION)) - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - } - - return resolved_expression_it->second; - } - - String node_alias = node->getAlias(); - ProjectionNames result_projection_names; - - if (node_alias.empty()) - { - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - else - { - result_projection_names.push_back(node_alias); - } - - bool is_duplicated_alias = scope.aliases.nodes_with_duplicated_aliases.contains(node); - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.insert({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - /** Do not use alias table if node has alias same as some other node. - * Example: WITH x -> x + 1 AS lambda SELECT 1 AS lambda; - * During 1 AS lambda resolve if we use alias table we replace node with x -> x + 1 AS lambda. - * - * Do not use alias table if allow_table_expression = true and we resolve query node directly. - * Example: SELECT a FROM test_table WHERE id IN (SELECT 1) AS a; - * To support both (SELECT 1) AS expression in projection and (SELECT 1) as subquery in IN, do not use - * alias table because in alias table subquery could be evaluated as scalar. - */ - bool use_alias_table = !ignore_alias; - if (is_duplicated_alias || (allow_table_expression && isSubqueryNodeType(node->getNodeType()))) - use_alias_table = false; - - if (!node_alias.empty() && use_alias_table) - { - /** Node could be potentially resolved by resolving other nodes. - * SELECT b, a as b FROM test_table; - * - * To resolve b we need to resolve a. - */ - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - node = it->second; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - node = it->second; - } - } - - scope.pushExpressionNode(node); - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & identifier_node = node->as(); - auto unresolved_identifier = identifier_node.getIdentifier(); - auto resolve_identifier_expression_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier_node = resolve_identifier_expression_result.resolved_identifier; - - if (resolved_identifier_node && result_projection_names.empty() && - (resolve_identifier_expression_result.isResolvedFromJoinTree() || resolve_identifier_expression_result.isResolvedFromExpressionArguments())) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier_node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - - if (!resolved_identifier_node && allow_lambda_expression) - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::FUNCTION}, scope).resolved_identifier; - - if (!resolved_identifier_node && allow_table_expression) - { - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::TABLE_EXPRESSION}, scope).resolved_identifier; - - if (resolved_identifier_node) - { - /// If table identifier is resolved as CTE clone it and resolve - auto * subquery_node = resolved_identifier_node->as(); - auto * union_node = resolved_identifier_node->as(); - bool resolved_as_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - - if (resolved_as_cte) - { - resolved_identifier_node = resolved_identifier_node->clone(); - subquery_node = resolved_identifier_node->as(); - union_node = resolved_identifier_node->as(); - - std::string_view cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - if (subquery_node) - subquery_node->setIsCTE(false); - else - union_node->setIsCTE(false); - - IdentifierResolveScope subquery_scope(resolved_identifier_node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - /// CTE is being resolved, it's required to forbid to resolve to it again - /// because recursive CTEs are not supported, e.g.: - /// - /// WITH test1 AS (SELECT i + 1, j + 1 FROM test1) SELECT toInt64(4) i, toInt64(5) j FROM numbers(3) WHERE (i, j) IN test1; - /// - /// In this example argument of function `in` is being resolve here. If CTE `test1` is not forbidden, - /// `test1` is resolved to CTE (not to the table) in `initializeQueryJoinTreeNode` function. - ctes_in_resolve_process.insert(cte_name); - - if (subquery_node) - resolveQuery(resolved_identifier_node, subquery_scope); - else - resolveUnion(resolved_identifier_node, subquery_scope); - - ctes_in_resolve_process.erase(cte_name); - } - } - } - - if (!resolved_identifier_node) - { - std::string message_clarification; - if (allow_lambda_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::FUNCTION); - - if (allow_table_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::TABLE_EXPRESSION); - - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(unresolved_identifier, - scope, - true, - allow_lambda_expression, - allow_table_expression, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(unresolved_identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {}{} identifier '{}' in scope {}{}", - toStringLowercase(IdentifierLookupContext::EXPRESSION), - message_clarification, - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - node = std::move(resolved_identifier_node); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - { - result_projection_names.clear(); - resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - return resolved_expression_it->second; - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier '{}' resolve into list node and list node projection names are not initialized. In scope {}", - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_projection_names.empty()) - result_projection_names.push_back(unresolved_identifier.getFullName()); - - break; - } - case QueryTreeNodeType::MATCHER: - { - result_projection_names = resolveMatcher(node, scope); - break; - } - case QueryTreeNodeType::LIST: - { - /** Edge case if list expression has alias. - * Matchers cannot have aliases, but `untuple` function can. - * Example: SELECT a, untuple(CAST(('hello', 1) AS Tuple(name String, count UInt32))) AS a; - * During resolveFunction `untuple` function is replaced by list of 2 constants 'hello', 1. - */ - result_projection_names = resolveExpressionNodeList(node, scope, allow_lambda_expression, allow_lambda_expression); - break; - } - case QueryTreeNodeType::CONSTANT: - { - if (result_projection_names.empty()) - { - const auto & constant_node = node->as(); - result_projection_names.push_back(constant_node.getValueStringRepresentation()); - } - - /// Already resolved - break; - } - case QueryTreeNodeType::COLUMN: - { - auto & column_node = node->as(); - if (column_node.hasExpression()) - resolveExpressionNode(column_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (result_projection_names.empty()) - result_projection_names.push_back(column_node.getColumnName()); - - break; - } - case QueryTreeNodeType::FUNCTION: - { - auto function_projection_names = resolveFunction(node, scope); - - if (result_projection_names.empty() || node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(function_projection_names); - - break; - } - case QueryTreeNodeType::LAMBDA: - { - if (!allow_lambda_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (result_projection_names.empty()) - result_projection_names.push_back(PROJECTION_NAME_PLACEHOLDER); - - /// Lambda must be resolved by caller - break; - } - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - std::string projection_name = "_subquery_" + std::to_string(subquery_counter); - ++subquery_counter; - - if (node_type == QueryTreeNodeType::QUERY) - resolveQuery(node, subquery_scope); - else - resolveUnion(node, subquery_scope); - - if (!allow_table_expression) - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - - if (result_projection_names.empty()) - result_projection_names.push_back(std::move(projection_name)); - - break; - } - case QueryTreeNodeType::TABLE: - { - if (!allow_table_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Table {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node = node->as(); - result_projection_names.push_back(table_node.getStorageID().getFullNameNotQuoted()); - - break; - } - case QueryTreeNodeType::TRANSFORMER: - [[fallthrough]]; - case QueryTreeNodeType::SORT: - [[fallthrough]]; - case QueryTreeNodeType::INTERPOLATE: - [[fallthrough]]; - case QueryTreeNodeType::WINDOW: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::ARRAY_JOIN: - [[fallthrough]]; - case QueryTreeNodeType::JOIN: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "{} {} is not allowed in expression context. In scope {}", - node->getNodeType(), - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - validateTreeSize(node, scope.context->getSettingsRef().max_expanded_ast_elements, node_to_tree_size); - - /// Lambda can be inside the aggregate function, so we should check parent scopes. - /// Most likely only the root scope can have an arrgegate function, but let's check all just in case. - bool in_aggregate_function_scope = false; - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - in_aggregate_function_scope = in_aggregate_function_scope || scope_ptr->expressions_in_resolve_process_stack.hasAggregateFunction(); - - if (!in_aggregate_function_scope) - { - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - { - auto it = scope_ptr->nullable_group_by_keys.find(node); - if (it != scope_ptr->nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - break; - } - } - } - - /** Update aliases after expression node was resolved. - * Do not update node in alias table if we resolve it for duplicate alias. - */ - if (!node_alias.empty() && use_alias_table && !scope.group_by_use_nulls) - { - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - it->second = node; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - it->second = node; - } - } - - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.erase({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - if (!ignore_alias) - resolved_expressions.emplace(node, result_projection_names); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - return result_projection_names; -} - -/** Resolve expression node list. - * If expression is CTE subquery node it is skipped. - * If expression is resolved in list, it is flattened into initial node list. - * - * Such examples must work: - * Example: CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; SELECT plus(*) FROM test_table; - * Example: SELECT *** FROM system.one; - */ -ProjectionNames QueryAnalyzer::resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression) -{ - auto & node_list_typed = node_list->as(); - size_t node_list_size = node_list_typed.getNodes().size(); - - QueryTreeNodes result_nodes; - result_nodes.reserve(node_list_size); - - ProjectionNames result_projection_names; - - for (auto & node : node_list_typed.getNodes()) - { - auto node_to_resolve = node; - auto expression_node_projection_names = resolveExpressionNode(node_to_resolve, scope, allow_lambda_expression, allow_table_expression); - size_t expected_projection_names_size = 1; - if (auto * expression_list = node_to_resolve->as()) - { - expected_projection_names_size = expression_list->getNodes().size(); - for (auto & expression_list_node : expression_list->getNodes()) - result_nodes.push_back(expression_list_node); - } - else - { - result_nodes.push_back(std::move(node_to_resolve)); - } - - if (expression_node_projection_names.size() != expected_projection_names_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected {} projection names. Actual {}", - expected_projection_names_size, - expression_node_projection_names.size()); - - result_projection_names.insert(result_projection_names.end(), expression_node_projection_names.begin(), expression_node_projection_names.end()); - expression_node_projection_names.clear(); - } - - node_list_typed.getNodes() = std::move(result_nodes); - - return result_projection_names; -} - -/** Resolve sort columns nodes list. - */ -ProjectionNames QueryAnalyzer::resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames result_projection_names; - ProjectionNames sort_expression_projection_names; - ProjectionNames fill_from_expression_projection_names; - ProjectionNames fill_to_expression_projection_names; - ProjectionNames fill_step_expression_projection_names; - - auto & sort_node_list_typed = sort_node_list->as(); - for (auto & node : sort_node_list_typed.getNodes()) - { - auto & sort_node = node->as(); - sort_expression_projection_names = resolveExpressionNode(sort_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (auto * sort_column_list_node = sort_node.getExpression()->as()) - { - size_t sort_column_list_node_size = sort_column_list_node->getNodes().size(); - if (sort_column_list_node_size != 1) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Sort column node expression resolved into list with size {}. Expected 1. In scope {}", - sort_column_list_node_size, - scope.scope_node->formatASTForErrorMessage()); - } - - sort_node.getExpression() = sort_column_list_node->getNodes().front(); - } - - size_t sort_expression_projection_names_size = sort_expression_projection_names.size(); - if (sort_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort expression expected 1 projection name. Actual {}", - sort_expression_projection_names_size); - - if (sort_node.hasFillFrom()) - { - fill_from_expression_projection_names = resolveExpressionNode(sort_node.getFillFrom(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillFrom()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL FROM expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_from_expression_projection_names_size = fill_from_expression_projection_names.size(); - if (fill_from_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL FROM expression expected 1 projection name. Actual {}", - fill_from_expression_projection_names_size); - } - - if (sort_node.hasFillTo()) - { - fill_to_expression_projection_names = resolveExpressionNode(sort_node.getFillTo(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillTo()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL TO expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_to_expression_projection_names_size = fill_to_expression_projection_names.size(); - if (fill_to_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL TO expression expected 1 projection name. Actual {}", - fill_to_expression_projection_names_size); - } - - if (sort_node.hasFillStep()) - { - fill_step_expression_projection_names = resolveExpressionNode(sort_node.getFillStep(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillStep()->as(); - if (!constant_node) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - bool is_number = isColumnedAsNumber(constant_node->getResultType()); - bool is_interval = WhichDataType(constant_node->getResultType()).isInterval(); - if (!is_number && !is_interval) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_step_expression_projection_names_size = fill_step_expression_projection_names.size(); - if (fill_step_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort FILL STEP expression expected 1 projection name. Actual {}", - fill_step_expression_projection_names_size); - } - - auto sort_column_projection_name = calculateSortColumnProjectionName(node, - sort_expression_projection_names[0], - fill_from_expression_projection_names.empty() ? "" : fill_from_expression_projection_names.front(), - fill_to_expression_projection_names.empty() ? "" : fill_to_expression_projection_names.front(), - fill_step_expression_projection_names.empty() ? "" : fill_step_expression_projection_names.front()); - - result_projection_names.push_back(std::move(sort_column_projection_name)); - - sort_expression_projection_names.clear(); - fill_from_expression_projection_names.clear(); - fill_to_expression_projection_names.clear(); - fill_step_expression_projection_names.clear(); - } - - return result_projection_names; -} - -namespace -{ - -void expandTuplesInList(QueryTreeNodes & key_list) -{ - QueryTreeNodes expanded_keys; - expanded_keys.reserve(key_list.size()); - for (auto const & key : key_list) - { - if (auto * function = key->as(); function != nullptr && function->getFunctionName() == "tuple") - { - std::copy(function->getArguments().begin(), function->getArguments().end(), std::back_inserter(expanded_keys)); - } - else - expanded_keys.push_back(key); - } - key_list = std::move(expanded_keys); -} - -} - -/** Resolve GROUP BY clause. - */ -void QueryAnalyzer::resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope) -{ - if (query_node_typed.isGroupByWithGroupingSets()) - { - for (auto & grouping_sets_keys_list_node : query_node_typed.getGroupBy().getNodes()) - { - replaceNodesWithPositionalArguments(grouping_sets_keys_list_node, query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(grouping_sets_keys_list_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = grouping_sets_keys_list_node->as().getNodes(); - expandTuplesInList(group_by_list); - } - - if (scope.group_by_use_nulls) - { - for (const auto & grouping_set : query_node_typed.getGroupBy().getNodes()) - { - for (const auto & group_by_elem : grouping_set->as()->getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } - } - else - { - replaceNodesWithPositionalArguments(query_node_typed.getGroupByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getGroupByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = query_node_typed.getGroupBy().getNodes(); - expandTuplesInList(group_by_list); - - if (scope.group_by_use_nulls) - { - for (const auto & group_by_elem : query_node_typed.getGroupBy().getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } -} - -/** Resolve interpolate columns nodes list. - */ -void QueryAnalyzer::resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope) -{ - auto & interpolate_node_list_typed = interpolate_node_list->as(); - - for (auto & interpolate_node : interpolate_node_list_typed.getNodes()) - { - auto & interpolate_node_typed = interpolate_node->as(); - - auto * column_to_interpolate = interpolate_node_typed.getExpression()->as(); - if (!column_to_interpolate) - throw Exception(ErrorCodes::LOGICAL_ERROR, "INTERPOLATE can work only for indentifiers, but {} is found", - interpolate_node_typed.getExpression()->formatASTForErrorMessage()); - auto column_to_interpolate_name = column_to_interpolate->getIdentifier().getFullName(); - - resolveExpressionNode(interpolate_node_typed.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool is_column_constant = interpolate_node_typed.getExpression()->getNodeType() == QueryTreeNodeType::CONSTANT; - - auto & interpolation_to_resolve = interpolate_node_typed.getInterpolateExpression(); - IdentifierResolveScope interpolate_scope(interpolation_to_resolve, &scope /*parent_scope*/); - - auto fake_column_node = std::make_shared(NameAndTypePair(column_to_interpolate_name, interpolate_node_typed.getExpression()->getResultType()), interpolate_node_typed.getExpression()); - if (is_column_constant) - interpolate_scope.expression_argument_name_to_node.emplace(column_to_interpolate_name, fake_column_node); - - resolveExpressionNode(interpolation_to_resolve, interpolate_scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (is_column_constant) - interpolation_to_resolve = interpolation_to_resolve->cloneAndReplace(fake_column_node, interpolate_node_typed.getExpression()); - } -} - -/** Resolve window nodes list. - */ -void QueryAnalyzer::resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope) -{ - auto & window_node_list_typed = window_node_list->as(); - for (auto & node : window_node_list_typed.getNodes()) - resolveWindow(node, scope); -} - -NamesAndTypes QueryAnalyzer::resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames projection_names = resolveExpressionNodeList(projection_node_list, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto projection_nodes = projection_node_list->as().getNodes(); - size_t projection_nodes_size = projection_nodes.size(); - - NamesAndTypes projection_columns; - projection_columns.reserve(projection_nodes_size); - - for (size_t i = 0; i < projection_nodes_size; ++i) - { - auto projection_node = projection_nodes[i]; - - if (!isExpressionNodeType(projection_node->getNodeType())) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Projection node must be constant, function, column, query or union"); - - projection_columns.emplace_back(projection_names[i], projection_node->getResultType()); - } - - return projection_columns; -} - -/** Initialize query join tree node. - * - * 1. Resolve identifiers. - * 2. Register table, table function, query, union, join, array join nodes in scope table expressions in resolve process. - */ -void QueryAnalyzer::initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope) -{ - std::deque join_tree_node_ptrs_to_process_queue; - join_tree_node_ptrs_to_process_queue.push_back(&join_tree_node); - - while (!join_tree_node_ptrs_to_process_queue.empty()) - { - auto * current_join_tree_node_ptr = join_tree_node_ptrs_to_process_queue.front(); - join_tree_node_ptrs_to_process_queue.pop_front(); - - auto & current_join_tree_node = *current_join_tree_node_ptr; - auto current_join_tree_node_type = current_join_tree_node->getNodeType(); - - switch (current_join_tree_node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & from_table_identifier = current_join_tree_node->as(); - auto table_identifier_lookup = IdentifierLookup{from_table_identifier.getIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - - auto from_table_identifier_alias = from_table_identifier.getAlias(); - - IdentifierResolveSettings resolve_settings; - /// In join tree initialization ignore join tree as identifier lookup source - resolve_settings.allow_to_check_join_tree = false; - /** Disable resolve of subquery during identifier resolution. - * Example: SELECT * FROM (SELECT 1) AS t1, t1; - * During `t1` identifier resolution we resolve it into subquery SELECT 1, but we want to disable - * subquery resolution at this stage, because JOIN TREE of parent query is not resolved. - */ - resolve_settings.allow_to_resolve_subquery_during_identifier_resolution = false; - - scope.pushExpressionNode(current_join_tree_node); - - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, resolve_settings); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - auto resolved_identifier = table_identifier_resolve_result.resolved_identifier; - - if (!resolved_identifier) - throw Exception(ErrorCodes::UNKNOWN_TABLE, - "Unknown table expression identifier '{}' in scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - resolved_identifier = resolved_identifier->clone(); - - /// Update alias name to table expression map - auto table_expression_it = scope.aliases.alias_name_to_table_expression_node.find(from_table_identifier_alias); - if (table_expression_it != scope.aliases.alias_name_to_table_expression_node.end()) - table_expression_it->second = resolved_identifier; - - auto table_expression_modifiers = from_table_identifier.getTableExpressionModifiers(); - - auto * resolved_identifier_query_node = resolved_identifier->as(); - auto * resolved_identifier_union_node = resolved_identifier->as(); - - if (resolved_identifier_query_node || resolved_identifier_union_node) - { - if (table_expression_modifiers.has_value()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Table expression modifiers {} are not supported for subquery {}", - table_expression_modifiers->formatForErrorMessage(), - resolved_identifier->formatASTForErrorMessage()); - } - } - else if (auto * resolved_identifier_table_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else if (auto * resolved_identifier_table_function_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_function_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier in JOIN TREE '{}' resolved into unexpected table expression. In scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto current_join_tree_node_alias = current_join_tree_node->getAlias(); - resolved_identifier->setAlias(current_join_tree_node_alias); - current_join_tree_node = resolved_identifier; - - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::QUERY: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::UNION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - auto & array_join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&array_join.getTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::JOIN: - { - auto & join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&join.getLeftTableExpression()); - join_tree_node_ptrs_to_process_queue.push_back(&join.getRightTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - ++scope.joins_count; - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, UNION, ARRAY JOIN or JOIN. Actual {} {}. In scope {}", - current_join_tree_node->getNodeTypeName(), - current_join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - } -} - -/// Initialize table expression data for table expression node -void QueryAnalyzer::initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto table_expression_data_it = scope.table_expression_node_to_data.find(table_expression_node); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - return; - - TableExpressionData table_expression_data; - - if (table_node) - { - if (!table_node->getTemporaryTableName().empty()) - { - table_expression_data.table_name = table_node->getTemporaryTableName(); - table_expression_data.table_expression_name = table_node->getTemporaryTableName(); - } - else - { - const auto & table_storage_id = table_node->getStorageID(); - table_expression_data.database_name = table_storage_id.database_name; - table_expression_data.table_name = table_storage_id.table_name; - table_expression_data.table_expression_name = table_storage_id.getFullNameNotQuoted(); - } - - table_expression_data.table_expression_description = "table"; - } - else if (query_node || union_node) - { - table_expression_data.table_name = query_node ? query_node->getCTEName() : union_node->getCTEName(); - table_expression_data.table_expression_description = "subquery"; - } - else if (table_function_node) - { - table_expression_data.table_expression_description = "table_function"; - } - - if (table_expression_node->hasAlias()) - table_expression_data.table_expression_name = table_expression_node->getAlias(); - - if (table_node || table_function_node) - { - const auto & storage_snapshot = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - - auto get_column_options = GetColumnsOptions(GetColumnsOptions::All).withExtendedObjects().withVirtuals(); - if (storage_snapshot->storage.supportsSubcolumns()) - get_column_options.withSubcolumns(); - - auto column_names_and_types = storage_snapshot->getColumns(get_column_options); - table_expression_data.column_names_and_types = NamesAndTypes(column_names_and_types.begin(), column_names_and_types.end()); - - const auto & columns_description = storage_snapshot->metadata->getColumns(); - - std::vector> alias_columns_to_resolve; - ColumnNameToColumnNodeMap column_name_to_column_node; - column_name_to_column_node.reserve(column_names_and_types.size()); - - /** For ALIAS columns in table we must additionally analyze ALIAS expressions. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + 5); - * - * To do that we collect alias columns and build table column name to column node map. - * For each alias column we build identifier resolve scope, initialize it with table column name to node map - * and resolve alias column. - */ - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - for (const auto & subcolumn : columns_description.getSubcolumns(column_name_and_type.name)) - table_expression_data.subcolumn_names.insert(subcolumn.name); - const auto & column_default = columns_description.getDefault(column_name_and_type.name); - - if (column_default && column_default->kind == ColumnDefaultKind::Alias) - { - auto alias_expression = buildQueryTree(column_default->expression, scope.context); - auto column_node = std::make_shared(column_name_and_type, std::move(alias_expression), table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - alias_columns_to_resolve.emplace_back(column_name_and_type.name, column_node); - } - else - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - for (auto & [alias_column_to_resolve_name, alias_column_to_resolve] : alias_columns_to_resolve) - { - /** Alias column could be potentially resolved during resolve of other ALIAS column. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + alias_value_2, alias_value_2 ALIAS id + 5) ENGINE=TinyLog; - * - * During resolve of alias_value_1, alias_value_2 column will be resolved. - */ - alias_column_to_resolve = column_name_to_column_node[alias_column_to_resolve_name]; - - IdentifierResolveScope alias_column_resolve_scope(alias_column_to_resolve, nullptr /*parent_scope*/); - alias_column_resolve_scope.column_name_to_column_node = std::move(column_name_to_column_node); - alias_column_resolve_scope.context = scope.context; - - /// Initialize aliases in alias column scope - QueryExpressionsAliasVisitor visitor(alias_column_resolve_scope.aliases); - visitor.visit(alias_column_to_resolve->getExpression()); - - resolveExpressionNode(alias_column_resolve_scope.scope_node, - alias_column_resolve_scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - auto & resolved_expression = alias_column_to_resolve->getExpression(); - if (!resolved_expression->getResultType()->equals(*alias_column_to_resolve->getResultType())) - resolved_expression = buildCastFunction(resolved_expression, alias_column_to_resolve->getResultType(), scope.context, true); - column_name_to_column_node = std::move(alias_column_resolve_scope.column_name_to_column_node); - column_name_to_column_node[alias_column_to_resolve_name] = alias_column_to_resolve; - } - - table_expression_data.column_name_to_column_node = std::move(column_name_to_column_node); - } - else if (query_node || union_node) - { - table_expression_data.column_names_and_types = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - table_expression_data.column_name_to_column_node.reserve(table_expression_data.column_names_and_types.size()); - - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - table_expression_data.column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - table_expression_data.column_identifier_first_parts.reserve(table_expression_data.column_name_to_column_node.size()); - - for (auto & [column_name, _] : table_expression_data.column_name_to_column_node) - { - Identifier column_name_identifier(column_name); - table_expression_data.column_identifier_first_parts.insert(column_name_identifier.at(0)); - } - - if (auto * scope_query_node = scope.scope_node->as()) - { - auto left_table_expression = extractLeftTableExpression(scope_query_node->getJoinTree()); - if (table_expression_node.get() == left_table_expression.get() && - scope.joins_count == 1 && - scope.context->getSettingsRef().single_join_prefer_left_table) - table_expression_data.should_qualify_columns = false; - } - - scope.table_expression_node_to_data.emplace(table_expression_node, std::move(table_expression_data)); -} - -bool findIdentifier(const FunctionNode & function) -{ - for (const auto & argument : function.getArguments()) - { - if (argument->as()) - return true; - if (const auto * f = argument->as(); f && findIdentifier(*f)) - return true; - } - return false; -} - -/// Resolve table function node in scope -void QueryAnalyzer::resolveTableFunction(QueryTreeNodePtr & table_function_node, - IdentifierResolveScope & scope, - QueryExpressionsAliasVisitor & expressions_visitor, - bool nested_table_function) -{ - auto & table_function_node_typed = table_function_node->as(); - - if (!nested_table_function) - expressions_visitor.visit(table_function_node_typed.getArgumentsNode()); - - const auto & table_function_name = table_function_node_typed.getTableFunctionName(); - - auto & scope_context = scope.context; - - TableFunctionPtr table_function_ptr = TableFunctionFactory::instance().tryGet(table_function_name, scope_context); - if (!table_function_ptr) - { - String database_name = scope_context->getCurrentDatabase(); - String table_name; - - auto function_ast = table_function_node->toAST(); - Identifier table_identifier{table_function_name}; - if (table_identifier.getPartsSize() == 1) - { - table_name = table_identifier[0]; - } - else if (table_identifier.getPartsSize() == 2) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - - auto parametrized_view_storage = scope_context->getQueryContext()->buildParametrizedViewStorage(function_ast, database_name, table_name); - if (parametrized_view_storage) - { - auto fake_table_node = std::make_shared(parametrized_view_storage, scope_context); - fake_table_node->setAlias(table_function_node->getAlias()); - table_function_node = fake_table_node; - return; - } - - auto hints = TableFunctionFactory::instance().getHints(table_function_name); - if (!hints.empty()) - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}. Maybe you meant: {}", - table_function_name, - DB::toString(hints)); - else - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}", - table_function_name); - } - - QueryTreeNodes result_table_function_arguments; - - auto skip_analysis_arguments_indexes = table_function_ptr->skipAnalysisForArguments(table_function_node, scope_context); - - auto & table_function_arguments = table_function_node_typed.getArguments().getNodes(); - size_t table_function_arguments_size = table_function_arguments.size(); - - for (size_t table_function_argument_index = 0; table_function_argument_index < table_function_arguments_size; ++table_function_argument_index) - { - auto & table_function_argument = table_function_arguments[table_function_argument_index]; - - auto skip_argument_index_it = std::find(skip_analysis_arguments_indexes.begin(), - skip_analysis_arguments_indexes.end(), - table_function_argument_index); - if (skip_argument_index_it != skip_analysis_arguments_indexes.end()) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - if (auto * identifier_node = table_function_argument->as()) - { - const auto & unresolved_identifier = identifier_node->getIdentifier(); - auto identifier_resolve_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier = std::move(identifier_resolve_result.resolved_identifier); - - if (resolved_identifier && resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - result_table_function_arguments.push_back(std::move(resolved_identifier)); - else - result_table_function_arguments.push_back(table_function_argument); - - continue; - } - else if (auto * table_function_argument_function = table_function_argument->as()) - { - const auto & table_function_argument_function_name = table_function_argument_function->getFunctionName(); - if (TableFunctionFactory::instance().isTableFunctionName(table_function_argument_function_name)) - { - auto table_function_node_to_resolve_typed = std::make_shared(table_function_argument_function_name); - table_function_node_to_resolve_typed->getArgumentsNode() = table_function_argument_function->getArgumentsNode(); - - QueryTreeNodePtr table_function_node_to_resolve = std::move(table_function_node_to_resolve_typed); - resolveTableFunction(table_function_node_to_resolve, scope, expressions_visitor, true /*nested_table_function*/); - - result_table_function_arguments.push_back(std::move(table_function_node_to_resolve)); - continue; - } - } - - /** Table functions arguments can contain expressions with invalid identifiers. - * We cannot skip analysis for such arguments, because some table functions cannot provide - * information if analysis for argument should be skipped until other arguments will be resolved. - * - * Example: SELECT key from remote('127.0.0.{1,2}', view(select number AS key from numbers(2)), cityHash64(key)); - * Example: SELECT id from remote('127.0.0.{1,2}', 'default', 'test_table', cityHash64(id)); - */ - try - { - resolveExpressionNode(table_function_argument, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - catch (const Exception & exception) - { - if (exception.code() == ErrorCodes::UNKNOWN_IDENTIFIER) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - throw; - } - - if (auto * expression_list = table_function_argument->as()) - { - for (auto & expression_list_node : expression_list->getNodes()) - result_table_function_arguments.push_back(expression_list_node); - } - else - { - result_table_function_arguments.push_back(table_function_argument); - } - } - - table_function_node_typed.getArguments().getNodes() = std::move(result_table_function_arguments); - - auto table_function_ast = table_function_node_typed.toAST(); - table_function_ptr->parseArguments(table_function_ast, scope_context); - - - uint64_t use_structure_from_insertion_table_in_table_functions = scope_context->getSettingsRef().use_structure_from_insertion_table_in_table_functions; - if (!nested_table_function && - use_structure_from_insertion_table_in_table_functions && - scope_context->hasInsertionTable() && - table_function_ptr->needStructureHint()) - { - const auto & insertion_table = scope_context->getInsertionTable(); - if (!insertion_table.empty()) - { - const auto & insert_columns = DatabaseCatalog::instance() - .getTable(insertion_table, scope_context) - ->getInMemoryMetadataPtr() - ->getColumns(); - const auto & insert_column_names = scope_context->hasInsertionTableColumnNames() ? *scope_context->getInsertionTableColumnNames() : insert_columns.getOrdinary().getNames(); - DB::ColumnsDescription structure_hint; - - bool use_columns_from_insert_query = true; - - /// Insert table matches columns against SELECT expression by position, so we want to map - /// insert table columns to table function columns through names from SELECT expression. - - auto insert_column_name_it = insert_column_names.begin(); - auto insert_column_names_end = insert_column_names.end(); /// end iterator of the range covered by possible asterisk - auto virtual_column_names = table_function_ptr->getVirtualsToCheckBeforeUsingStructureHint(); - bool asterisk = false; - const auto & expression_list = scope.scope_node->as().getProjection(); - auto expression = expression_list.begin(); - - /// We want to go through SELECT expression list and correspond each expression to column in insert table - /// which type will be used as a hint for the file structure inference. - for (; expression != expression_list.end() && insert_column_name_it != insert_column_names_end; ++expression) - { - if (auto * identifier_node = (*expression)->as()) - { - - if (!virtual_column_names.contains(identifier_node->getIdentifier().getFullName())) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - ColumnDescription column = insert_columns.get(*insert_column_name_it); - column.name = identifier_node->getIdentifier().getFullName(); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else if (auto * matcher_node = (*expression)->as(); matcher_node && matcher_node->getMatcherType() == MatcherNodeType::ASTERISK) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Only one asterisk can be used in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - if (!structure_hint.empty()) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - asterisk = true; - } - else if (auto * function = (*expression)->as()) - { - if (use_structure_from_insertion_table_in_table_functions == 2 && findIdentifier(*function)) - { - use_columns_from_insert_query = false; - break; - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else - { - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - } - - if (use_structure_from_insertion_table_in_table_functions == 2 && !asterisk) - { - /// For input function we should check if input format supports reading subset of columns. - if (table_function_ptr->getName() == "input") - use_columns_from_insert_query = FormatFactory::instance().checkIfFormatSupportsSubsetOfColumns(scope.context->getInsertFormat(), scope.context); - else - use_columns_from_insert_query = table_function_ptr->supportsReadingSubsetOfColumns(scope.context); - } - - if (use_columns_from_insert_query) - { - if (expression == expression_list.end()) - { - /// Append tail of insert structure to the hint - if (asterisk) - { - for (; insert_column_name_it != insert_column_names_end; ++insert_column_name_it) - { - ColumnDescription column = insert_columns.get(*insert_column_name_it); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - } - - if (!structure_hint.empty()) - table_function_ptr->setStructureHint(structure_hint); - - } else if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::NUMBER_OF_COLUMNS_DOESNT_MATCH, "Number of columns in insert table less than required by SELECT expression."); - } - } - } - - auto table_function_storage = scope_context->getQueryContext()->executeTableFunction(table_function_ast, table_function_ptr); - table_function_node_typed.resolve(std::move(table_function_ptr), std::move(table_function_storage), scope_context, std::move(skip_analysis_arguments_indexes)); -} - -/// Resolve array join node in scope -void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & array_join_node_typed = array_join_node->as(); - resolveQueryJoinTreeNode(array_join_node_typed.getTableExpression(), scope, expressions_visitor); - - std::unordered_set array_join_column_names; - - /// Wrap array join expressions into column nodes, where array join expression is inner expression - - auto & array_join_nodes = array_join_node_typed.getJoinExpressions().getNodes(); - size_t array_join_nodes_size = array_join_nodes.size(); - - if (array_join_nodes_size == 0) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, - "ARRAY JOIN requires at least single expression"); - - std::vector array_join_column_expressions; - array_join_column_expressions.reserve(array_join_nodes_size); - - for (auto & array_join_expression : array_join_nodes) - { - auto array_join_expression_alias = array_join_expression->getAlias(); - - for (const auto & elem : array_join_nodes) - { - if (elem->hasAlias()) - scope.aliases.array_join_aliases.insert(elem->getAlias()); - - for (auto & child : elem->getChildren()) - { - if (child) - expressions_visitor.visit(child); - } - } - - std::string identifier_full_name; - - if (auto * identifier_node = array_join_expression->as()) - identifier_full_name = identifier_node->getIdentifier().getFullName(); - - resolveExpressionNode(array_join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/, true /*ignore_alias*/); - - auto process_array_join_expression = [&](QueryTreeNodePtr & expression) - { - auto result_type = expression->getResultType(); - bool is_array_type = isArray(result_type); - bool is_map_type = isMap(result_type); - - if (!is_array_type && !is_map_type) - throw Exception(ErrorCodes::TYPE_MISMATCH, - "ARRAY JOIN {} requires expression {} with Array or Map type. Actual {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - expression->formatASTForErrorMessage(), - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_map_type) - result_type = assert_cast(*result_type).getNestedType(); - - result_type = assert_cast(*result_type).getNestedType(); - - String array_join_column_name; - - if (!array_join_expression_alias.empty()) - { - array_join_column_name = array_join_expression_alias; - } - else if (auto * array_join_expression_inner_column = array_join_expression->as()) - { - array_join_column_name = array_join_expression_inner_column->getColumnName(); - } - else if (!identifier_full_name.empty()) - { - array_join_column_name = identifier_full_name; - } - else - { - array_join_column_name = "__array_join_expression_" + std::to_string(array_join_expressions_counter); - ++array_join_expressions_counter; - } - - if (array_join_column_names.contains(array_join_column_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "ARRAY JOIN {} multiple columns with name {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - array_join_column_name, - scope.scope_node->formatASTForErrorMessage()); - array_join_column_names.emplace(array_join_column_name); - - NameAndTypePair array_join_column(array_join_column_name, result_type); - auto array_join_column_node = std::make_shared(std::move(array_join_column), expression, array_join_node); - array_join_column_node->setAlias(array_join_expression_alias); - array_join_column_expressions.push_back(std::move(array_join_column_node)); - }; - - // Support ARRAY JOIN COLUMNS(...). COLUMNS transformer is resolved to list of columns. - if (auto * columns_list = array_join_expression->as()) - { - for (auto & array_join_subexpression : columns_list->getNodes()) - process_array_join_expression(array_join_subexpression); - } - else - { - process_array_join_expression(array_join_expression); - } - } - - array_join_nodes = std::move(array_join_column_expressions); -} - -void QueryAnalyzer::checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope) -{ - Names column_names; - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - if (join_node->as().getKind() != JoinKind::Paste) - return; - - auto * left_node = left_table_expr->as(); - auto * right_node = right_table_expr->as(); - - if (!left_node && !right_node) - return; - - if (left_node) - for (const auto & name_and_type : left_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - if (right_node) - for (const auto & name_and_type : right_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - - if (column_names.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of projection columns cannot be empty"); - - std::sort(column_names.begin(), column_names.end()); - for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is no any duplicates because it will lead to broken result - if (column_names[i] == column_names[i+1]) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add/change aliases to avoid duplication)" - "While processing '{}'", join_node->formatASTForErrorMessage()); -} - -/// Resolve join node in scope -void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & join_node_typed = join_node->as(); - - resolveQueryJoinTreeNode(join_node_typed.getLeftTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getLeftTableExpression(), scope); - - resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); - - if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) - checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope); - - if (join_node_typed.isOnJoinExpression()) - { - expressions_visitor.visit(join_node_typed.getJoinExpression()); - auto join_expression = join_node_typed.getJoinExpression(); - resolveExpressionNode(join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - join_node_typed.getJoinExpression() = std::move(join_expression); - } - else if (join_node_typed.isUsingJoinExpression()) - { - auto & join_using_list = join_node_typed.getJoinExpression()->as(); - std::unordered_set join_using_identifiers; - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto * identifier_node = join_using_node->as(); - if (!identifier_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} USING clause expected identifier. Actual {}", - join_node_typed.formatASTForErrorMessage(), - join_using_node->formatASTForErrorMessage()); - - const auto & identifier_full_name = identifier_node->getIdentifier().getFullName(); - - if (join_using_identifiers.contains(identifier_full_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} identifier '{}' appears more than once in USING clause", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name); - - join_using_identifiers.insert(identifier_full_name); - - const auto & settings = scope.context->getSettingsRef(); - - /** While resolving JOIN USING identifier, try to resolve identifier from parent subquery projection. - * Example: SELECT a + 1 AS b FROM (SELECT 1 AS a) t1 JOIN (SELECT 2 AS b) USING b - * In this case `b` is not in the left table expression, but it is in the parent subquery projection. - */ - auto try_resolve_identifier_from_query_projection = [this](const String & identifier_full_name_, - const QueryTreeNodePtr & left_table_expression, - const IdentifierResolveScope & scope_) -> QueryTreeNodePtr - { - const QueryNode * query_node = scope_.scope_node ? scope_.scope_node->as() : nullptr; - if (!query_node) - return nullptr; - - const auto & projection_list = query_node->getProjection(); - for (const auto & projection_node : projection_list.getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name_ == projection_node->getAlias()) - { - auto left_subquery = std::make_shared(query_node->getMutableContext()); - left_subquery->getProjection().getNodes().push_back(projection_node->clone()); - left_subquery->getJoinTree() = left_table_expression; - - IdentifierResolveScope left_subquery_scope(left_subquery, nullptr /*parent_scope*/); - resolveQuery(left_subquery, left_subquery_scope); - - const auto & resolved_nodes = left_subquery->getProjection().getNodes(); - if (resolved_nodes.size() == 1) - { - /// Create ColumnNode with expression from parent projection - return std::make_shared( - NameAndTypePair{identifier_full_name_, resolved_nodes.front()->getResultType()}, - resolved_nodes.front(), left_table_expression); - } - } - } - return nullptr; - }; - - QueryTreeNodePtr result_left_table_expression = nullptr; - /** With `analyzer_compatibility_join_using_top_level_identifier` alias in projection has higher priority than column from left table. - * But if aliased expression cannot be resolved from left table, we get UNKNOW_IDENTIFIER error, - * despite the fact that column from USING could be resolved from left table. - * It's compatibility with a default behavior for old analyzer. - */ - if (settings.analyzer_compatibility_join_using_top_level_identifier) - result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - IdentifierLookup identifier_lookup{identifier_node->getIdentifier(), IdentifierLookupContext::EXPRESSION}; - if (!result_left_table_expression) - result_left_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getLeftTableExpression(), scope); - - /** Here we may try to resolve identifier from projection in case it's not resolved from left table expression - * and analyzer_compatibility_join_using_top_level_identifier is disabled. - * For now we do not do this, because not all corner cases are clear. - * But let's at least mention it in error message - */ - /// if (!settings.analyzer_compatibility_join_using_top_level_identifier && !result_left_table_expression) - /// result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - if (!result_left_table_expression) - { - String extra_message; - const QueryNode * query_node = scope.scope_node ? scope.scope_node->as() : nullptr; - if (settings.analyzer_compatibility_join_using_top_level_identifier && query_node) - { - for (const auto & projection_node : query_node->getProjection().getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name == projection_node->getAlias()) - { - extra_message = fmt::format( - ", but alias '{}' is present in SELECT list." - " You may try to SET analyzer_compatibility_join_using_top_level_identifier = 1, to allow to use it in USING clause", - projection_node->formatASTForErrorMessage()); - break; - } - } - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from left table expression{}. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - extra_message, - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_left_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from left table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto result_right_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getRightTableExpression(), scope); - if (!result_right_table_expression) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - if (result_right_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto expression_types = DataTypes{result_left_table_expression->getResultType(), result_right_table_expression->getResultType()}; - DataTypePtr common_type = tryGetLeastSupertype(expression_types); - - if (!common_type) - throw Exception(ErrorCodes::NO_COMMON_TYPE, - "JOIN {} cannot infer common type for {} and {} in USING for identifier '{}'. In scope {}", - join_node_typed.formatASTForErrorMessage(), - result_left_table_expression->getResultType()->getName(), - result_right_table_expression->getResultType()->getName(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - NameAndTypePair join_using_column(identifier_full_name, common_type); - ListNodePtr join_using_expression = std::make_shared(QueryTreeNodes{result_left_table_expression, result_right_table_expression}); - auto join_using_column_node = std::make_shared(std::move(join_using_column), std::move(join_using_expression), join_node); - join_using_node = std::move(join_using_column_node); - } - } -} - -/** Resolve query join tree. - * - * Query join tree must be initialized before calling this function. - */ -void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto from_node_type = join_tree_node->getNodeType(); - - switch (from_node_type) - { - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - resolveExpressionNode(join_tree_node, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - resolveTableFunction(join_tree_node, scope, expressions_visitor, false /*nested_table_function*/); - break; - } - case QueryTreeNodeType::TABLE: - { - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - resolveArrayJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::JOIN: - { - resolveJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::IDENTIFIER: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifiers in FROM section must be already resolved. Node {}, scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, ARRAY JOIN or JOIN. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - auto join_tree_node_type = join_tree_node->getNodeType(); - if (isTableExpressionNodeType(join_tree_node_type)) - { - validateTableExpressionModifiers(join_tree_node, scope); - initializeTableExpressionData(join_tree_node, scope); - - auto & query_node = scope.scope_node->as(); - auto & mutable_context = query_node.getMutableContext(); - - if (!mutable_context->isDistributed()) - { - bool is_distributed = false; - - if (auto * table_node = join_tree_node->as()) - is_distributed = table_node->getStorage()->isRemote(); - else if (auto * table_function_node = join_tree_node->as()) - is_distributed = table_function_node->getStorage()->isRemote(); - - mutable_context->setDistributed(is_distributed); - } - } - - auto add_table_expression_alias_into_scope = [&](const QueryTreeNodePtr & table_expression_node) - { - const auto & alias_name = table_expression_node->getAlias(); - if (alias_name.empty()) - return; - - auto [it, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(alias_name, table_expression_node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Duplicate aliases {} for table expressions in FROM section are not allowed. Try to register {}. Already registered {}.", - alias_name, - table_expression_node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage()); - }; - - add_table_expression_alias_into_scope(join_tree_node); - scope.table_expressions_in_resolve_process.erase(join_tree_node.get()); -} - -/** Resolve query. - * This function modifies query node during resolve. It is caller responsibility to clone query node before resolve - * if it is needed for later use. - * - * query_node - query_tree_node that must have QueryNode type. - * scope - query scope. It is caller responsibility to create it. - * - * Resolve steps: - * 1. Validate subqueries depth, perform GROUP BY validation that does not depend on information about aggregate functions. - * 2. Initialize query scope with aliases. - * 3. Register CTE subqueries from WITH section in scope and remove them from WITH section. - * 4. Resolve JOIN TREE. - * 5. Resolve projection columns. - * 6. Resolve expressions in other query parts. - * 7. Validate nodes with duplicate aliases. - * 8. Validate aggregate functions, GROUPING function, window functions. - * 9. Remove WITH and WINDOW sections from query. - * 10. Remove aliases from expression and lambda nodes. - * 11. Resolve query tree node with projection columns. - */ -void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope) -{ - size_t max_subquery_depth = scope.context->getSettingsRef().max_subquery_depth; - if (max_subquery_depth && scope.subquery_depth > max_subquery_depth) - throw Exception(ErrorCodes::TOO_DEEP_SUBQUERIES, - "Too deep subqueries. Maximum: {}", - max_subquery_depth); - - auto & query_node_typed = query_node->as(); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.insert(query_node_typed.getCTEName()); - - bool is_rollup_or_cube = query_node_typed.isGroupByWithRollup() || query_node_typed.isGroupByWithCube(); - - if (query_node_typed.isGroupByWithGroupingSets() - && query_node_typed.isGroupByWithTotals() - && query_node_typed.getGroupBy().getNodes().size() != 1) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and GROUPING SETS are not supported together"); - - if (query_node_typed.isGroupByWithGroupingSets() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "GROUPING SETS are not supported together with ROLLUP and CUBE"); - - if (query_node_typed.isGroupByWithRollup() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithCube())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "ROLLUP is not supported together with GROUPING SETS and CUBE"); - - if (query_node_typed.isGroupByWithCube() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithRollup())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "CUBE is not supported together with GROUPING SETS and ROLLUP"); - - if (query_node_typed.hasHaving() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of HAVING"); - - if (query_node_typed.hasQualify() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of QUALIFY"); - - /// Initialize aliases in query node scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - - if (query_node_typed.hasWith()) - visitor.visit(query_node_typed.getWithNode()); - - if (!query_node_typed.getProjection().getNodes().empty()) - visitor.visit(query_node_typed.getProjectionNode()); - - if (query_node_typed.getPrewhere()) - visitor.visit(query_node_typed.getPrewhere()); - - if (query_node_typed.getWhere()) - visitor.visit(query_node_typed.getWhere()); - - if (query_node_typed.hasGroupBy()) - visitor.visit(query_node_typed.getGroupByNode()); - - if (query_node_typed.hasHaving()) - visitor.visit(query_node_typed.getHaving()); - - if (query_node_typed.hasWindow()) - visitor.visit(query_node_typed.getWindowNode()); - - if (query_node_typed.hasQualify()) - visitor.visit(query_node_typed.getQualify()); - - if (query_node_typed.hasOrderBy()) - visitor.visit(query_node_typed.getOrderByNode()); - - if (query_node_typed.hasInterpolate()) - visitor.visit(query_node_typed.getInterpolate()); - - if (query_node_typed.hasLimitByLimit()) - visitor.visit(query_node_typed.getLimitByLimit()); - - if (query_node_typed.hasLimitByOffset()) - visitor.visit(query_node_typed.getLimitByOffset()); - - if (query_node_typed.hasLimitBy()) - visitor.visit(query_node_typed.getLimitByNode()); - - if (query_node_typed.hasLimit()) - visitor.visit(query_node_typed.getLimit()); - - if (query_node_typed.hasOffset()) - visitor.visit(query_node_typed.getOffset()); - - /// Register CTE subqueries and remove them from WITH section - - auto & with_nodes = query_node_typed.getWith().getNodes(); - - for (auto & node : with_nodes) - { - auto * subquery_node = node->as(); - auto * union_node = node->as(); - - bool subquery_is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - if (!subquery_is_cte) - continue; - - const auto & cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - auto [_, inserted] = scope.cte_name_to_query_node.emplace(cte_name, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "CTE with name {} already exists. In scope {}", - cte_name, - scope.scope_node->formatASTForErrorMessage()); - } - - /** WITH section can be safely removed, because WITH section only can provide aliases to query expressions - * and CTE for other sections to use. - * - * Example: WITH 1 AS constant, (x -> x + 1) AS lambda, a AS (SELECT * FROM test_table); - */ - query_node_typed.getWith().getNodes().clear(); - - for (auto & window_node : query_node_typed.getWindow().getNodes()) - { - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - if (!parent_window_name.empty()) - { - auto window_node_it = scope.window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope.window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - scope.scope_node->formatASTForErrorMessage()); - - mergeWindowWithParentWindow(window_node, window_node_it->second, scope); - window_node_typed.setParentWindowName({}); - } - - auto [_, inserted] = scope.window_name_to_window_node.emplace(window_node_typed.getAlias(), window_node); - if (!inserted) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' is already defined. In scope {}", - window_node_typed.getAlias(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** Disable identifier cache during JOIN TREE resolve. - * Depending on JOIN expression section, identifier with same name - * can be resolved in different columns. - * - * Example: SELECT id FROM test_table AS t1 INNER JOIN test_table AS t2 ON t1.id = t2.id INNER JOIN test_table AS t3 ON t1.id = t3.id - * In first join expression ON t1.id = t2.id t1.id is resolved into test_table.id column. - * In second join expression ON t1.id = t3.id t1.id must be resolved into test_table.id column after first JOIN. - */ - scope.use_identifier_lookup_to_result_cache = false; - - if (query_node_typed.getJoinTree()) - { - TableExpressionsAliasVisitor table_expressions_visitor(scope); - table_expressions_visitor.visit(query_node_typed.getJoinTree()); - - initializeQueryJoinTreeNode(query_node_typed.getJoinTree(), scope); - scope.aliases.alias_name_to_table_expression_node.clear(); - - resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor); - } - - if (!scope.group_by_use_nulls) - scope.use_identifier_lookup_to_result_cache = true; - - /// Resolve query node sections. - - NamesAndTypes projection_columns; - - if (!scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - if (auto & prewhere_node = query_node_typed.getPrewhere()) - { - resolveExpressionNode(prewhere_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** Expressions in PREWHERE with JOIN should not change their type. - * Example: SELECT * FROM t1 JOIN t2 USING (a) PREWHERE a = 1 - * Column `a` in PREWHERE should be resolved from the left table - * and should not change its type to Nullable or to the supertype of `a` from t1 and t2. - * Here's a more complicated example where the column is somewhere inside an expression: - * SELECT a + 1 as b FROM t1 JOIN t2 USING (id) PREWHERE b = 1 - * The expression `a + 1 as b` in the projection and in PREWHERE should have different `a`. - */ - prewhere_node = prewhere_node->clone(); - ReplaceColumnsVisitor replace_visitor(scope.join_columns_with_changed_types, scope.context); - replace_visitor.visit(prewhere_node); - } - - if (query_node_typed.getWhere()) - resolveExpressionNode(query_node_typed.getWhere(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasGroupBy()) - resolveGroupByNode(query_node_typed, scope); - - if (scope.group_by_use_nulls) - { - resolved_expressions.clear(); - /// Clone is needed cause aliases share subtrees. - /// If not clone, the same (shared) subtree could be resolved again with different (Nullable) type - /// See 03023_group_by_use_nulls_analyzer_crashes - for (auto & [key, node] : scope.aliases.alias_name_to_expression_node_before_group_by) - scope.aliases.alias_name_to_expression_node_after_group_by[key] = node->clone(); - - scope.aliases.alias_name_to_expression_node = &scope.aliases.alias_name_to_expression_node_after_group_by; - } - - if (query_node_typed.hasHaving()) - resolveExpressionNode(query_node_typed.getHaving(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasWindow()) - resolveWindowNodeList(query_node_typed.getWindowNode(), scope); - - if (query_node_typed.hasQualify()) - resolveExpressionNode(query_node_typed.getQualify(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasOrderBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getOrderByNode(), query_node_typed.getProjection().getNodes(), scope); - - const auto & settings = scope.context->getSettingsRef(); - - expandOrderByAll(query_node_typed, settings); - resolveSortNodeList(query_node_typed.getOrderByNode(), scope); - } - - if (query_node_typed.hasInterpolate()) - resolveInterpolateColumnsNodeList(query_node_typed.getInterpolate(), scope); - - if (query_node_typed.hasLimitByLimit()) - { - resolveExpressionNode(query_node_typed.getLimitByLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByLimit(), "LIMIT BY LIMIT", scope); - } - - if (query_node_typed.hasLimitByOffset()) - { - resolveExpressionNode(query_node_typed.getLimitByOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByOffset(), "LIMIT BY OFFSET", scope); - } - - if (query_node_typed.hasLimitBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getLimitByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getLimitByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - - if (query_node_typed.hasLimit()) - { - resolveExpressionNode(query_node_typed.getLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimit(), "LIMIT", scope); - } - - if (query_node_typed.hasOffset()) - { - resolveExpressionNode(query_node_typed.getOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getOffset(), "OFFSET", scope); - } - - if (scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - /** Resolve nodes with duplicate aliases. - * Table expressions cannot have duplicate aliases. - * - * Such nodes during scope aliases collection are placed into duplicated array. - * After scope nodes are resolved, we can compare node with duplicate alias with - * node from scope alias table. - */ - for (const auto & node_with_duplicated_alias : scope.aliases.cloned_nodes_with_duplicated_aliases) - { - auto node = node_with_duplicated_alias; - auto node_alias = node->getAlias(); - - /// Add current alias to non cached set, because in case of cyclic alias identifier should not be substituted from cache. - /// See 02896_cyclic_aliases_crash. - resolveExpressionNode(node, scope, true /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool has_node_in_alias_table = false; - - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - if (!has_node_in_alias_table) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node {} with duplicate alias {} does not exist in alias table. In scope {}", - node->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - - node->removeAlias(); - } - - expandGroupByAll(query_node_typed); - - validateFilters(query_node); - validateAggregates(query_node, { .group_by_use_nulls = scope.group_by_use_nulls }); - - for (const auto & column : projection_columns) - { - if (isNotCreatable(column.type)) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Invalid projection column with type {}. In scope {}", - column.type->getName(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** WINDOW section can be safely removed, because WINDOW section can only provide window definition to window functions. - * - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - */ - query_node_typed.getWindow().getNodes().clear(); - - /// Remove aliases from expression and lambda nodes - - for (auto & [_, node] : *scope.aliases.alias_name_to_expression_node) - node->removeAlias(); - - for (auto & [_, node] : scope.aliases.alias_name_to_lambda_node) - node->removeAlias(); - - query_node_typed.resolveProjectionColumns(std::move(projection_columns)); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.erase(query_node_typed.getCTEName()); -} - -void QueryAnalyzer::resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope) -{ - auto & union_node_typed = union_node->as(); - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.insert(union_node_typed.getCTEName()); - - auto & queries_nodes = union_node_typed.getQueries().getNodes(); - - std::optional recursive_cte_table; - TableNodePtr recursive_cte_table_node; - - if (union_node_typed.isCTE() && union_node_typed.isRecursiveCTE()) - { - auto & non_recursive_query = queries_nodes[0]; - bool non_recursive_query_is_query_node = non_recursive_query->getNodeType() == QueryTreeNodeType::QUERY; - auto & non_recursive_query_mutable_context = non_recursive_query_is_query_node ? non_recursive_query->as().getMutableContext() - : non_recursive_query->as().getMutableContext(); - - IdentifierResolveScope non_recursive_subquery_scope(non_recursive_query, &scope /*parent_scope*/); - non_recursive_subquery_scope.subquery_depth = scope.subquery_depth + 1; - - if (non_recursive_query_is_query_node) - resolveQuery(non_recursive_query, non_recursive_subquery_scope); - else - resolveUnion(non_recursive_query, non_recursive_subquery_scope); - - auto temporary_table_columns = non_recursive_query_is_query_node - ? non_recursive_query->as().getProjectionColumns() - : non_recursive_query->as().computeProjectionColumns(); - - auto temporary_table_holder = std::make_shared( - non_recursive_query_mutable_context, - ColumnsDescription{NamesAndTypesList{temporary_table_columns.begin(), temporary_table_columns.end()}}, - ConstraintsDescription{}, - nullptr /*query*/, - true /*create_for_global_subquery*/); - auto temporary_table_storage = temporary_table_holder->getTable(); - - recursive_cte_table_node = std::make_shared(temporary_table_storage, non_recursive_query_mutable_context); - recursive_cte_table_node->setTemporaryTableName(union_node_typed.getCTEName()); - - recursive_cte_table.emplace(std::move(temporary_table_holder), std::move(temporary_table_storage), std::move(temporary_table_columns)); - } - - size_t queries_nodes_size = queries_nodes.size(); - for (size_t i = recursive_cte_table.has_value(); i < queries_nodes_size; ++i) - { - auto & query_node = queries_nodes[i]; - - IdentifierResolveScope subquery_scope(query_node, &scope /*parent_scope*/); - - if (recursive_cte_table_node) - subquery_scope.expression_argument_name_to_node[union_node_typed.getCTEName()] = recursive_cte_table_node; - - auto query_node_type = query_node->getNodeType(); - - if (query_node_type == QueryTreeNodeType::QUERY) - { - resolveQuery(query_node, subquery_scope); - } - else if (query_node_type == QueryTreeNodeType::UNION) - { - resolveUnion(query_node, subquery_scope); - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "UNION unsupported node {}. In scope {}", - query_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (recursive_cte_table && isStorageUsedInTree(recursive_cte_table->storage, union_node.get())) - { - if (union_node_typed.getUnionMode() != SelectUnionMode::UNION_ALL) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive CTE subquery {} with {} union mode is unsupported, only UNION ALL union mode is supported", - union_node_typed.formatASTForErrorMessage(), - toString(union_node_typed.getUnionMode())); - - union_node_typed.setRecursiveCTETable(std::move(*recursive_cte_table)); - } - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.erase(union_node_typed.getCTEName()); -} - -} - -QueryAnalysisPass::QueryAnalysisPass(QueryTreeNodePtr table_expression_, bool only_analyze_) - : table_expression(std::move(table_expression_)) - , only_analyze(only_analyze_) -{} - -QueryAnalysisPass::QueryAnalysisPass(bool only_analyze_) : only_analyze(only_analyze_) {} - -void QueryAnalysisPass::run(QueryTreeNodePtr & query_tree_node, ContextPtr context) -{ - QueryAnalyzer analyzer(only_analyze); - analyzer.resolve(query_tree_node, table_expression, context); - createUniqueTableAliases(query_tree_node, table_expression, context); -} - } diff --git a/src/Analyzer/QueryAnalysis/QueryAnalysisPass.cpp b/src/Analyzer/QueryAnalysis/QueryAnalysisPass.cpp new file mode 100644 index 00000000000..b3de3e063b0 --- /dev/null +++ b/src/Analyzer/QueryAnalysis/QueryAnalysisPass.cpp @@ -0,0 +1,22 @@ +#include +#include +#include + +namespace DB +{ + +QueryAnalysisPass::QueryAnalysisPass(QueryTreeNodePtr table_expression_, bool only_analyze_) + : table_expression(std::move(table_expression_)) + , only_analyze(only_analyze_) +{} + +QueryAnalysisPass::QueryAnalysisPass(bool only_analyze_) : only_analyze(only_analyze_) {} + +void QueryAnalysisPass::run(QueryTreeNodePtr & query_tree_node, ContextPtr context) +{ + QueryAnalyzer analyzer(only_analyze); + analyzer.resolve(query_tree_node, table_expression, context); + createUniqueTableAliases(query_tree_node, table_expression, context); +} + +} diff --git a/src/Analyzer/QueryAnalysis/QueryAnalyzer.cpp b/src/Analyzer/QueryAnalysis/QueryAnalyzer.cpp index 3fca66e6eb8..a7af7bd2dbb 100644 --- a/src/Analyzer/QueryAnalysis/QueryAnalyzer.cpp +++ b/src/Analyzer/QueryAnalysis/QueryAnalyzer.cpp @@ -1,16 +1,3 @@ -#include - -#include - -#include -#include -#include - -#include -#include -#include - -#include #include #include #include @@ -20,42 +7,26 @@ #include #include #include -#include #include -#include -#include -#include - #include #include #include #include -#include - #include #include -#include - #include -#include #include #include #include -#include -#include -#include -#include -#include #include #include #include -#include #include #include #include @@ -85,6 +56,11 @@ #include #include +#include +#include +#include +#include + namespace ProfileEvents { extern const Event ScalarSubqueriesGlobalCacheHit; @@ -94,7 +70,6 @@ namespace ProfileEvents namespace DB { - namespace ErrorCodes { extern const int UNSUPPORTED_METHOD; @@ -130,1470 +105,146 @@ namespace ErrorCodes extern const int INVALID_IDENTIFIER; } -/** Query analyzer implementation overview. Please check documentation in QueryAnalysisPass.h first. - * And additional documentation for each method, where special cases are described in detail. - * - * Each node in query must be resolved. For each query tree node resolved state is specific. - * - * For constant node no resolve process exists, it is resolved during construction. - * - * For table node no resolve process exists, it is resolved during construction. - * - * For function node to be resolved parameters and arguments must be resolved, function node must be initialized with concrete aggregate or - * non aggregate function and with result type. - * - * For lambda node there can be 2 different cases. - * 1. Standalone: WITH (x -> x + 1) AS lambda SELECT lambda(1); Such lambdas are inlined in query tree during query analysis pass. - * 2. Function arguments: WITH (x -> x + 1) AS lambda SELECT arrayMap(lambda, [1, 2, 3]); For such lambda resolution must - * set concrete lambda arguments (initially they are identifier nodes) and resolve lambda expression body. - * - * For query node resolve process must resolve all its inner nodes. - * - * For matcher node resolve process must replace it with matched nodes. - * - * For identifier node resolve process must replace it with concrete non identifier node. This part is most complex because - * for identifier resolution scopes and identifier lookup context play important part. - * - * ClickHouse SQL support lexical scoping for identifier resolution. Scope can be defined by query node or by expression node. - * Expression nodes that can define scope are lambdas and table ALIAS columns. - * - * Identifier lookup context can be expression, function, table. - * - * Examples: WITH (x -> x + 1) as func SELECT func() FROM func; During function `func` resolution identifier lookup is performed - * in function context. - * - * If there are no information of identifier context rules are following: - * 1. Try to resolve identifier in expression context. - * 2. Try to resolve identifier in function context, if it is allowed. Example: SELECT func(arguments); Here func identifier cannot be resolved in function context - * because query projection does not support that. - * 3. Try to resolve identifier in table context, if it is allowed. Example: SELECT table; Here table identifier cannot be resolved in function context - * because query projection does not support that. - * - * TODO: This does not supported properly before, because matchers could not be resolved from aliases. - * - * Identifiers are resolved with following rules: - * Resolution starts with current scope. - * 1. Try to resolve identifier from expression scope arguments. Lambda expression arguments are greatest priority. - * 2. Try to resolve identifier from aliases. - * 3. Try to resolve identifier from join tree if scope is query, or if there are registered table columns in scope. - * Steps 2 and 3 can be changed using prefer_column_name_to_alias setting. - * 4. If it is table lookup, try to resolve identifier from CTE. - * If identifier could not be resolved in current scope, resolution must be continued in parent scopes. - * 5. Try to resolve identifier from parent scopes. - * - * Additional rules about aliases and scopes. - * 1. Parent scope cannot refer alias from child scope. - * 2. Child scope can refer to alias in parent scope. - * - * Example: SELECT arrayMap(x -> x + 1 AS a, [1,2,3]), a; Identifier a is unknown in parent scope. - * Example: SELECT a FROM (SELECT 1 as a); Here we do not refer to alias a from child query scope. But we query it projection result, similar to tables. - * Example: WITH 1 as a SELECT (SELECT a) as b; Here in child scope identifier a is resolved using alias from parent scope. - * - * Additional rules about identifier binding. - * Bind for identifier to entity means that identifier first part match some node during analysis. - * If other parts of identifier cannot be resolved in that node, exception must be thrown. - * - * Example: - * CREATE TABLE test_table (id UInt64, compound_value Tuple(value UInt64)) ENGINE=TinyLog; - * SELECT compound_value.value, 1 AS compound_value FROM test_table; - * Identifier first part compound_value bound to entity with alias compound_value, but nested identifier part cannot be resolved from entity, - * lookup should not be continued, and exception must be thrown because if lookup continues that way identifier can be resolved from join tree. - * - * TODO: This was not supported properly before analyzer because nested identifier could not be resolved from alias. - * - * More complex example: - * CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; - * WITH cast(('Value'), 'Tuple (value UInt64') AS value SELECT (SELECT value FROM test_table); - * Identifier first part value bound to test_table column value, but nested identifier part cannot be resolved from it, - * lookup should not be continued, and exception must be thrown because if lookup continues identifier can be resolved from parent scope. - * - * TODO: Update exception messages - * TODO: Table identifiers with optional UUID. - * TODO: Lookup functions arrayReduce(sum, [1, 2, 3]); - * TODO: Support function identifier resolve from parent query scope, if lambda in parent scope does not capture any columns. - */ +QueryAnalyzer::QueryAnalyzer(bool only_analyze_) : only_analyze(only_analyze_) {} +QueryAnalyzer::~QueryAnalyzer() = default; -namespace +void QueryAnalyzer::resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context) { + IdentifierResolveScope scope(node, nullptr /*parent_scope*/); -/// Identifier lookup context -enum class IdentifierLookupContext : uint8_t -{ - EXPRESSION = 0, - FUNCTION, - TABLE_EXPRESSION, -}; + if (!scope.context) + scope.context = context; -const char * toString(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) + auto node_type = node->getNodeType(); + + switch (node_type) { - case IdentifierLookupContext::EXPRESSION: return "EXPRESSION"; - case IdentifierLookupContext::FUNCTION: return "FUNCTION"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "TABLE_EXPRESSION"; + case QueryTreeNodeType::QUERY: + { + if (table_expression) + throw Exception(ErrorCodes::LOGICAL_ERROR, + "For query analysis table expression must be empty"); + + resolveQuery(node, scope); + break; + } + case QueryTreeNodeType::UNION: + { + if (table_expression) + throw Exception(ErrorCodes::LOGICAL_ERROR, + "For union analysis table expression must be empty"); + + resolveUnion(node, scope); + break; + } + case QueryTreeNodeType::IDENTIFIER: + [[fallthrough]]; + case QueryTreeNodeType::CONSTANT: + [[fallthrough]]; + case QueryTreeNodeType::COLUMN: + [[fallthrough]]; + case QueryTreeNodeType::FUNCTION: + [[fallthrough]]; + case QueryTreeNodeType::LIST: + { + if (table_expression) + { + scope.expression_join_tree_node = table_expression; + validateTableExpressionModifiers(scope.expression_join_tree_node, scope); + initializeTableExpressionData(scope.expression_join_tree_node, scope); + } + + if (node_type == QueryTreeNodeType::LIST) + resolveExpressionNodeList(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); + else + resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); + + break; + } + case QueryTreeNodeType::TABLE_FUNCTION: + { + QueryExpressionsAliasVisitor expressions_alias_visitor(scope.aliases); + resolveTableFunction(node, scope, expressions_alias_visitor, false /*nested_table_function*/); + break; + } + default: + { + throw Exception(ErrorCodes::BAD_ARGUMENTS, + "Node {} with type {} is not supported by query analyzer. " + "Supported nodes are query, union, identifier, constant, column, function, list.", + node->formatASTForErrorMessage(), + node->getNodeTypeName()); + } } } -const char * toStringLowercase(IdentifierLookupContext identifier_lookup_context) +std::optional QueryAnalyzer::getColumnSideFromJoinTree(const QueryTreeNodePtr & resolved_identifier, const JoinNode & join_node) { - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "expression"; - case IdentifierLookupContext::FUNCTION: return "function"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "table expression"; - } -} - -/** Structure that represent identifier lookup during query analysis. - * Lookup can be in query expression, function, table context. - */ -struct IdentifierLookup -{ - Identifier identifier; - IdentifierLookupContext lookup_context; - - bool isExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::EXPRESSION; - } - - bool isFunctionLookup() const - { - return lookup_context == IdentifierLookupContext::FUNCTION; - } - - bool isTableExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::TABLE_EXPRESSION; - } - - String dump() const - { - return identifier.getFullName() + ' ' + toString(lookup_context); - } -}; - -inline bool operator==(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return lhs.identifier.getFullName() == rhs.identifier.getFullName() && lhs.lookup_context == rhs.lookup_context; -} - -[[maybe_unused]] inline bool operator!=(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return !(lhs == rhs); -} - -struct IdentifierLookupHash -{ - size_t operator()(const IdentifierLookup & identifier_lookup) const - { - return std::hash()(identifier_lookup.identifier.getFullName()) ^ static_cast(identifier_lookup.lookup_context); - } -}; - -enum class IdentifierResolvePlace : UInt8 -{ - NONE = 0, - EXPRESSION_ARGUMENTS, - ALIASES, - JOIN_TREE, - /// Valid only for table lookup - CTE, - /// Valid only for table lookup - DATABASE_CATALOG -}; - -const char * toString(IdentifierResolvePlace resolved_identifier_place) -{ - switch (resolved_identifier_place) - { - case IdentifierResolvePlace::NONE: return "NONE"; - case IdentifierResolvePlace::EXPRESSION_ARGUMENTS: return "EXPRESSION_ARGUMENTS"; - case IdentifierResolvePlace::ALIASES: return "ALIASES"; - case IdentifierResolvePlace::JOIN_TREE: return "JOIN_TREE"; - case IdentifierResolvePlace::CTE: return "CTE"; - case IdentifierResolvePlace::DATABASE_CATALOG: return "DATABASE_CATALOG"; - } -} - -struct IdentifierResolveResult -{ - IdentifierResolveResult() = default; - - QueryTreeNodePtr resolved_identifier; - IdentifierResolvePlace resolve_place = IdentifierResolvePlace::NONE; - bool resolved_from_parent_scopes = false; - - [[maybe_unused]] bool isResolved() const - { - return resolve_place != IdentifierResolvePlace::NONE; - } - - [[maybe_unused]] bool isResolvedFromParentScopes() const - { - return resolved_from_parent_scopes; - } - - [[maybe_unused]] bool isResolvedFromExpressionArguments() const - { - return resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - } - - [[maybe_unused]] bool isResolvedFromAliases() const - { - return resolve_place == IdentifierResolvePlace::ALIASES; - } - - [[maybe_unused]] bool isResolvedFromJoinTree() const - { - return resolve_place == IdentifierResolvePlace::JOIN_TREE; - } - - [[maybe_unused]] bool isResolvedFromCTEs() const - { - return resolve_place == IdentifierResolvePlace::CTE; - } - - void dump(WriteBuffer & buffer) const - { - if (!resolved_identifier) - { - buffer << "unresolved"; - return; - } - - buffer << resolved_identifier->formatASTForErrorMessage() << " place " << toString(resolve_place) << " resolved from parent scopes " << resolved_from_parent_scopes; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -struct IdentifierResolveState -{ - IdentifierResolveResult resolve_result; - bool cyclic_identifier_resolve = false; -}; - -struct IdentifierResolveSettings -{ - /// Allow to check join tree during identifier resolution - bool allow_to_check_join_tree = true; - - /// Allow to check CTEs during table identifier resolution - bool allow_to_check_cte = true; - - /// Allow to check parent scopes during identifier resolution - bool allow_to_check_parent_scopes = true; - - /// Allow to check database catalog during table identifier resolution - bool allow_to_check_database_catalog = true; - - /// Allow to resolve subquery during identifier resolution - bool allow_to_resolve_subquery_during_identifier_resolution = true; -}; - -struct StringTransparentHash -{ - using is_transparent = void; - using hash = std::hash; - - [[maybe_unused]] size_t operator()(const char * data) const - { - return hash()(data); - } - - size_t operator()(std::string_view data) const - { - return hash()(data); - } - - size_t operator()(const std::string & data) const - { - return hash()(data); - } -}; - -using ColumnNameToColumnNodeMap = std::unordered_map>; - -struct TableExpressionData -{ - std::string table_expression_name; - std::string table_expression_description; - std::string database_name; - std::string table_name; - bool should_qualify_columns = true; - NamesAndTypes column_names_and_types; - ColumnNameToColumnNodeMap column_name_to_column_node; - std::unordered_set subcolumn_names; /// Subset columns that are subcolumns of other columns - std::unordered_set> column_identifier_first_parts; - - bool hasFullIdentifierName(IdentifierView identifier_view) const - { - return column_name_to_column_node.contains(identifier_view.getFullName()); - } - - bool canBindIdentifier(IdentifierView identifier_view) const - { - return column_identifier_first_parts.contains(identifier_view.at(0)); - } - - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Table expression name " << table_expression_name; - - if (!table_expression_description.empty()) - buffer << " table expression description " << table_expression_description; - - if (!database_name.empty()) - buffer << " database name " << database_name; - - if (!table_name.empty()) - buffer << " table name " << table_name; - - buffer << " should qualify columns " << should_qualify_columns; - buffer << " columns size " << column_name_to_column_node.size() << '\n'; - - for (const auto & [column_name, column_node] : column_name_to_column_node) - buffer << "Column name " << column_name << " column node " << column_node->dumpTree() << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -class ExpressionsStack -{ -public: - void push(const QueryTreeNodePtr & node) - { - if (node->hasAlias()) - { - const auto & node_alias = node->getAlias(); - alias_name_to_expressions[node_alias].push_back(node); - } - - if (const auto * function = node->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - ++aggregate_functions_counter; - } - - expressions.emplace_back(node); - } - - void pop() - { - const auto & top_expression = expressions.back(); - const auto & top_expression_alias = top_expression->getAlias(); - - if (!top_expression_alias.empty()) - { - auto it = alias_name_to_expressions.find(top_expression_alias); - auto & alias_expressions = it->second; - alias_expressions.pop_back(); - - if (alias_expressions.empty()) - alias_name_to_expressions.erase(it); - } - - if (const auto * function = top_expression->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - --aggregate_functions_counter; - } - - expressions.pop_back(); - } - - [[maybe_unused]] const QueryTreeNodePtr & getRoot() const - { - return expressions.front(); - } - - const QueryTreeNodePtr & getTop() const - { - return expressions.back(); - } - - [[maybe_unused]] bool hasExpressionWithAlias(const std::string & alias) const - { - return alias_name_to_expressions.contains(alias); - } - - bool hasAggregateFunction() const - { - return aggregate_functions_counter > 0; - } - - QueryTreeNodePtr getExpressionWithAlias(const std::string & alias) const - { - auto expression_it = alias_name_to_expressions.find(alias); - if (expression_it == alias_name_to_expressions.end()) - return {}; - - return expression_it->second.front(); - } - - [[maybe_unused]] size_t size() const - { - return expressions.size(); - } - - bool empty() const - { - return expressions.empty(); - } - - void dump(WriteBuffer & buffer) const - { - buffer << expressions.size() << '\n'; - - for (const auto & expression : expressions) - { - buffer << "Expression "; - buffer << expression->formatASTForErrorMessage(); - - const auto & alias = expression->getAlias(); - if (!alias.empty()) - buffer << " alias " << alias; - - buffer << '\n'; - } - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } - -private: - QueryTreeNodes expressions; - size_t aggregate_functions_counter = 0; - std::unordered_map alias_name_to_expressions; -}; - -struct ScopeAliases -{ - /// Alias name to query expression node - std::unordered_map alias_name_to_expression_node_before_group_by; - std::unordered_map alias_name_to_expression_node_after_group_by; - - std::unordered_map * alias_name_to_expression_node = nullptr; - - /// Alias name to lambda node - std::unordered_map alias_name_to_lambda_node; - - /// Alias name to table expression node - std::unordered_map alias_name_to_table_expression_node; - - /// Expressions like `x as y` where we can't say whether it's a function, expression or table. - std::unordered_map transitive_aliases; - - /// Nodes with duplicated aliases - std::unordered_set nodes_with_duplicated_aliases; - std::vector cloned_nodes_with_duplicated_aliases; - - /// Names which are aliases from ARRAY JOIN. - /// This is needed to properly qualify columns from matchers and avoid name collision. - std::unordered_set array_join_aliases; - - std::unordered_map & getAliasMap(IdentifierLookupContext lookup_context) - { - switch (lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return *alias_name_to_expression_node; - case IdentifierLookupContext::FUNCTION: return alias_name_to_lambda_node; - case IdentifierLookupContext::TABLE_EXPRESSION: return alias_name_to_table_expression_node; - } - } - - enum class FindOption - { - FIRST_NAME, - FULL_NAME, - }; - - const std::string & getKey(const Identifier & identifier, FindOption find_option) - { - switch (find_option) - { - case FindOption::FIRST_NAME: return identifier.front(); - case FindOption::FULL_NAME: return identifier.getFullName(); - } - } - - QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) - { - auto & alias_map = getAliasMap(lookup.lookup_context); - const std::string * key = &getKey(lookup.identifier, find_option); - - auto it = alias_map.find(*key); - - if (it != alias_map.end()) - return &it->second; - - if (lookup.lookup_context == IdentifierLookupContext::TABLE_EXPRESSION) - return {}; - - while (it == alias_map.end()) - { - auto jt = transitive_aliases.find(*key); - if (jt == transitive_aliases.end()) - return {}; - - key = &(getKey(jt->second, find_option)); - it = alias_map.find(*key); - } - - return &it->second; - } - - const QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) const - { - return const_cast(this)->find(lookup, find_option); - } -}; - - -/** Projection names is name of query tree node that is used in projection part of query node. - * Example: SELECT id FROM test_table; - * `id` is projection name of column node - * - * Example: SELECT id AS id_alias FROM test_table; - * `id_alias` is projection name of column node - * - * Calculation of projection names is done during expression nodes resolution. This is done this way - * because after identifier node is resolved we lose information about identifier name. We could - * potentially save this information in query tree node itself, but that would require to clone it in some cases. - * Example: SELECT big_scalar_subquery AS a, a AS b, b AS c; - * All 3 nodes in projection are the same big_scalar_subquery, but they have different projection names. - * If we want to save it in query tree node, we have to clone subquery node that could lead to performance degradation. - * - * Possible solution is to separate query node metadata and query node content. So only node metadata could be cloned - * if we want to change projection name. This solution does not seem to be easy for client of query tree because projection - * name will be part of interface. If we potentially could hide projection names calculation in analyzer without introducing additional - * changes in query tree structure that would be preferable. - * - * Currently each resolve method returns projection names array. Resolve method must compute projection names of node. - * If node is resolved as list node this is case for `untuple` function or `matcher` result projection names array must contain projection names - * for result nodes. - * If node is not resolved as list node, projection names array contain single projection name for node. - * - * Rules for projection names: - * 1. If node has alias. It is node projection name. - * Except scenario where `untuple` function has alias. Example: SELECT untuple(expr) AS alias, alias. - * - * 2. For constant it is constant value string representation. - * - * 3. For identifier: - * If identifier is resolved from JOIN TREE, we want to remove additional identifier qualifications. - * Example: SELECT default.test_table.id FROM test_table. - * Result projection name is `id`. - * - * Example: SELECT t1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In example both test_table_1, test_table_2 have `id` column. - * In such case projection name is `t1.id` because if additional qualification is removed then column projection name `id` will be ambiguous. - * - * Example: SELECT default.test_table_1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In such case projection name is `test_table_1.id` because we remove unnecessary database qualification, but table name qualification cannot be removed - * because otherwise column projection name `id` will be ambiguous. - * - * If identifier is not resolved from JOIN TREE. Identifier name is projection name. - * Except scenario where `untuple` function resolved using identifier. Example: SELECT untuple(expr) AS alias, alias. - * Example: SELECT sum(1, 1) AS value, value. - * In such case both nodes have `value` projection names. - * - * Example: SELECT id AS value, value FROM test_table. - * In such case both nodes have have `value` projection names. - * - * Special case is `untuple` function. If `untuple` function specified with alias, then result nodes will have alias.tuple_column_name projection names. - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value) AS a; - * Result projection names are `value`, `a.id`. - * - * If `untuple` function does not have alias then result nodes will have `tupleElement(untuple_expression_projection_name, 'tuple_column_name') projection names. - * - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value); - * Result projection names are `value`, `tupleElement(value, 'id')`; - * - * 4. For function: - * Projection name consists from function_name(parameters_projection_names)(arguments_projection_names). - * Additionally if function is window function. Window node projection name is used with OVER clause. - * Example: function_name (parameters_names)(argument_projection_names) OVER window_name; - * Example: function_name (parameters_names)(argument_projection_names) OVER (PARTITION BY id ORDER BY id). - * Example: function_name (parameters_names)(argument_projection_names) OVER (window_name ORDER BY id). - * - * 5. For lambda: - * If it is standalone lambda that returns single expression, function projection name is used. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(1). - * Projection name is `lambda(1)`. - * - * If is it standalone lambda that returns list, projection names of list nodes are used. - * Example: WITH (x -> *) AS lambda SELECT lambda(1) FROM test_table; - * If test_table has two columns `id`, `value`. Then result projection names are `id`, `value`. - * - * If lambda is argument of function. - * Then projection name consists from lambda(tuple(lambda_arguments)(lambda_body_projection_name)); - * - * 6. For matcher: - * Matched nodes projection names are used as matcher projection names. - * - * Matched nodes must be qualified if needed. - * Example: SELECT * FROM test_table_1 AS t1, test_table_2 AS t2. - * In example table test_table_1 and test_table_2 both have `id`, `value` columns. - * Matched nodes after unqualified matcher resolve must be qualified to avoid ambiguous projection names. - * Result projection names must be `t1.id`, `t1.value`, `t2.id`, `t2.value`. - * - * There are special cases - * 1. For lambda inside APPLY matcher transformer: - * Example: SELECT * APPLY x -> toString(x) FROM test_table. - * In such case lambda argument projection name `x` will be replaced by matched node projection name. - * If table has two columns `id` and `value`. Then result projection names are `toString(id)`, `toString(value)`; - * - * 2. For unqualified matcher when JOIN tree contains JOIN with USING. - * Example: SELECT * FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING(id); - * Result projection names must be `id`, `t1.value`, `t2.value`. - * - * 7. For subquery: - * For subquery projection name consists of `_subquery_` prefix and implementation specific unique number suffix. - * Example: SELECT (SELECT 1), (SELECT 1 UNION DISTINCT SELECT 1); - * Result projection name can be `_subquery_1`, `subquery_2`; - * - * 8. For table: - * Table node can be used in expression context only as right argument of IN function. In that case identifier is used - * as table node projection name. - * Example: SELECT id IN test_table FROM test_table; - * Result projection name is `in(id, test_table)`. - */ -using ProjectionName = String; -using ProjectionNames = std::vector; -constexpr auto PROJECTION_NAME_PLACEHOLDER = "__projection_name_placeholder"; - -struct IdentifierResolveScope -{ - /// Construct identifier resolve scope using scope node, and parent scope - IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) - : scope_node(std::move(scope_node_)) - , parent_scope(parent_scope_) - { - if (parent_scope) - { - subquery_depth = parent_scope->subquery_depth; - context = parent_scope->context; - projection_mask_map = parent_scope->projection_mask_map; - } - else - projection_mask_map = std::make_shared>(); - - if (auto * union_node = scope_node->as()) - { - context = union_node->getContext(); - } - else if (auto * query_node = scope_node->as()) - { - context = query_node->getContext(); - group_by_use_nulls = context->getSettingsRef().group_by_use_nulls && - (query_node->isGroupByWithGroupingSets() || query_node->isGroupByWithRollup() || query_node->isGroupByWithCube()); - } - - if (context) - join_use_nulls = context->getSettingsRef().join_use_nulls; - else if (parent_scope) - join_use_nulls = parent_scope->join_use_nulls; - - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - QueryTreeNodePtr scope_node; - - IdentifierResolveScope * parent_scope = nullptr; - - ContextPtr context; - - /// Identifier lookup to result - std::unordered_map identifier_lookup_to_resolve_state; - - /// Argument can be expression like constant, column, function or table expression - std::unordered_map expression_argument_name_to_node; - - ScopeAliases aliases; - - /// Table column name to column node. Valid only during table ALIAS columns resolve. - ColumnNameToColumnNodeMap column_name_to_column_node; - - /// CTE name to query node - std::unordered_map cte_name_to_query_node; - - /// Window name to window node - std::unordered_map window_name_to_window_node; - - /// Current scope expression in resolve process stack - ExpressionsStack expressions_in_resolve_process_stack; - - /// Table expressions in resolve process - std::unordered_set table_expressions_in_resolve_process; - - /// Current scope expression - std::unordered_set non_cached_identifier_lookups_during_expression_resolve; - - /// Table expression node to data - std::unordered_map table_expression_node_to_data; - - QueryTreeNodePtrWithHashIgnoreTypesSet nullable_group_by_keys; - /// Here we count the number of nullable GROUP BY keys we met resolving expression. - /// E.g. for a query `SELECT tuple(tuple(number)) FROM numbers(10) GROUP BY (number, tuple(number)) with cube` - /// both `number` and `tuple(number)` would be in nullable_group_by_keys. - /// But when we resolve `tuple(tuple(number))` we should figure out that `tuple(number)` is already a key, - /// and we should not convert `number` to nullable. - size_t found_nullable_group_by_key_in_scope = 0; - - /** It's possible that after a JOIN, a column in the projection has a type different from the column in the source table. - * (For example, after join_use_nulls or USING column casted to supertype) - * However, the column in the projection still refers to the table as its source. - * This map is used to revert these columns back to their original columns in the source table. - */ - QueryTreeNodePtrWithHashMap join_columns_with_changed_types; - - /// Use identifier lookup to result cache - bool use_identifier_lookup_to_result_cache = true; - - /// Apply nullability to aggregation keys - bool group_by_use_nulls = false; - /// Join retutns NULLs instead of default values - bool join_use_nulls = false; - - /// JOINs count - size_t joins_count = 0; - - /// Subquery depth - size_t subquery_depth = 0; - - /** Scope join tree node for expression. - * Valid only during analysis construction for single expression. - */ - QueryTreeNodePtr expression_join_tree_node; - - /// Node hash to mask id map - std::shared_ptr> projection_mask_map; - - struct ResolvedFunctionsCache - { - FunctionOverloadResolverPtr resolver; - FunctionBasePtr function_base; - }; - - std::map functions_cache; - - [[maybe_unused]] const IdentifierResolveScope * getNearestQueryScope() const - { - const IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - IdentifierResolveScope * getNearestQueryScope() - { - IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - const TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - void pushExpressionNode(const QueryTreeNodePtr & node) - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.push(node); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - void popExpressionNode() - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.pop(); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_after_group_by; - } - - /// Dump identifier resolve scope - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Scope node " << scope_node->formatASTForErrorMessage() << '\n'; - buffer << "Identifier lookup to resolve state " << identifier_lookup_to_resolve_state.size() << '\n'; - for (const auto & [identifier, state] : identifier_lookup_to_resolve_state) - { - buffer << "Identifier " << identifier.dump() << " resolve result "; - state.resolve_result.dump(buffer); - buffer << '\n'; - } - - buffer << "Expression argument name to node " << expression_argument_name_to_node.size() << '\n'; - for (const auto & [alias_name, node] : expression_argument_name_to_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to expression node table size " << aliases.alias_name_to_expression_node->size() << '\n'; - for (const auto & [alias_name, node] : *aliases.alias_name_to_expression_node) - buffer << "Alias name " << alias_name << " expression node " << node->dumpTree() << '\n'; - - buffer << "Alias name to function node table size " << aliases.alias_name_to_lambda_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_lambda_node) - buffer << "Alias name " << alias_name << " lambda node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to table expression node table size " << aliases.alias_name_to_table_expression_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_table_expression_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "CTE name to query node table size " << cte_name_to_query_node.size() << '\n'; - for (const auto & [cte_name, node] : cte_name_to_query_node) - buffer << "CTE name " << cte_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "WINDOW name to window node table size " << window_name_to_window_node.size() << '\n'; - for (const auto & [window_name, node] : window_name_to_window_node) - buffer << "CTE name " << window_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Nodes with duplicated aliases size " << aliases.nodes_with_duplicated_aliases.size() << '\n'; - for (const auto & node : aliases.nodes_with_duplicated_aliases) - buffer << "Alias name " << node->getAlias() << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Expression resolve process stack " << '\n'; - expressions_in_resolve_process_stack.dump(buffer); - - buffer << "Table expressions in resolve process size " << table_expressions_in_resolve_process.size() << '\n'; - for (const auto & node : table_expressions_in_resolve_process) - buffer << "Table expression " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Non cached identifier lookups during expression resolve " << non_cached_identifier_lookups_during_expression_resolve.size() << '\n'; - for (const auto & identifier_lookup : non_cached_identifier_lookups_during_expression_resolve) - buffer << "Identifier lookup " << identifier_lookup.dump() << '\n'; - - buffer << "Table expression node to data " << table_expression_node_to_data.size() << '\n'; - for (const auto & [table_expression_node, table_expression_data] : table_expression_node_to_data) - buffer << "Table expression node " << table_expression_node->formatASTForErrorMessage() << " data " << table_expression_data.dump() << '\n'; - - buffer << "Use identifier lookup to result cache " << use_identifier_lookup_to_result_cache << '\n'; - buffer << "Subquery depth " << subquery_depth << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - - -/** Visitor that extracts expression and function aliases from node and initialize scope tables with it. - * Does not go into child lambdas and queries. - * - * Important: - * Identifier nodes with aliases are added both in alias to expression and alias to function map. - * - * These is necessary because identifier with alias can give alias name to any query tree node. - * - * Example: - * WITH (x -> x + 1) AS id, id AS value SELECT value(1); - * In this example id as value is identifier node that has alias, during scope initialization we cannot derive - * that id is actually lambda or expression. - * - * There are no easy solution here, without trying to make full featured expression resolution at this stage. - * Example: - * WITH (x -> x + 1) AS id, id AS id_1, id_1 AS id_2 SELECT id_2(1); - * Example: SELECT a, b AS a, b AS c, 1 AS c; - * - * It is client responsibility after resolving identifier node with alias, make following actions: - * 1. If identifier node was resolved in function scope, remove alias from scope expression map. - * 2. If identifier node was resolved in expression scope, remove alias from scope function map. - * - * That way we separate alias map initialization and expressions resolution. - */ -class QueryExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit QueryExpressionsAliasVisitor(ScopeAliases & aliases_) - : aliases(aliases_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node, false /*is_lambda_node*/); - } - - bool needChildVisit(const QueryTreeNodePtr &, const QueryTreeNodePtr & child) - { - if (auto * lambda_node = child->as()) - { - updateAliasesIfNeeded(child, true /*is_lambda_node*/); - return false; - } - else if (auto * query_tree_node = child->as()) - { - if (query_tree_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - else if (auto * union_node = child->as()) - { - if (union_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - - return true; - } -private: - void addDuplicatingAlias(const QueryTreeNodePtr & node) - { - aliases.nodes_with_duplicated_aliases.emplace(node); - auto cloned_node = node->clone(); - aliases.cloned_nodes_with_duplicated_aliases.emplace_back(cloned_node); - aliases.nodes_with_duplicated_aliases.emplace(cloned_node); - } - - void updateAliasesIfNeeded(const QueryTreeNodePtr & node, bool is_lambda_node) - { - if (!node->hasAlias()) - return; - - // We should not resolve expressions to WindowNode - if (node->getNodeType() == QueryTreeNodeType::WINDOW) - return; - - const auto & alias = node->getAlias(); - - if (is_lambda_node) - { - if (aliases.alias_name_to_expression_node->contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_lambda_node.insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - return; - } - - if (aliases.alias_name_to_lambda_node.contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_expression_node->insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - /// If node is identifier put it into transitive aliases map. - if (const auto * identifier = typeid_cast(node.get())) - aliases.transitive_aliases.insert(std::make_pair(alias, identifier->getIdentifier())); - } - - ScopeAliases & aliases; -}; - -class TableExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit TableExpressionsAliasVisitor(IdentifierResolveScope & scope_) - : scope(scope_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node); - } - - static bool needChildVisit(const QueryTreeNodePtr & node, const QueryTreeNodePtr & child) - { - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::ARRAY_JOIN: - { - const auto & array_join_node = node->as(); - return child.get() == array_join_node.getTableExpression().get(); - } - case QueryTreeNodeType::JOIN: - { - const auto & join_node = node->as(); - return child.get() == join_node.getLeftTableExpression().get() || child.get() == join_node.getRightTableExpression().get(); - } - default: - { - break; - } - } - - return false; - } - -private: - void updateAliasesIfNeeded(const QueryTreeNodePtr & node) - { - if (!node->hasAlias()) - return; - - const auto & node_alias = node->getAlias(); - auto [_, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(node_alias, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple table expressions with same alias {}. In scope {}", - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - IdentifierResolveScope & scope; -}; - -class QueryAnalyzer -{ -public: - explicit QueryAnalyzer(bool only_analyze_) : only_analyze(only_analyze_) {} - - void resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context) - { - IdentifierResolveScope scope(node, nullptr /*parent_scope*/); - - if (!scope.context) - scope.context = context; - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::QUERY: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For query analysis table expression must be empty"); - - resolveQuery(node, scope); - break; - } - case QueryTreeNodeType::UNION: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For union analysis table expression must be empty"); - - resolveUnion(node, scope); - break; - } - case QueryTreeNodeType::IDENTIFIER: - [[fallthrough]]; - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - [[fallthrough]]; - case QueryTreeNodeType::FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::LIST: - { - if (table_expression) - { - scope.expression_join_tree_node = table_expression; - validateTableExpressionModifiers(scope.expression_join_tree_node, scope); - initializeTableExpressionData(scope.expression_join_tree_node, scope); - } - - if (node_type == QueryTreeNodeType::LIST) - resolveExpressionNodeList(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - else - resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - QueryExpressionsAliasVisitor expressions_alias_visitor(scope.aliases); - resolveTableFunction(node, scope, expressions_alias_visitor, false /*nested_table_function*/); - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Node {} with type {} is not supported by query analyzer. " - "Supported nodes are query, union, identifier, constant, column, function, list.", - node->formatASTForErrorMessage(), - node->getNodeTypeName()); - } - } - } - -private: - /// Utility functions - - static bool isExpressionNodeType(QueryTreeNodeType node_type); - - static bool isFunctionExpressionNodeType(QueryTreeNodeType node_type); - - static bool isSubqueryNodeType(QueryTreeNodeType node_type); - - static bool isTableExpressionNodeType(QueryTreeNodeType node_type); - - static DataTypePtr getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node); - - static ProjectionName calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, - const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names); - - static ProjectionName calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name); - - static ProjectionName calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, - const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, - const ProjectionName & fill_to_expression_projection_name, - const ProjectionName & fill_step_expression_projection_name); - - static void collectCompoundExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result); - - static void collectTableExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result); - - static void collectScopeValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static void collectScopeWithParentScopesValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static std::vector collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers); - - static QueryTreeNodePtr wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path); - - QueryTreeNodePtr tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context); - - void evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & query_tree_node, IdentifierResolveScope & scope); - - static void mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope); - - void replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope); - - static void convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope); - - static void validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope); - - static std::pair recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into); - - static void expandGroupByAll(QueryNode & query_tree_node_typed); - - void expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings); - - static std::string - rewriteAggregateFunctionNameIfNeeded(const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context); - - static std::optional getColumnSideFromJoinTree(const QueryTreeNodePtr & resolved_identifier, const JoinNode & join_node) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - return {}; - - if (resolved_identifier->getNodeType() == QueryTreeNodeType::FUNCTION) - { - const auto & resolved_function = resolved_identifier->as(); - - const auto & argument_nodes = resolved_function.getArguments().getNodes(); - - std::optional result; - for (const auto & argument_node : argument_nodes) - { - auto table_side = getColumnSideFromJoinTree(argument_node, join_node); - if (table_side && result && *table_side != *result) - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Ambiguous identifier {}. In scope {}", - resolved_identifier->formatASTForErrorMessage(), - join_node.formatASTForErrorMessage()); - } - result = table_side; - } - return result; - } - - const auto * column_src = resolved_identifier->as().getColumnSource().get(); - - if (join_node.getLeftTableExpression().get() == column_src) - return JoinTableSide::Left; - if (join_node.getRightTableExpression().get() == column_src) - return JoinTableSide::Right; + if (resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) return {}; - } - static QueryTreeNodePtr convertJoinedColumnTypeToNullIfNeeded( - const QueryTreeNodePtr & resolved_identifier, - const JoinKind & join_kind, - std::optional resolved_side, - IdentifierResolveScope & scope) + if (resolved_identifier->getNodeType() == QueryTreeNodeType::FUNCTION) { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && - JoinCommon::canBecomeNullable(resolved_identifier->getResultType()) && - (isFull(join_kind) || - (isLeft(join_kind) && resolved_side && *resolved_side == JoinTableSide::Right) || - (isRight(join_kind) && resolved_side && *resolved_side == JoinTableSide::Left))) + const auto & resolved_function = resolved_identifier->as(); + + const auto & argument_nodes = resolved_function.getArguments().getNodes(); + + std::optional result; + for (const auto & argument_node : argument_nodes) { - auto nullable_resolved_identifier = resolved_identifier->clone(); - auto & resolved_column = nullable_resolved_identifier->as(); - auto new_result_type = makeNullableOrLowCardinalityNullable(resolved_column.getColumnType()); - resolved_column.setColumnType(new_result_type); - if (resolved_column.hasExpression()) + auto table_side = getColumnSideFromJoinTree(argument_node, join_node); + if (table_side && result && *table_side != *result) { - auto & resolved_expression = resolved_column.getExpression(); - if (!resolved_expression->getResultType()->equals(*new_result_type)) - resolved_expression = buildCastFunction(resolved_expression, new_result_type, scope.context, true); + throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, + "Ambiguous identifier {}. In scope {}", + resolved_identifier->formatASTForErrorMessage(), + join_node.formatASTForErrorMessage()); } - if (!nullable_resolved_identifier->isEqual(*resolved_identifier)) - scope.join_columns_with_changed_types[nullable_resolved_identifier] = resolved_identifier; - return nullable_resolved_identifier; + result = table_side; } - return nullptr; + return result; } - /// Resolve identifier functions + const auto * column_src = resolved_identifier->as().getColumnSource().get(); - static QueryTreeNodePtr tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context); + if (join_node.getLeftTableExpression().get() == column_src) + return JoinTableSide::Left; + if (join_node.getRightTableExpression().get() == column_src) + return JoinTableSide::Right; + return {}; +} - QueryTreeNodePtr tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found = false); - - QueryTreeNodePtr tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings); - - QueryTreeNodePtr tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings = {}); - - QueryTreeNodePtr tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found = false); - - /// Resolve query tree nodes functions - - void qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static GetColumnsOptions buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context); - - using QueryTreeNodesWithNames = std::vector>; - - QueryTreeNodesWithNames getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope); - - void updateMatchedColumnsFromJoinUsing(QueryTreeNodesWithNames & result_matched_column_nodes_with_names, const QueryTreeNodePtr & source_table_expression, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionNames resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionName resolveWindow(QueryTreeNodePtr & window_node, IdentifierResolveScope & scope); - - ProjectionNames resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope); - - ProjectionNames resolveFunction(QueryTreeNodePtr & function_node, IdentifierResolveScope & scope); - - ProjectionNames resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias = false); - - ProjectionNames resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression); - - ProjectionNames resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope); - - void resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope); - - void resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope); - - void resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope); - - NamesAndTypes resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope); - - void initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope); - - void initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - void resolveTableFunction(QueryTreeNodePtr & table_function_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, bool nested_table_function); - - void resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope); - - void resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope); - - /// Lambdas that are currently in resolve process - std::unordered_set lambdas_in_resolve_process; - - /// CTEs that are currently in resolve process - std::unordered_set ctes_in_resolve_process; - - /// Function name to user defined lambda map - std::unordered_map function_name_to_user_defined_lambda; - - /// Array join expressions counter - size_t array_join_expressions_counter = 1; - - /// Subquery counter - size_t subquery_counter = 1; - - /// Global expression node to projection name map - std::unordered_map node_to_projection_name; - - /// Global resolve expression node to projection names map - std::unordered_map resolved_expressions; - - /// Global resolve expression node to tree size - std::unordered_map node_to_tree_size; - - /// Global scalar subquery to scalar value map - std::unordered_map scalar_subquery_to_scalar_value_local; - std::unordered_map scalar_subquery_to_scalar_value_global; - - const bool only_analyze; -}; +QueryTreeNodePtr QueryAnalyzer::convertJoinedColumnTypeToNullIfNeeded( + const QueryTreeNodePtr & resolved_identifier, + const JoinKind & join_kind, + std::optional resolved_side, + IdentifierResolveScope & scope) +{ + if (resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && + JoinCommon::canBecomeNullable(resolved_identifier->getResultType()) && + (isFull(join_kind) || + (isLeft(join_kind) && resolved_side && *resolved_side == JoinTableSide::Right) || + (isRight(join_kind) && resolved_side && *resolved_side == JoinTableSide::Left))) + { + auto nullable_resolved_identifier = resolved_identifier->clone(); + auto & resolved_column = nullable_resolved_identifier->as(); + auto new_result_type = makeNullableOrLowCardinalityNullable(resolved_column.getColumnType()); + resolved_column.setColumnType(new_result_type); + if (resolved_column.hasExpression()) + { + auto & resolved_expression = resolved_column.getExpression(); + if (!resolved_expression->getResultType()->equals(*new_result_type)) + resolved_expression = buildCastFunction(resolved_expression, new_result_type, scope.context, true); + } + if (!nullable_resolved_identifier->isEqual(*resolved_identifier)) + scope.join_columns_with_changed_types[nullable_resolved_identifier] = resolved_identifier; + return nullable_resolved_identifier; + } + return nullptr; +} /// Utility functions implementation - bool QueryAnalyzer::isExpressionNodeType(QueryTreeNodeType node_type) { return node_type == QueryTreeNodeType::CONSTANT || node_type == QueryTreeNodeType::COLUMN || node_type == QueryTreeNodeType::FUNCTION @@ -1862,7 +513,7 @@ void QueryAnalyzer::collectCompoundExpressionValidIdentifiersForTypoCorrection( void QueryAnalyzer::collectTableExpressionValidIdentifiersForTypoCorrection( const Identifier & unresolved_identifier, const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, + const AnalysisTableExpressionData & table_expression_data, std::unordered_set & valid_identifiers_result) { for (const auto & [column_name, column_node] : table_expression_data.column_name_to_column_node) @@ -3118,7 +1769,7 @@ bool QueryAnalyzer::tryBindIdentifierToTableExpressions(const IdentifierLookup & QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromStorage( const Identifier & identifier, const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, + const AnalysisTableExpressionData & table_expression_data, IdentifierResolveScope & scope, size_t identifier_column_qualifier_parts, bool can_be_not_found) @@ -4388,7 +3039,7 @@ QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::getMatchedColumnNodesWithN /** Use resolved columns from table expression data in nearest query scope if available. * It is important for ALIAS columns to use column nodes with resolved ALIAS expression. */ - const TableExpressionData * table_expression_data = nullptr; + const AnalysisTableExpressionData * table_expression_data = nullptr; const auto * nearest_query_scope = scope.getNearestQueryScope(); if (nearest_query_scope) table_expression_data = &nearest_query_scope->getTableExpressionDataOrThrow(table_expression_node); @@ -7141,7 +5792,7 @@ void QueryAnalyzer::initializeTableExpressionData(const QueryTreeNodePtr & table if (table_expression_data_it != scope.table_expression_node_to_data.end()) return; - TableExpressionData table_expression_data; + AnalysisTableExpressionData table_expression_data; if (table_node) { @@ -8461,19 +7112,3 @@ void QueryAnalyzer::resolveUnion(const QueryTreeNodePtr & union_node, Identifier } } - -QueryAnalysisPass::QueryAnalysisPass(QueryTreeNodePtr table_expression_, bool only_analyze_) - : table_expression(std::move(table_expression_)) - , only_analyze(only_analyze_) -{} - -QueryAnalysisPass::QueryAnalysisPass(bool only_analyze_) : only_analyze(only_analyze_) {} - -void QueryAnalysisPass::run(QueryTreeNodePtr & query_tree_node, ContextPtr context) -{ - QueryAnalyzer analyzer(only_analyze); - analyzer.resolve(query_tree_node, table_expression, context); - createUniqueTableAliases(query_tree_node, table_expression, context); -} - -} diff --git a/src/Analyzer/QueryAnalysis/QueryAnalyzer.h b/src/Analyzer/QueryAnalysis/QueryAnalyzer.h index 3fca66e6eb8..579455b6faf 100644 --- a/src/Analyzer/QueryAnalysis/QueryAnalyzer.h +++ b/src/Analyzer/QueryAnalysis/QueryAnalyzer.h @@ -1,134 +1,31 @@ -#include +#pragma once -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include +#include -namespace ProfileEvents -{ - extern const Event ScalarSubqueriesGlobalCacheHit; - extern const Event ScalarSubqueriesLocalCacheHit; - extern const Event ScalarSubqueriesCacheMiss; -} +#include +#include + +#include namespace DB { -namespace ErrorCodes -{ - extern const int UNSUPPORTED_METHOD; - extern const int UNKNOWN_IDENTIFIER; - extern const int UNKNOWN_FUNCTION; - extern const int LOGICAL_ERROR; - extern const int CYCLIC_ALIASES; - extern const int INCORRECT_RESULT_OF_SCALAR_SUBQUERY; - extern const int BAD_ARGUMENTS; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int MULTIPLE_EXPRESSIONS_FOR_ALIAS; - extern const int TYPE_MISMATCH; - extern const int AMBIGUOUS_IDENTIFIER; - extern const int INVALID_WITH_FILL_EXPRESSION; - extern const int INVALID_LIMIT_EXPRESSION; - extern const int EMPTY_LIST_OF_COLUMNS_QUERIED; - extern const int TOO_DEEP_SUBQUERIES; - extern const int UNKNOWN_AGGREGATE_FUNCTION; - extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION; - extern const int TOO_MANY_ARGUMENTS_FOR_FUNCTION; - extern const int ILLEGAL_FINAL; - extern const int SAMPLING_NOT_SUPPORTED; - extern const int NO_COMMON_TYPE; - extern const int NOT_IMPLEMENTED; - extern const int ALIAS_REQUIRED; - extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; - extern const int UNKNOWN_TABLE; - extern const int ILLEGAL_COLUMN; - extern const int NUMBER_OF_COLUMNS_DOESNT_MATCH; - extern const int FUNCTION_CANNOT_HAVE_PARAMETERS; - extern const int SYNTAX_ERROR; - extern const int UNEXPECTED_EXPRESSION; - extern const int INVALID_IDENTIFIER; -} +struct GetColumnsOptions; +struct IdentifierResolveScope; +struct AnalysisTableExpressionData; +class QueryExpressionsAliasVisitor ; + +class QueryNode; +class JoinNode; +class ColumnNode; + +using ProjectionName = String; +using ProjectionNames = std::vector; + +struct Settings; /** Query analyzer implementation overview. Please check documentation in QueryAnalysisPass.h first. * And additional documentation for each method, where special cases are described in detail. @@ -213,1069 +110,13 @@ namespace ErrorCodes * TODO: Support function identifier resolve from parent query scope, if lambda in parent scope does not capture any columns. */ -namespace -{ - -/// Identifier lookup context -enum class IdentifierLookupContext : uint8_t -{ - EXPRESSION = 0, - FUNCTION, - TABLE_EXPRESSION, -}; - -const char * toString(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "EXPRESSION"; - case IdentifierLookupContext::FUNCTION: return "FUNCTION"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "TABLE_EXPRESSION"; - } -} - -const char * toStringLowercase(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "expression"; - case IdentifierLookupContext::FUNCTION: return "function"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "table expression"; - } -} - -/** Structure that represent identifier lookup during query analysis. - * Lookup can be in query expression, function, table context. - */ -struct IdentifierLookup -{ - Identifier identifier; - IdentifierLookupContext lookup_context; - - bool isExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::EXPRESSION; - } - - bool isFunctionLookup() const - { - return lookup_context == IdentifierLookupContext::FUNCTION; - } - - bool isTableExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::TABLE_EXPRESSION; - } - - String dump() const - { - return identifier.getFullName() + ' ' + toString(lookup_context); - } -}; - -inline bool operator==(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return lhs.identifier.getFullName() == rhs.identifier.getFullName() && lhs.lookup_context == rhs.lookup_context; -} - -[[maybe_unused]] inline bool operator!=(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return !(lhs == rhs); -} - -struct IdentifierLookupHash -{ - size_t operator()(const IdentifierLookup & identifier_lookup) const - { - return std::hash()(identifier_lookup.identifier.getFullName()) ^ static_cast(identifier_lookup.lookup_context); - } -}; - -enum class IdentifierResolvePlace : UInt8 -{ - NONE = 0, - EXPRESSION_ARGUMENTS, - ALIASES, - JOIN_TREE, - /// Valid only for table lookup - CTE, - /// Valid only for table lookup - DATABASE_CATALOG -}; - -const char * toString(IdentifierResolvePlace resolved_identifier_place) -{ - switch (resolved_identifier_place) - { - case IdentifierResolvePlace::NONE: return "NONE"; - case IdentifierResolvePlace::EXPRESSION_ARGUMENTS: return "EXPRESSION_ARGUMENTS"; - case IdentifierResolvePlace::ALIASES: return "ALIASES"; - case IdentifierResolvePlace::JOIN_TREE: return "JOIN_TREE"; - case IdentifierResolvePlace::CTE: return "CTE"; - case IdentifierResolvePlace::DATABASE_CATALOG: return "DATABASE_CATALOG"; - } -} - -struct IdentifierResolveResult -{ - IdentifierResolveResult() = default; - - QueryTreeNodePtr resolved_identifier; - IdentifierResolvePlace resolve_place = IdentifierResolvePlace::NONE; - bool resolved_from_parent_scopes = false; - - [[maybe_unused]] bool isResolved() const - { - return resolve_place != IdentifierResolvePlace::NONE; - } - - [[maybe_unused]] bool isResolvedFromParentScopes() const - { - return resolved_from_parent_scopes; - } - - [[maybe_unused]] bool isResolvedFromExpressionArguments() const - { - return resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - } - - [[maybe_unused]] bool isResolvedFromAliases() const - { - return resolve_place == IdentifierResolvePlace::ALIASES; - } - - [[maybe_unused]] bool isResolvedFromJoinTree() const - { - return resolve_place == IdentifierResolvePlace::JOIN_TREE; - } - - [[maybe_unused]] bool isResolvedFromCTEs() const - { - return resolve_place == IdentifierResolvePlace::CTE; - } - - void dump(WriteBuffer & buffer) const - { - if (!resolved_identifier) - { - buffer << "unresolved"; - return; - } - - buffer << resolved_identifier->formatASTForErrorMessage() << " place " << toString(resolve_place) << " resolved from parent scopes " << resolved_from_parent_scopes; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -struct IdentifierResolveState -{ - IdentifierResolveResult resolve_result; - bool cyclic_identifier_resolve = false; -}; - -struct IdentifierResolveSettings -{ - /// Allow to check join tree during identifier resolution - bool allow_to_check_join_tree = true; - - /// Allow to check CTEs during table identifier resolution - bool allow_to_check_cte = true; - - /// Allow to check parent scopes during identifier resolution - bool allow_to_check_parent_scopes = true; - - /// Allow to check database catalog during table identifier resolution - bool allow_to_check_database_catalog = true; - - /// Allow to resolve subquery during identifier resolution - bool allow_to_resolve_subquery_during_identifier_resolution = true; -}; - -struct StringTransparentHash -{ - using is_transparent = void; - using hash = std::hash; - - [[maybe_unused]] size_t operator()(const char * data) const - { - return hash()(data); - } - - size_t operator()(std::string_view data) const - { - return hash()(data); - } - - size_t operator()(const std::string & data) const - { - return hash()(data); - } -}; - -using ColumnNameToColumnNodeMap = std::unordered_map>; - -struct TableExpressionData -{ - std::string table_expression_name; - std::string table_expression_description; - std::string database_name; - std::string table_name; - bool should_qualify_columns = true; - NamesAndTypes column_names_and_types; - ColumnNameToColumnNodeMap column_name_to_column_node; - std::unordered_set subcolumn_names; /// Subset columns that are subcolumns of other columns - std::unordered_set> column_identifier_first_parts; - - bool hasFullIdentifierName(IdentifierView identifier_view) const - { - return column_name_to_column_node.contains(identifier_view.getFullName()); - } - - bool canBindIdentifier(IdentifierView identifier_view) const - { - return column_identifier_first_parts.contains(identifier_view.at(0)); - } - - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Table expression name " << table_expression_name; - - if (!table_expression_description.empty()) - buffer << " table expression description " << table_expression_description; - - if (!database_name.empty()) - buffer << " database name " << database_name; - - if (!table_name.empty()) - buffer << " table name " << table_name; - - buffer << " should qualify columns " << should_qualify_columns; - buffer << " columns size " << column_name_to_column_node.size() << '\n'; - - for (const auto & [column_name, column_node] : column_name_to_column_node) - buffer << "Column name " << column_name << " column node " << column_node->dumpTree() << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -class ExpressionsStack -{ -public: - void push(const QueryTreeNodePtr & node) - { - if (node->hasAlias()) - { - const auto & node_alias = node->getAlias(); - alias_name_to_expressions[node_alias].push_back(node); - } - - if (const auto * function = node->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - ++aggregate_functions_counter; - } - - expressions.emplace_back(node); - } - - void pop() - { - const auto & top_expression = expressions.back(); - const auto & top_expression_alias = top_expression->getAlias(); - - if (!top_expression_alias.empty()) - { - auto it = alias_name_to_expressions.find(top_expression_alias); - auto & alias_expressions = it->second; - alias_expressions.pop_back(); - - if (alias_expressions.empty()) - alias_name_to_expressions.erase(it); - } - - if (const auto * function = top_expression->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - --aggregate_functions_counter; - } - - expressions.pop_back(); - } - - [[maybe_unused]] const QueryTreeNodePtr & getRoot() const - { - return expressions.front(); - } - - const QueryTreeNodePtr & getTop() const - { - return expressions.back(); - } - - [[maybe_unused]] bool hasExpressionWithAlias(const std::string & alias) const - { - return alias_name_to_expressions.contains(alias); - } - - bool hasAggregateFunction() const - { - return aggregate_functions_counter > 0; - } - - QueryTreeNodePtr getExpressionWithAlias(const std::string & alias) const - { - auto expression_it = alias_name_to_expressions.find(alias); - if (expression_it == alias_name_to_expressions.end()) - return {}; - - return expression_it->second.front(); - } - - [[maybe_unused]] size_t size() const - { - return expressions.size(); - } - - bool empty() const - { - return expressions.empty(); - } - - void dump(WriteBuffer & buffer) const - { - buffer << expressions.size() << '\n'; - - for (const auto & expression : expressions) - { - buffer << "Expression "; - buffer << expression->formatASTForErrorMessage(); - - const auto & alias = expression->getAlias(); - if (!alias.empty()) - buffer << " alias " << alias; - - buffer << '\n'; - } - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } - -private: - QueryTreeNodes expressions; - size_t aggregate_functions_counter = 0; - std::unordered_map alias_name_to_expressions; -}; - -struct ScopeAliases -{ - /// Alias name to query expression node - std::unordered_map alias_name_to_expression_node_before_group_by; - std::unordered_map alias_name_to_expression_node_after_group_by; - - std::unordered_map * alias_name_to_expression_node = nullptr; - - /// Alias name to lambda node - std::unordered_map alias_name_to_lambda_node; - - /// Alias name to table expression node - std::unordered_map alias_name_to_table_expression_node; - - /// Expressions like `x as y` where we can't say whether it's a function, expression or table. - std::unordered_map transitive_aliases; - - /// Nodes with duplicated aliases - std::unordered_set nodes_with_duplicated_aliases; - std::vector cloned_nodes_with_duplicated_aliases; - - /// Names which are aliases from ARRAY JOIN. - /// This is needed to properly qualify columns from matchers and avoid name collision. - std::unordered_set array_join_aliases; - - std::unordered_map & getAliasMap(IdentifierLookupContext lookup_context) - { - switch (lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return *alias_name_to_expression_node; - case IdentifierLookupContext::FUNCTION: return alias_name_to_lambda_node; - case IdentifierLookupContext::TABLE_EXPRESSION: return alias_name_to_table_expression_node; - } - } - - enum class FindOption - { - FIRST_NAME, - FULL_NAME, - }; - - const std::string & getKey(const Identifier & identifier, FindOption find_option) - { - switch (find_option) - { - case FindOption::FIRST_NAME: return identifier.front(); - case FindOption::FULL_NAME: return identifier.getFullName(); - } - } - - QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) - { - auto & alias_map = getAliasMap(lookup.lookup_context); - const std::string * key = &getKey(lookup.identifier, find_option); - - auto it = alias_map.find(*key); - - if (it != alias_map.end()) - return &it->second; - - if (lookup.lookup_context == IdentifierLookupContext::TABLE_EXPRESSION) - return {}; - - while (it == alias_map.end()) - { - auto jt = transitive_aliases.find(*key); - if (jt == transitive_aliases.end()) - return {}; - - key = &(getKey(jt->second, find_option)); - it = alias_map.find(*key); - } - - return &it->second; - } - - const QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) const - { - return const_cast(this)->find(lookup, find_option); - } -}; - - -/** Projection names is name of query tree node that is used in projection part of query node. - * Example: SELECT id FROM test_table; - * `id` is projection name of column node - * - * Example: SELECT id AS id_alias FROM test_table; - * `id_alias` is projection name of column node - * - * Calculation of projection names is done during expression nodes resolution. This is done this way - * because after identifier node is resolved we lose information about identifier name. We could - * potentially save this information in query tree node itself, but that would require to clone it in some cases. - * Example: SELECT big_scalar_subquery AS a, a AS b, b AS c; - * All 3 nodes in projection are the same big_scalar_subquery, but they have different projection names. - * If we want to save it in query tree node, we have to clone subquery node that could lead to performance degradation. - * - * Possible solution is to separate query node metadata and query node content. So only node metadata could be cloned - * if we want to change projection name. This solution does not seem to be easy for client of query tree because projection - * name will be part of interface. If we potentially could hide projection names calculation in analyzer without introducing additional - * changes in query tree structure that would be preferable. - * - * Currently each resolve method returns projection names array. Resolve method must compute projection names of node. - * If node is resolved as list node this is case for `untuple` function or `matcher` result projection names array must contain projection names - * for result nodes. - * If node is not resolved as list node, projection names array contain single projection name for node. - * - * Rules for projection names: - * 1. If node has alias. It is node projection name. - * Except scenario where `untuple` function has alias. Example: SELECT untuple(expr) AS alias, alias. - * - * 2. For constant it is constant value string representation. - * - * 3. For identifier: - * If identifier is resolved from JOIN TREE, we want to remove additional identifier qualifications. - * Example: SELECT default.test_table.id FROM test_table. - * Result projection name is `id`. - * - * Example: SELECT t1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In example both test_table_1, test_table_2 have `id` column. - * In such case projection name is `t1.id` because if additional qualification is removed then column projection name `id` will be ambiguous. - * - * Example: SELECT default.test_table_1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In such case projection name is `test_table_1.id` because we remove unnecessary database qualification, but table name qualification cannot be removed - * because otherwise column projection name `id` will be ambiguous. - * - * If identifier is not resolved from JOIN TREE. Identifier name is projection name. - * Except scenario where `untuple` function resolved using identifier. Example: SELECT untuple(expr) AS alias, alias. - * Example: SELECT sum(1, 1) AS value, value. - * In such case both nodes have `value` projection names. - * - * Example: SELECT id AS value, value FROM test_table. - * In such case both nodes have have `value` projection names. - * - * Special case is `untuple` function. If `untuple` function specified with alias, then result nodes will have alias.tuple_column_name projection names. - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value) AS a; - * Result projection names are `value`, `a.id`. - * - * If `untuple` function does not have alias then result nodes will have `tupleElement(untuple_expression_projection_name, 'tuple_column_name') projection names. - * - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value); - * Result projection names are `value`, `tupleElement(value, 'id')`; - * - * 4. For function: - * Projection name consists from function_name(parameters_projection_names)(arguments_projection_names). - * Additionally if function is window function. Window node projection name is used with OVER clause. - * Example: function_name (parameters_names)(argument_projection_names) OVER window_name; - * Example: function_name (parameters_names)(argument_projection_names) OVER (PARTITION BY id ORDER BY id). - * Example: function_name (parameters_names)(argument_projection_names) OVER (window_name ORDER BY id). - * - * 5. For lambda: - * If it is standalone lambda that returns single expression, function projection name is used. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(1). - * Projection name is `lambda(1)`. - * - * If is it standalone lambda that returns list, projection names of list nodes are used. - * Example: WITH (x -> *) AS lambda SELECT lambda(1) FROM test_table; - * If test_table has two columns `id`, `value`. Then result projection names are `id`, `value`. - * - * If lambda is argument of function. - * Then projection name consists from lambda(tuple(lambda_arguments)(lambda_body_projection_name)); - * - * 6. For matcher: - * Matched nodes projection names are used as matcher projection names. - * - * Matched nodes must be qualified if needed. - * Example: SELECT * FROM test_table_1 AS t1, test_table_2 AS t2. - * In example table test_table_1 and test_table_2 both have `id`, `value` columns. - * Matched nodes after unqualified matcher resolve must be qualified to avoid ambiguous projection names. - * Result projection names must be `t1.id`, `t1.value`, `t2.id`, `t2.value`. - * - * There are special cases - * 1. For lambda inside APPLY matcher transformer: - * Example: SELECT * APPLY x -> toString(x) FROM test_table. - * In such case lambda argument projection name `x` will be replaced by matched node projection name. - * If table has two columns `id` and `value`. Then result projection names are `toString(id)`, `toString(value)`; - * - * 2. For unqualified matcher when JOIN tree contains JOIN with USING. - * Example: SELECT * FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING(id); - * Result projection names must be `id`, `t1.value`, `t2.value`. - * - * 7. For subquery: - * For subquery projection name consists of `_subquery_` prefix and implementation specific unique number suffix. - * Example: SELECT (SELECT 1), (SELECT 1 UNION DISTINCT SELECT 1); - * Result projection name can be `_subquery_1`, `subquery_2`; - * - * 8. For table: - * Table node can be used in expression context only as right argument of IN function. In that case identifier is used - * as table node projection name. - * Example: SELECT id IN test_table FROM test_table; - * Result projection name is `in(id, test_table)`. - */ -using ProjectionName = String; -using ProjectionNames = std::vector; -constexpr auto PROJECTION_NAME_PLACEHOLDER = "__projection_name_placeholder"; - -struct IdentifierResolveScope -{ - /// Construct identifier resolve scope using scope node, and parent scope - IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) - : scope_node(std::move(scope_node_)) - , parent_scope(parent_scope_) - { - if (parent_scope) - { - subquery_depth = parent_scope->subquery_depth; - context = parent_scope->context; - projection_mask_map = parent_scope->projection_mask_map; - } - else - projection_mask_map = std::make_shared>(); - - if (auto * union_node = scope_node->as()) - { - context = union_node->getContext(); - } - else if (auto * query_node = scope_node->as()) - { - context = query_node->getContext(); - group_by_use_nulls = context->getSettingsRef().group_by_use_nulls && - (query_node->isGroupByWithGroupingSets() || query_node->isGroupByWithRollup() || query_node->isGroupByWithCube()); - } - - if (context) - join_use_nulls = context->getSettingsRef().join_use_nulls; - else if (parent_scope) - join_use_nulls = parent_scope->join_use_nulls; - - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - QueryTreeNodePtr scope_node; - - IdentifierResolveScope * parent_scope = nullptr; - - ContextPtr context; - - /// Identifier lookup to result - std::unordered_map identifier_lookup_to_resolve_state; - - /// Argument can be expression like constant, column, function or table expression - std::unordered_map expression_argument_name_to_node; - - ScopeAliases aliases; - - /// Table column name to column node. Valid only during table ALIAS columns resolve. - ColumnNameToColumnNodeMap column_name_to_column_node; - - /// CTE name to query node - std::unordered_map cte_name_to_query_node; - - /// Window name to window node - std::unordered_map window_name_to_window_node; - - /// Current scope expression in resolve process stack - ExpressionsStack expressions_in_resolve_process_stack; - - /// Table expressions in resolve process - std::unordered_set table_expressions_in_resolve_process; - - /// Current scope expression - std::unordered_set non_cached_identifier_lookups_during_expression_resolve; - - /// Table expression node to data - std::unordered_map table_expression_node_to_data; - - QueryTreeNodePtrWithHashIgnoreTypesSet nullable_group_by_keys; - /// Here we count the number of nullable GROUP BY keys we met resolving expression. - /// E.g. for a query `SELECT tuple(tuple(number)) FROM numbers(10) GROUP BY (number, tuple(number)) with cube` - /// both `number` and `tuple(number)` would be in nullable_group_by_keys. - /// But when we resolve `tuple(tuple(number))` we should figure out that `tuple(number)` is already a key, - /// and we should not convert `number` to nullable. - size_t found_nullable_group_by_key_in_scope = 0; - - /** It's possible that after a JOIN, a column in the projection has a type different from the column in the source table. - * (For example, after join_use_nulls or USING column casted to supertype) - * However, the column in the projection still refers to the table as its source. - * This map is used to revert these columns back to their original columns in the source table. - */ - QueryTreeNodePtrWithHashMap join_columns_with_changed_types; - - /// Use identifier lookup to result cache - bool use_identifier_lookup_to_result_cache = true; - - /// Apply nullability to aggregation keys - bool group_by_use_nulls = false; - /// Join retutns NULLs instead of default values - bool join_use_nulls = false; - - /// JOINs count - size_t joins_count = 0; - - /// Subquery depth - size_t subquery_depth = 0; - - /** Scope join tree node for expression. - * Valid only during analysis construction for single expression. - */ - QueryTreeNodePtr expression_join_tree_node; - - /// Node hash to mask id map - std::shared_ptr> projection_mask_map; - - struct ResolvedFunctionsCache - { - FunctionOverloadResolverPtr resolver; - FunctionBasePtr function_base; - }; - - std::map functions_cache; - - [[maybe_unused]] const IdentifierResolveScope * getNearestQueryScope() const - { - const IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - IdentifierResolveScope * getNearestQueryScope() - { - IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - const TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - void pushExpressionNode(const QueryTreeNodePtr & node) - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.push(node); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - void popExpressionNode() - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.pop(); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_after_group_by; - } - - /// Dump identifier resolve scope - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Scope node " << scope_node->formatASTForErrorMessage() << '\n'; - buffer << "Identifier lookup to resolve state " << identifier_lookup_to_resolve_state.size() << '\n'; - for (const auto & [identifier, state] : identifier_lookup_to_resolve_state) - { - buffer << "Identifier " << identifier.dump() << " resolve result "; - state.resolve_result.dump(buffer); - buffer << '\n'; - } - - buffer << "Expression argument name to node " << expression_argument_name_to_node.size() << '\n'; - for (const auto & [alias_name, node] : expression_argument_name_to_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to expression node table size " << aliases.alias_name_to_expression_node->size() << '\n'; - for (const auto & [alias_name, node] : *aliases.alias_name_to_expression_node) - buffer << "Alias name " << alias_name << " expression node " << node->dumpTree() << '\n'; - - buffer << "Alias name to function node table size " << aliases.alias_name_to_lambda_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_lambda_node) - buffer << "Alias name " << alias_name << " lambda node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to table expression node table size " << aliases.alias_name_to_table_expression_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_table_expression_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "CTE name to query node table size " << cte_name_to_query_node.size() << '\n'; - for (const auto & [cte_name, node] : cte_name_to_query_node) - buffer << "CTE name " << cte_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "WINDOW name to window node table size " << window_name_to_window_node.size() << '\n'; - for (const auto & [window_name, node] : window_name_to_window_node) - buffer << "CTE name " << window_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Nodes with duplicated aliases size " << aliases.nodes_with_duplicated_aliases.size() << '\n'; - for (const auto & node : aliases.nodes_with_duplicated_aliases) - buffer << "Alias name " << node->getAlias() << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Expression resolve process stack " << '\n'; - expressions_in_resolve_process_stack.dump(buffer); - - buffer << "Table expressions in resolve process size " << table_expressions_in_resolve_process.size() << '\n'; - for (const auto & node : table_expressions_in_resolve_process) - buffer << "Table expression " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Non cached identifier lookups during expression resolve " << non_cached_identifier_lookups_during_expression_resolve.size() << '\n'; - for (const auto & identifier_lookup : non_cached_identifier_lookups_during_expression_resolve) - buffer << "Identifier lookup " << identifier_lookup.dump() << '\n'; - - buffer << "Table expression node to data " << table_expression_node_to_data.size() << '\n'; - for (const auto & [table_expression_node, table_expression_data] : table_expression_node_to_data) - buffer << "Table expression node " << table_expression_node->formatASTForErrorMessage() << " data " << table_expression_data.dump() << '\n'; - - buffer << "Use identifier lookup to result cache " << use_identifier_lookup_to_result_cache << '\n'; - buffer << "Subquery depth " << subquery_depth << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - - -/** Visitor that extracts expression and function aliases from node and initialize scope tables with it. - * Does not go into child lambdas and queries. - * - * Important: - * Identifier nodes with aliases are added both in alias to expression and alias to function map. - * - * These is necessary because identifier with alias can give alias name to any query tree node. - * - * Example: - * WITH (x -> x + 1) AS id, id AS value SELECT value(1); - * In this example id as value is identifier node that has alias, during scope initialization we cannot derive - * that id is actually lambda or expression. - * - * There are no easy solution here, without trying to make full featured expression resolution at this stage. - * Example: - * WITH (x -> x + 1) AS id, id AS id_1, id_1 AS id_2 SELECT id_2(1); - * Example: SELECT a, b AS a, b AS c, 1 AS c; - * - * It is client responsibility after resolving identifier node with alias, make following actions: - * 1. If identifier node was resolved in function scope, remove alias from scope expression map. - * 2. If identifier node was resolved in expression scope, remove alias from scope function map. - * - * That way we separate alias map initialization and expressions resolution. - */ -class QueryExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit QueryExpressionsAliasVisitor(ScopeAliases & aliases_) - : aliases(aliases_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node, false /*is_lambda_node*/); - } - - bool needChildVisit(const QueryTreeNodePtr &, const QueryTreeNodePtr & child) - { - if (auto * lambda_node = child->as()) - { - updateAliasesIfNeeded(child, true /*is_lambda_node*/); - return false; - } - else if (auto * query_tree_node = child->as()) - { - if (query_tree_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - else if (auto * union_node = child->as()) - { - if (union_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - - return true; - } -private: - void addDuplicatingAlias(const QueryTreeNodePtr & node) - { - aliases.nodes_with_duplicated_aliases.emplace(node); - auto cloned_node = node->clone(); - aliases.cloned_nodes_with_duplicated_aliases.emplace_back(cloned_node); - aliases.nodes_with_duplicated_aliases.emplace(cloned_node); - } - - void updateAliasesIfNeeded(const QueryTreeNodePtr & node, bool is_lambda_node) - { - if (!node->hasAlias()) - return; - - // We should not resolve expressions to WindowNode - if (node->getNodeType() == QueryTreeNodeType::WINDOW) - return; - - const auto & alias = node->getAlias(); - - if (is_lambda_node) - { - if (aliases.alias_name_to_expression_node->contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_lambda_node.insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - return; - } - - if (aliases.alias_name_to_lambda_node.contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_expression_node->insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - /// If node is identifier put it into transitive aliases map. - if (const auto * identifier = typeid_cast(node.get())) - aliases.transitive_aliases.insert(std::make_pair(alias, identifier->getIdentifier())); - } - - ScopeAliases & aliases; -}; - -class TableExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit TableExpressionsAliasVisitor(IdentifierResolveScope & scope_) - : scope(scope_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node); - } - - static bool needChildVisit(const QueryTreeNodePtr & node, const QueryTreeNodePtr & child) - { - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::ARRAY_JOIN: - { - const auto & array_join_node = node->as(); - return child.get() == array_join_node.getTableExpression().get(); - } - case QueryTreeNodeType::JOIN: - { - const auto & join_node = node->as(); - return child.get() == join_node.getLeftTableExpression().get() || child.get() == join_node.getRightTableExpression().get(); - } - default: - { - break; - } - } - - return false; - } - -private: - void updateAliasesIfNeeded(const QueryTreeNodePtr & node) - { - if (!node->hasAlias()) - return; - - const auto & node_alias = node->getAlias(); - auto [_, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(node_alias, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple table expressions with same alias {}. In scope {}", - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - IdentifierResolveScope & scope; -}; - class QueryAnalyzer { public: - explicit QueryAnalyzer(bool only_analyze_) : only_analyze(only_analyze_) {} + explicit QueryAnalyzer(bool only_analyze_); + ~QueryAnalyzer(); - void resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context) - { - IdentifierResolveScope scope(node, nullptr /*parent_scope*/); - - if (!scope.context) - scope.context = context; - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::QUERY: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For query analysis table expression must be empty"); - - resolveQuery(node, scope); - break; - } - case QueryTreeNodeType::UNION: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For union analysis table expression must be empty"); - - resolveUnion(node, scope); - break; - } - case QueryTreeNodeType::IDENTIFIER: - [[fallthrough]]; - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - [[fallthrough]]; - case QueryTreeNodeType::FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::LIST: - { - if (table_expression) - { - scope.expression_join_tree_node = table_expression; - validateTableExpressionModifiers(scope.expression_join_tree_node, scope); - initializeTableExpressionData(scope.expression_join_tree_node, scope); - } - - if (node_type == QueryTreeNodeType::LIST) - resolveExpressionNodeList(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - else - resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - QueryExpressionsAliasVisitor expressions_alias_visitor(scope.aliases); - resolveTableFunction(node, scope, expressions_alias_visitor, false /*nested_table_function*/); - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Node {} with type {} is not supported by query analyzer. " - "Supported nodes are query, union, identifier, constant, column, function, list.", - node->formatASTForErrorMessage(), - node->getNodeTypeName()); - } - } - } + void resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context); private: /// Utility functions @@ -1315,7 +156,7 @@ private: static void collectTableExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, + const AnalysisTableExpressionData & table_expression_data, std::unordered_set & valid_identifiers_result); static void collectScopeValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, @@ -1361,70 +202,13 @@ private: static std::string rewriteAggregateFunctionNameIfNeeded(const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context); - static std::optional getColumnSideFromJoinTree(const QueryTreeNodePtr & resolved_identifier, const JoinNode & join_node) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - return {}; - - if (resolved_identifier->getNodeType() == QueryTreeNodeType::FUNCTION) - { - const auto & resolved_function = resolved_identifier->as(); - - const auto & argument_nodes = resolved_function.getArguments().getNodes(); - - std::optional result; - for (const auto & argument_node : argument_nodes) - { - auto table_side = getColumnSideFromJoinTree(argument_node, join_node); - if (table_side && result && *table_side != *result) - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Ambiguous identifier {}. In scope {}", - resolved_identifier->formatASTForErrorMessage(), - join_node.formatASTForErrorMessage()); - } - result = table_side; - } - return result; - } - - const auto * column_src = resolved_identifier->as().getColumnSource().get(); - - if (join_node.getLeftTableExpression().get() == column_src) - return JoinTableSide::Left; - if (join_node.getRightTableExpression().get() == column_src) - return JoinTableSide::Right; - return {}; - } + static std::optional getColumnSideFromJoinTree(const QueryTreeNodePtr & resolved_identifier, const JoinNode & join_node); static QueryTreeNodePtr convertJoinedColumnTypeToNullIfNeeded( const QueryTreeNodePtr & resolved_identifier, const JoinKind & join_kind, std::optional resolved_side, - IdentifierResolveScope & scope) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && - JoinCommon::canBecomeNullable(resolved_identifier->getResultType()) && - (isFull(join_kind) || - (isLeft(join_kind) && resolved_side && *resolved_side == JoinTableSide::Right) || - (isRight(join_kind) && resolved_side && *resolved_side == JoinTableSide::Left))) - { - auto nullable_resolved_identifier = resolved_identifier->clone(); - auto & resolved_column = nullable_resolved_identifier->as(); - auto new_result_type = makeNullableOrLowCardinalityNullable(resolved_column.getColumnType()); - resolved_column.setColumnType(new_result_type); - if (resolved_column.hasExpression()) - { - auto & resolved_expression = resolved_column.getExpression(); - if (!resolved_expression->getResultType()->equals(*new_result_type)) - resolved_expression = buildCastFunction(resolved_expression, new_result_type, scope.context, true); - } - if (!nullable_resolved_identifier->isEqual(*resolved_identifier)) - scope.join_columns_with_changed_types[nullable_resolved_identifier] = resolved_identifier; - return nullable_resolved_identifier; - } - return nullptr; - } + IdentifierResolveScope & scope); /// Resolve identifier functions @@ -1493,7 +277,7 @@ private: QueryTreeNodePtr tryResolveIdentifierFromStorage( const Identifier & identifier, const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, + const AnalysisTableExpressionData & table_expression_data, IdentifierResolveScope & scope, size_t identifier_column_qualifier_parts, bool can_be_not_found = false); @@ -1591,6889 +375,4 @@ private: const bool only_analyze; }; -/// Utility functions implementation - - -bool QueryAnalyzer::isExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::CONSTANT || node_type == QueryTreeNodeType::COLUMN || node_type == QueryTreeNodeType::FUNCTION - || node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isFunctionExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::LAMBDA; -} - -bool QueryAnalyzer::isSubqueryNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isTableExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::TABLE || node_type == QueryTreeNodeType::TABLE_FUNCTION || - isSubqueryNodeType(node_type); -} - -DataTypePtr QueryAnalyzer::getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node) -{ - auto node_type = query_tree_node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - { - return query_tree_node->getResultType(); - } - case QueryTreeNodeType::FUNCTION: - { - auto & function_node = query_tree_node->as(); - if (function_node.isResolved()) - return function_node.getResultType(); - break; - } - default: - { - break; - } - } - - return nullptr; -} - -ProjectionName QueryAnalyzer::calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names) -{ - const auto & function_node_typed = function_node->as(); - const auto & function_node_name = function_node_typed.getFunctionName(); - - bool is_array_function = function_node_name == "array"; - bool is_tuple_function = function_node_name == "tuple"; - - WriteBufferFromOwnString buffer; - - if (!is_array_function && !is_tuple_function) - buffer << function_node_name; - - if (!parameters_projection_names.empty()) - { - buffer << '('; - - size_t function_parameters_projection_names_size = parameters_projection_names.size(); - for (size_t i = 0; i < function_parameters_projection_names_size; ++i) - { - buffer << parameters_projection_names[i]; - - if (i + 1 != function_parameters_projection_names_size) - buffer << ", "; - } - - buffer << ')'; - } - - char open_bracket = '('; - char close_bracket = ')'; - - if (is_array_function) - { - open_bracket = '['; - close_bracket = ']'; - } - - buffer << open_bracket; - - size_t function_arguments_projection_names_size = arguments_projection_names.size(); - for (size_t i = 0; i < function_arguments_projection_names_size; ++i) - { - buffer << arguments_projection_names[i]; - - if (i + 1 != function_arguments_projection_names_size) - buffer << ", "; - } - - buffer << close_bracket; - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name) -{ - const auto & window_node_typed = window_node->as(); - const auto & window_frame = window_node_typed.getWindowFrame(); - - bool parent_window_node_has_partition_by = false; - bool parent_window_node_has_order_by = false; - - if (parent_window_node) - { - const auto & parent_window_node_typed = parent_window_node->as(); - parent_window_node_has_partition_by = parent_window_node_typed.hasPartitionBy(); - parent_window_node_has_order_by = parent_window_node_typed.hasOrderBy(); - } - - WriteBufferFromOwnString buffer; - - if (!parent_window_name.empty()) - buffer << parent_window_name; - - if (!partition_by_projection_names.empty() && !parent_window_node_has_partition_by) - { - if (!parent_window_name.empty()) - buffer << ' '; - - buffer << "PARTITION BY "; - - size_t partition_by_projection_names_size = partition_by_projection_names.size(); - for (size_t i = 0; i < partition_by_projection_names_size; ++i) - { - buffer << partition_by_projection_names[i]; - if (i + 1 != partition_by_projection_names_size) - buffer << ", "; - } - } - - if (!order_by_projection_names.empty() && !parent_window_node_has_order_by) - { - if (!partition_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << "ORDER BY "; - - size_t order_by_projection_names_size = order_by_projection_names.size(); - for (size_t i = 0; i < order_by_projection_names_size; ++i) - { - buffer << order_by_projection_names[i]; - if (i + 1 != order_by_projection_names_size) - buffer << ", "; - } - } - - if (!window_frame.is_default) - { - if (!partition_by_projection_names.empty() || !order_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << window_frame.type << " BETWEEN "; - if (window_frame.begin_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.begin_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_begin_offset_projection_name; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - - buffer << " AND "; - - if (window_frame.end_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.end_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_end_offset_projection_name; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - } - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, const ProjectionName & fill_to_expression_projection_name, const ProjectionName & fill_step_expression_projection_name) -{ - auto & sort_node_typed = sort_column_node->as(); - - WriteBufferFromOwnString sort_column_projection_name_buffer; - sort_column_projection_name_buffer << sort_expression_projection_name; - - auto sort_direction = sort_node_typed.getSortDirection(); - sort_column_projection_name_buffer << (sort_direction == SortDirection::ASCENDING ? " ASC" : " DESC"); - - auto nulls_sort_direction = sort_node_typed.getNullsSortDirection(); - - if (nulls_sort_direction) - sort_column_projection_name_buffer << " NULLS " << (nulls_sort_direction == sort_direction ? "LAST" : "FIRST"); - - if (auto collator = sort_node_typed.getCollator()) - sort_column_projection_name_buffer << " COLLATE " << collator->getLocale(); - - if (sort_node_typed.withFill()) - { - sort_column_projection_name_buffer << " WITH FILL"; - - if (sort_node_typed.hasFillFrom()) - sort_column_projection_name_buffer << " FROM " << fill_from_expression_projection_name; - - if (sort_node_typed.hasFillTo()) - sort_column_projection_name_buffer << " TO " << fill_to_expression_projection_name; - - if (sort_node_typed.hasFillStep()) - sort_column_projection_name_buffer << " STEP " << fill_step_expression_projection_name; - } - - return sort_column_projection_name_buffer.str(); -} - -/// Get valid identifiers for typo correction from compound expression -void QueryAnalyzer::collectCompoundExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result) -{ - IDataType::forEachSubcolumn([&](const auto &, const auto & name, const auto &) - { - Identifier subcolumn_indentifier(name); - size_t new_identifier_size = valid_identifier_prefix.getPartsSize() + subcolumn_indentifier.getPartsSize(); - - if (new_identifier_size == unresolved_identifier.getPartsSize()) - { - auto new_identifier = valid_identifier_prefix; - for (const auto & part : subcolumn_indentifier) - new_identifier.push_back(part); - - valid_identifiers_result.insert(std::move(new_identifier)); - } - }, ISerialization::SubstreamData(compound_expression_type->getDefaultSerialization())); -} - -/// Get valid identifiers for typo correction from table expression -void QueryAnalyzer::collectTableExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result) -{ - for (const auto & [column_name, column_node] : table_expression_data.column_name_to_column_node) - { - Identifier column_identifier(column_name); - if (unresolved_identifier.getPartsSize() == column_identifier.getPartsSize()) - valid_identifiers_result.insert(column_identifier); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier, - valid_identifiers_result); - - if (table_expression->hasAlias()) - { - Identifier column_identifier_with_alias({table_expression->getAlias()}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_alias.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_alias.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_alias); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_alias, - valid_identifiers_result); - } - - if (!table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name({table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name, - valid_identifiers_result); - } - - if (!table_expression_data.database_name.empty() && !table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name_and_database_name({table_expression_data.database_name, table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name_and_database_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name_and_database_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name_and_database_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name_and_database_name, - valid_identifiers_result); - } - } -} - -/// Get valid identifiers for typo correction from scope without looking at parent scopes -void QueryAnalyzer::collectScopeValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - bool identifier_is_short = unresolved_identifier.isShort(); - bool identifier_is_compound = unresolved_identifier.isCompound(); - - if (allow_expression_identifiers) - { - for (const auto & [name, expression] : *scope.aliases.alias_name_to_expression_node) - { - assert(expression); - auto expression_identifier = Identifier(name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - - for (const auto & [table_expression, table_expression_data] : scope.table_expression_node_to_data) - { - collectTableExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - table_expression, - table_expression_data, - valid_identifiers_result); - } - } - - if (identifier_is_short) - { - if (allow_function_identifiers) - { - for (const auto & [name, _] : *scope.aliases.alias_name_to_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - - if (allow_table_expression_identifiers) - { - for (const auto & [name, _] : scope.aliases.alias_name_to_table_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - } - - for (const auto & [argument_name, expression] : scope.expression_argument_name_to_node) - { - assert(expression); - auto expression_node_type = expression->getNodeType(); - - if (allow_expression_identifiers && isExpressionNodeType(expression_node_type)) - { - auto expression_identifier = Identifier(argument_name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - else if (identifier_is_short && allow_function_identifiers && isFunctionExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - else if (allow_table_expression_identifiers && isTableExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - } -} - -void QueryAnalyzer::collectScopeWithParentScopesValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - const IdentifierResolveScope * current_scope = &scope; - - while (current_scope) - { - collectScopeValidIdentifiersForTypoCorrection(unresolved_identifier, - *current_scope, - allow_expression_identifiers, - allow_function_identifiers, - allow_table_expression_identifiers, - valid_identifiers_result); - - current_scope = current_scope->parent_scope; - } -} - -std::vector QueryAnalyzer::collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers) -{ - std::vector prompting_strings; - prompting_strings.reserve(valid_identifiers.size()); - - for (const auto & valid_identifier : valid_identifiers) - prompting_strings.push_back(valid_identifier.getFullName()); - - return NamePrompter<1>::getHints(unresolved_identifier.getFullName(), prompting_strings); -} - -/** Wrap expression node in tuple element function calls for nested paths. - * Example: Expression node: compound_expression. Nested path: nested_path_1.nested_path_2. - * Result: tupleElement(tupleElement(compound_expression, 'nested_path_1'), 'nested_path_2'). - */ -QueryTreeNodePtr QueryAnalyzer::wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path) -{ - size_t nested_path_parts_size = nested_path.getPartsSize(); - for (size_t i = 0; i < nested_path_parts_size; ++i) - { - const auto & nested_path_part = nested_path[i]; - auto tuple_element_function = std::make_shared("tupleElement"); - - auto & tuple_element_function_arguments_nodes = tuple_element_function->getArguments().getNodes(); - tuple_element_function_arguments_nodes.reserve(2); - tuple_element_function_arguments_nodes.push_back(expression_node); - tuple_element_function_arguments_nodes.push_back(std::make_shared(nested_path_part)); - - expression_node = std::move(tuple_element_function); - } - - return expression_node; -} - -/** Try to get lambda node from sql user defined functions if sql user defined function with function name exists. - * Returns lambda node if function exists, nullptr otherwise. - */ -QueryTreeNodePtr QueryAnalyzer::tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context) -{ - auto user_defined_function = UserDefinedSQLFunctionFactory::instance().tryGet(function_name); - if (!user_defined_function) - return {}; - - auto it = function_name_to_user_defined_lambda.find(function_name); - if (it != function_name_to_user_defined_lambda.end()) - return it->second; - - const auto & create_function_query = user_defined_function->as(); - auto result_node = buildQueryTree(create_function_query->function_core, context); - if (result_node->getNodeType() != QueryTreeNodeType::LAMBDA) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "SQL user defined function {} must represent lambda expression. Actual {}", - function_name, - create_function_query->function_core->formatForErrorMessage()); - - function_name_to_user_defined_lambda.emplace(function_name, result_node); - - return result_node; -} - -bool subtreeHasViewSource(const IQueryTreeNode * node, const Context & context) -{ - if (!node) - return false; - - if (const auto * table_node = node->as()) - { - if (table_node->getStorageID().getFullNameNotQuoted() == context.getViewSource()->getStorageID().getFullNameNotQuoted()) - return true; - } - - for (const auto & child : node->getChildren()) - if (subtreeHasViewSource(child.get(), context)) - return true; - - return false; -} - -/// Evaluate scalar subquery and perform constant folding if scalar subquery does not have constant value -void QueryAnalyzer::evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - auto * query_node = node->as(); - auto * union_node = node->as(); - if (!query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node must have query or union type. Actual {} {}", - node->getNodeTypeName(), - node->formatASTForErrorMessage()); - - auto & context = scope.context; - - Block scalar_block; - - auto node_without_alias = node->clone(); - node_without_alias->removeAlias(); - - QueryTreeNodePtrWithHash node_with_hash(node_without_alias); - auto str_hash = DB::toString(node_with_hash.hash); - - bool can_use_global_scalars = !only_analyze && !(context->getViewSource() && subtreeHasViewSource(node_without_alias.get(), *context)); - - auto & scalars_cache = can_use_global_scalars ? scalar_subquery_to_scalar_value_global : scalar_subquery_to_scalar_value_local; - - if (scalars_cache.contains(node_with_hash)) - { - if (can_use_global_scalars) - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - else - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesLocalCacheHit); - - scalar_block = scalars_cache.at(node_with_hash); - } - else if (context->hasQueryContext() && can_use_global_scalars && context->getQueryContext()->hasScalar(str_hash)) - { - scalar_block = context->getQueryContext()->getScalar(str_hash); - scalar_subquery_to_scalar_value_global.emplace(node_with_hash, scalar_block); - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - } - else - { - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesCacheMiss); - auto subquery_context = Context::createCopy(context); - - Settings subquery_settings = context->getSettings(); - subquery_settings.max_result_rows = 1; - subquery_settings.extremes = false; - subquery_context->setSettings(subquery_settings); - /// When execute `INSERT INTO t WITH ... SELECT ...`, it may lead to `Unknown columns` - /// exception with this settings enabled(https://github.com/ClickHouse/ClickHouse/issues/52494). - subquery_context->setSetting("use_structure_from_insertion_table_in_table_functions", false); - - auto options = SelectQueryOptions(QueryProcessingStage::Complete, scope.subquery_depth, true /*is_subquery*/); - options.only_analyze = only_analyze; - auto interpreter = std::make_unique(node->toAST(), subquery_context, subquery_context->getViewSource(), options); - - if (only_analyze) - { - /// If query is only analyzed, then constants are not correct. - scalar_block = interpreter->getSampleBlock(); - for (auto & column : scalar_block) - { - if (column.column->empty()) - { - auto mut_col = column.column->cloneEmpty(); - mut_col->insertDefault(); - column.column = std::move(mut_col); - } - } - } - else - { - auto io = interpreter->execute(); - PullingAsyncPipelineExecutor executor(io.pipeline); - io.pipeline.setProgressCallback(context->getProgressCallback()); - io.pipeline.setProcessListElement(context->getProcessListElement()); - - Block block; - - while (block.rows() == 0 && executor.pull(block)) - { - } - - if (block.rows() == 0) - { - auto types = interpreter->getSampleBlock().getDataTypes(); - if (types.size() != 1) - types = {std::make_shared(types)}; - - auto & type = types[0]; - if (!type->isNullable()) - { - if (!type->canBeInsideNullable()) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, - "Scalar subquery returned empty result of type {} which cannot be Nullable", - type->getName()); - - type = makeNullable(type); - } - - auto scalar_column = type->createColumn(); - scalar_column->insert(Null()); - scalar_block.insert({std::move(scalar_column), type, "null"}); - } - else - { - if (block.rows() != 1) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - Block tmp_block; - while (tmp_block.rows() == 0 && executor.pull(tmp_block)) - { - } - - if (tmp_block.rows() != 0) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - block = materializeBlock(block); - size_t columns = block.columns(); - - if (columns == 1) - { - auto & column = block.getByPosition(0); - /// Here we wrap type to nullable if we can. - /// It is needed cause if subquery return no rows, it's result will be Null. - /// In case of many columns, do not check it cause tuple can't be nullable. - if (!column.type->isNullable() && column.type->canBeInsideNullable()) - { - column.type = makeNullable(column.type); - column.column = makeNullable(column.column); - } - - scalar_block = block; - } - else - { - /** Make unique column names for tuple. - * - * Example: SELECT (SELECT 2 AS x, x) - */ - makeUniqueColumnNamesInBlock(block); - - scalar_block.insert({ - ColumnTuple::create(block.getColumns()), - std::make_shared(block.getDataTypes(), block.getNames()), - "tuple"}); - } - } - } - - scalars_cache.emplace(node_with_hash, scalar_block); - if (can_use_global_scalars && context->hasQueryContext()) - context->getQueryContext()->addScalar(str_hash, scalar_block); - } - - const auto & scalar_column_with_type = scalar_block.safeGetByPosition(0); - const auto & scalar_type = scalar_column_with_type.type; - - Field scalar_value; - scalar_column_with_type.column->get(0, scalar_value); - - const auto * scalar_type_name = scalar_block.safeGetByPosition(0).type->getFamilyName(); - static const std::set useless_literal_types = {"Array", "Tuple", "AggregateFunction", "Function", "Set", "LowCardinality"}; - auto * nearest_query_scope = scope.getNearestQueryScope(); - - /// Always convert to literals when there is no query context - if (!context->getSettingsRef().enable_scalar_subquery_optimization || - !useless_literal_types.contains(scalar_type_name) || - !context->hasQueryContext() || - !nearest_query_scope) - { - auto constant_value = std::make_shared(std::move(scalar_value), scalar_type); - auto constant_node = std::make_shared(constant_value, node); - - if (constant_node->getValue().isNull()) - { - node = buildCastFunction(constant_node, constant_node->getResultType(), context); - node = std::make_shared(std::move(constant_value), node); - } - else - node = std::move(constant_node); - - return; - } - - auto & nearest_query_scope_query_node = nearest_query_scope->scope_node->as(); - auto & mutable_context = nearest_query_scope_query_node.getMutableContext(); - - auto scalar_query_hash_string = DB::toString(node_with_hash.hash) + (only_analyze ? "_analyze" : ""); - - if (mutable_context->hasQueryContext()) - mutable_context->getQueryContext()->addScalar(scalar_query_hash_string, scalar_block); - - mutable_context->addScalar(scalar_query_hash_string, scalar_block); - - std::string get_scalar_function_name = "__getScalar"; - - auto scalar_query_hash_constant_value = std::make_shared(std::move(scalar_query_hash_string), std::make_shared()); - auto scalar_query_hash_constant_node = std::make_shared(std::move(scalar_query_hash_constant_value)); - - auto get_scalar_function_node = std::make_shared(get_scalar_function_name); - get_scalar_function_node->getArguments().getNodes().push_back(std::move(scalar_query_hash_constant_node)); - - auto get_scalar_function = FunctionFactory::instance().get(get_scalar_function_name, mutable_context); - get_scalar_function_node->resolveAsFunction(get_scalar_function->build(get_scalar_function_node->getArgumentColumns())); - - node = std::move(get_scalar_function_node); -} - -void QueryAnalyzer::mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope) -{ - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - - auto & parent_window_node_typed = parent_window_node->as(); - - /** If an existing_window_name is specified it must refer to an earlier - * entry in the WINDOW list; the new window copies its partitioning clause - * from that entry, as well as its ordering clause if any. In this case - * the new window cannot specify its own PARTITION BY clause, and it can - * specify ORDER BY only if the copied window does not have one. The new - * window always uses its own frame clause; the copied window must not - * specify a frame clause. - * https://www.postgresql.org/docs/current/sql-select.html - */ - if (window_node_typed.hasPartitionBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override PARTITION BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (window_node_typed.hasOrderBy() && parent_window_node_typed.hasOrderBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override a non-empty ORDER BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (!parent_window_node_typed.getWindowFrame().is_default) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parent window '{}' is not allowed to define a frame: while processing derived window definition '{}'. In scope {}", - parent_window_name, - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - window_node_typed.getPartitionByNode() = parent_window_node_typed.getPartitionBy().clone(); - - if (parent_window_node_typed.hasOrderBy()) - window_node_typed.getOrderByNode() = parent_window_node_typed.getOrderBy().clone(); -} - -/** Replace nodes in node list with positional arguments. - * - * Example: SELECT id, value FROM test_table GROUP BY 1, 2; - * Example: SELECT id, value FROM test_table ORDER BY 1, 2; - * Example: SELECT id, value FROM test_table LIMIT 5 BY 1, 2; - */ -void QueryAnalyzer::replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope) -{ - const auto & settings = scope.context->getSettingsRef(); - if (!settings.enable_positional_arguments || scope.context->getClientInfo().query_kind != ClientInfo::QueryKind::INITIAL_QUERY) - return; - - auto & node_list_typed = node_list->as(); - - for (auto & node : node_list_typed.getNodes()) - { - auto * node_to_replace = &node; - - if (auto * sort_node = node->as()) - node_to_replace = &sort_node->getExpression(); - - auto * constant_node = (*node_to_replace)->as(); - - if (!constant_node - || (constant_node->getValue().getType() != Field::Types::UInt64 - && constant_node->getValue().getType() != Field::Types::Int64)) - continue; - - UInt64 pos; - if (constant_node->getValue().getType() == Field::Types::UInt64) - { - pos = constant_node->getValue().get(); - } - else // Int64 - { - auto value = constant_node->getValue().get(); - if (value > 0) - pos = value; - else - { - if (value < -static_cast(projection_nodes.size())) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Negative positional argument number {} is out of bounds. Expected in range [-{}, -1]. In scope {}", - value, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - pos = projection_nodes.size() + value + 1; - } - } - - if (!pos || pos > projection_nodes.size()) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Positional argument number {} is out of bounds. Expected in range [1, {}]. In scope {}", - pos, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - - --pos; - *node_to_replace = projection_nodes[pos]->clone(); - if (auto it = resolved_expressions.find(projection_nodes[pos]); it != resolved_expressions.end()) - { - resolved_expressions[*node_to_replace] = it->second; - } - } -} - -void QueryAnalyzer::convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope) -{ - const auto * limit_offset_constant_node = expression_node->as(); - if (!limit_offset_constant_node || !isNativeNumber(removeNullable(limit_offset_constant_node->getResultType()))) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} expression must be constant with numeric type. Actual {}. In scope {}", - expression_description, - expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - Field converted_value = convertFieldToType(limit_offset_constant_node->getValue(), DataTypeUInt64()); - if (converted_value.isNull()) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} numeric constant expression is not representable as UInt64", - expression_description); - - auto constant_value = std::make_shared(std::move(converted_value), std::make_shared()); - auto result_constant_node = std::make_shared(std::move(constant_value)); - result_constant_node->getSourceExpression() = limit_offset_constant_node->getSourceExpression(); - - expression_node = std::move(result_constant_node); -} - -void QueryAnalyzer::validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unexpected table expression. Expected table, table function, query or union node. Table node: {}, scope node: {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (table_node || table_function_node) - { - auto table_expression_modifiers = table_node ? table_node->getTableExpressionModifiers() : table_function_node->getTableExpressionModifiers(); - - if (table_expression_modifiers.has_value()) - { - const auto & storage = table_node ? table_node->getStorage() : table_function_node->getStorage(); - if (table_expression_modifiers->hasFinal() && !storage->supportsFinal()) - throw Exception(ErrorCodes::ILLEGAL_FINAL, - "Storage {} doesn't support FINAL", - storage->getName()); - - if (table_expression_modifiers->hasSampleSizeRatio() && !storage->supportsSampling()) - throw Exception(ErrorCodes::SAMPLING_NOT_SUPPORTED, - "Storage {} doesn't support sampling", - storage->getStorageID().getFullNameNotQuoted()); - } - } -} - -void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - bool table_expression_has_alias = table_expression_node->hasAlias(); - if (table_expression_has_alias) - return; - - if (join_node->as().getKind() == JoinKind::Paste) - return; - - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - if ((query_node && !query_node->getCTEName().empty()) || (union_node && !union_node->getCTEName().empty())) - return; - - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || - table_expression_node_type == QueryTreeNodeType::QUERY || - table_expression_node_type == QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::ALIAS_REQUIRED, - "JOIN {} no alias for subquery or table function {}. " - "In scope {} (set joined_subquery_requires_alias = 0 to disable restriction)", - join_node->formatASTForErrorMessage(), - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); -} - -std::pair QueryAnalyzer::recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into) -{ - checkStackSize(); - - if (node->as()) - { - into.push_back(node); - return {false, 1}; - } - - auto * function = node->as(); - - if (!function) - return {false, 0}; - - if (function->isAggregateFunction()) - return {true, 0}; - - UInt64 pushed_children = 0; - bool has_aggregate = false; - - for (auto & child : function->getArguments().getNodes()) - { - auto [child_has_aggregate, child_pushed_children] = recursivelyCollectMaxOrdinaryExpressions(child, into); - has_aggregate |= child_has_aggregate; - pushed_children += child_pushed_children; - } - - /// The current function is not aggregate function and there is no aggregate function in its arguments, - /// so use the current function to replace its arguments - if (!has_aggregate) - { - for (UInt64 i = 0; i < pushed_children; i++) - into.pop_back(); - - into.push_back(node); - pushed_children = 1; - } - - return {has_aggregate, pushed_children}; -} - -/** Expand GROUP BY ALL by extracting all the SELECT-ed expressions that are not aggregate functions. - * - * For a special case that if there is a function having both aggregate functions and other fields as its arguments, - * the `GROUP BY` keys will contain the maximum non-aggregate fields we can extract from it. - * - * Example: - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY ALL - * will expand as - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY substring(a, 4, 2), substring(a, 1, 2) - */ -void QueryAnalyzer::expandGroupByAll(QueryNode & query_tree_node_typed) -{ - if (!query_tree_node_typed.isGroupByAll()) - return; - - auto & group_by_nodes = query_tree_node_typed.getGroupBy().getNodes(); - auto & projection_list = query_tree_node_typed.getProjection(); - - for (auto & node : projection_list.getNodes()) - recursivelyCollectMaxOrdinaryExpressions(node, group_by_nodes); - query_tree_node_typed.setIsGroupByAll(false); -} - -void QueryAnalyzer::expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings) -{ - if (!settings.enable_order_by_all || !query_tree_node_typed.isOrderByAll()) - return; - - auto * all_node = query_tree_node_typed.getOrderBy().getNodes()[0]->as(); - if (!all_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Select analyze for not sort node."); - - auto & projection_nodes = query_tree_node_typed.getProjection().getNodes(); - auto list_node = std::make_shared(); - list_node->getNodes().reserve(projection_nodes.size()); - - for (auto & node : projection_nodes) - { - /// Detect and reject ambiguous statements: - /// E.g. for a table with columns "all", "a", "b": - /// - SELECT all, a, b ORDER BY all; -- should we sort by all columns in SELECT or by column "all"? - /// - SELECT a, b AS all ORDER BY all; -- like before but "all" as alias - /// - SELECT func(...) AS all ORDER BY all; -- like before but "all" as function - /// - SELECT a, b ORDER BY all; -- tricky in other way: does the user want to sort by columns in SELECT clause or by not SELECTed column "all"? - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - auto projection_names = resolved_expression_it->second; - if (projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected 1 projection names. Actual {}", - projection_names.size()); - if (boost::iequals(projection_names[0], "all")) - throw Exception(ErrorCodes::UNEXPECTED_EXPRESSION, - "Cannot use ORDER BY ALL to sort a column with name 'all', please disable setting `enable_order_by_all` and try again"); - } - - auto sort_node = std::make_shared(node, all_node->getSortDirection(), all_node->getNullsSortDirection()); - list_node->getNodes().push_back(sort_node); - } - - query_tree_node_typed.getOrderByNode() = list_node; - query_tree_node_typed.setIsOrderByAll(false); -} - -std::string QueryAnalyzer::rewriteAggregateFunctionNameIfNeeded( - const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context) -{ - std::string result_aggregate_function_name = aggregate_function_name; - auto aggregate_function_name_lowercase = Poco::toLower(aggregate_function_name); - - const auto & settings = context->getSettingsRef(); - - if (aggregate_function_name_lowercase == "countdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - } - else if (aggregate_function_name_lowercase == "countdistinctif" || aggregate_function_name_lowercase == "countifdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - result_aggregate_function_name += "If"; - } - - /// Replace aggregateFunctionIfDistinct into aggregateFunctionDistinctIf to make execution more optimal - if (result_aggregate_function_name.ends_with("ifdistinct")) - { - size_t prefix_length = result_aggregate_function_name.size() - strlen("ifdistinct"); - result_aggregate_function_name = result_aggregate_function_name.substr(0, prefix_length) + "DistinctIf"; - } - - bool need_add_or_null = settings.aggregate_functions_null_for_empty && !result_aggregate_function_name.ends_with("OrNull"); - if (need_add_or_null) - { - auto properties = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (!properties->returns_default_when_only_null) - result_aggregate_function_name += "OrNull"; - } - - /** Move -OrNull suffix ahead, this should execute after add -OrNull suffix. - * Used to rewrite aggregate functions with -OrNull suffix in some cases. - * Example: sumIfOrNull. - * Result: sumOrNullIf. - */ - if (result_aggregate_function_name.ends_with("OrNull")) - { - auto function_properies = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (function_properies && !function_properies->returns_default_when_only_null) - { - size_t function_name_size = result_aggregate_function_name.size(); - - static constexpr std::array suffixes_to_replace = {"MergeState", "Merge", "State", "If"}; - for (const auto & suffix : suffixes_to_replace) - { - auto suffix_string_value = String(suffix); - auto suffix_to_check = suffix_string_value + "OrNull"; - - if (!result_aggregate_function_name.ends_with(suffix_to_check)) - continue; - - result_aggregate_function_name = result_aggregate_function_name.substr(0, function_name_size - suffix_to_check.size()); - result_aggregate_function_name += "OrNull"; - result_aggregate_function_name += suffix_string_value; - - break; - } - } - } - - return result_aggregate_function_name; -} - -/// Resolve identifier functions implementation - -/// Try resolve table identifier from database catalog -QueryTreeNodePtr QueryAnalyzer::tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context) -{ - size_t parts_size = table_identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected table identifier to contain 1 or 2 parts. Actual '{}'", - table_identifier.getFullName()); - - std::string database_name; - std::string table_name; - - if (table_identifier.isCompound()) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - else - { - table_name = table_identifier[0]; - } - - StorageID storage_id(database_name, table_name); - storage_id = context->resolveStorageID(storage_id); - bool is_temporary_table = storage_id.getDatabaseName() == DatabaseCatalog::TEMPORARY_DATABASE; - - StoragePtr storage; - - if (is_temporary_table) - storage = DatabaseCatalog::instance().getTable(storage_id, context); - else - storage = DatabaseCatalog::instance().tryGetTable(storage_id, context); - - if (!storage) - return {}; - - auto storage_lock = storage->lockForShare(context->getInitialQueryId(), context->getSettingsRef().lock_acquire_timeout); - auto storage_snapshot = storage->getStorageSnapshot(storage->getInMemoryMetadataPtr(), context); - auto result = std::make_shared(std::move(storage), std::move(storage_lock), std::move(storage_snapshot)); - if (is_temporary_table) - result->setTemporaryTableName(table_name); - - return result; -} - -/// Resolve identifier from compound expression -/// If identifier cannot be resolved throw exception or return nullptr if can_be_not_found is true -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found) -{ - Identifier compound_expression_identifier; - for (size_t i = 0; i < identifier_bind_size; ++i) - compound_expression_identifier.push_back(expression_identifier[i]); - - IdentifierView nested_path(expression_identifier); - nested_path.popFirst(identifier_bind_size); - - auto expression_type = compound_expression->getResultType(); - - if (!expression_type->hasSubcolumn(nested_path.getFullName())) - { - if (auto * column = compound_expression->as()) - { - const DataTypePtr & column_type = column->getColumn().getTypeInStorage(); - if (column_type->getTypeId() == TypeIndex::Object) - { - const auto * object_type = checkAndGetDataType(column_type.get()); - if (object_type->getSchemaFormat() == "json" && object_type->hasNullableSubcolumns()) - { - QueryTreeNodePtr constant_node_null = std::make_shared(Field()); - return constant_node_null; - } - } - } - - if (can_be_not_found) - return {}; - - std::unordered_set valid_identifiers; - collectCompoundExpressionValidIdentifiersForTypoCorrection(expression_identifier, - expression_type, - compound_expression_identifier, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(expression_identifier, valid_identifiers); - - String compound_expression_from_error_message; - if (!compound_expression_source.empty()) - { - compound_expression_from_error_message += " from "; - compound_expression_from_error_message += compound_expression_source; - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier {} nested path {} cannot be resolved from type {}{}. In scope {}{}", - expression_identifier, - nested_path, - expression_type->getName(), - compound_expression_from_error_message, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - QueryTreeNodePtr get_subcolumn_function = std::make_shared("getSubcolumn"); - auto & get_subcolumn_function_arguments_nodes = get_subcolumn_function->as()->getArguments().getNodes(); - - get_subcolumn_function_arguments_nodes.reserve(2); - get_subcolumn_function_arguments_nodes.push_back(compound_expression); - get_subcolumn_function_arguments_nodes.push_back(std::make_shared(nested_path.getFullName())); - - resolveFunction(get_subcolumn_function, scope); - return get_subcolumn_function; -} - -/** Resolve identifier from expression arguments. - * - * Expression arguments can be initialized during lambda analysis or they could be provided externally. - * Expression arguments must be already resolved nodes. This is client responsibility to resolve them. - * - * Example: SELECT arrayMap(x -> x + 1, [1,2,3]); - * For lambda x -> x + 1, `x` is lambda expression argument. - * - * Resolve strategy: - * 1. Try to bind identifier to scope argument name to node map. - * 2. If identifier is binded but expression context and node type are incompatible return nullptr. - * - * It is important to support edge cases, where we lookup for table or function node, but argument has same name. - * Example: WITH (x -> x + 1) AS func, (func -> func(1) + func) AS lambda SELECT lambda(1); - * - * 3. If identifier is compound and identifier lookup is in expression context use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - auto it = scope.expression_argument_name_to_node.find(identifier_lookup.identifier.getFullName()); - bool resolve_full_identifier = it != scope.expression_argument_name_to_node.end(); - - if (!resolve_full_identifier) - { - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - it = scope.expression_argument_name_to_node.find(identifier_bind_part); - if (it == scope.expression_argument_name_to_node.end()) - return {}; - } - - auto node_type = it->second->getNodeType(); - if (identifier_lookup.isExpressionLookup() && !isExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isTableExpressionLookup() && !isTableExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isFunctionLookup() && !isFunctionExpressionNodeType(node_type)) - return {}; - - if (!resolve_full_identifier && identifier_lookup.identifier.isCompound() && identifier_lookup.isExpressionLookup()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return it->second; -} - -bool QueryAnalyzer::tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope) -{ - return scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME) != nullptr || scope.aliases.array_join_aliases.contains(identifier_lookup.identifier.front()); -} - -/** Resolve identifier from scope aliases. - * - * Resolve strategy: - * 1. If alias is registered in current expressions that are in resolve process and if top expression is not part of bottom expression with the same alias subtree - * throw cyclic aliases exception. - * Otherwise prevent cache usage for identifier lookup and return nullptr. - * - * This is special scenario where identifier has name the same as alias name in one of its parent expressions including itself. - * In such case we cannot resolve identifier from aliases because of recursion. It is client responsibility to register and deregister alias - * names during expressions resolve. - * - * We must prevent cache usage for lookup because lookup outside of expression is supposed to return other value. - * Example: SELECT (id + 1) AS id, id + 2. Lookup for id inside (id + 1) as id should return id from table, but lookup (id + 2) should return - * (id + 1) AS id. - * - * Below cases should work: - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * SELECT (id + 1) AS id FROM test_table; - * SELECT (1 + (1 + id)) AS id FROM test_table; - * - * Below cases should throw cyclic aliases exception: - * SELECT (id + b) AS id, id as b FROM test_table; - * SELECT (1 + b + 1 + id) AS id, b as c, id as b FROM test_table; - * - * 2. Depending on IdentifierLookupContext get alias name to node map from IdentifierResolveScope. - * 3. Try to bind identifier to alias name in map. If there are no such binding return nullptr. - * 4. If node in map is not resolved, resolve it. It is important in case of compound expressions. - * Example: SELECT value.a, cast('(1)', 'Tuple(a UInt64)') AS value; - * - * Special case if node is identifier node. - * Example: SELECT value, id AS value FROM test_table; - * - * Add node in current scope expressions in resolve process stack. - * Try to resolve identifier. - * If identifier is resolved, depending on lookup context, erase entry from expression or lambda map. Check QueryExpressionsAliasVisitor documentation. - * Pop node from current scope expressions in resolve process stack. - * - * 5. If identifier is compound and identifier lookup is in expression context, use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - auto * it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME); - if (it == nullptr) - return {}; - - QueryTreeNodePtr & alias_node = *it; - - if (!alias_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node with alias {} is not valid. In scope {}", - identifier_bind_part, - scope.scope_node->formatASTForErrorMessage()); - - if (auto root_expression_with_alias = scope.expressions_in_resolve_process_stack.getExpressionWithAlias(identifier_bind_part)) - { - const auto top_expression = scope.expressions_in_resolve_process_stack.getTop(); - - if (!isNodePartOfTree(top_expression.get(), root_expression_with_alias.get())) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - scope.non_cached_identifier_lookups_during_expression_resolve.insert(identifier_lookup); - return {}; - } - - auto node_type = alias_node->getNodeType(); - - /// Resolve expression if necessary - if (node_type == QueryTreeNodeType::IDENTIFIER) - { - scope.pushExpressionNode(alias_node); - - auto & alias_identifier_node = alias_node->as(); - auto identifier = alias_identifier_node.getIdentifier(); - auto lookup_result = tryResolveIdentifier(IdentifierLookup{identifier, identifier_lookup.lookup_context}, scope, identifier_resolve_settings); - if (!lookup_result.resolved_identifier) - { - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(identifier, scope, true, false, false, valid_identifiers); - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {} identifier '{}'. In scope {}{}", - toStringLowercase(identifier_lookup.lookup_context), - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - alias_node = lookup_result.resolved_identifier; - scope.popExpressionNode(); - } - else if (node_type == QueryTreeNodeType::FUNCTION) - { - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - else if (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION) - { - if (identifier_resolve_settings.allow_to_resolve_subquery_during_identifier_resolution) - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, identifier_lookup.isTableExpressionLookup() /*allow_table_expression*/); - } - - if (identifier_lookup.identifier.isCompound() && alias_node) - { - if (identifier_lookup.isExpressionLookup()) - { - return tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - 1 /*identifier_bind_size*/, - alias_node, - {} /* compound_expression_source */, - scope, - identifier_resolve_settings.allow_to_check_join_tree /* can_be_not_found */); - } - else if (identifier_lookup.isFunctionLookup() || identifier_lookup.isTableExpressionLookup()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Compound identifier '{}' cannot be resolved as {}. In scope {}", - identifier_lookup.identifier.getFullName(), - identifier_lookup.isFunctionLookup() ? "function" : "table expression", - scope.scope_node->formatASTForErrorMessage()); - } - } - - return alias_node; -} - -/** Resolve identifier from table columns. - * - * 1. If table column nodes are empty or identifier is not expression lookup return nullptr. - * 2. If identifier full name match table column use column. Save information that we resolve identifier using full name. - * 3. Else if identifier binds to table column, use column. - * 4. Try to resolve column ALIAS expression if it exists. - * 5. If identifier was compound and was not resolved using full name during step 1 use `tryResolveIdentifierFromCompoundExpression`. - * This can be the case with compound ALIAS columns. - * - * Example: - * CREATE TABLE test_table (id UInt64, value Tuple(id UInt64, value String), alias_value ALIAS value.id) ENGINE=TinyLog; - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - if (scope.column_name_to_column_node.empty() || !identifier_lookup.isExpressionLookup()) - return {}; - - const auto & identifier = identifier_lookup.identifier; - auto it = scope.column_name_to_column_node.find(identifier.getFullName()); - bool full_column_name_match = it != scope.column_name_to_column_node.end(); - - if (!full_column_name_match) - { - it = scope.column_name_to_column_node.find(identifier_lookup.identifier[0]); - if (it == scope.column_name_to_column_node.end()) - return {}; - } - - if (it->second->hasExpression()) - resolveExpressionNode(it->second->getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - QueryTreeNodePtr result = it->second; - - if (!full_column_name_match && identifier.isCompound()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return result; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - if (parts_size == 1 && path_start == table_name) - return true; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return true; - else - return false; - } - - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier)) || table_expression_data.canBindIdentifier(IdentifierView(identifier))) - return true; - - if (identifier.getPartsSize() == 1) - return false; - - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return true; - - if (identifier.getPartsSize() == 2) - return false; - - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return true; - - return false; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node_to_ignore, - const IdentifierResolveScope & scope) -{ - bool can_bind_identifier_to_table_expression = false; - - for (const auto & [table_expression_node, _] : scope.table_expression_node_to_data) - { - if (table_expression_node.get() == table_expression_node_to_ignore.get()) - continue; - - can_bind_identifier_to_table_expression = tryBindIdentifierToTableExpression(identifier_lookup, table_expression_node, scope); - if (can_bind_identifier_to_table_expression) - break; - } - - return can_bind_identifier_to_table_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found) -{ - auto identifier_without_column_qualifier = identifier; - identifier_without_column_qualifier.popFirst(identifier_column_qualifier_parts); - - /** Compound identifier cannot be resolved directly from storage if storage is not table. - * - * Example: SELECT test_table.id.value1.value2 FROM test_table; - * In table storage column test_table.id.value1.value2 will exists. - * - * Example: SELECT test_subquery.compound_expression.value FROM (SELECT compound_expression AS value) AS test_subquery; - * Here there is no column with name test_subquery.compound_expression.value, and additional wrap in tuple element is required. - */ - - QueryTreeNodePtr result_expression; - bool match_full_identifier = false; - - const auto & identifier_full_name = identifier_without_column_qualifier.getFullName(); - auto it = table_expression_data.column_name_to_column_node.find(identifier_full_name); - bool can_resolve_directly_from_storage = it != table_expression_data.column_name_to_column_node.end(); - if (can_resolve_directly_from_storage && table_expression_data.subcolumn_names.contains(identifier_full_name)) - { - /** In the case when we have an ARRAY JOIN, we should not resolve subcolumns directly from storage. - * For example, consider the following SQL query: - * SELECT ProfileEvents.Values FROM system.query_log ARRAY JOIN ProfileEvents - * In this case, ProfileEvents.Values should also be array joined, not directly resolved from storage. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - if (nearest_query_scope_query_node && nearest_query_scope_query_node->getJoinTree()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - can_resolve_directly_from_storage = false; - } - - if (can_resolve_directly_from_storage) - { - match_full_identifier = true; - result_expression = it->second; - } - else - { - it = table_expression_data.column_name_to_column_node.find(identifier_without_column_qualifier.at(0)); - if (it != table_expression_data.column_name_to_column_node.end()) - result_expression = it->second; - } - - bool clone_is_needed = true; - - String table_expression_source = table_expression_data.table_expression_description; - if (!table_expression_data.table_expression_name.empty()) - table_expression_source += " with name " + table_expression_data.table_expression_name; - - if (result_expression && !match_full_identifier && identifier_without_column_qualifier.isCompound()) - { - size_t identifier_bind_size = identifier_column_qualifier_parts + 1; - result_expression = tryResolveIdentifierFromCompoundExpression(identifier, - identifier_bind_size, - result_expression, - table_expression_source, - scope, - can_be_not_found); - if (can_be_not_found && !result_expression) - return {}; - clone_is_needed = false; - } - - if (!result_expression) - { - QueryTreeNodes nested_column_nodes; - DataTypes nested_types; - Array nested_names_array; - - for (const auto & [column_name, _] : table_expression_data.column_names_and_types) - { - Identifier column_name_identifier_without_last_part(column_name); - auto column_name_identifier_last_part = column_name_identifier_without_last_part.getParts().back(); - column_name_identifier_without_last_part.popLast(); - - if (identifier_without_column_qualifier.getFullName() != column_name_identifier_without_last_part.getFullName()) - continue; - - auto column_node_it = table_expression_data.column_name_to_column_node.find(column_name); - if (column_node_it == table_expression_data.column_name_to_column_node.end()) - continue; - - const auto & column_node = column_node_it->second; - const auto & column_type = column_node->getColumnType(); - const auto * column_type_array = typeid_cast(column_type.get()); - if (!column_type_array) - continue; - - nested_column_nodes.push_back(column_node); - nested_types.push_back(column_type_array->getNestedType()); - nested_names_array.push_back(Field(std::move(column_name_identifier_last_part))); - } - - if (!nested_types.empty()) - { - auto nested_function_node = std::make_shared("nested"); - auto & nested_function_node_arguments = nested_function_node->getArguments().getNodes(); - - auto nested_function_names_array_type = std::make_shared(std::make_shared()); - auto nested_function_names_constant_node = std::make_shared(std::move(nested_names_array), - std::move(nested_function_names_array_type)); - nested_function_node_arguments.push_back(std::move(nested_function_names_constant_node)); - nested_function_node_arguments.insert(nested_function_node_arguments.end(), - nested_column_nodes.begin(), - nested_column_nodes.end()); - - auto nested_function = FunctionFactory::instance().get(nested_function_node->getFunctionName(), scope.context); - nested_function_node->resolveAsFunction(nested_function->build(nested_function_node->getArgumentColumns())); - - clone_is_needed = false; - result_expression = std::move(nested_function_node); - } - } - - if (!result_expression) - { - if (can_be_not_found) - return {}; - std::unordered_set valid_identifiers; - collectTableExpressionValidIdentifiersForTypoCorrection(identifier, - table_expression_node, - table_expression_data, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Identifier '{}' cannot be resolved from {}. In scope {}{}", - identifier.getFullName(), - table_expression_source, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (clone_is_needed) - result_expression = result_expression->clone(); - - auto qualified_identifier = identifier; - - for (size_t i = 0; i < identifier_column_qualifier_parts; ++i) - { - auto qualified_identifier_with_removed_part = qualified_identifier; - qualified_identifier_with_removed_part.popFirst(); - - if (qualified_identifier_with_removed_part.empty()) - break; - - IdentifierLookup column_identifier_lookup = {qualified_identifier_with_removed_part, IdentifierLookupContext::EXPRESSION}; - if (tryBindIdentifierToAliases(column_identifier_lookup, scope)) - break; - - if (table_expression_data.should_qualify_columns && - tryBindIdentifierToTableExpressions(column_identifier_lookup, table_expression_node, scope)) - break; - - qualified_identifier = std::move(qualified_identifier_with_removed_part); - } - - auto qualified_identifier_full_name = qualified_identifier.getFullName(); - node_to_projection_name.emplace(result_expression, std::move(qualified_identifier_full_name)); - - return result_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (parts_size == 1 && path_start == table_name) - return table_expression_node; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return table_expression_node; - else - return {}; - } - - /** If identifier first part binds to some column start or table has full identifier name. Then we can try to find whole identifier in table. - * 1. Try to bind identifier first part to column in table, if true get full identifier from table or throw exception. - * 2. Try to bind identifier first part to table name or storage alias, if true remove first part and try to get full identifier from table or throw exception. - * Storage alias works for subquery, table function as well. - * 3. Try to bind identifier first parts to database name and table name, if true remove first two parts and try to get full identifier from table or throw exception. - */ - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier))) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/); - - if (table_expression_data.canBindIdentifier(IdentifierView(identifier))) - { - /** This check is insufficient to determine whether and identifier can be resolved from table expression. - * A further check will be performed in `tryResolveIdentifierFromStorage` to see if we have such a subcolumn. - * In cases where the subcolumn cannot be found we want to have `nullptr` instead of exception. - * So, we set `can_be_not_found = true` to have an attempt to resolve the identifier from another table expression. - * Example: `SELECT t.t from (SELECT 1 as t) AS a FULL JOIN (SELECT 1 as t) as t ON a.t = t.t;` - * Initially, we will try to resolve t.t from `a` because `t.` is bound to `1 as t`. However, as it is not a nested column, we will need to resolve it from the second table expression. - */ - auto resolved_identifier = tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/, true /*can_be_not_found*/); - if (resolved_identifier) - return resolved_identifier; - } - - if (identifier.getPartsSize() == 1) - return {}; - - const auto & table_name = table_expression_data.table_name; - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 1 /*identifier_column_qualifier_parts*/); - - if (identifier.getPartsSize() == 2) - return {}; - - const auto & database_name = table_expression_data.database_name; - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 2 /*identifier_column_qualifier_parts*/); - - return {}; -} - -QueryTreeNodePtr checkIsMissedObjectJSONSubcolumn(const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier) -{ - if (left_resolved_identifier && right_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT - && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL" && right_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (left_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (right_resolved_identifier && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & right_resolved_column = right_resolved_identifier->as(); - if (right_resolved_column.getValueStringRepresentation() == "NULL") - return right_resolved_identifier; - } - return {}; -} - -/// Used to replace columns that changed type because of JOIN to their original type -class ReplaceColumnsVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit ReplaceColumnsVisitor(const QueryTreeNodePtrWithHashMap & replacement_map_, const ContextPtr & context_) - : replacement_map(replacement_map_) - , context(context_) - {} - - /// Apply replacement transitively, because column may change it's type twice, one to have a supertype and then because of `joun_use_nulls` - static QueryTreeNodePtr findTransitiveReplacement(QueryTreeNodePtr node, const QueryTreeNodePtrWithHashMap & replacement_map_) - { - auto it = replacement_map_.find(node); - QueryTreeNodePtr result_node = nullptr; - for (; it != replacement_map_.end(); it = replacement_map_.find(result_node)) - { - if (result_node && result_node->isEqual(*it->second)) - { - Strings map_dump; - for (const auto & [k, v]: replacement_map_) - map_dump.push_back(fmt::format("{} -> {} (is_equals: {}, is_same: {})", - k.node->dumpTree(), v->dumpTree(), k.node->isEqual(*v), k.node == v)); - throw Exception(ErrorCodes::LOGICAL_ERROR, "Infinite loop in query tree replacement map: {}", fmt::join(map_dump, "; ")); - } - chassert(it->second); - - result_node = it->second; - } - return result_node; - } - - void visitImpl(QueryTreeNodePtr & node) - { - if (auto replacement_node = findTransitiveReplacement(node, replacement_map)) - node = replacement_node; - - if (auto * function_node = node->as(); function_node && function_node->isResolved()) - rerunFunctionResolve(function_node, context); - } - - /// We want to re-run resolve for function _after_ its arguments are replaced - bool shouldTraverseTopToBottom() const { return false; } - - bool needChildVisit(QueryTreeNodePtr & /* parent */, QueryTreeNodePtr & child) - { - /// Visit only expressions, but not subqueries - return child->getNodeType() == QueryTreeNodeType::IDENTIFIER - || child->getNodeType() == QueryTreeNodeType::LIST - || child->getNodeType() == QueryTreeNodeType::FUNCTION - || child->getNodeType() == QueryTreeNodeType::COLUMN; - } - -private: - const QueryTreeNodePtrWithHashMap & replacement_map; - const ContextPtr & context; -}; - -/// Compare resolved identifiers considering columns that become nullable after JOIN -bool resolvedIdenfiersFromJoinAreEquals( - const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier, - const IdentifierResolveScope & scope) -{ - auto left_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(left_resolved_identifier, scope.join_columns_with_changed_types); - const auto & left_resolved_to_compare = left_original_node ? left_original_node : left_resolved_identifier; - - auto right_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(right_resolved_identifier, scope.join_columns_with_changed_types); - const auto & right_resolved_to_compare = right_original_node ? right_original_node : right_resolved_identifier; - - return left_resolved_to_compare->isEqual(*right_resolved_to_compare, IQueryTreeNode::CompareOptions{.compare_aliases = false}); -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_join_node = table_expression_node->as(); - auto left_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getLeftTableExpression(), scope); - auto right_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getRightTableExpression(), scope); - - if (!identifier_lookup.isExpressionLookup()) - { - if (left_resolved_identifier && right_resolved_identifier) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.dump(), - scope.scope_node->formatASTForErrorMessage()); - - return left_resolved_identifier ? left_resolved_identifier : right_resolved_identifier; - } - - bool join_node_in_resolve_process = scope.table_expressions_in_resolve_process.contains(table_expression_node.get()); - - std::unordered_map join_using_column_name_to_column_node; - - if (!join_node_in_resolve_process && from_join_node.isUsingJoinExpression()) - { - auto & join_using_list = from_join_node.getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & column_node = join_using_node->as(); - join_using_column_name_to_column_node.emplace(column_node.getColumnName(), std::static_pointer_cast(join_using_node)); - } - } - - auto check_nested_column_not_in_using = [&join_using_column_name_to_column_node, &identifier_lookup](const QueryTreeNodePtr & node) - { - /** tldr: When an identifier is resolved into the function `nested` or `getSubcolumn`, and - * some column in its argument is in the USING list and its type has to be updated, we throw an error to avoid overcomplication. - * - * Identifiers can be resolved into functions in case of nested or subcolumns. - * For example `t.t.t` can be resolved into `getSubcolumn(t, 't.t')` function in case of `t` is `Tuple`. - * So, `t` in USING list is resolved from JOIN itself and has supertype of columns from left and right table. - * But `t` in `getSubcolumn` argument is still resolved from table and we need to update its type. - * - * Example: - * - * SELECT t.t FROM ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t UInt32, s1 String), s1 String) as t - * ) AS a FULL JOIN ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t Int32, s2 String), s2 String) as t - * ) AS b USING t; - * - * Result type of `t` is `Tuple(Tuple(Int64, String), String)` (different type and no names for subcolumns), - * so it may be tricky to have a correct type for `t.t` that is resolved into getSubcolumn(t, 't'). - * - * It can be more complicated in case of Nested subcolumns, in that case in query: - * SELECT t FROM ... JOIN ... USING (t.t) - * Here, `t` is resolved into function `nested(['t', 's'], t.t, t.s) so, `t.t` should be from JOIN and `t.s` should be from table. - * - * Updating type accordingly is pretty complicated, so just forbid such cases. - * - * While it still may work for storages that support selecting subcolumns directly without `getSubcolumn` function: - * SELECT t, t.t, toTypeName(t), toTypeName(t.t) FROM t1 AS a FULL JOIN t2 AS b USING t.t; - * We just support it as a best-effort: `t` will have original type from table, but `t.t` will have super-type from JOIN. - * Probably it's good to prohibit such cases as well, but it's not clear how to check it in general case. - */ - if (node->getNodeType() != QueryTreeNodeType::FUNCTION) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {}, expected function node", node->getNodeType()); - - const auto & function_argument_nodes = node->as().getArguments().getNodes(); - for (const auto & argument_node : function_argument_nodes) - { - if (argument_node->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_name = argument_node->as().getColumnName(); - if (join_using_column_name_to_column_node.contains(column_name)) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Cannot select subcolumn for identifier '{}' while joining using column '{}'", - identifier_lookup.identifier, column_name); - } - else if (argument_node->getNodeType() == QueryTreeNodeType::CONSTANT) - { - continue; - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {} for argument node in {}", - argument_node->getNodeType(), node->formatASTForErrorMessage()); - } - } - }; - - std::optional resolved_side; - QueryTreeNodePtr resolved_identifier; - - JoinKind join_kind = from_join_node.getKind(); - - /// If columns from left or right table were missed Object(Nullable('json')) subcolumns, they will be replaced - /// to ConstantNode(NULL), which can't be cast to ColumnNode, so we resolve it here. - if (auto missed_subcolumn_identifier = checkIsMissedObjectJSONSubcolumn(left_resolved_identifier, right_resolved_identifier)) - return missed_subcolumn_identifier; - - if (left_resolved_identifier && right_resolved_identifier) - { - auto using_column_node_it = join_using_column_name_to_column_node.end(); - if (left_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && right_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getColumnName() == right_resolved_column.getColumnName()) - using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - } - else - { - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(left_resolved_identifier); - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(right_resolved_identifier); - } - - if (using_column_node_it != join_using_column_name_to_column_node.end()) - { - JoinTableSide using_column_inner_column_table_side = isRight(join_kind) ? JoinTableSide::Right : JoinTableSide::Left; - auto & using_column_node = using_column_node_it->second->as(); - auto & using_expression_list = using_column_node.getExpression()->as(); - - size_t inner_column_node_index = using_column_inner_column_table_side == JoinTableSide::Left ? 0 : 1; - const auto & inner_column_node = using_expression_list.getNodes().at(inner_column_node_index); - - auto result_column_node = inner_column_node->clone(); - auto & result_column = result_column_node->as(); - result_column.setColumnType(using_column_node.getColumnType()); - - const auto & join_using_left_column = using_expression_list.getNodes().at(0); - if (!result_column_node->isEqual(*join_using_left_column)) - scope.join_columns_with_changed_types[result_column_node] = join_using_left_column; - - resolved_identifier = std::move(result_column_node); - } - else if (resolvedIdenfiersFromJoinAreEquals(left_resolved_identifier, right_resolved_identifier, scope)) - { - const auto & identifier_path_part = identifier_lookup.identifier.front(); - auto * left_resolved_identifier_column = left_resolved_identifier->as(); - auto * right_resolved_identifier_column = right_resolved_identifier->as(); - - if (left_resolved_identifier_column && right_resolved_identifier_column) - { - const auto & left_column_source_alias = left_resolved_identifier_column->getColumnSource()->getAlias(); - const auto & right_column_source_alias = right_resolved_identifier_column->getColumnSource()->getAlias(); - - /** If column from right table was resolved using alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one JOIN system.one AS A ON A.dummy = system.one.dummy; - * - * If alias is specified for left table, and alias is not specified for right table and identifier was resolved - * without using left table alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one AS A JOIN system.one ON A.dummy = system.one.dummy; - * - * Otherwise we prefer column from left table. - */ - bool column_resolved_using_right_alias = identifier_path_part == right_column_source_alias; - bool column_resolved_without_using_left_alias = !left_column_source_alias.empty() - && right_column_source_alias.empty() - && identifier_path_part != left_column_source_alias; - if (column_resolved_using_right_alias || column_resolved_without_using_left_alias) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else if (scope.joins_count == 1 && scope.context->getSettingsRef().single_join_prefer_left_table) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - else - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier '{}'. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - else if (left_resolved_identifier) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(left_resolved_identifier); - } - else - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*left_resolved_column.getColumnType())) - { - auto left_resolved_column_clone = std::static_pointer_cast(left_resolved_column.clone()); - left_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(left_resolved_column_clone); - - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - else if (right_resolved_identifier) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(right_resolved_identifier); - } - else - { - auto & right_resolved_column = right_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(right_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*right_resolved_column.getColumnType())) - { - auto right_resolved_column_clone = std::static_pointer_cast(right_resolved_column.clone()); - right_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(right_resolved_column_clone); - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - - if (join_node_in_resolve_process || !resolved_identifier) - return resolved_identifier; - - if (scope.join_use_nulls) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier); - auto nullable_resolved_identifier = convertJoinedColumnTypeToNullIfNeeded(resolved_identifier, join_kind, resolved_side, scope); - if (nullable_resolved_identifier) - { - resolved_identifier = nullable_resolved_identifier; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(resolved_identifier, projection_name_it->second); - } - } - } - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope) -{ - const auto * resolved_function = resolved_expression->as(); - if (!resolved_function || resolved_function->getFunctionName() != "getSubcolumn") - return {}; - - const auto * array_join_parent_column = array_join_column_inner_expression.get(); - - /** If both resolved and array-joined expressions are subcolumns, try to match them: - * For example, in `SELECT t.map.values FROM (SELECT * FROM tbl) ARRAY JOIN t.map` - * Identifier `t.map.values` is resolved into `getSubcolumn(t, 'map.values')` and t.map is resolved into `getSubcolumn(t, 'map')` - * Since we need to perform array join on `getSubcolumn(t, 'map')`, `t.map.values` should become `getSubcolumn(getSubcolumn(t, 'map'), 'values')` - * - * Note: It doesn't work when subcolumn in ARRAY JOIN is transformed by another expression, for example - * SELECT c.map, c.map.values FROM (SELECT * FROM tbl) ARRAY JOIN mapApply(x -> x, t.map); - */ - String array_join_subcolumn_prefix; - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "getSubcolumn") - { - const auto & argument_nodes = array_join_column_inner_expression_function->getArguments().getNodes(); - if (argument_nodes.size() == 2 && argument_nodes.at(1)->getNodeType() == QueryTreeNodeType::CONSTANT) - { - const auto & constant_node = argument_nodes.at(1)->as(); - const auto & constant_node_value = constant_node.getValue(); - if (constant_node_value.getType() == Field::Types::String) - { - array_join_subcolumn_prefix = constant_node_value.get() + "."; - array_join_parent_column = argument_nodes.at(0).get(); - } - } - } - - const auto & argument_nodes = resolved_function->getArguments().getNodes(); - if (argument_nodes.size() != 2 && !array_join_parent_column->isEqual(*argument_nodes.at(0))) - return {}; - - const auto * second_argument = argument_nodes.at(1)->as(); - if (!second_argument || second_argument->getValue().getType() != Field::Types::String) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected constant string as second argument of getSubcolumn function {}", resolved_function->dumpTree()); - - const auto & resolved_subcolumn_path = second_argument->getValue().get(); - if (!startsWith(resolved_subcolumn_path, array_join_subcolumn_prefix)) - return {}; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(array_join_column_expression_typed.getColumn(), array_join_column_expression_typed.getColumnSource())); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(resolved_subcolumn_path.substr(array_join_subcolumn_prefix.size()))); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - return function_query_node; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & array_join_node = table_expression_node->as(); - const auto & array_join_column_expressions_list = array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions_list.getNodes(); - - QueryTreeNodePtr array_join_resolved_expression; - - /** Special case when qualified or unqualified identifier point to array join expression without alias. - * - * CREATE TABLE test_table (id UInt64, value String, value_array Array(UInt8)) ENGINE=TinyLog; - * SELECT id, value, value_array, test_table.value_array, default.test_table.value_array FROM test_table ARRAY JOIN value_array; - * - * value_array, test_table.value_array, default.test_table.value_array must be resolved into array join expression. - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - if (array_join_column_expression_typed.hasAlias()) - continue; - - auto & array_join_column_inner_expression = array_join_column_expression_typed.getExpressionOrThrow(); - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "nested" && - array_join_column_inner_expression_function->getArguments().getNodes().size() > 1 && - isTuple(array_join_column_expression_typed.getResultType())) - { - const auto & nested_function_arguments = array_join_column_inner_expression_function->getArguments().getNodes(); - size_t nested_function_arguments_size = nested_function_arguments.size(); - - const auto & nested_keys_names_constant_node = nested_function_arguments[0]->as(); - const auto & nested_keys_names = nested_keys_names_constant_node.getValue().get(); - size_t nested_keys_names_size = nested_keys_names.size(); - - if (nested_keys_names_size == nested_function_arguments_size - 1) - { - for (size_t i = 1; i < nested_function_arguments_size; ++i) - { - if (!nested_function_arguments[i]->isEqual(*resolved_expression)) - continue; - - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - - const auto & nested_key_name = nested_keys_names[i - 1].get(); - Identifier nested_identifier = Identifier(nested_key_name); - auto tuple_element_function = wrapExpressionNodeInTupleElement(array_join_column, nested_identifier); - resolveFunction(tuple_element_function, scope); - - array_join_resolved_expression = std::move(tuple_element_function); - break; - } - } - } - - if (array_join_resolved_expression) - break; - - if (array_join_column_inner_expression->isEqual(*resolved_expression)) - { - array_join_resolved_expression = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - break; - } - - /// When we select subcolumn of array joined column it also should be array joined - array_join_resolved_expression = matchArrayJoinSubcolumns(array_join_column_inner_expression, array_join_column_expression_typed, resolved_expression, scope); - if (array_join_resolved_expression) - break; - } - return array_join_resolved_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_array_join_node = table_expression_node->as(); - auto resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_array_join_node.getTableExpression(), scope); - - if (scope.table_expressions_in_resolve_process.contains(table_expression_node.get()) || !identifier_lookup.isExpressionLookup()) - return resolved_identifier; - - const auto & array_join_column_expressions = from_array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions.getNodes(); - - /** Allow JOIN with USING with ARRAY JOIN. - * - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN [1,2,3] AS id INNER JOIN test_table_2 AS t2 USING (id); - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN t1.id AS id INNER JOIN test_table_2 AS t2 USING (id); - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - - IdentifierView identifier_view(identifier_lookup.identifier); - - if (identifier_view.isCompound() && from_array_join_node.hasAlias() && identifier_view.front() == from_array_join_node.getAlias()) - identifier_view.popFirst(); - - const auto & alias_or_name = array_join_column_expression_typed.hasAlias() - ? array_join_column_expression_typed.getAlias() - : array_join_column_expression_typed.getColumnName(); - - if (identifier_view.front() == alias_or_name) - identifier_view.popFirst(); - else if (identifier_view.getFullName() == alias_or_name) - identifier_view.popFirst(identifier_view.getPartsSize()); /// Clear - else - continue; - - if (identifier_view.empty()) - { - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - return array_join_column; - } - - auto compound_expr = tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - identifier_lookup.identifier.getPartsSize() - identifier_view.getPartsSize() /*identifier_bind_size*/, - array_join_column_expression, - {} /* compound_expression_source */, - scope, - true /* can_be_not_found */); - - if (compound_expr) - return compound_expr; - } - - if (!resolved_identifier) - return nullptr; - - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(resolved_identifier, table_expression_node, scope); - if (array_join_resolved_expression) - resolved_identifier = std::move(array_join_resolved_expression); - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope) -{ - auto join_tree_node_type = join_tree_node->getNodeType(); - - switch (join_tree_node_type) - { - case QueryTreeNodeType::JOIN: - return tryResolveIdentifierFromJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::ARRAY_JOIN: - return tryResolveIdentifierFromArrayJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - [[fallthrough]]; - case QueryTreeNodeType::TABLE: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - { - /** Edge case scenario when subquery in FROM node try to resolve identifier from parent scopes, when FROM is not resolved. - * SELECT subquery.b AS value FROM (SELECT value, 1 AS b) AS subquery; - * TODO: This can be supported - */ - if (scope.table_expressions_in_resolve_process.contains(join_tree_node.get())) - return {}; - - return tryResolveIdentifierFromTableExpression(identifier_lookup, join_tree_node, scope); - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Scope FROM section expected table, table function, query, union, join or array join. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } -} - -/** Resolve identifier from scope join tree. - * - * 1. If identifier is in function lookup context return nullptr. - * 2. Try to resolve identifier from table columns. - * 3. If there is no FROM section return nullptr. - * 4. If identifier is in table lookup context, check if it has 1 or 2 parts, otherwise throw exception. - * If identifier has 2 parts try to match it with database_name and table_name. - * If identifier has 1 part try to match it with table_name, then try to match it with table alias. - * 5. If identifier is in expression lookup context, we first need to bind identifier to some table column using identifier first part. - * Start with identifier first part, if it match some column name in table try to get column with full identifier name. - * TODO: Need to check if it is okay to throw exception if compound identifier first part bind to column but column is not valid. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope) -{ - if (identifier_lookup.isFunctionLookup()) - return {}; - - /// Try to resolve identifier from table columns - if (auto resolved_identifier = tryResolveIdentifierFromTableColumns(identifier_lookup, scope)) - return resolved_identifier; - - if (scope.expression_join_tree_node) - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, scope.expression_join_tree_node, scope); - - auto * query_scope_node = scope.scope_node->as(); - if (!query_scope_node || !query_scope_node->getJoinTree()) - return {}; - - const auto & join_tree_node = query_scope_node->getJoinTree(); - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_tree_node, scope); -} - -/** Try resolve identifier in current scope parent scopes. - * - * TODO: If column is matched, throw exception that nested subqueries are not supported. - * - * If initial scope is expression. Then try to resolve identifier in parent scopes until query scope is hit. - * For query scope resolve strategy is same as if initial scope if query. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - bool initial_scope_is_query = scope.scope_node->getNodeType() == QueryTreeNodeType::QUERY; - bool initial_scope_is_expression = !initial_scope_is_query; - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_parent_scopes = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - IdentifierResolveScope * scope_to_check = scope.parent_scope; - - if (initial_scope_is_expression) - { - while (scope_to_check != nullptr) - { - auto resolve_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - if (resolve_result.resolved_identifier) - return resolve_result; - - bool scope_was_query = scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY; - scope_to_check = scope_to_check->parent_scope; - - if (scope_was_query) - break; - } - } - - if (!scope.context->getSettingsRef().enable_global_with_statement) - return {}; - - /** Nested subqueries cannot access outer subqueries table expressions from JOIN tree because - * that can prevent resolution of table expression from CTE. - * - * Example: WITH a AS (SELECT number FROM numbers(1)), b AS (SELECT number FROM a) SELECT * FROM a as l, b as r; - */ - if (identifier_lookup.isTableExpressionLookup()) - identifier_resolve_settings.allow_to_check_join_tree = false; - - while (scope_to_check != nullptr) - { - auto lookup_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - const auto & resolved_identifier = lookup_result.resolved_identifier; - - scope_to_check = scope_to_check->parent_scope; - - if (resolved_identifier) - { - auto * subquery_node = resolved_identifier->as(); - auto * union_node = resolved_identifier->as(); - - bool is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - bool is_table_from_expression_arguments = lookup_result.resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS && - resolved_identifier->getNodeType() == QueryTreeNodeType::TABLE; - bool is_valid_table_expression = is_cte || is_table_from_expression_arguments; - - /** From parent scopes we can resolve table identifiers only as CTE. - * Example: SELECT (SELECT 1 FROM a) FROM test_table AS a; - * - * During child scope table identifier resolve a, table node test_table with alias a from parent scope - * is invalid. - */ - if (identifier_lookup.isTableExpressionLookup() && !is_valid_table_expression) - continue; - - if (is_valid_table_expression || resolved_identifier->as()) - { - return lookup_result; - } - else if (auto * resolved_function = resolved_identifier->as()) - { - /// Special case: scalar subquery was executed and replaced by __getScalar function. - /// Handle it as a constant. - if (resolved_function->getFunctionName() == "__getScalar") - return lookup_result; - } - - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Resolve identifier '{}' from parent scope only supported for constants and CTE. Actual {} node type {}. In scope {}", - identifier_lookup.identifier.getFullName(), - resolved_identifier->formatASTForErrorMessage(), - resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - return {}; -} - -/** Resolve identifier in scope. - * - * If identifier was resolved resolve identified lookup status will be updated. - * - * Steps: - * 1. Register identifier lookup in scope identifier lookup to resolve status table. - * If entry is already registered and is not resolved, that means that we have cyclic aliases for identifier. - * Example: SELECT a AS b, b AS a; - * Try resolve identifier in current scope: - * 3. Try resolve identifier from expression arguments. - * - * If prefer_column_name_to_alias = true. - * 4. Try to resolve identifier from join tree. - * 5. Try to resolve identifier from aliases. - * Otherwise. - * 4. Try to resolve identifier from aliases. - * 5. Try to resolve identifier from join tree. - * - * 6. If it is table identifier lookup try to lookup identifier in current scope CTEs. - * - * 7. If identifier is not resolved in current scope, try to resolve it in parent scopes. - * 8. If identifier is not resolved from parent scopes and it is table identifier lookup try to lookup identifier - * in database catalog. - * - * Same is not done for functions because function resolution is more complex, and in case of aggregate functions requires not only name - * but also argument types, it is responsibility of resolve function method to handle resolution of function name. - * - * 9. If identifier was not resolved, or identifier caching was disabled remove it from identifier lookup to resolve status table. - * - * It is okay for identifier to be not resolved, in case we want first try to lookup identifier in one context, - * then if there is no identifier in this context, try to lookup in another context. - * Example: Try to lookup identifier as expression, if it is not found, lookup as function. - * Example: Try to lookup identifier as expression, if it is not found, lookup as table. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - auto it = scope.identifier_lookup_to_resolve_state.find(identifier_lookup); - if (it != scope.identifier_lookup_to_resolve_state.end()) - { - if (it->second.cyclic_identifier_resolve) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (!it->second.resolve_result.isResolved()) - it->second.cyclic_identifier_resolve = true; - - if (it->second.resolve_result.isResolved() && - scope.use_identifier_lookup_to_result_cache && - !scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) && - (!it->second.resolve_result.isResolvedFromCTEs() || !ctes_in_resolve_process.contains(identifier_lookup.identifier.getFullName()))) - return it->second.resolve_result; - } - else - { - auto [insert_it, _] = scope.identifier_lookup_to_resolve_state.insert({identifier_lookup, IdentifierResolveState()}); - it = insert_it; - } - - /// Resolve identifier from current scope - - IdentifierResolveResult resolve_result; - resolve_result.resolved_identifier = tryResolveIdentifierFromExpressionArguments(identifier_lookup, scope); - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - - if (!resolve_result.resolved_identifier) - { - bool prefer_column_name_to_alias = scope.context->getSettingsRef().prefer_column_name_to_alias; - - if (identifier_lookup.isExpressionLookup()) - { - /* For aliases from ARRAY JOIN we prefer column from join tree: - * SELECT id FROM ( SELECT ... ) AS subquery ARRAY JOIN [0] AS id INNER JOIN second_table USING (id) - * In the example, identifier `id` should be resolved into one from USING (id) column. - */ - - auto * alias_it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FULL_NAME); - if (alias_it && (*alias_it)->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_node = (*alias_it)->as(); - if (column_node.getColumnSource()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - prefer_column_name_to_alias = true; - } - } - - if (unlikely(prefer_column_name_to_alias)) - { - if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - - if (!resolve_result.resolved_identifier) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - } - else - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - { - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - else if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - } - } - - if (!resolve_result.resolved_identifier && identifier_lookup.isTableExpressionLookup()) - { - auto full_name = identifier_lookup.identifier.getFullName(); - auto cte_query_node_it = scope.cte_name_to_query_node.find(full_name); - - /// CTE may reference table expressions with the same name, e.g.: - /// - /// WITH test1 AS (SELECT * FROM test1) SELECT * FROM test1; - /// - /// Since we don't support recursive CTEs, `test1` identifier inside of CTE - /// references to table .test1. - /// This means that the example above is equivalent to the following query: - /// - /// SELECT * FROM test1; - /// - /// To accomplish this behaviour it's not allowed to resolve identifiers to - /// CTE that is being resolved. - if (cte_query_node_it != scope.cte_name_to_query_node.end() - && !ctes_in_resolve_process.contains(full_name)) - { - resolve_result.resolved_identifier = cte_query_node_it->second; - resolve_result.resolve_place = IdentifierResolvePlace::CTE; - } - } - - /// Try to resolve identifier from parent scopes - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_parent_scopes) - { - resolve_result = tryResolveIdentifierInParentScopes(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolved_from_parent_scopes = true; - } - - /// Try to resolve table identifier from database catalog - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_database_catalog && identifier_lookup.isTableExpressionLookup()) - { - resolve_result.resolved_identifier = tryResolveTableIdentifierFromDatabaseCatalog(identifier_lookup.identifier, scope.context); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::DATABASE_CATALOG; - } - - bool was_cyclic_identifier_resolve = it->second.cyclic_identifier_resolve; - if (!was_cyclic_identifier_resolve) - it->second.resolve_result = resolve_result; - it->second.cyclic_identifier_resolve = false; - - /** If identifier was not resolved, or during expression resolution identifier was explicitly added into non cached set, - * or identifier caching was disabled in resolve scope we remove identifier lookup result from identifier lookup to result table. - */ - if (!was_cyclic_identifier_resolve && (!resolve_result.resolved_identifier || - scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) || - !scope.use_identifier_lookup_to_result_cache)) - scope.identifier_lookup_to_resolve_state.erase(it); - - return resolve_result; -} - -/// Resolve query tree nodes functions implementation - -/** Qualify column nodes with projection names. - * - * Example: SELECT * FROM test_table AS t1, test_table AS t2; - */ -void QueryAnalyzer::qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - /// Build additional column qualification parts array - std::vector additional_column_qualification_parts; - - if (table_expression_node->hasAlias()) - additional_column_qualification_parts = {table_expression_node->getAlias()}; - else if (auto * table_node = table_expression_node->as()) - additional_column_qualification_parts = {table_node->getStorageID().getDatabaseName(), table_node->getStorageID().getTableName()}; - - size_t additional_column_qualification_parts_size = additional_column_qualification_parts.size(); - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - /** For each matched column node iterate over additional column qualifications and apply them if column needs to be qualified. - * To check if column needs to be qualified we check if column name can bind to any other table expression in scope or to scope aliases. - */ - std::vector column_qualified_identifier_parts; - - for (const auto & column_node : column_nodes) - { - const auto & column_name = column_node->as().getColumnName(); - column_qualified_identifier_parts = Identifier(column_name).getParts(); - - /// Iterate over additional column qualifications and apply them if needed - for (size_t i = 0; i < additional_column_qualification_parts_size; ++i) - { - auto identifier_to_check = Identifier(column_qualified_identifier_parts); - IdentifierLookup identifier_lookup{identifier_to_check, IdentifierLookupContext::EXPRESSION}; - bool need_to_qualify = table_expression_data.should_qualify_columns; - if (need_to_qualify) - need_to_qualify = tryBindIdentifierToTableExpressions(identifier_lookup, table_expression_node, scope); - - if (tryBindIdentifierToAliases(identifier_lookup, scope)) - need_to_qualify = true; - - if (need_to_qualify) - { - /** Add last qualification part that was not used into column qualified identifier. - * If additional column qualification parts consists from [database_name, table_name]. - * On first iteration if column is needed to be qualified to qualify it with table_name. - * On second iteration if column is needed to be qualified to qualify it with database_name. - */ - size_t part_index_to_use_for_qualification = additional_column_qualification_parts_size - i - 1; - const auto & part_to_use = additional_column_qualification_parts[part_index_to_use_for_qualification]; - column_qualified_identifier_parts.insert(column_qualified_identifier_parts.begin(), part_to_use); - } - else - { - break; - } - } - - auto qualified_node_name = Identifier(column_qualified_identifier_parts).getFullName(); - node_to_projection_name.emplace(column_node, qualified_node_name); - } -} - -/// Build get columns options for matcher -GetColumnsOptions QueryAnalyzer::buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context) -{ - auto & matcher_node_typed = matcher_node->as(); - UInt8 get_columns_options_kind = GetColumnsOptions::AllPhysicalAndAliases; - - if (matcher_node_typed.isAsteriskMatcher()) - { - get_columns_options_kind = GetColumnsOptions::Ordinary; - - const auto & settings = context->getSettingsRef(); - - if (settings.asterisk_include_alias_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Aliases; - - if (settings.asterisk_include_materialized_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Materialized; - } - - return GetColumnsOptions(static_cast(get_columns_options_kind)); -} - -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - /** Use resolved columns from table expression data in nearest query scope if available. - * It is important for ALIAS columns to use column nodes with resolved ALIAS expression. - */ - const TableExpressionData * table_expression_data = nullptr; - const auto * nearest_query_scope = scope.getNearestQueryScope(); - if (nearest_query_scope) - table_expression_data = &nearest_query_scope->getTableExpressionDataOrThrow(table_expression_node); - - QueryTreeNodes matched_column_nodes; - - for (const auto & column : matched_columns) - { - const auto & column_name = column.name; - if (!matcher_node_typed.isMatchingColumn(column_name)) - continue; - - if (table_expression_data) - { - auto column_node_it = table_expression_data->column_name_to_column_node.find(column_name); - if (column_node_it != table_expression_data->column_name_to_column_node.end()) - { - matched_column_nodes.emplace_back(column_node_it->second); - continue; - } - } - - matched_column_nodes.emplace_back(std::make_shared(column, table_expression_node)); - } - - const auto & qualify_matched_column_nodes_scope = nearest_query_scope ? *nearest_query_scope : scope; - qualifyColumnNodesWithProjectionNames(matched_column_nodes, table_expression_node, qualify_matched_column_nodes_scope); - - QueryAnalyzer::QueryTreeNodesWithNames matched_column_nodes_with_names; - matched_column_nodes_with_names.reserve(matched_column_nodes.size()); - - for (auto && matched_column_node : matched_column_nodes) - { - auto column_name = matched_column_node->as().getColumnName(); - matched_column_nodes_with_names.emplace_back(std::move(matched_column_node), std::move(column_name)); - } - - return matched_column_nodes_with_names; -} - -bool hasTableExpressionInJoinTree(const QueryTreeNodePtr & join_tree_node, const QueryTreeNodePtr & table_expression) -{ - QueryTreeNodes nodes_to_process; - nodes_to_process.push_back(join_tree_node); - - while (!nodes_to_process.empty()) - { - auto node_to_process = std::move(nodes_to_process.back()); - nodes_to_process.pop_back(); - if (node_to_process == table_expression) - return true; - - if (node_to_process->getNodeType() == QueryTreeNodeType::JOIN) - { - const auto & join_node = node_to_process->as(); - nodes_to_process.push_back(join_node.getLeftTableExpression()); - nodes_to_process.push_back(join_node.getRightTableExpression()); - } - } - return false; -} - -/// Columns that resolved from matcher can also match columns from JOIN USING. -/// In that case we update type to type of column in USING section. -/// TODO: It's not completely correct for qualified matchers, so t1.* should be resolved to left table column type. -/// But in planner we do not distinguish such cases. -void QueryAnalyzer::updateMatchedColumnsFromJoinUsing( - QueryTreeNodesWithNames & result_matched_column_nodes_with_names, - const QueryTreeNodePtr & source_table_expression, - IdentifierResolveScope & scope) -{ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "There are no table sources. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - const auto & join_tree = nearest_query_scope_query_node->getJoinTree(); - - const auto * join_node = join_tree->as(); - if (join_node && join_node->isUsingJoinExpression()) - { - const auto & join_using_list = join_node->getJoinExpression()->as(); - const auto & join_using_nodes = join_using_list.getNodes(); - - for (auto & [matched_column_node, _] : result_matched_column_nodes_with_names) - { - auto & matched_column_node_typed = matched_column_node->as(); - const auto & matched_column_name = matched_column_node_typed.getColumnName(); - - for (const auto & join_using_node : join_using_nodes) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (matched_column_name != join_using_column_name) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - auto it = node_to_projection_name.find(matched_column_node); - - if (hasTableExpressionInJoinTree(join_node->getLeftTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(0); - else if (hasTableExpressionInJoinTree(join_node->getRightTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(1); - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Cannot find column {} in JOIN USING section {}", - matched_column_node->dumpTree(), join_node->dumpTree()); - - matched_column_node = matched_column_node->clone(); - if (it != node_to_projection_name.end()) - node_to_projection_name.emplace(matched_column_node, it->second); - - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - } - } - } -} - -/** Resolve qualified tree matcher. - * - * First try to match qualified identifier to expression. If qualified identifier matched expression node then - * if expression is compound match it column names using matcher `isMatchingColumn` method, if expression is not compound, throw exception. - * If qualified identifier did not match expression in query tree, try to lookup qualified identifier in table context. - */ -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isQualified()); - - auto expression_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::EXPRESSION}; - auto expression_identifier_resolve_result = tryResolveIdentifier(expression_identifier_lookup, scope); - auto expression_query_tree_node = expression_identifier_resolve_result.resolved_identifier; - - /// Try to resolve unqualified matcher for query expression - - if (expression_query_tree_node) - { - auto result_type = expression_query_tree_node->getResultType(); - - while (true) - { - if (const auto * array_type = typeid_cast(result_type.get())) - result_type = array_type->getNestedType(); - else if (const auto * map_type = typeid_cast(result_type.get())) - result_type = map_type->getNestedType(); - else - break; - } - - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Qualified matcher {} find non compound expression {} with type {}. Expected tuple or array of tuples. In scope {}", - matcher_node->formatASTForErrorMessage(), - expression_query_tree_node->formatASTForErrorMessage(), - expression_query_tree_node->getResultType()->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - auto qualified_matcher_element_identifier = matcher_node_typed.getQualifiedIdentifier(); - for (const auto & element_name : element_names) - { - if (!matcher_node_typed.isMatchingColumn(element_name)) - continue; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back(expression_query_tree_node); - get_subcolumn_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - qualified_matcher_element_identifier.push_back(element_name); - node_to_projection_name.emplace(function_query_node, qualified_matcher_element_identifier.getFullName()); - qualified_matcher_element_identifier.pop_back(); - - matched_expression_nodes_with_column_names.emplace_back(std::move(function_query_node), element_name); - } - - return matched_expression_nodes_with_column_names; - } - - /// Try to resolve qualified matcher for table expression - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_cte = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - auto table_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, identifier_resolve_settings); - auto table_expression_node = table_identifier_resolve_result.resolved_identifier; - - if (!table_expression_node) - { - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Qualified matcher {} does not find table. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - NamesAndTypes matched_columns; - - auto * table_expression_query_node = table_expression_node->as(); - auto * table_expression_union_node = table_expression_node->as(); - auto * table_expression_table_node = table_expression_node->as(); - auto * table_expression_table_function_node = table_expression_node->as(); - - if (table_expression_query_node || table_expression_union_node) - { - matched_columns = table_expression_query_node ? table_expression_query_node->getProjectionColumns() - : table_expression_union_node->computeProjectionColumns(); - } - else if (table_expression_table_node || table_expression_table_function_node) - { - const auto & storage_snapshot = table_expression_table_node ? table_expression_table_node->getStorageSnapshot() - : table_expression_table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - matched_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Invalid table expression node {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto result_matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression_node, - matched_columns, - scope); - - updateMatchedColumnsFromJoinUsing(result_matched_column_nodes_with_names, table_expression_node, scope); - - return result_matched_column_nodes_with_names; -} - -/// Resolve non qualified matcher, using scope join tree node. -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isUnqualified()); - - /** There can be edge case if matcher is inside lambda expression. - * Try to find parent query expression using parent scopes. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unqualified matcher {} cannot be resolved. There are no table sources. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** For unqualifited matcher resolve we build table expressions stack from JOIN tree and then process it. - * For table, table function, query, union table expressions add matched columns into table expressions columns stack. - * For array join continue processing. - * For join node combine last left and right table expressions columns on stack together. It is important that if JOIN has USING - * we must add USING columns before combining left and right table expressions columns. Columns from left and right table - * expressions that have same names as columns in USING clause must be skipped. - */ - - auto table_expressions_stack = buildTableExpressionsStack(nearest_query_scope_query_node->getJoinTree()); - std::vector table_expressions_column_nodes_with_names_stack; - - std::unordered_set table_expression_column_names_to_skip; - - QueryTreeNodesWithNames result; - - if (matcher_node_typed.getMatcherType() == MatcherNodeType::COLUMNS_LIST) - { - auto identifiers = matcher_node_typed.getColumnsIdentifiers(); - result.reserve(identifiers.size()); - - for (const auto & identifier : identifiers) - { - auto resolve_result = tryResolveIdentifier(IdentifierLookup{identifier, IdentifierLookupContext::EXPRESSION}, scope); - if (!resolve_result.isResolved()) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Unknown identifier '{}' inside COLUMNS matcher. In scope {}", - identifier.getFullName(), scope.dump()); - - // TODO: Introduce IdentifierLookupContext::COLUMN and get rid of this check - auto * resolved_column = resolve_result.resolved_identifier->as(); - if (!resolved_column) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier '{}' inside COLUMNS matcher must resolve into a column, but got {}. In scope {}", - identifier.getFullName(), - resolve_result.resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - result.emplace_back(resolve_result.resolved_identifier, resolved_column->getColumnName()); - } - return result; - } - - result.resize(matcher_node_typed.getColumnsIdentifiers().size()); - - for (auto & table_expression : table_expressions_stack) - { - bool table_expression_in_resolve_process = nearest_query_scope->table_expressions_in_resolve_process.contains(table_expression.get()); - - if (auto * array_join_node = table_expression->as()) - { - if (table_expressions_column_nodes_with_names_stack.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 1 table expressions on stack before ARRAY JOIN processing"); - - if (table_expression_in_resolve_process) - continue; - - auto & table_expression_column_nodes_with_names = table_expressions_column_nodes_with_names_stack.back(); - - for (auto & [table_expression_column_node, _] : table_expression_column_nodes_with_names) - { - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(table_expression_column_node, - table_expression, - scope); - if (array_join_resolved_expression) - table_expression_column_node = std::move(array_join_resolved_expression); - } - - continue; - } - - auto * join_node = table_expression->as(); - - if (join_node) - { - size_t table_expressions_column_nodes_with_names_stack_size = table_expressions_column_nodes_with_names_stack.size(); - if (table_expressions_column_nodes_with_names_stack_size < 2) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 2 table expressions on stack before JOIN processing. Actual {}", - table_expressions_column_nodes_with_names_stack_size); - - auto right_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - auto left_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - table_expression_column_names_to_skip.clear(); - - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - /** If there is JOIN with USING we need to match only single USING column and do not use left table expression - * and right table expression column with same name. - * - * Example: SELECT id FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING (id); - */ - if (!table_expression_in_resolve_process && join_node->isUsingJoinExpression()) - { - auto & join_using_list = join_node->getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (!matcher_node_typed.isMatchingColumn(join_using_column_name)) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - /** If column doesn't exists in the table, then do not match column from USING clause. - * Example: SELECT a + 1 AS id, * FROM (SELECT 1 AS a) AS t1 JOIN (SELECT 2 AS id) AS t2 USING (id); - * In this case `id` is not present in the left table expression, - * so asterisk should return `id` from the right table expression. - */ - auto is_column_from_parent_scope = [&scope](const QueryTreeNodePtr & using_node_from_table) - { - const auto & using_column_from_table = using_node_from_table->as(); - auto table_expression_data_it = scope.table_expression_node_to_data.find(using_column_from_table.getColumnSource()); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - { - const auto & table_expression_data = table_expression_data_it->second; - const auto & column_name = using_column_from_table.getColumnName(); - return !table_expression_data.column_name_to_column_node.contains(column_name); - } - return false; - }; - - if (is_column_from_parent_scope(join_using_column_nodes.at(0)) || - is_column_from_parent_scope(join_using_column_nodes.at(1))) - continue; - - QueryTreeNodePtr matched_column_node; - - if (isRight(join_node->getKind())) - matched_column_node = join_using_column_nodes.at(1); - else - matched_column_node = join_using_column_nodes.at(0); - - matched_column_node = matched_column_node->clone(); - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - - table_expression_column_names_to_skip.insert(join_using_column_name); - matched_expression_nodes_with_column_names.emplace_back(std::move(matched_column_node), join_using_column_name); - } - } - - for (auto && left_table_column_with_name : left_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(left_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(left_table_column_with_name)); - } - - for (auto && right_table_column_with_name : right_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(right_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(right_table_column_with_name)); - } - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_expression_nodes_with_column_names)); - continue; - } - - if (table_expression_in_resolve_process) - { - table_expressions_column_nodes_with_names_stack.emplace_back(); - continue; - } - - auto * table_node = table_expression->as(); - auto * table_function_node = table_expression->as(); - auto * query_node = table_expression->as(); - auto * union_node = table_expression->as(); - - NamesAndTypes table_expression_columns; - - if (query_node || union_node) - { - table_expression_columns = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - } - else if (table_node || table_function_node) - { - const auto & storage_snapshot - = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - table_expression_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unqualified matcher {} resolve unexpected table expression. In scope {}", - matcher_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression, - table_expression_columns, - scope); - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_column_nodes_with_names)); - } - - for (auto & table_expression_column_nodes_with_names : table_expressions_column_nodes_with_names_stack) - { - for (auto && table_expression_column_node_with_name : table_expression_column_nodes_with_names) - result.push_back(std::move(table_expression_column_node_with_name)); - } - - return result; -} - - -/** Resolve query tree matcher. Check MatcherNode.h for detailed matcher description. Check ColumnTransformers.h for detailed transformers description. - * - * 1. Populate matched expression nodes resolving qualified or unqualified matcher. - * 2. Apply column transformers to matched expression nodes. For strict column transformers save used column names. - * 3. Validate strict column transformers. - */ -ProjectionNames QueryAnalyzer::resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - QueryTreeNodesWithNames matched_expression_nodes_with_names; - - if (matcher_node_typed.isQualified()) - matched_expression_nodes_with_names = resolveQualifiedMatcher(matcher_node, scope); - else - matched_expression_nodes_with_names = resolveUnqualifiedMatcher(matcher_node, scope); - - if (scope.join_use_nulls) - { - /** If we are resolving matcher came from the result of JOIN and `join_use_nulls` is set, - * we need to convert joined column type to Nullable. - * We are taking the nearest JoinNode to check to which table column belongs, - * because for LEFT/RIGHT join, we convert only the corresponding side. - */ - const auto * nearest_query_scope = scope.getNearestQueryScope(); - const QueryNode * nearest_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - const QueryTreeNodePtr & nearest_scope_join_tree = nearest_scope_query_node ? nearest_scope_query_node->getJoinTree() : nullptr; - const JoinNode * nearest_scope_join_node = nearest_scope_join_tree ? nearest_scope_join_tree->as() : nullptr; - if (nearest_scope_join_node) - { - for (auto & [node, node_name] : matched_expression_nodes_with_names) - { - auto join_identifier_side = getColumnSideFromJoinTree(node, *nearest_scope_join_node); - auto projection_name_it = node_to_projection_name.find(node); - auto nullable_node = convertJoinedColumnTypeToNullIfNeeded(node, nearest_scope_join_node->getKind(), join_identifier_side, scope); - if (nullable_node) - { - node = nullable_node; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(node, projection_name_it->second); - } - } - } - } - } - - if (!scope.expressions_in_resolve_process_stack.hasAggregateFunction()) - { - for (auto & [node, _] : matched_expression_nodes_with_names) - { - auto it = scope.nullable_group_by_keys.find(node); - if (it != scope.nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - } - } - } - - std::unordered_map> strict_transformer_to_used_column_names; - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - auto * except_transformer = transformer->as(); - auto * replace_transformer = transformer->as(); - - if (except_transformer && except_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(except_transformer, std::unordered_set()); - else if (replace_transformer && replace_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(replace_transformer, std::unordered_set()); - } - - ListNodePtr list = std::make_shared(); - ProjectionNames result_projection_names; - ProjectionNames node_projection_names; - - for (auto & [node, column_name] : matched_expression_nodes_with_names) - { - bool apply_transformer_was_used = false; - bool replace_transformer_was_used = false; - bool execute_apply_transformer = false; - bool execute_replace_transformer = false; - - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - else - result_projection_names.push_back(column_name); - - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - if (auto * apply_transformer = transformer->as()) - { - const auto & expression_node = apply_transformer->getExpressionNode(); - apply_transformer_was_used = true; - - if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::LAMBDA) - { - auto lambda_expression_to_resolve = expression_node->clone(); - IdentifierResolveScope lambda_scope(expression_node, &scope /*parent_scope*/); - node_projection_names = resolveLambda(expression_node, lambda_expression_to_resolve, {node}, lambda_scope); - auto & lambda_expression_to_resolve_typed = lambda_expression_to_resolve->as(); - node = lambda_expression_to_resolve_typed.getExpression(); - } - else if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::FUNCTION) - { - auto function_to_resolve_untyped = expression_node->clone(); - auto & function_to_resolve_typed = function_to_resolve_untyped->as(); - function_to_resolve_typed.getArguments().getNodes().push_back(node); - node_projection_names = resolveFunction(function_to_resolve_untyped, scope); - node = function_to_resolve_untyped; - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unsupported apply matcher expression type. Expected lambda or function apply transformer. Actual {}. In scope {}", - transformer->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - execute_apply_transformer = true; - } - else if (auto * except_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - if (except_transformer->isColumnMatching(column_name)) - { - if (except_transformer->isStrict()) - strict_transformer_to_used_column_names[except_transformer].insert(column_name); - - node = {}; - break; - } - } - else if (auto * replace_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - auto replace_expression = replace_transformer->findReplacementExpression(column_name); - if (!replace_expression) - continue; - - replace_transformer_was_used = true; - - if (replace_transformer->isStrict()) - strict_transformer_to_used_column_names[replace_transformer].insert(column_name); - - node = replace_expression->clone(); - node_projection_names = resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** If replace expression resolved as single node, we want to use replace column name as result projection name, instead - * of using replace expression projection name. - * - * Example: SELECT * REPLACE id + 5 AS id FROM test_table; - */ - if (node_projection_names.size() == 1) - node_projection_names[0] = column_name; - - execute_replace_transformer = true; - } - - if (execute_apply_transformer || execute_replace_transformer) - { - if (auto * node_list = node->as()) - { - auto & node_list_nodes = node_list->getNodes(); - size_t node_list_nodes_size = node_list_nodes.size(); - - if (node_list_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "{} transformer {} resolved as list node with size {}. Expected 1. In scope {}", - execute_apply_transformer ? "APPLY" : "REPLACE", - transformer->formatASTForErrorMessage(), - node_list_nodes_size, - scope.scope_node->formatASTForErrorMessage()); - - node = node_list_nodes[0]; - } - - if (node_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Matcher node expected 1 projection name. Actual {}", node_projection_names.size()); - - result_projection_names.back() = std::move(node_projection_names[0]); - node_to_projection_name.emplace(node, result_projection_names.back()); - node_projection_names.clear(); - } - } - - if (node) - list->getNodes().push_back(node); - else - result_projection_names.pop_back(); - } - - for (auto & [strict_transformer, used_column_names] : strict_transformer_to_used_column_names) - { - auto strict_transformer_type = strict_transformer->getTransformerType(); - const Names * strict_transformer_column_names = nullptr; - - switch (strict_transformer_type) - { - case ColumnTransfomerType::EXCEPT: - { - const auto * except_transformer = static_cast(strict_transformer); - const auto & except_names = except_transformer->getExceptColumnNames(); - - if (except_names.size() != used_column_names.size()) - strict_transformer_column_names = &except_transformer->getExceptColumnNames(); - - break; - } - case ColumnTransfomerType::REPLACE: - { - const auto * replace_transformer = static_cast(strict_transformer); - const auto & replacement_names = replace_transformer->getReplacementsNames(); - - if (replacement_names.size() != used_column_names.size()) - strict_transformer_column_names = &replace_transformer->getReplacementsNames(); - - break; - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected strict EXCEPT or REPLACE column transformer. Actual type {}. In scope {}", - toString(strict_transformer_type), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (!strict_transformer_column_names) - continue; - - Names non_matched_column_names; - size_t strict_transformer_column_names_size = strict_transformer_column_names->size(); - for (size_t i = 0; i < strict_transformer_column_names_size; ++i) - { - const auto & column_name = (*strict_transformer_column_names)[i]; - if (used_column_names.find(column_name) == used_column_names.end()) - non_matched_column_names.push_back(column_name); - } - - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Strict {} column transformer {} expects following column(s) : {}. In scope {}", - toString(strict_transformer_type), - strict_transformer->formatASTForErrorMessage(), - fmt::join(non_matched_column_names, ", "), - scope.scope_node->formatASTForErrorMessage()); - } - - auto original_ast = matcher_node->getOriginalAST(); - matcher_node = std::move(list); - if (original_ast) - matcher_node->setOriginalAST(original_ast); - - return result_projection_names; -} - -/** Resolve window function window node. - * - * Node can be identifier or window node. - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - * Example: SELECT count(*) OVER (PARTITION BY id); - * - * If node has parent window name specified, then parent window definition is searched in nearest query scope WINDOW section. - * If node is identifier, than node is replaced with window definition. - * If node is window, that window node is merged with parent window node. - * - * Window node PARTITION BY and ORDER BY parts are resolved. - * If window node has frame begin OFFSET or frame end OFFSET specified, they are resolved, and window node frame constants are updated. - * Window node frame is validated. - */ -ProjectionName QueryAnalyzer::resolveWindow(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - std::string parent_window_name; - auto * identifier_node = node->as(); - - ProjectionName result_projection_name; - QueryTreeNodePtr parent_window_node; - - if (identifier_node) - parent_window_name = identifier_node->getIdentifier().getFullName(); - else if (auto * window_node = node->as()) - parent_window_name = window_node->getParentWindowName(); - - if (!parent_window_name.empty()) - { - auto * nearest_query_scope = scope.getNearestQueryScope(); - - if (!nearest_query_scope) - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Window '{}' does not exist.", parent_window_name); - - auto & scope_window_name_to_window_node = nearest_query_scope->window_name_to_window_node; - - auto window_node_it = scope_window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope_window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - nearest_query_scope->scope_node->formatASTForErrorMessage()); - - parent_window_node = window_node_it->second; - - if (identifier_node) - { - node = parent_window_node->clone(); - result_projection_name = parent_window_name; - } - else - { - mergeWindowWithParentWindow(node, parent_window_node, scope); - } - } - - auto & window_node = node->as(); - window_node.setParentWindowName({}); - - ProjectionNames partition_by_projection_names = resolveExpressionNodeList(window_node.getPartitionByNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - ProjectionNames order_by_projection_names = resolveSortNodeList(window_node.getOrderByNode(), scope); - - ProjectionNames frame_begin_offset_projection_names; - ProjectionNames frame_end_offset_projection_names; - - if (window_node.hasFrameBeginOffset()) - { - frame_begin_offset_projection_names = resolveExpressionNode(window_node.getFrameBeginOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_begin_constant_node = window_node.getFrameBeginOffsetNode()->as(); - if (!window_frame_begin_constant_node || !isNativeNumber(removeNullable(window_frame_begin_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameBeginOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().begin_offset = window_frame_begin_constant_node->getValue(); - if (frame_begin_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_begin_offset_projection_names.size()); - } - - if (window_node.hasFrameEndOffset()) - { - frame_end_offset_projection_names = resolveExpressionNode(window_node.getFrameEndOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_end_constant_node = window_node.getFrameEndOffsetNode()->as(); - if (!window_frame_end_constant_node || !isNativeNumber(removeNullable(window_frame_end_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameEndOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().end_offset = window_frame_end_constant_node->getValue(); - if (frame_end_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_end_offset_projection_names.size()); - } - - window_node.getWindowFrame().checkValid(); - - if (result_projection_name.empty()) - { - result_projection_name = calculateWindowProjectionName(node, - parent_window_node, - parent_window_name, - partition_by_projection_names, - order_by_projection_names, - frame_begin_offset_projection_names.empty() ? "" : frame_begin_offset_projection_names.front(), - frame_end_offset_projection_names.empty() ? "" : frame_end_offset_projection_names.front()); - } - - return result_projection_name; -} - -/** Resolve lambda function. - * This function modified lambda_node during resolve. It is caller responsibility to clone lambda before resolve - * if it is needed for later use. - * - * Lambda body expression result projection names is used as lambda projection names. - * - * Lambda expression can be resolved into list node. It is caller responsibility to handle it properly. - * - * lambda_node - node that must have LambdaNode type. - * lambda_node_to_resolve - lambda node to resolve that must have LambdaNode type. - * arguments - lambda arguments. - * scope - lambda scope. It is client responsibility to create it. - * - * Resolve steps: - * 1. Validate arguments. - * 2. Register lambda node in lambdas in resolve process. This is necessary to prevent recursive lambda resolving. - * 3. Initialize scope with lambda aliases. - * 4. Validate lambda argument names, and scope expressions. - * 5. Resolve lambda body expression. - * 6. Deregister lambda node from lambdas in resolve process. - */ -ProjectionNames QueryAnalyzer::resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope) -{ - auto & lambda_to_resolve = lambda_node_to_resolve->as(); - auto & lambda_arguments_nodes = lambda_to_resolve.getArguments().getNodes(); - size_t lambda_arguments_nodes_size = lambda_arguments_nodes.size(); - - /** Register lambda as being resolved, to prevent recursive lambdas resolution. - * Example: WITH (x -> x + lambda_2(x)) AS lambda_1, (x -> x + lambda_1(x)) AS lambda_2 SELECT 1; - */ - auto it = lambdas_in_resolve_process.find(lambda_node.get()); - if (it != lambdas_in_resolve_process.end()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive lambda {}. In scope {}", - lambda_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - lambdas_in_resolve_process.emplace(lambda_node.get()); - - size_t arguments_size = lambda_arguments.size(); - if (lambda_arguments_nodes_size != arguments_size) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} expect {} arguments. Actual {}. In scope {}", - lambda_to_resolve.formatASTForErrorMessage(), - lambda_arguments_nodes_size, - arguments_size, - scope.scope_node->formatASTForErrorMessage()); - - /// Initialize aliases in lambda scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - visitor.visit(lambda_to_resolve.getExpression()); - - /** Replace lambda arguments with new arguments. - * Additionally validate that there are no aliases with same name as lambda arguments. - * Arguments are registered in current scope expression_argument_name_to_node map. - */ - QueryTreeNodes lambda_new_arguments_nodes; - lambda_new_arguments_nodes.reserve(lambda_arguments_nodes_size); - - for (size_t i = 0; i < lambda_arguments_nodes_size; ++i) - { - auto & lambda_argument_node = lambda_arguments_nodes[i]; - const auto * lambda_argument_identifier = lambda_argument_node->as(); - const auto * lambda_argument_column = lambda_argument_node->as(); - if (!lambda_argument_identifier && !lambda_argument_column) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected IDENTIFIER or COLUMN as lambda argument, got {}", lambda_node->dumpTree()); - const auto & lambda_argument_name = lambda_argument_identifier ? lambda_argument_identifier->getIdentifier().getFullName() - : lambda_argument_column->getColumnName(); - - bool has_expression_node = scope.aliases.alias_name_to_expression_node->contains(lambda_argument_name); - bool has_alias_node = scope.aliases.alias_name_to_lambda_node.contains(lambda_argument_name); - - if (has_expression_node || has_alias_node) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Alias name '{}' inside lambda {} cannot have same name as lambda argument. In scope {}", - lambda_argument_name, - lambda_argument_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - scope.expression_argument_name_to_node.emplace(lambda_argument_name, lambda_arguments[i]); - lambda_new_arguments_nodes.push_back(lambda_arguments[i]); - } - - lambda_to_resolve.getArguments().getNodes() = std::move(lambda_new_arguments_nodes); - - /// Lambda body expression is resolved as standard query expression node. - auto result_projection_names = resolveExpressionNode(lambda_to_resolve.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - lambdas_in_resolve_process.erase(lambda_node.get()); - - return result_projection_names; -} - -namespace -{ -void checkFunctionNodeHasEmptyNullsAction(FunctionNode const & node) -{ - if (node.getNullsAction() != NullsAction::EMPTY) - throw Exception( - ErrorCodes::SYNTAX_ERROR, - "Function with name '{}' cannot use {} NULLS", - node.getFunctionName(), - node.getNullsAction() == NullsAction::IGNORE_NULLS ? "IGNORE" : "RESPECT"); -} -} - -/** Resolve function node in scope. - * During function node resolve, function node can be replaced with another expression (if it match lambda or sql user defined function), - * with constant (if it allow constant folding), or with expression list. It is caller responsibility to handle such cases appropriately. - * - * Steps: - * 1. Resolve function parameters. Validate that each function parameter must be constant node. - * 2. Try to lookup function as lambda in current scope. If it is lambda we can skip `in` and `count` special handling. - * 3. If function is count function, that take unqualified ASTERISK matcher, remove it from its arguments. Example: SELECT count(*) FROM test_table; - * 4. If function is `IN` function, then right part of `IN` function is replaced as subquery. - * 5. Resolve function arguments list, lambda expressions are allowed as function arguments. - * For `IN` function table expressions are allowed as function arguments. - * 6. Initialize argument_columns, argument_types, function_lambda_arguments_indexes arrays from function arguments. - * 7. If function name identifier was not resolved as function in current scope, try to lookup lambda from sql user defined functions factory. - * 8. If function was resolve as lambda from step 2 or 7, then resolve lambda using function arguments and replace function node with lambda result. - * After than function node is resolved. - * 9. If function was not resolved during step 6 as lambda, then try to resolve function as window function or executable user defined function - * or ordinary function or aggregate function. - * - * If function is resolved as window function or executable user defined function or aggregate function, function node is resolved - * no additional special handling is required. - * - * 8. If function was resolved as non aggregate function. Then if some of function arguments are lambda expressions, their result types need to be initialized and - * they must be resolved. - * 9. If function is suitable for constant folding, try to perform constant folding for function node. - */ -ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - FunctionNodePtr function_node_ptr = std::static_pointer_cast(node); - auto function_name = function_node_ptr->getFunctionName(); - - /// Resolve function parameters - - auto parameters_projection_names = resolveExpressionNodeList(function_node_ptr->getParametersNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - /// Convert function parameters into constant parameters array - - Array parameters; - - auto & parameters_nodes = function_node_ptr->getParameters().getNodes(); - parameters.reserve(parameters_nodes.size()); - - for (auto & parameter_node : parameters_nodes) - { - const auto * constant_node = parameter_node->as(); - if (!constant_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parameter for function '{}' expected to have constant value. Actual {}. In scope {}", - function_name, - parameter_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - parameters.push_back(constant_node->getValue()); - } - - //// If function node is not window function try to lookup function node name as lambda identifier. - QueryTreeNodePtr lambda_expression_untyped; - if (!function_node_ptr->isWindowFunction()) - { - auto function_lookup_result = tryResolveIdentifier({Identifier{function_name}, IdentifierLookupContext::FUNCTION}, scope); - lambda_expression_untyped = function_lookup_result.resolved_identifier; - } - - bool is_special_function_in = false; - bool is_special_function_dict_get = false; - bool is_special_function_join_get = false; - bool is_special_function_exists = false; - bool is_special_function_if = false; - - if (!lambda_expression_untyped) - { - is_special_function_in = isNameOfInFunction(function_name); - is_special_function_dict_get = functionIsDictGet(function_name); - is_special_function_join_get = functionIsJoinGet(function_name); - is_special_function_exists = function_name == "exists"; - is_special_function_if = function_name == "if"; - - auto function_name_lowercase = Poco::toLower(function_name); - - /** Special handling for count and countState functions. - * - * Example: SELECT count(*) FROM test_table - * Example: SELECT countState(*) FROM test_table; - */ - if (function_node_ptr->getArguments().getNodes().size() == 1 && - (function_name_lowercase == "count" || function_name_lowercase == "countstate")) - { - auto * matcher_node = function_node_ptr->getArguments().getNodes().front()->as(); - if (matcher_node && matcher_node->isUnqualified()) - function_node_ptr->getArguments().getNodes().clear(); - } - } - - /** Special functions dictGet and its variations and joinGet can be executed when first argument is identifier. - * Example: SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Try to resolve identifier as expression identifier and if it is resolved use it. - * Example: WITH 'dict_name' AS identifier SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Otherwise replace identifier with identifier full name constant. - * Validation that dictionary exists or table exists will be performed during function `getReturnType` method call. - */ - if ((is_special_function_dict_get || is_special_function_join_get) && - !function_node_ptr->getArguments().getNodes().empty() && - function_node_ptr->getArguments().getNodes()[0]->getNodeType() == QueryTreeNodeType::IDENTIFIER) - { - auto & first_argument = function_node_ptr->getArguments().getNodes()[0]; - auto & first_argument_identifier = first_argument->as(); - auto identifier = first_argument_identifier.getIdentifier(); - - IdentifierLookup identifier_lookup{identifier, IdentifierLookupContext::EXPRESSION}; - auto resolve_result = tryResolveIdentifier(identifier_lookup, scope); - - if (resolve_result.isResolved()) - { - first_argument = std::move(resolve_result.resolved_identifier); - } - else - { - size_t parts_size = identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected {} function first argument identifier to contain 1 or 2 parts. Actual '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_special_function_dict_get) - { - scope.context->getExternalDictionariesLoader().assertDictionaryStructureExists(identifier.getFullName(), scope.context); - } - else - { - auto table_node = tryResolveTableIdentifierFromDatabaseCatalog(identifier, scope.context); - if (!table_node) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} first argument expected table identifier '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node_typed = table_node->as(); - if (!std::dynamic_pointer_cast(table_node_typed.getStorage())) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} table '{}' should have engine StorageJoin. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - first_argument = std::make_shared(identifier.getFullName()); - } - } - - if (is_special_function_exists) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /// Rewrite EXISTS (subquery) into 1 IN (SELECT 1 FROM (subquery) LIMIT 1). - auto & exists_subquery_argument = function_node_ptr->getArguments().getNodes().at(0); - - auto constant_data_type = std::make_shared(); - - auto in_subquery = std::make_shared(Context::createCopy(scope.context)); - in_subquery->setIsSubquery(true); - in_subquery->getProjection().getNodes().push_back(std::make_shared(1UL, constant_data_type)); - in_subquery->getJoinTree() = exists_subquery_argument; - in_subquery->getLimit() = std::make_shared(1UL, constant_data_type); - - function_node_ptr = std::make_shared("in"); - function_node_ptr->getArguments().getNodes() = {std::make_shared(1UL, constant_data_type), in_subquery}; - node = function_node_ptr; - function_name = "in"; - is_special_function_in = true; - } - - if (is_special_function_if && !function_node_ptr->getArguments().getNodes().empty()) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /** Handle special case with constant If function, even if some of the arguments are invalid. - * - * SELECT if(hasColumnInTable('system', 'numbers', 'not_existing_column'), not_existing_column, 5) FROM system.numbers; - */ - auto & if_function_arguments = function_node_ptr->getArguments().getNodes(); - auto if_function_condition = if_function_arguments[0]; - resolveExpressionNode(if_function_condition, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto constant_condition = tryExtractConstantFromConditionNode(if_function_condition); - - if (constant_condition.has_value() && if_function_arguments.size() == 3) - { - QueryTreeNodePtr constant_if_result_node; - QueryTreeNodePtr possibly_invalid_argument_node; - - if (*constant_condition) - { - possibly_invalid_argument_node = if_function_arguments[2]; - constant_if_result_node = if_function_arguments[1]; - } - else - { - possibly_invalid_argument_node = if_function_arguments[1]; - constant_if_result_node = if_function_arguments[2]; - } - - bool apply_constant_if_optimization = false; - - try - { - resolveExpressionNode(possibly_invalid_argument_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - } - catch (...) - { - apply_constant_if_optimization = true; - } - - if (apply_constant_if_optimization) - { - auto result_projection_names = resolveExpressionNode(constant_if_result_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - node = std::move(constant_if_result_node); - return result_projection_names; - } - } - } - - /// Resolve function arguments - bool allow_table_expressions = is_special_function_in; - auto arguments_projection_names = resolveExpressionNodeList(function_node_ptr->getArgumentsNode(), - scope, - true /*allow_lambda_expression*/, - allow_table_expressions /*allow_table_expression*/); - - /// Mask arguments if needed - if (!scope.context->getSettingsRef().format_display_secrets_in_show_and_select) - { - if (FunctionSecretArgumentsFinder::Result secret_arguments = FunctionSecretArgumentsFinderTreeNode(*function_node_ptr).getResult(); secret_arguments.count) - { - auto & argument_nodes = function_node_ptr->getArgumentsNode()->as().getNodes(); - - for (size_t n = secret_arguments.start; n < secret_arguments.start + secret_arguments.count; ++n) - { - if (auto * constant = argument_nodes[n]->as()) - { - auto mask = scope.projection_mask_map->insert({constant->getTreeHash(), scope.projection_mask_map->size() + 1}).first->second; - constant->setMaskId(mask); - arguments_projection_names[n] = "[HIDDEN id: " + std::to_string(mask) + "]"; - } - } - } - } - - auto & function_node = *function_node_ptr; - - /// Replace right IN function argument if it is table or table function with subquery that read ordinary columns - if (is_special_function_in) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - if (scope.context->getSettingsRef().transform_null_in) - { - static constexpr std::array, 4> in_function_to_replace_null_in_function_map = - {{ - {"in", "nullIn"}, - {"notIn", "notNullIn"}, - {"globalIn", "globalNullIn"}, - {"globalNotIn", "globalNotNullIn"}, - }}; - - for (const auto & [in_function_name, in_function_name_to_replace] : in_function_to_replace_null_in_function_map) - { - if (function_name == in_function_name) - { - function_name = in_function_name_to_replace; - break; - } - } - } - - auto & function_in_arguments_nodes = function_node.getArguments().getNodes(); - if (function_in_arguments_nodes.size() != 2) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function '{}' expects 2 arguments", function_name); - - auto & in_second_argument = function_in_arguments_nodes[1]; - auto * table_node = in_second_argument->as(); - auto * table_function_node = in_second_argument->as(); - - if (table_node) - { - /// If table is already prepared set, we do not replace it with subquery. - /// If table is not a StorageSet, we'll create plan to build set in the Planner. - } - else if (table_function_node) - { - const auto & storage_snapshot = table_function_node->getStorageSnapshot(); - auto columns_to_select = storage_snapshot->getColumns(GetColumnsOptions(GetColumnsOptions::Ordinary)); - - size_t columns_to_select_size = columns_to_select.size(); - - auto column_nodes_to_select = std::make_shared(); - column_nodes_to_select->getNodes().reserve(columns_to_select_size); - - NamesAndTypes projection_columns; - projection_columns.reserve(columns_to_select_size); - - for (auto & column : columns_to_select) - { - column_nodes_to_select->getNodes().emplace_back(std::make_shared(column, in_second_argument)); - projection_columns.emplace_back(column.name, column.type); - } - - auto in_second_argument_query_node = std::make_shared(Context::createCopy(scope.context)); - in_second_argument_query_node->setIsSubquery(true); - in_second_argument_query_node->getProjectionNode() = std::move(column_nodes_to_select); - in_second_argument_query_node->getJoinTree() = std::move(in_second_argument); - in_second_argument_query_node->resolveProjectionColumns(std::move(projection_columns)); - - in_second_argument = std::move(in_second_argument_query_node); - } - else - { - /// Replace storage with values storage of insertion block - if (StoragePtr storage = scope.context->getViewSource()) - { - QueryTreeNodePtr table_expression; - /// Process possibly nested sub-selects - for (auto * query_node = in_second_argument->as(); query_node; query_node = table_expression->as()) - table_expression = extractLeftTableExpression(query_node->getJoinTree()); - - if (table_expression) - { - if (auto * query_table_node = table_expression->as()) - { - if (query_table_node->getStorageID().getFullNameNotQuoted() == storage->getStorageID().getFullNameNotQuoted()) - { - auto replacement_table_expression = std::make_shared(storage, scope.context); - if (std::optional table_expression_modifiers = query_table_node->getTableExpressionModifiers()) - replacement_table_expression->setTableExpressionModifiers(*table_expression_modifiers); - in_second_argument = in_second_argument->cloneAndReplace(table_expression, std::move(replacement_table_expression)); - } - } - } - } - - resolveExpressionNode(in_second_argument, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - } - } - - /// Initialize function argument columns - - ColumnsWithTypeAndName argument_columns; - DataTypes argument_types; - bool all_arguments_constants = true; - std::vector function_lambda_arguments_indexes; - - auto & function_arguments = function_node.getArguments().getNodes(); - size_t function_arguments_size = function_arguments.size(); - - for (size_t function_argument_index = 0; function_argument_index < function_arguments_size; ++function_argument_index) - { - auto & function_argument = function_arguments[function_argument_index]; - - ColumnWithTypeAndName argument_column; - argument_column.name = arguments_projection_names[function_argument_index]; - - /** If function argument is lambda, save lambda argument index and initialize argument type as DataTypeFunction - * where function argument types are initialized with empty array of lambda arguments size. - */ - if (const auto * lambda_node = function_argument->as()) - { - size_t lambda_arguments_size = lambda_node->getArguments().getNodes().size(); - argument_column.type = std::make_shared(DataTypes(lambda_arguments_size, nullptr), nullptr); - function_lambda_arguments_indexes.push_back(function_argument_index); - } - else if (is_special_function_in && function_argument_index == 1) - { - argument_column.type = std::make_shared(); - } - else - { - argument_column.type = function_argument->getResultType(); - } - - if (!argument_column.type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' argument is not resolved. In scope {}", - function_name, - scope.scope_node->formatASTForErrorMessage()); - - bool argument_is_constant = false; - const auto * constant_node = function_argument->as(); - if (constant_node) - { - argument_column.column = constant_node->getResultType()->createColumnConst(1, constant_node->getValue()); - argument_column.type = constant_node->getResultType(); - argument_is_constant = true; - } - else if (const auto * get_scalar_function_node = function_argument->as(); - get_scalar_function_node && get_scalar_function_node->getFunctionName() == "__getScalar") - { - /// Allow constant folding through getScalar - const auto * get_scalar_const_arg = get_scalar_function_node->getArguments().getNodes().at(0)->as(); - if (get_scalar_const_arg && scope.context->hasQueryContext()) - { - auto query_context = scope.context->getQueryContext(); - auto scalar_string = toString(get_scalar_const_arg->getValue()); - if (query_context->hasScalar(scalar_string)) - { - auto scalar = query_context->getScalar(scalar_string); - argument_column.column = ColumnConst::create(scalar.getByPosition(0).column, 1); - argument_column.type = get_scalar_function_node->getResultType(); - argument_is_constant = true; - } - } - } - - all_arguments_constants &= argument_is_constant; - - argument_types.push_back(argument_column.type); - argument_columns.emplace_back(std::move(argument_column)); - } - - /// Calculate function projection name - ProjectionNames result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - - /** Try to resolve function as - * 1. Lambda function in current scope. Example: WITH (x -> x + 1) AS lambda SELECT lambda(1); - * 2. Lambda function from sql user defined functions. - * 3. Special `untuple` function. - * 4. Special `grouping` function. - * 5. Window function. - * 6. Executable user defined function. - * 7. Ordinary function. - * 8. Aggregate function. - * - * TODO: Provide better error hints. - */ - if (!function_node.isWindowFunction()) - { - if (!lambda_expression_untyped) - lambda_expression_untyped = tryGetLambdaFromSQLUserDefinedFunctions(function_node.getFunctionName(), scope.context); - - /** If function is resolved as lambda. - * Clone lambda before resolve. - * Initialize lambda arguments as function arguments. - * Resolve lambda and then replace function node with resolved lambda expression body. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(value) FROM test_table; - * Result: SELECT value + 1 FROM test_table; - */ - if (lambda_expression_untyped) - { - auto * lambda_expression = lambda_expression_untyped->as(); - if (!lambda_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function identifier '{}' must be resolved as lambda. Actual {}. In scope {}", - function_node.getFunctionName(), - lambda_expression_untyped->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - if (!parameters.empty()) - { - throw Exception( - ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_node.formatASTForErrorMessage()); - } - - auto lambda_expression_clone = lambda_expression_untyped->clone(); - - IdentifierResolveScope lambda_scope(lambda_expression_clone, &scope /*parent_scope*/); - ProjectionNames lambda_projection_names = resolveLambda(lambda_expression_untyped, lambda_expression_clone, function_arguments, lambda_scope); - - auto & resolved_lambda = lambda_expression_clone->as(); - node = resolved_lambda.getExpression(); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(lambda_projection_names); - - return result_projection_names; - } - - if (function_name == "untuple") - { - /// Special handling of `untuple` function - - if (function_arguments.size() != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' must have 1 argument. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - const auto & untuple_argument = function_arguments[0]; - /// Handle this special case first as `getResultType()` might return nullptr - if (untuple_argument->as()) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Function untuple can't have lambda-expressions as arguments"); - - auto result_type = untuple_argument->getResultType(); - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' argument must have compound type. Actual type {}. In scope {}", - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - - auto result_list = std::make_shared(); - result_list->getNodes().reserve(element_names.size()); - - for (const auto & element_name : element_names) - { - auto tuple_element_function = std::make_shared("tupleElement"); - tuple_element_function->getArguments().getNodes().push_back(untuple_argument); - tuple_element_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = tuple_element_function; - resolveFunction(function_query_node, scope); - - result_list->getNodes().push_back(std::move(function_query_node)); - } - - auto untuple_argument_projection_name = arguments_projection_names.at(0); - result_projection_names.clear(); - - for (const auto & element_name : element_names) - { - if (node->hasAlias()) - result_projection_names.push_back(node->getAlias() + '.' + element_name); - else - result_projection_names.push_back(fmt::format("tupleElement({}, '{}')", untuple_argument_projection_name, element_name)); - } - - node = std::move(result_list); - return result_projection_names; - } - else if (function_name == "grouping") - { - /// It is responsibility of planner to perform additional handling of grouping function - if (function_arguments_size == 0) - throw Exception(ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING expects at least one argument"); - else if (function_arguments_size > 64) - throw Exception(ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING can have up to 64 arguments, but {} provided", - function_arguments_size); - checkFunctionNodeHasEmptyNullsAction(function_node); - - bool force_grouping_standard_compatibility = scope.context->getSettingsRef().force_grouping_standard_compatibility; - auto grouping_function = std::make_shared(force_grouping_standard_compatibility); - auto grouping_function_adaptor = std::make_shared(std::move(grouping_function)); - function_node.resolveAsFunction(grouping_function_adaptor->build(argument_columns)); - - return result_projection_names; - } - } - - if (function_node.isWindowFunction()) - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - throw Exception(ErrorCodes::UNKNOWN_AGGREGATE_FUNCTION, "Aggregate function with name '{}' does not exist. In scope {}{}", - function_name, scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(AggregateFunctionFactory::instance().getHints(function_name))); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Window function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsWindowFunction(std::move(aggregate_function)); - - bool window_node_is_identifier = function_node.getWindowNode()->getNodeType() == QueryTreeNodeType::IDENTIFIER; - ProjectionName window_projection_name = resolveWindow(function_node.getWindowNode(), scope); - - if (window_node_is_identifier) - result_projection_names[0] += " OVER " + window_projection_name; - else - result_projection_names[0] += " OVER (" + window_projection_name + ')'; - - return result_projection_names; - } - - FunctionOverloadResolverPtr function = UserDefinedExecutableFunctionFactory::instance().tryGet(function_name, scope.context, parameters); /// NOLINT(readability-static-accessed-through-instance) - bool is_executable_udf = true; - - IdentifierResolveScope::ResolvedFunctionsCache * function_cache = nullptr; - - if (!function) - { - /// This is a hack to allow a query like `select randConstant(), randConstant(), randConstant()`. - /// Function randConstant() would return the same value for the same arguments (in scope). - - auto hash = function_node_ptr->getTreeHash(); - function_cache = &scope.functions_cache[hash]; - if (!function_cache->resolver) - function_cache->resolver = FunctionFactory::instance().tryGet(function_name, scope.context); - - function = function_cache->resolver; - - is_executable_udf = false; - } - - if (function) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - } - else - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - std::vector possible_function_names; - - auto function_names = UserDefinedExecutableFunctionFactory::instance().getRegisteredNames(scope.context); /// NOLINT(readability-static-accessed-through-instance) - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = UserDefinedSQLFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = FunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = AggregateFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - for (auto & [name, lambda_node] : scope.aliases.alias_name_to_lambda_node) - { - if (lambda_node->getNodeType() == QueryTreeNodeType::LAMBDA) - possible_function_names.push_back(name); - } - - auto hints = NamePrompter<2>::getHints(function_name, possible_function_names); - - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Function with name '{}' does not exist. In scope {}{}", - function_name, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Aggregate function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsAggregateFunction(std::move(aggregate_function)); - - return result_projection_names; - } - - /// Executable UDFs may have parameters. They are checked in UserDefinedExecutableFunctionFactory. - if (!parameters.empty() && !is_executable_udf) - { - throw Exception(ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_name); - } - - /** For lambda arguments we need to initialize lambda argument types DataTypeFunction using `getLambdaArgumentTypes` function. - * Then each lambda arguments are initialized with columns, where column source is lambda. - * This information is important for later steps of query processing. - * Example: SELECT arrayMap(x -> x + 1, [1, 2, 3]). - * lambda node x -> x + 1 identifier x is resolved as column where source is lambda node. - */ - bool has_lambda_arguments = !function_lambda_arguments_indexes.empty(); - if (has_lambda_arguments) - { - function->getLambdaArgumentTypes(argument_types); - - ProjectionNames lambda_projection_names; - for (auto & function_lambda_argument_index : function_lambda_arguments_indexes) - { - auto & lambda_argument = function_arguments[function_lambda_argument_index]; - auto lambda_to_resolve = lambda_argument->clone(); - auto & lambda_to_resolve_typed = lambda_to_resolve->as(); - - const auto & lambda_argument_names = lambda_to_resolve_typed.getArgumentNames(); - size_t lambda_arguments_size = lambda_to_resolve_typed.getArguments().getNodes().size(); - - const auto * function_data_type = typeid_cast(argument_types[function_lambda_argument_index].get()); - if (!function_data_type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' expected function data type for lambda argument with index {}. Actual {}. In scope {}", - function_name, - function_lambda_argument_index, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & function_data_type_argument_types = function_data_type->getArgumentTypes(); - size_t function_data_type_arguments_size = function_data_type_argument_types.size(); - if (function_data_type_arguments_size != lambda_arguments_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}" - "' function data type for lambda argument with index {} arguments size mismatch. " - "Actual {}. Expected {}. In scope {}", - function_name, - function_data_type_arguments_size, - lambda_arguments_size, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - QueryTreeNodes lambda_arguments; - lambda_arguments.reserve(lambda_arguments_size); - - for (size_t i = 0; i < lambda_arguments_size; ++i) - { - const auto & argument_type = function_data_type_argument_types[i]; - auto column_name_and_type = NameAndTypePair{lambda_argument_names[i], argument_type}; - lambda_arguments.push_back(std::make_shared(std::move(column_name_and_type), lambda_to_resolve)); - } - - IdentifierResolveScope lambda_scope(lambda_to_resolve, &scope /*parent_scope*/); - lambda_projection_names = resolveLambda(lambda_argument, lambda_to_resolve, lambda_arguments, lambda_scope); - - if (auto * lambda_list_node_result = lambda_to_resolve_typed.getExpression()->as()) - { - size_t lambda_list_node_result_nodes_size = lambda_list_node_result->getNodes().size(); - - if (lambda_list_node_result_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Lambda as function argument resolved as list node with size {}. Expected 1. In scope {}", - lambda_list_node_result_nodes_size, - lambda_to_resolve->formatASTForErrorMessage()); - - lambda_to_resolve_typed.getExpression() = lambda_list_node_result->getNodes().front(); - } - - if (arguments_projection_names.at(function_lambda_argument_index) == PROJECTION_NAME_PLACEHOLDER) - { - size_t lambda_projection_names_size =lambda_projection_names.size(); - if (lambda_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Lambda argument inside function expected to have 1 projection name. Actual {}", - lambda_projection_names_size); - - WriteBufferFromOwnString lambda_argument_projection_name_buffer; - lambda_argument_projection_name_buffer << "lambda("; - lambda_argument_projection_name_buffer << "tuple("; - - size_t lambda_argument_names_size = lambda_argument_names.size(); - - for (size_t i = 0; i < lambda_argument_names_size; ++i) - { - const auto & lambda_argument_name = lambda_argument_names[i]; - lambda_argument_projection_name_buffer << lambda_argument_name; - - if (i + 1 != lambda_argument_names_size) - lambda_argument_projection_name_buffer << ", "; - } - - lambda_argument_projection_name_buffer << "), "; - lambda_argument_projection_name_buffer << lambda_projection_names[0]; - lambda_argument_projection_name_buffer << ")"; - - lambda_projection_names.clear(); - - arguments_projection_names[function_lambda_argument_index] = lambda_argument_projection_name_buffer.str(); - } - - auto lambda_resolved_type = std::make_shared(function_data_type_argument_types, lambda_to_resolve_typed.getExpression()->getResultType()); - lambda_to_resolve_typed.resolve(lambda_resolved_type); - - argument_types[function_lambda_argument_index] = lambda_resolved_type; - argument_columns[function_lambda_argument_index].type = lambda_resolved_type; - function_arguments[function_lambda_argument_index] = std::move(lambda_to_resolve); - } - - /// Recalculate function projection name after lambda resolution - result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - } - - /** Create SET column for special function IN to allow constant folding - * if left and right arguments are constants. - * - * Example: SELECT * FROM test_table LIMIT 1 IN 1; - */ - if (is_special_function_in) - { - const auto * first_argument_constant_node = function_arguments[0]->as(); - const auto * second_argument_constant_node = function_arguments[1]->as(); - - if (first_argument_constant_node && second_argument_constant_node) - { - const auto & first_argument_constant_type = first_argument_constant_node->getResultType(); - const auto & second_argument_constant_literal = second_argument_constant_node->getValue(); - const auto & second_argument_constant_type = second_argument_constant_node->getResultType(); - - const auto & settings = scope.context->getSettingsRef(); - - auto result_block = getSetElementsForConstantValue(first_argument_constant_type, - second_argument_constant_literal, - second_argument_constant_type, - settings.transform_null_in); - - SizeLimits size_limits_for_set = {settings.max_rows_in_set, settings.max_bytes_in_set, settings.set_overflow_mode}; - - auto set = std::make_shared(size_limits_for_set, 0, settings.transform_null_in); - - set->setHeader(result_block.cloneEmpty().getColumnsWithTypeAndName()); - set->insertFromBlock(result_block.getColumnsWithTypeAndName()); - set->finishInsert(); - - auto future_set = std::make_shared(std::move(set)); - - /// Create constant set column for constant folding - - auto column_set = ColumnSet::create(1, std::move(future_set)); - argument_columns[1].column = ColumnConst::create(std::move(column_set), 1); - } - - argument_columns[1].type = std::make_shared(); - } - - std::shared_ptr constant_value; - - try - { - FunctionBasePtr function_base; - if (function_cache) - { - auto & cached_function = function_cache->function_base; - if (!cached_function) - cached_function = function->build(argument_columns); - - function_base = cached_function; - } - else - function_base = function->build(argument_columns); - - /// Do not constant fold get scalar functions - bool disable_constant_folding = function_name == "__getScalar" || function_name == "shardNum" || - function_name == "shardCount" || function_name == "hostName" || function_name == "tcpPort"; - - /** If function is suitable for constant folding try to convert it to constant. - * Example: SELECT plus(1, 1); - * Result: SELECT 2; - */ - if (function_base->isSuitableForConstantFolding() && !disable_constant_folding) - { - auto result_type = function_base->getResultType(); - auto executable_function = function_base->prepare(argument_columns); - - ColumnPtr column; - - if (all_arguments_constants) - { - size_t num_rows = function_arguments.empty() ? 0 : argument_columns.front().column->size(); - column = executable_function->execute(argument_columns, result_type, num_rows, true); - } - else - { - column = function_base->getConstantResultForNonConstArguments(argument_columns, result_type); - } - - if (column && column->getDataType() != result_type->getColumnType()) - throw Exception( - ErrorCodes::LOGICAL_ERROR, - "Unexpected return type from {}. Expected {}. Got {}", - function->getName(), - result_type->getColumnType(), - column->getDataType()); - - /** Do not perform constant folding if there are aggregate or arrayJoin functions inside function. - * Example: SELECT toTypeName(sum(number)) FROM numbers(10); - */ - if (column && isColumnConst(*column) && !typeid_cast(column.get())->getDataColumn().isDummy() && - !hasAggregateFunctionNodes(node) && !hasFunctionNode(node, "arrayJoin") && - /// Sanity check: do not convert large columns to constants - column->byteSize() < 1_MiB) - { - /// Replace function node with result constant node - Field column_constant_value; - column->get(0, column_constant_value); - constant_value = std::make_shared(std::move(column_constant_value), result_type); - } - } - - function_node.resolveAsFunction(std::move(function_base)); - } - catch (Exception & e) - { - e.addMessage("In scope {}", scope.scope_node->formatASTForErrorMessage()); - throw; - } - - if (constant_value) - node = std::make_shared(std::move(constant_value), node); - - return result_projection_names; -} - -/** Resolve expression node. - * Argument node can be replaced with different node, or even with list node in case of matcher resolution. - * Example: SELECT * FROM test_table; - * * - is matcher node, and it can be resolved into ListNode. - * - * Steps: - * 1. If node has alias, replace node with its value in scope alias map. Register alias in expression_aliases_in_resolve_process, to prevent resolving identifier - * which can bind to expression alias name. Check tryResolveIdentifierFromAliases documentation for additional explanation. - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * - * 2. Call specific resolve method depending on node type. - * - * If allow_table_expression = true and node is query node, then it is not evaluated as scalar subquery. - * Although if node is identifier that is resolved into query node that query is evaluated as scalar subquery. - * SELECT id, (SELECT 1) AS c FROM test_table WHERE a IN c; - * SELECT id, FROM test_table WHERE a IN (SELECT 1); - * - * 3. Special case identifier node. - * Try resolve it as expression identifier. - * Then if allow_lambda_expression = true try to resolve it as function. - * Then if allow_table_expression = true try to resolve it as table expression. - * - * 4. If node has alias, update its value in scope alias map. Deregister alias from expression_aliases_in_resolve_process. - */ -ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias) -{ - checkStackSize(); - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - /** There can be edge case, when subquery for IN function is resolved multiple times in different context. - * SELECT id IN (subquery AS value), value FROM test_table; - * When we start to resolve `value` identifier, subquery is already resolved but constant folding is not performed. - */ - auto node_type = node->getNodeType(); - if (!allow_table_expression && (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION)) - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - } - - return resolved_expression_it->second; - } - - String node_alias = node->getAlias(); - ProjectionNames result_projection_names; - - if (node_alias.empty()) - { - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - else - { - result_projection_names.push_back(node_alias); - } - - bool is_duplicated_alias = scope.aliases.nodes_with_duplicated_aliases.contains(node); - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.insert({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - /** Do not use alias table if node has alias same as some other node. - * Example: WITH x -> x + 1 AS lambda SELECT 1 AS lambda; - * During 1 AS lambda resolve if we use alias table we replace node with x -> x + 1 AS lambda. - * - * Do not use alias table if allow_table_expression = true and we resolve query node directly. - * Example: SELECT a FROM test_table WHERE id IN (SELECT 1) AS a; - * To support both (SELECT 1) AS expression in projection and (SELECT 1) as subquery in IN, do not use - * alias table because in alias table subquery could be evaluated as scalar. - */ - bool use_alias_table = !ignore_alias; - if (is_duplicated_alias || (allow_table_expression && isSubqueryNodeType(node->getNodeType()))) - use_alias_table = false; - - if (!node_alias.empty() && use_alias_table) - { - /** Node could be potentially resolved by resolving other nodes. - * SELECT b, a as b FROM test_table; - * - * To resolve b we need to resolve a. - */ - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - node = it->second; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - node = it->second; - } - } - - scope.pushExpressionNode(node); - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & identifier_node = node->as(); - auto unresolved_identifier = identifier_node.getIdentifier(); - auto resolve_identifier_expression_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier_node = resolve_identifier_expression_result.resolved_identifier; - - if (resolved_identifier_node && result_projection_names.empty() && - (resolve_identifier_expression_result.isResolvedFromJoinTree() || resolve_identifier_expression_result.isResolvedFromExpressionArguments())) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier_node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - - if (!resolved_identifier_node && allow_lambda_expression) - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::FUNCTION}, scope).resolved_identifier; - - if (!resolved_identifier_node && allow_table_expression) - { - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::TABLE_EXPRESSION}, scope).resolved_identifier; - - if (resolved_identifier_node) - { - /// If table identifier is resolved as CTE clone it and resolve - auto * subquery_node = resolved_identifier_node->as(); - auto * union_node = resolved_identifier_node->as(); - bool resolved_as_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - - if (resolved_as_cte) - { - resolved_identifier_node = resolved_identifier_node->clone(); - subquery_node = resolved_identifier_node->as(); - union_node = resolved_identifier_node->as(); - - std::string_view cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - if (subquery_node) - subquery_node->setIsCTE(false); - else - union_node->setIsCTE(false); - - IdentifierResolveScope subquery_scope(resolved_identifier_node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - /// CTE is being resolved, it's required to forbid to resolve to it again - /// because recursive CTEs are not supported, e.g.: - /// - /// WITH test1 AS (SELECT i + 1, j + 1 FROM test1) SELECT toInt64(4) i, toInt64(5) j FROM numbers(3) WHERE (i, j) IN test1; - /// - /// In this example argument of function `in` is being resolve here. If CTE `test1` is not forbidden, - /// `test1` is resolved to CTE (not to the table) in `initializeQueryJoinTreeNode` function. - ctes_in_resolve_process.insert(cte_name); - - if (subquery_node) - resolveQuery(resolved_identifier_node, subquery_scope); - else - resolveUnion(resolved_identifier_node, subquery_scope); - - ctes_in_resolve_process.erase(cte_name); - } - } - } - - if (!resolved_identifier_node) - { - std::string message_clarification; - if (allow_lambda_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::FUNCTION); - - if (allow_table_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::TABLE_EXPRESSION); - - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(unresolved_identifier, - scope, - true, - allow_lambda_expression, - allow_table_expression, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(unresolved_identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {}{} identifier '{}' in scope {}{}", - toStringLowercase(IdentifierLookupContext::EXPRESSION), - message_clarification, - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - node = std::move(resolved_identifier_node); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - { - result_projection_names.clear(); - resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - return resolved_expression_it->second; - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier '{}' resolve into list node and list node projection names are not initialized. In scope {}", - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_projection_names.empty()) - result_projection_names.push_back(unresolved_identifier.getFullName()); - - break; - } - case QueryTreeNodeType::MATCHER: - { - result_projection_names = resolveMatcher(node, scope); - break; - } - case QueryTreeNodeType::LIST: - { - /** Edge case if list expression has alias. - * Matchers cannot have aliases, but `untuple` function can. - * Example: SELECT a, untuple(CAST(('hello', 1) AS Tuple(name String, count UInt32))) AS a; - * During resolveFunction `untuple` function is replaced by list of 2 constants 'hello', 1. - */ - result_projection_names = resolveExpressionNodeList(node, scope, allow_lambda_expression, allow_lambda_expression); - break; - } - case QueryTreeNodeType::CONSTANT: - { - if (result_projection_names.empty()) - { - const auto & constant_node = node->as(); - result_projection_names.push_back(constant_node.getValueStringRepresentation()); - } - - /// Already resolved - break; - } - case QueryTreeNodeType::COLUMN: - { - auto & column_node = node->as(); - if (column_node.hasExpression()) - resolveExpressionNode(column_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (result_projection_names.empty()) - result_projection_names.push_back(column_node.getColumnName()); - - break; - } - case QueryTreeNodeType::FUNCTION: - { - auto function_projection_names = resolveFunction(node, scope); - - if (result_projection_names.empty() || node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(function_projection_names); - - break; - } - case QueryTreeNodeType::LAMBDA: - { - if (!allow_lambda_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (result_projection_names.empty()) - result_projection_names.push_back(PROJECTION_NAME_PLACEHOLDER); - - /// Lambda must be resolved by caller - break; - } - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - std::string projection_name = "_subquery_" + std::to_string(subquery_counter); - ++subquery_counter; - - if (node_type == QueryTreeNodeType::QUERY) - resolveQuery(node, subquery_scope); - else - resolveUnion(node, subquery_scope); - - if (!allow_table_expression) - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - - if (result_projection_names.empty()) - result_projection_names.push_back(std::move(projection_name)); - - break; - } - case QueryTreeNodeType::TABLE: - { - if (!allow_table_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Table {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node = node->as(); - result_projection_names.push_back(table_node.getStorageID().getFullNameNotQuoted()); - - break; - } - case QueryTreeNodeType::TRANSFORMER: - [[fallthrough]]; - case QueryTreeNodeType::SORT: - [[fallthrough]]; - case QueryTreeNodeType::INTERPOLATE: - [[fallthrough]]; - case QueryTreeNodeType::WINDOW: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::ARRAY_JOIN: - [[fallthrough]]; - case QueryTreeNodeType::JOIN: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "{} {} is not allowed in expression context. In scope {}", - node->getNodeType(), - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - validateTreeSize(node, scope.context->getSettingsRef().max_expanded_ast_elements, node_to_tree_size); - - /// Lambda can be inside the aggregate function, so we should check parent scopes. - /// Most likely only the root scope can have an arrgegate function, but let's check all just in case. - bool in_aggregate_function_scope = false; - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - in_aggregate_function_scope = in_aggregate_function_scope || scope_ptr->expressions_in_resolve_process_stack.hasAggregateFunction(); - - if (!in_aggregate_function_scope) - { - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - { - auto it = scope_ptr->nullable_group_by_keys.find(node); - if (it != scope_ptr->nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - break; - } - } - } - - /** Update aliases after expression node was resolved. - * Do not update node in alias table if we resolve it for duplicate alias. - */ - if (!node_alias.empty() && use_alias_table && !scope.group_by_use_nulls) - { - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - it->second = node; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - it->second = node; - } - } - - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.erase({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - if (!ignore_alias) - resolved_expressions.emplace(node, result_projection_names); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - return result_projection_names; -} - -/** Resolve expression node list. - * If expression is CTE subquery node it is skipped. - * If expression is resolved in list, it is flattened into initial node list. - * - * Such examples must work: - * Example: CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; SELECT plus(*) FROM test_table; - * Example: SELECT *** FROM system.one; - */ -ProjectionNames QueryAnalyzer::resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression) -{ - auto & node_list_typed = node_list->as(); - size_t node_list_size = node_list_typed.getNodes().size(); - - QueryTreeNodes result_nodes; - result_nodes.reserve(node_list_size); - - ProjectionNames result_projection_names; - - for (auto & node : node_list_typed.getNodes()) - { - auto node_to_resolve = node; - auto expression_node_projection_names = resolveExpressionNode(node_to_resolve, scope, allow_lambda_expression, allow_table_expression); - size_t expected_projection_names_size = 1; - if (auto * expression_list = node_to_resolve->as()) - { - expected_projection_names_size = expression_list->getNodes().size(); - for (auto & expression_list_node : expression_list->getNodes()) - result_nodes.push_back(expression_list_node); - } - else - { - result_nodes.push_back(std::move(node_to_resolve)); - } - - if (expression_node_projection_names.size() != expected_projection_names_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected {} projection names. Actual {}", - expected_projection_names_size, - expression_node_projection_names.size()); - - result_projection_names.insert(result_projection_names.end(), expression_node_projection_names.begin(), expression_node_projection_names.end()); - expression_node_projection_names.clear(); - } - - node_list_typed.getNodes() = std::move(result_nodes); - - return result_projection_names; -} - -/** Resolve sort columns nodes list. - */ -ProjectionNames QueryAnalyzer::resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames result_projection_names; - ProjectionNames sort_expression_projection_names; - ProjectionNames fill_from_expression_projection_names; - ProjectionNames fill_to_expression_projection_names; - ProjectionNames fill_step_expression_projection_names; - - auto & sort_node_list_typed = sort_node_list->as(); - for (auto & node : sort_node_list_typed.getNodes()) - { - auto & sort_node = node->as(); - sort_expression_projection_names = resolveExpressionNode(sort_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (auto * sort_column_list_node = sort_node.getExpression()->as()) - { - size_t sort_column_list_node_size = sort_column_list_node->getNodes().size(); - if (sort_column_list_node_size != 1) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Sort column node expression resolved into list with size {}. Expected 1. In scope {}", - sort_column_list_node_size, - scope.scope_node->formatASTForErrorMessage()); - } - - sort_node.getExpression() = sort_column_list_node->getNodes().front(); - } - - size_t sort_expression_projection_names_size = sort_expression_projection_names.size(); - if (sort_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort expression expected 1 projection name. Actual {}", - sort_expression_projection_names_size); - - if (sort_node.hasFillFrom()) - { - fill_from_expression_projection_names = resolveExpressionNode(sort_node.getFillFrom(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillFrom()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL FROM expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_from_expression_projection_names_size = fill_from_expression_projection_names.size(); - if (fill_from_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL FROM expression expected 1 projection name. Actual {}", - fill_from_expression_projection_names_size); - } - - if (sort_node.hasFillTo()) - { - fill_to_expression_projection_names = resolveExpressionNode(sort_node.getFillTo(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillTo()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL TO expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_to_expression_projection_names_size = fill_to_expression_projection_names.size(); - if (fill_to_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL TO expression expected 1 projection name. Actual {}", - fill_to_expression_projection_names_size); - } - - if (sort_node.hasFillStep()) - { - fill_step_expression_projection_names = resolveExpressionNode(sort_node.getFillStep(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillStep()->as(); - if (!constant_node) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - bool is_number = isColumnedAsNumber(constant_node->getResultType()); - bool is_interval = WhichDataType(constant_node->getResultType()).isInterval(); - if (!is_number && !is_interval) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_step_expression_projection_names_size = fill_step_expression_projection_names.size(); - if (fill_step_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort FILL STEP expression expected 1 projection name. Actual {}", - fill_step_expression_projection_names_size); - } - - auto sort_column_projection_name = calculateSortColumnProjectionName(node, - sort_expression_projection_names[0], - fill_from_expression_projection_names.empty() ? "" : fill_from_expression_projection_names.front(), - fill_to_expression_projection_names.empty() ? "" : fill_to_expression_projection_names.front(), - fill_step_expression_projection_names.empty() ? "" : fill_step_expression_projection_names.front()); - - result_projection_names.push_back(std::move(sort_column_projection_name)); - - sort_expression_projection_names.clear(); - fill_from_expression_projection_names.clear(); - fill_to_expression_projection_names.clear(); - fill_step_expression_projection_names.clear(); - } - - return result_projection_names; -} - -namespace -{ - -void expandTuplesInList(QueryTreeNodes & key_list) -{ - QueryTreeNodes expanded_keys; - expanded_keys.reserve(key_list.size()); - for (auto const & key : key_list) - { - if (auto * function = key->as(); function != nullptr && function->getFunctionName() == "tuple") - { - std::copy(function->getArguments().begin(), function->getArguments().end(), std::back_inserter(expanded_keys)); - } - else - expanded_keys.push_back(key); - } - key_list = std::move(expanded_keys); -} - -} - -/** Resolve GROUP BY clause. - */ -void QueryAnalyzer::resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope) -{ - if (query_node_typed.isGroupByWithGroupingSets()) - { - for (auto & grouping_sets_keys_list_node : query_node_typed.getGroupBy().getNodes()) - { - replaceNodesWithPositionalArguments(grouping_sets_keys_list_node, query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(grouping_sets_keys_list_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = grouping_sets_keys_list_node->as().getNodes(); - expandTuplesInList(group_by_list); - } - - if (scope.group_by_use_nulls) - { - for (const auto & grouping_set : query_node_typed.getGroupBy().getNodes()) - { - for (const auto & group_by_elem : grouping_set->as()->getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } - } - else - { - replaceNodesWithPositionalArguments(query_node_typed.getGroupByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getGroupByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = query_node_typed.getGroupBy().getNodes(); - expandTuplesInList(group_by_list); - - if (scope.group_by_use_nulls) - { - for (const auto & group_by_elem : query_node_typed.getGroupBy().getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } -} - -/** Resolve interpolate columns nodes list. - */ -void QueryAnalyzer::resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope) -{ - auto & interpolate_node_list_typed = interpolate_node_list->as(); - - for (auto & interpolate_node : interpolate_node_list_typed.getNodes()) - { - auto & interpolate_node_typed = interpolate_node->as(); - - auto * column_to_interpolate = interpolate_node_typed.getExpression()->as(); - if (!column_to_interpolate) - throw Exception(ErrorCodes::LOGICAL_ERROR, "INTERPOLATE can work only for indentifiers, but {} is found", - interpolate_node_typed.getExpression()->formatASTForErrorMessage()); - auto column_to_interpolate_name = column_to_interpolate->getIdentifier().getFullName(); - - resolveExpressionNode(interpolate_node_typed.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool is_column_constant = interpolate_node_typed.getExpression()->getNodeType() == QueryTreeNodeType::CONSTANT; - - auto & interpolation_to_resolve = interpolate_node_typed.getInterpolateExpression(); - IdentifierResolveScope interpolate_scope(interpolation_to_resolve, &scope /*parent_scope*/); - - auto fake_column_node = std::make_shared(NameAndTypePair(column_to_interpolate_name, interpolate_node_typed.getExpression()->getResultType()), interpolate_node_typed.getExpression()); - if (is_column_constant) - interpolate_scope.expression_argument_name_to_node.emplace(column_to_interpolate_name, fake_column_node); - - resolveExpressionNode(interpolation_to_resolve, interpolate_scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (is_column_constant) - interpolation_to_resolve = interpolation_to_resolve->cloneAndReplace(fake_column_node, interpolate_node_typed.getExpression()); - } -} - -/** Resolve window nodes list. - */ -void QueryAnalyzer::resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope) -{ - auto & window_node_list_typed = window_node_list->as(); - for (auto & node : window_node_list_typed.getNodes()) - resolveWindow(node, scope); -} - -NamesAndTypes QueryAnalyzer::resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames projection_names = resolveExpressionNodeList(projection_node_list, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto projection_nodes = projection_node_list->as().getNodes(); - size_t projection_nodes_size = projection_nodes.size(); - - NamesAndTypes projection_columns; - projection_columns.reserve(projection_nodes_size); - - for (size_t i = 0; i < projection_nodes_size; ++i) - { - auto projection_node = projection_nodes[i]; - - if (!isExpressionNodeType(projection_node->getNodeType())) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Projection node must be constant, function, column, query or union"); - - projection_columns.emplace_back(projection_names[i], projection_node->getResultType()); - } - - return projection_columns; -} - -/** Initialize query join tree node. - * - * 1. Resolve identifiers. - * 2. Register table, table function, query, union, join, array join nodes in scope table expressions in resolve process. - */ -void QueryAnalyzer::initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope) -{ - std::deque join_tree_node_ptrs_to_process_queue; - join_tree_node_ptrs_to_process_queue.push_back(&join_tree_node); - - while (!join_tree_node_ptrs_to_process_queue.empty()) - { - auto * current_join_tree_node_ptr = join_tree_node_ptrs_to_process_queue.front(); - join_tree_node_ptrs_to_process_queue.pop_front(); - - auto & current_join_tree_node = *current_join_tree_node_ptr; - auto current_join_tree_node_type = current_join_tree_node->getNodeType(); - - switch (current_join_tree_node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & from_table_identifier = current_join_tree_node->as(); - auto table_identifier_lookup = IdentifierLookup{from_table_identifier.getIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - - auto from_table_identifier_alias = from_table_identifier.getAlias(); - - IdentifierResolveSettings resolve_settings; - /// In join tree initialization ignore join tree as identifier lookup source - resolve_settings.allow_to_check_join_tree = false; - /** Disable resolve of subquery during identifier resolution. - * Example: SELECT * FROM (SELECT 1) AS t1, t1; - * During `t1` identifier resolution we resolve it into subquery SELECT 1, but we want to disable - * subquery resolution at this stage, because JOIN TREE of parent query is not resolved. - */ - resolve_settings.allow_to_resolve_subquery_during_identifier_resolution = false; - - scope.pushExpressionNode(current_join_tree_node); - - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, resolve_settings); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - auto resolved_identifier = table_identifier_resolve_result.resolved_identifier; - - if (!resolved_identifier) - throw Exception(ErrorCodes::UNKNOWN_TABLE, - "Unknown table expression identifier '{}' in scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - resolved_identifier = resolved_identifier->clone(); - - /// Update alias name to table expression map - auto table_expression_it = scope.aliases.alias_name_to_table_expression_node.find(from_table_identifier_alias); - if (table_expression_it != scope.aliases.alias_name_to_table_expression_node.end()) - table_expression_it->second = resolved_identifier; - - auto table_expression_modifiers = from_table_identifier.getTableExpressionModifiers(); - - auto * resolved_identifier_query_node = resolved_identifier->as(); - auto * resolved_identifier_union_node = resolved_identifier->as(); - - if (resolved_identifier_query_node || resolved_identifier_union_node) - { - if (table_expression_modifiers.has_value()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Table expression modifiers {} are not supported for subquery {}", - table_expression_modifiers->formatForErrorMessage(), - resolved_identifier->formatASTForErrorMessage()); - } - } - else if (auto * resolved_identifier_table_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else if (auto * resolved_identifier_table_function_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_function_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier in JOIN TREE '{}' resolved into unexpected table expression. In scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto current_join_tree_node_alias = current_join_tree_node->getAlias(); - resolved_identifier->setAlias(current_join_tree_node_alias); - current_join_tree_node = resolved_identifier; - - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::QUERY: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::UNION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - auto & array_join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&array_join.getTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::JOIN: - { - auto & join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&join.getLeftTableExpression()); - join_tree_node_ptrs_to_process_queue.push_back(&join.getRightTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - ++scope.joins_count; - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, UNION, ARRAY JOIN or JOIN. Actual {} {}. In scope {}", - current_join_tree_node->getNodeTypeName(), - current_join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - } -} - -/// Initialize table expression data for table expression node -void QueryAnalyzer::initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto table_expression_data_it = scope.table_expression_node_to_data.find(table_expression_node); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - return; - - TableExpressionData table_expression_data; - - if (table_node) - { - if (!table_node->getTemporaryTableName().empty()) - { - table_expression_data.table_name = table_node->getTemporaryTableName(); - table_expression_data.table_expression_name = table_node->getTemporaryTableName(); - } - else - { - const auto & table_storage_id = table_node->getStorageID(); - table_expression_data.database_name = table_storage_id.database_name; - table_expression_data.table_name = table_storage_id.table_name; - table_expression_data.table_expression_name = table_storage_id.getFullNameNotQuoted(); - } - - table_expression_data.table_expression_description = "table"; - } - else if (query_node || union_node) - { - table_expression_data.table_name = query_node ? query_node->getCTEName() : union_node->getCTEName(); - table_expression_data.table_expression_description = "subquery"; - } - else if (table_function_node) - { - table_expression_data.table_expression_description = "table_function"; - } - - if (table_expression_node->hasAlias()) - table_expression_data.table_expression_name = table_expression_node->getAlias(); - - if (table_node || table_function_node) - { - const auto & storage_snapshot = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - - auto get_column_options = GetColumnsOptions(GetColumnsOptions::All).withExtendedObjects().withVirtuals(); - if (storage_snapshot->storage.supportsSubcolumns()) - get_column_options.withSubcolumns(); - - auto column_names_and_types = storage_snapshot->getColumns(get_column_options); - table_expression_data.column_names_and_types = NamesAndTypes(column_names_and_types.begin(), column_names_and_types.end()); - - const auto & columns_description = storage_snapshot->metadata->getColumns(); - - std::vector> alias_columns_to_resolve; - ColumnNameToColumnNodeMap column_name_to_column_node; - column_name_to_column_node.reserve(column_names_and_types.size()); - - /** For ALIAS columns in table we must additionally analyze ALIAS expressions. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + 5); - * - * To do that we collect alias columns and build table column name to column node map. - * For each alias column we build identifier resolve scope, initialize it with table column name to node map - * and resolve alias column. - */ - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - for (const auto & subcolumn : columns_description.getSubcolumns(column_name_and_type.name)) - table_expression_data.subcolumn_names.insert(subcolumn.name); - const auto & column_default = columns_description.getDefault(column_name_and_type.name); - - if (column_default && column_default->kind == ColumnDefaultKind::Alias) - { - auto alias_expression = buildQueryTree(column_default->expression, scope.context); - auto column_node = std::make_shared(column_name_and_type, std::move(alias_expression), table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - alias_columns_to_resolve.emplace_back(column_name_and_type.name, column_node); - } - else - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - for (auto & [alias_column_to_resolve_name, alias_column_to_resolve] : alias_columns_to_resolve) - { - /** Alias column could be potentially resolved during resolve of other ALIAS column. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + alias_value_2, alias_value_2 ALIAS id + 5) ENGINE=TinyLog; - * - * During resolve of alias_value_1, alias_value_2 column will be resolved. - */ - alias_column_to_resolve = column_name_to_column_node[alias_column_to_resolve_name]; - - IdentifierResolveScope alias_column_resolve_scope(alias_column_to_resolve, nullptr /*parent_scope*/); - alias_column_resolve_scope.column_name_to_column_node = std::move(column_name_to_column_node); - alias_column_resolve_scope.context = scope.context; - - /// Initialize aliases in alias column scope - QueryExpressionsAliasVisitor visitor(alias_column_resolve_scope.aliases); - visitor.visit(alias_column_to_resolve->getExpression()); - - resolveExpressionNode(alias_column_resolve_scope.scope_node, - alias_column_resolve_scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - auto & resolved_expression = alias_column_to_resolve->getExpression(); - if (!resolved_expression->getResultType()->equals(*alias_column_to_resolve->getResultType())) - resolved_expression = buildCastFunction(resolved_expression, alias_column_to_resolve->getResultType(), scope.context, true); - column_name_to_column_node = std::move(alias_column_resolve_scope.column_name_to_column_node); - column_name_to_column_node[alias_column_to_resolve_name] = alias_column_to_resolve; - } - - table_expression_data.column_name_to_column_node = std::move(column_name_to_column_node); - } - else if (query_node || union_node) - { - table_expression_data.column_names_and_types = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - table_expression_data.column_name_to_column_node.reserve(table_expression_data.column_names_and_types.size()); - - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - table_expression_data.column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - table_expression_data.column_identifier_first_parts.reserve(table_expression_data.column_name_to_column_node.size()); - - for (auto & [column_name, _] : table_expression_data.column_name_to_column_node) - { - Identifier column_name_identifier(column_name); - table_expression_data.column_identifier_first_parts.insert(column_name_identifier.at(0)); - } - - if (auto * scope_query_node = scope.scope_node->as()) - { - auto left_table_expression = extractLeftTableExpression(scope_query_node->getJoinTree()); - if (table_expression_node.get() == left_table_expression.get() && - scope.joins_count == 1 && - scope.context->getSettingsRef().single_join_prefer_left_table) - table_expression_data.should_qualify_columns = false; - } - - scope.table_expression_node_to_data.emplace(table_expression_node, std::move(table_expression_data)); -} - -bool findIdentifier(const FunctionNode & function) -{ - for (const auto & argument : function.getArguments()) - { - if (argument->as()) - return true; - if (const auto * f = argument->as(); f && findIdentifier(*f)) - return true; - } - return false; -} - -/// Resolve table function node in scope -void QueryAnalyzer::resolveTableFunction(QueryTreeNodePtr & table_function_node, - IdentifierResolveScope & scope, - QueryExpressionsAliasVisitor & expressions_visitor, - bool nested_table_function) -{ - auto & table_function_node_typed = table_function_node->as(); - - if (!nested_table_function) - expressions_visitor.visit(table_function_node_typed.getArgumentsNode()); - - const auto & table_function_name = table_function_node_typed.getTableFunctionName(); - - auto & scope_context = scope.context; - - TableFunctionPtr table_function_ptr = TableFunctionFactory::instance().tryGet(table_function_name, scope_context); - if (!table_function_ptr) - { - String database_name = scope_context->getCurrentDatabase(); - String table_name; - - auto function_ast = table_function_node->toAST(); - Identifier table_identifier{table_function_name}; - if (table_identifier.getPartsSize() == 1) - { - table_name = table_identifier[0]; - } - else if (table_identifier.getPartsSize() == 2) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - - auto parametrized_view_storage = scope_context->getQueryContext()->buildParametrizedViewStorage(function_ast, database_name, table_name); - if (parametrized_view_storage) - { - auto fake_table_node = std::make_shared(parametrized_view_storage, scope_context); - fake_table_node->setAlias(table_function_node->getAlias()); - table_function_node = fake_table_node; - return; - } - - auto hints = TableFunctionFactory::instance().getHints(table_function_name); - if (!hints.empty()) - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}. Maybe you meant: {}", - table_function_name, - DB::toString(hints)); - else - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}", - table_function_name); - } - - QueryTreeNodes result_table_function_arguments; - - auto skip_analysis_arguments_indexes = table_function_ptr->skipAnalysisForArguments(table_function_node, scope_context); - - auto & table_function_arguments = table_function_node_typed.getArguments().getNodes(); - size_t table_function_arguments_size = table_function_arguments.size(); - - for (size_t table_function_argument_index = 0; table_function_argument_index < table_function_arguments_size; ++table_function_argument_index) - { - auto & table_function_argument = table_function_arguments[table_function_argument_index]; - - auto skip_argument_index_it = std::find(skip_analysis_arguments_indexes.begin(), - skip_analysis_arguments_indexes.end(), - table_function_argument_index); - if (skip_argument_index_it != skip_analysis_arguments_indexes.end()) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - if (auto * identifier_node = table_function_argument->as()) - { - const auto & unresolved_identifier = identifier_node->getIdentifier(); - auto identifier_resolve_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier = std::move(identifier_resolve_result.resolved_identifier); - - if (resolved_identifier && resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - result_table_function_arguments.push_back(std::move(resolved_identifier)); - else - result_table_function_arguments.push_back(table_function_argument); - - continue; - } - else if (auto * table_function_argument_function = table_function_argument->as()) - { - const auto & table_function_argument_function_name = table_function_argument_function->getFunctionName(); - if (TableFunctionFactory::instance().isTableFunctionName(table_function_argument_function_name)) - { - auto table_function_node_to_resolve_typed = std::make_shared(table_function_argument_function_name); - table_function_node_to_resolve_typed->getArgumentsNode() = table_function_argument_function->getArgumentsNode(); - - QueryTreeNodePtr table_function_node_to_resolve = std::move(table_function_node_to_resolve_typed); - resolveTableFunction(table_function_node_to_resolve, scope, expressions_visitor, true /*nested_table_function*/); - - result_table_function_arguments.push_back(std::move(table_function_node_to_resolve)); - continue; - } - } - - /** Table functions arguments can contain expressions with invalid identifiers. - * We cannot skip analysis for such arguments, because some table functions cannot provide - * information if analysis for argument should be skipped until other arguments will be resolved. - * - * Example: SELECT key from remote('127.0.0.{1,2}', view(select number AS key from numbers(2)), cityHash64(key)); - * Example: SELECT id from remote('127.0.0.{1,2}', 'default', 'test_table', cityHash64(id)); - */ - try - { - resolveExpressionNode(table_function_argument, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - catch (const Exception & exception) - { - if (exception.code() == ErrorCodes::UNKNOWN_IDENTIFIER) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - throw; - } - - if (auto * expression_list = table_function_argument->as()) - { - for (auto & expression_list_node : expression_list->getNodes()) - result_table_function_arguments.push_back(expression_list_node); - } - else - { - result_table_function_arguments.push_back(table_function_argument); - } - } - - table_function_node_typed.getArguments().getNodes() = std::move(result_table_function_arguments); - - auto table_function_ast = table_function_node_typed.toAST(); - table_function_ptr->parseArguments(table_function_ast, scope_context); - - - uint64_t use_structure_from_insertion_table_in_table_functions = scope_context->getSettingsRef().use_structure_from_insertion_table_in_table_functions; - if (!nested_table_function && - use_structure_from_insertion_table_in_table_functions && - scope_context->hasInsertionTable() && - table_function_ptr->needStructureHint()) - { - const auto & insertion_table = scope_context->getInsertionTable(); - if (!insertion_table.empty()) - { - const auto & insert_columns = DatabaseCatalog::instance() - .getTable(insertion_table, scope_context) - ->getInMemoryMetadataPtr() - ->getColumns(); - const auto & insert_column_names = scope_context->hasInsertionTableColumnNames() ? *scope_context->getInsertionTableColumnNames() : insert_columns.getOrdinary().getNames(); - DB::ColumnsDescription structure_hint; - - bool use_columns_from_insert_query = true; - - /// Insert table matches columns against SELECT expression by position, so we want to map - /// insert table columns to table function columns through names from SELECT expression. - - auto insert_column_name_it = insert_column_names.begin(); - auto insert_column_names_end = insert_column_names.end(); /// end iterator of the range covered by possible asterisk - auto virtual_column_names = table_function_ptr->getVirtualsToCheckBeforeUsingStructureHint(); - bool asterisk = false; - const auto & expression_list = scope.scope_node->as().getProjection(); - auto expression = expression_list.begin(); - - /// We want to go through SELECT expression list and correspond each expression to column in insert table - /// which type will be used as a hint for the file structure inference. - for (; expression != expression_list.end() && insert_column_name_it != insert_column_names_end; ++expression) - { - if (auto * identifier_node = (*expression)->as()) - { - - if (!virtual_column_names.contains(identifier_node->getIdentifier().getFullName())) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - ColumnDescription column = insert_columns.get(*insert_column_name_it); - column.name = identifier_node->getIdentifier().getFullName(); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else if (auto * matcher_node = (*expression)->as(); matcher_node && matcher_node->getMatcherType() == MatcherNodeType::ASTERISK) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Only one asterisk can be used in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - if (!structure_hint.empty()) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - asterisk = true; - } - else if (auto * function = (*expression)->as()) - { - if (use_structure_from_insertion_table_in_table_functions == 2 && findIdentifier(*function)) - { - use_columns_from_insert_query = false; - break; - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else - { - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - } - - if (use_structure_from_insertion_table_in_table_functions == 2 && !asterisk) - { - /// For input function we should check if input format supports reading subset of columns. - if (table_function_ptr->getName() == "input") - use_columns_from_insert_query = FormatFactory::instance().checkIfFormatSupportsSubsetOfColumns(scope.context->getInsertFormat(), scope.context); - else - use_columns_from_insert_query = table_function_ptr->supportsReadingSubsetOfColumns(scope.context); - } - - if (use_columns_from_insert_query) - { - if (expression == expression_list.end()) - { - /// Append tail of insert structure to the hint - if (asterisk) - { - for (; insert_column_name_it != insert_column_names_end; ++insert_column_name_it) - { - ColumnDescription column = insert_columns.get(*insert_column_name_it); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - } - - if (!structure_hint.empty()) - table_function_ptr->setStructureHint(structure_hint); - - } else if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::NUMBER_OF_COLUMNS_DOESNT_MATCH, "Number of columns in insert table less than required by SELECT expression."); - } - } - } - - auto table_function_storage = scope_context->getQueryContext()->executeTableFunction(table_function_ast, table_function_ptr); - table_function_node_typed.resolve(std::move(table_function_ptr), std::move(table_function_storage), scope_context, std::move(skip_analysis_arguments_indexes)); -} - -/// Resolve array join node in scope -void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & array_join_node_typed = array_join_node->as(); - resolveQueryJoinTreeNode(array_join_node_typed.getTableExpression(), scope, expressions_visitor); - - std::unordered_set array_join_column_names; - - /// Wrap array join expressions into column nodes, where array join expression is inner expression - - auto & array_join_nodes = array_join_node_typed.getJoinExpressions().getNodes(); - size_t array_join_nodes_size = array_join_nodes.size(); - - if (array_join_nodes_size == 0) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, - "ARRAY JOIN requires at least single expression"); - - std::vector array_join_column_expressions; - array_join_column_expressions.reserve(array_join_nodes_size); - - for (auto & array_join_expression : array_join_nodes) - { - auto array_join_expression_alias = array_join_expression->getAlias(); - - for (const auto & elem : array_join_nodes) - { - if (elem->hasAlias()) - scope.aliases.array_join_aliases.insert(elem->getAlias()); - - for (auto & child : elem->getChildren()) - { - if (child) - expressions_visitor.visit(child); - } - } - - std::string identifier_full_name; - - if (auto * identifier_node = array_join_expression->as()) - identifier_full_name = identifier_node->getIdentifier().getFullName(); - - resolveExpressionNode(array_join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/, true /*ignore_alias*/); - - auto process_array_join_expression = [&](QueryTreeNodePtr & expression) - { - auto result_type = expression->getResultType(); - bool is_array_type = isArray(result_type); - bool is_map_type = isMap(result_type); - - if (!is_array_type && !is_map_type) - throw Exception(ErrorCodes::TYPE_MISMATCH, - "ARRAY JOIN {} requires expression {} with Array or Map type. Actual {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - expression->formatASTForErrorMessage(), - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_map_type) - result_type = assert_cast(*result_type).getNestedType(); - - result_type = assert_cast(*result_type).getNestedType(); - - String array_join_column_name; - - if (!array_join_expression_alias.empty()) - { - array_join_column_name = array_join_expression_alias; - } - else if (auto * array_join_expression_inner_column = array_join_expression->as()) - { - array_join_column_name = array_join_expression_inner_column->getColumnName(); - } - else if (!identifier_full_name.empty()) - { - array_join_column_name = identifier_full_name; - } - else - { - array_join_column_name = "__array_join_expression_" + std::to_string(array_join_expressions_counter); - ++array_join_expressions_counter; - } - - if (array_join_column_names.contains(array_join_column_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "ARRAY JOIN {} multiple columns with name {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - array_join_column_name, - scope.scope_node->formatASTForErrorMessage()); - array_join_column_names.emplace(array_join_column_name); - - NameAndTypePair array_join_column(array_join_column_name, result_type); - auto array_join_column_node = std::make_shared(std::move(array_join_column), expression, array_join_node); - array_join_column_node->setAlias(array_join_expression_alias); - array_join_column_expressions.push_back(std::move(array_join_column_node)); - }; - - // Support ARRAY JOIN COLUMNS(...). COLUMNS transformer is resolved to list of columns. - if (auto * columns_list = array_join_expression->as()) - { - for (auto & array_join_subexpression : columns_list->getNodes()) - process_array_join_expression(array_join_subexpression); - } - else - { - process_array_join_expression(array_join_expression); - } - } - - array_join_nodes = std::move(array_join_column_expressions); -} - -void QueryAnalyzer::checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope) -{ - Names column_names; - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - if (join_node->as().getKind() != JoinKind::Paste) - return; - - auto * left_node = left_table_expr->as(); - auto * right_node = right_table_expr->as(); - - if (!left_node && !right_node) - return; - - if (left_node) - for (const auto & name_and_type : left_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - if (right_node) - for (const auto & name_and_type : right_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - - if (column_names.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of projection columns cannot be empty"); - - std::sort(column_names.begin(), column_names.end()); - for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is no any duplicates because it will lead to broken result - if (column_names[i] == column_names[i+1]) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add/change aliases to avoid duplication)" - "While processing '{}'", join_node->formatASTForErrorMessage()); -} - -/// Resolve join node in scope -void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & join_node_typed = join_node->as(); - - resolveQueryJoinTreeNode(join_node_typed.getLeftTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getLeftTableExpression(), scope); - - resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); - - if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) - checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope); - - if (join_node_typed.isOnJoinExpression()) - { - expressions_visitor.visit(join_node_typed.getJoinExpression()); - auto join_expression = join_node_typed.getJoinExpression(); - resolveExpressionNode(join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - join_node_typed.getJoinExpression() = std::move(join_expression); - } - else if (join_node_typed.isUsingJoinExpression()) - { - auto & join_using_list = join_node_typed.getJoinExpression()->as(); - std::unordered_set join_using_identifiers; - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto * identifier_node = join_using_node->as(); - if (!identifier_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} USING clause expected identifier. Actual {}", - join_node_typed.formatASTForErrorMessage(), - join_using_node->formatASTForErrorMessage()); - - const auto & identifier_full_name = identifier_node->getIdentifier().getFullName(); - - if (join_using_identifiers.contains(identifier_full_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} identifier '{}' appears more than once in USING clause", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name); - - join_using_identifiers.insert(identifier_full_name); - - const auto & settings = scope.context->getSettingsRef(); - - /** While resolving JOIN USING identifier, try to resolve identifier from parent subquery projection. - * Example: SELECT a + 1 AS b FROM (SELECT 1 AS a) t1 JOIN (SELECT 2 AS b) USING b - * In this case `b` is not in the left table expression, but it is in the parent subquery projection. - */ - auto try_resolve_identifier_from_query_projection = [this](const String & identifier_full_name_, - const QueryTreeNodePtr & left_table_expression, - const IdentifierResolveScope & scope_) -> QueryTreeNodePtr - { - const QueryNode * query_node = scope_.scope_node ? scope_.scope_node->as() : nullptr; - if (!query_node) - return nullptr; - - const auto & projection_list = query_node->getProjection(); - for (const auto & projection_node : projection_list.getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name_ == projection_node->getAlias()) - { - auto left_subquery = std::make_shared(query_node->getMutableContext()); - left_subquery->getProjection().getNodes().push_back(projection_node->clone()); - left_subquery->getJoinTree() = left_table_expression; - - IdentifierResolveScope left_subquery_scope(left_subquery, nullptr /*parent_scope*/); - resolveQuery(left_subquery, left_subquery_scope); - - const auto & resolved_nodes = left_subquery->getProjection().getNodes(); - if (resolved_nodes.size() == 1) - { - /// Create ColumnNode with expression from parent projection - return std::make_shared( - NameAndTypePair{identifier_full_name_, resolved_nodes.front()->getResultType()}, - resolved_nodes.front(), left_table_expression); - } - } - } - return nullptr; - }; - - QueryTreeNodePtr result_left_table_expression = nullptr; - /** With `analyzer_compatibility_join_using_top_level_identifier` alias in projection has higher priority than column from left table. - * But if aliased expression cannot be resolved from left table, we get UNKNOW_IDENTIFIER error, - * despite the fact that column from USING could be resolved from left table. - * It's compatibility with a default behavior for old analyzer. - */ - if (settings.analyzer_compatibility_join_using_top_level_identifier) - result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - IdentifierLookup identifier_lookup{identifier_node->getIdentifier(), IdentifierLookupContext::EXPRESSION}; - if (!result_left_table_expression) - result_left_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getLeftTableExpression(), scope); - - /** Here we may try to resolve identifier from projection in case it's not resolved from left table expression - * and analyzer_compatibility_join_using_top_level_identifier is disabled. - * For now we do not do this, because not all corner cases are clear. - * But let's at least mention it in error message - */ - /// if (!settings.analyzer_compatibility_join_using_top_level_identifier && !result_left_table_expression) - /// result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - if (!result_left_table_expression) - { - String extra_message; - const QueryNode * query_node = scope.scope_node ? scope.scope_node->as() : nullptr; - if (settings.analyzer_compatibility_join_using_top_level_identifier && query_node) - { - for (const auto & projection_node : query_node->getProjection().getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name == projection_node->getAlias()) - { - extra_message = fmt::format( - ", but alias '{}' is present in SELECT list." - " You may try to SET analyzer_compatibility_join_using_top_level_identifier = 1, to allow to use it in USING clause", - projection_node->formatASTForErrorMessage()); - break; - } - } - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from left table expression{}. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - extra_message, - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_left_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from left table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto result_right_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getRightTableExpression(), scope); - if (!result_right_table_expression) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - if (result_right_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto expression_types = DataTypes{result_left_table_expression->getResultType(), result_right_table_expression->getResultType()}; - DataTypePtr common_type = tryGetLeastSupertype(expression_types); - - if (!common_type) - throw Exception(ErrorCodes::NO_COMMON_TYPE, - "JOIN {} cannot infer common type for {} and {} in USING for identifier '{}'. In scope {}", - join_node_typed.formatASTForErrorMessage(), - result_left_table_expression->getResultType()->getName(), - result_right_table_expression->getResultType()->getName(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - NameAndTypePair join_using_column(identifier_full_name, common_type); - ListNodePtr join_using_expression = std::make_shared(QueryTreeNodes{result_left_table_expression, result_right_table_expression}); - auto join_using_column_node = std::make_shared(std::move(join_using_column), std::move(join_using_expression), join_node); - join_using_node = std::move(join_using_column_node); - } - } -} - -/** Resolve query join tree. - * - * Query join tree must be initialized before calling this function. - */ -void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto from_node_type = join_tree_node->getNodeType(); - - switch (from_node_type) - { - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - resolveExpressionNode(join_tree_node, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - resolveTableFunction(join_tree_node, scope, expressions_visitor, false /*nested_table_function*/); - break; - } - case QueryTreeNodeType::TABLE: - { - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - resolveArrayJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::JOIN: - { - resolveJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::IDENTIFIER: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifiers in FROM section must be already resolved. Node {}, scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, ARRAY JOIN or JOIN. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - auto join_tree_node_type = join_tree_node->getNodeType(); - if (isTableExpressionNodeType(join_tree_node_type)) - { - validateTableExpressionModifiers(join_tree_node, scope); - initializeTableExpressionData(join_tree_node, scope); - - auto & query_node = scope.scope_node->as(); - auto & mutable_context = query_node.getMutableContext(); - - if (!mutable_context->isDistributed()) - { - bool is_distributed = false; - - if (auto * table_node = join_tree_node->as()) - is_distributed = table_node->getStorage()->isRemote(); - else if (auto * table_function_node = join_tree_node->as()) - is_distributed = table_function_node->getStorage()->isRemote(); - - mutable_context->setDistributed(is_distributed); - } - } - - auto add_table_expression_alias_into_scope = [&](const QueryTreeNodePtr & table_expression_node) - { - const auto & alias_name = table_expression_node->getAlias(); - if (alias_name.empty()) - return; - - auto [it, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(alias_name, table_expression_node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Duplicate aliases {} for table expressions in FROM section are not allowed. Try to register {}. Already registered {}.", - alias_name, - table_expression_node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage()); - }; - - add_table_expression_alias_into_scope(join_tree_node); - scope.table_expressions_in_resolve_process.erase(join_tree_node.get()); -} - -/** Resolve query. - * This function modifies query node during resolve. It is caller responsibility to clone query node before resolve - * if it is needed for later use. - * - * query_node - query_tree_node that must have QueryNode type. - * scope - query scope. It is caller responsibility to create it. - * - * Resolve steps: - * 1. Validate subqueries depth, perform GROUP BY validation that does not depend on information about aggregate functions. - * 2. Initialize query scope with aliases. - * 3. Register CTE subqueries from WITH section in scope and remove them from WITH section. - * 4. Resolve JOIN TREE. - * 5. Resolve projection columns. - * 6. Resolve expressions in other query parts. - * 7. Validate nodes with duplicate aliases. - * 8. Validate aggregate functions, GROUPING function, window functions. - * 9. Remove WITH and WINDOW sections from query. - * 10. Remove aliases from expression and lambda nodes. - * 11. Resolve query tree node with projection columns. - */ -void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope) -{ - size_t max_subquery_depth = scope.context->getSettingsRef().max_subquery_depth; - if (max_subquery_depth && scope.subquery_depth > max_subquery_depth) - throw Exception(ErrorCodes::TOO_DEEP_SUBQUERIES, - "Too deep subqueries. Maximum: {}", - max_subquery_depth); - - auto & query_node_typed = query_node->as(); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.insert(query_node_typed.getCTEName()); - - bool is_rollup_or_cube = query_node_typed.isGroupByWithRollup() || query_node_typed.isGroupByWithCube(); - - if (query_node_typed.isGroupByWithGroupingSets() - && query_node_typed.isGroupByWithTotals() - && query_node_typed.getGroupBy().getNodes().size() != 1) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and GROUPING SETS are not supported together"); - - if (query_node_typed.isGroupByWithGroupingSets() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "GROUPING SETS are not supported together with ROLLUP and CUBE"); - - if (query_node_typed.isGroupByWithRollup() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithCube())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "ROLLUP is not supported together with GROUPING SETS and CUBE"); - - if (query_node_typed.isGroupByWithCube() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithRollup())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "CUBE is not supported together with GROUPING SETS and ROLLUP"); - - if (query_node_typed.hasHaving() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of HAVING"); - - if (query_node_typed.hasQualify() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of QUALIFY"); - - /// Initialize aliases in query node scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - - if (query_node_typed.hasWith()) - visitor.visit(query_node_typed.getWithNode()); - - if (!query_node_typed.getProjection().getNodes().empty()) - visitor.visit(query_node_typed.getProjectionNode()); - - if (query_node_typed.getPrewhere()) - visitor.visit(query_node_typed.getPrewhere()); - - if (query_node_typed.getWhere()) - visitor.visit(query_node_typed.getWhere()); - - if (query_node_typed.hasGroupBy()) - visitor.visit(query_node_typed.getGroupByNode()); - - if (query_node_typed.hasHaving()) - visitor.visit(query_node_typed.getHaving()); - - if (query_node_typed.hasWindow()) - visitor.visit(query_node_typed.getWindowNode()); - - if (query_node_typed.hasQualify()) - visitor.visit(query_node_typed.getQualify()); - - if (query_node_typed.hasOrderBy()) - visitor.visit(query_node_typed.getOrderByNode()); - - if (query_node_typed.hasInterpolate()) - visitor.visit(query_node_typed.getInterpolate()); - - if (query_node_typed.hasLimitByLimit()) - visitor.visit(query_node_typed.getLimitByLimit()); - - if (query_node_typed.hasLimitByOffset()) - visitor.visit(query_node_typed.getLimitByOffset()); - - if (query_node_typed.hasLimitBy()) - visitor.visit(query_node_typed.getLimitByNode()); - - if (query_node_typed.hasLimit()) - visitor.visit(query_node_typed.getLimit()); - - if (query_node_typed.hasOffset()) - visitor.visit(query_node_typed.getOffset()); - - /// Register CTE subqueries and remove them from WITH section - - auto & with_nodes = query_node_typed.getWith().getNodes(); - - for (auto & node : with_nodes) - { - auto * subquery_node = node->as(); - auto * union_node = node->as(); - - bool subquery_is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - if (!subquery_is_cte) - continue; - - const auto & cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - auto [_, inserted] = scope.cte_name_to_query_node.emplace(cte_name, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "CTE with name {} already exists. In scope {}", - cte_name, - scope.scope_node->formatASTForErrorMessage()); - } - - /** WITH section can be safely removed, because WITH section only can provide aliases to query expressions - * and CTE for other sections to use. - * - * Example: WITH 1 AS constant, (x -> x + 1) AS lambda, a AS (SELECT * FROM test_table); - */ - query_node_typed.getWith().getNodes().clear(); - - for (auto & window_node : query_node_typed.getWindow().getNodes()) - { - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - if (!parent_window_name.empty()) - { - auto window_node_it = scope.window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope.window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - scope.scope_node->formatASTForErrorMessage()); - - mergeWindowWithParentWindow(window_node, window_node_it->second, scope); - window_node_typed.setParentWindowName({}); - } - - auto [_, inserted] = scope.window_name_to_window_node.emplace(window_node_typed.getAlias(), window_node); - if (!inserted) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' is already defined. In scope {}", - window_node_typed.getAlias(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** Disable identifier cache during JOIN TREE resolve. - * Depending on JOIN expression section, identifier with same name - * can be resolved in different columns. - * - * Example: SELECT id FROM test_table AS t1 INNER JOIN test_table AS t2 ON t1.id = t2.id INNER JOIN test_table AS t3 ON t1.id = t3.id - * In first join expression ON t1.id = t2.id t1.id is resolved into test_table.id column. - * In second join expression ON t1.id = t3.id t1.id must be resolved into test_table.id column after first JOIN. - */ - scope.use_identifier_lookup_to_result_cache = false; - - if (query_node_typed.getJoinTree()) - { - TableExpressionsAliasVisitor table_expressions_visitor(scope); - table_expressions_visitor.visit(query_node_typed.getJoinTree()); - - initializeQueryJoinTreeNode(query_node_typed.getJoinTree(), scope); - scope.aliases.alias_name_to_table_expression_node.clear(); - - resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor); - } - - if (!scope.group_by_use_nulls) - scope.use_identifier_lookup_to_result_cache = true; - - /// Resolve query node sections. - - NamesAndTypes projection_columns; - - if (!scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - if (auto & prewhere_node = query_node_typed.getPrewhere()) - { - resolveExpressionNode(prewhere_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** Expressions in PREWHERE with JOIN should not change their type. - * Example: SELECT * FROM t1 JOIN t2 USING (a) PREWHERE a = 1 - * Column `a` in PREWHERE should be resolved from the left table - * and should not change its type to Nullable or to the supertype of `a` from t1 and t2. - * Here's a more complicated example where the column is somewhere inside an expression: - * SELECT a + 1 as b FROM t1 JOIN t2 USING (id) PREWHERE b = 1 - * The expression `a + 1 as b` in the projection and in PREWHERE should have different `a`. - */ - prewhere_node = prewhere_node->clone(); - ReplaceColumnsVisitor replace_visitor(scope.join_columns_with_changed_types, scope.context); - replace_visitor.visit(prewhere_node); - } - - if (query_node_typed.getWhere()) - resolveExpressionNode(query_node_typed.getWhere(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasGroupBy()) - resolveGroupByNode(query_node_typed, scope); - - if (scope.group_by_use_nulls) - { - resolved_expressions.clear(); - /// Clone is needed cause aliases share subtrees. - /// If not clone, the same (shared) subtree could be resolved again with different (Nullable) type - /// See 03023_group_by_use_nulls_analyzer_crashes - for (auto & [key, node] : scope.aliases.alias_name_to_expression_node_before_group_by) - scope.aliases.alias_name_to_expression_node_after_group_by[key] = node->clone(); - - scope.aliases.alias_name_to_expression_node = &scope.aliases.alias_name_to_expression_node_after_group_by; - } - - if (query_node_typed.hasHaving()) - resolveExpressionNode(query_node_typed.getHaving(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasWindow()) - resolveWindowNodeList(query_node_typed.getWindowNode(), scope); - - if (query_node_typed.hasQualify()) - resolveExpressionNode(query_node_typed.getQualify(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasOrderBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getOrderByNode(), query_node_typed.getProjection().getNodes(), scope); - - const auto & settings = scope.context->getSettingsRef(); - - expandOrderByAll(query_node_typed, settings); - resolveSortNodeList(query_node_typed.getOrderByNode(), scope); - } - - if (query_node_typed.hasInterpolate()) - resolveInterpolateColumnsNodeList(query_node_typed.getInterpolate(), scope); - - if (query_node_typed.hasLimitByLimit()) - { - resolveExpressionNode(query_node_typed.getLimitByLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByLimit(), "LIMIT BY LIMIT", scope); - } - - if (query_node_typed.hasLimitByOffset()) - { - resolveExpressionNode(query_node_typed.getLimitByOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByOffset(), "LIMIT BY OFFSET", scope); - } - - if (query_node_typed.hasLimitBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getLimitByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getLimitByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - - if (query_node_typed.hasLimit()) - { - resolveExpressionNode(query_node_typed.getLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimit(), "LIMIT", scope); - } - - if (query_node_typed.hasOffset()) - { - resolveExpressionNode(query_node_typed.getOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getOffset(), "OFFSET", scope); - } - - if (scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - /** Resolve nodes with duplicate aliases. - * Table expressions cannot have duplicate aliases. - * - * Such nodes during scope aliases collection are placed into duplicated array. - * After scope nodes are resolved, we can compare node with duplicate alias with - * node from scope alias table. - */ - for (const auto & node_with_duplicated_alias : scope.aliases.cloned_nodes_with_duplicated_aliases) - { - auto node = node_with_duplicated_alias; - auto node_alias = node->getAlias(); - - /// Add current alias to non cached set, because in case of cyclic alias identifier should not be substituted from cache. - /// See 02896_cyclic_aliases_crash. - resolveExpressionNode(node, scope, true /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool has_node_in_alias_table = false; - - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - if (!has_node_in_alias_table) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node {} with duplicate alias {} does not exist in alias table. In scope {}", - node->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - - node->removeAlias(); - } - - expandGroupByAll(query_node_typed); - - validateFilters(query_node); - validateAggregates(query_node, { .group_by_use_nulls = scope.group_by_use_nulls }); - - for (const auto & column : projection_columns) - { - if (isNotCreatable(column.type)) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Invalid projection column with type {}. In scope {}", - column.type->getName(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** WINDOW section can be safely removed, because WINDOW section can only provide window definition to window functions. - * - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - */ - query_node_typed.getWindow().getNodes().clear(); - - /// Remove aliases from expression and lambda nodes - - for (auto & [_, node] : *scope.aliases.alias_name_to_expression_node) - node->removeAlias(); - - for (auto & [_, node] : scope.aliases.alias_name_to_lambda_node) - node->removeAlias(); - - query_node_typed.resolveProjectionColumns(std::move(projection_columns)); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.erase(query_node_typed.getCTEName()); -} - -void QueryAnalyzer::resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope) -{ - auto & union_node_typed = union_node->as(); - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.insert(union_node_typed.getCTEName()); - - auto & queries_nodes = union_node_typed.getQueries().getNodes(); - - std::optional recursive_cte_table; - TableNodePtr recursive_cte_table_node; - - if (union_node_typed.isCTE() && union_node_typed.isRecursiveCTE()) - { - auto & non_recursive_query = queries_nodes[0]; - bool non_recursive_query_is_query_node = non_recursive_query->getNodeType() == QueryTreeNodeType::QUERY; - auto & non_recursive_query_mutable_context = non_recursive_query_is_query_node ? non_recursive_query->as().getMutableContext() - : non_recursive_query->as().getMutableContext(); - - IdentifierResolveScope non_recursive_subquery_scope(non_recursive_query, &scope /*parent_scope*/); - non_recursive_subquery_scope.subquery_depth = scope.subquery_depth + 1; - - if (non_recursive_query_is_query_node) - resolveQuery(non_recursive_query, non_recursive_subquery_scope); - else - resolveUnion(non_recursive_query, non_recursive_subquery_scope); - - auto temporary_table_columns = non_recursive_query_is_query_node - ? non_recursive_query->as().getProjectionColumns() - : non_recursive_query->as().computeProjectionColumns(); - - auto temporary_table_holder = std::make_shared( - non_recursive_query_mutable_context, - ColumnsDescription{NamesAndTypesList{temporary_table_columns.begin(), temporary_table_columns.end()}}, - ConstraintsDescription{}, - nullptr /*query*/, - true /*create_for_global_subquery*/); - auto temporary_table_storage = temporary_table_holder->getTable(); - - recursive_cte_table_node = std::make_shared(temporary_table_storage, non_recursive_query_mutable_context); - recursive_cte_table_node->setTemporaryTableName(union_node_typed.getCTEName()); - - recursive_cte_table.emplace(std::move(temporary_table_holder), std::move(temporary_table_storage), std::move(temporary_table_columns)); - } - - size_t queries_nodes_size = queries_nodes.size(); - for (size_t i = recursive_cte_table.has_value(); i < queries_nodes_size; ++i) - { - auto & query_node = queries_nodes[i]; - - IdentifierResolveScope subquery_scope(query_node, &scope /*parent_scope*/); - - if (recursive_cte_table_node) - subquery_scope.expression_argument_name_to_node[union_node_typed.getCTEName()] = recursive_cte_table_node; - - auto query_node_type = query_node->getNodeType(); - - if (query_node_type == QueryTreeNodeType::QUERY) - { - resolveQuery(query_node, subquery_scope); - } - else if (query_node_type == QueryTreeNodeType::UNION) - { - resolveUnion(query_node, subquery_scope); - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "UNION unsupported node {}. In scope {}", - query_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (recursive_cte_table && isStorageUsedInTree(recursive_cte_table->storage, union_node.get())) - { - if (union_node_typed.getUnionMode() != SelectUnionMode::UNION_ALL) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive CTE subquery {} with {} union mode is unsupported, only UNION ALL union mode is supported", - union_node_typed.formatASTForErrorMessage(), - toString(union_node_typed.getUnionMode())); - - union_node_typed.setRecursiveCTETable(std::move(*recursive_cte_table)); - } - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.erase(union_node_typed.getCTEName()); -} - -} - -QueryAnalysisPass::QueryAnalysisPass(QueryTreeNodePtr table_expression_, bool only_analyze_) - : table_expression(std::move(table_expression_)) - , only_analyze(only_analyze_) -{} - -QueryAnalysisPass::QueryAnalysisPass(bool only_analyze_) : only_analyze(only_analyze_) {} - -void QueryAnalysisPass::run(QueryTreeNodePtr & query_tree_node, ContextPtr context) -{ - QueryAnalyzer analyzer(only_analyze); - analyzer.resolve(query_tree_node, table_expression, context); - createUniqueTableAliases(query_tree_node, table_expression, context); -} - } diff --git a/src/Analyzer/QueryAnalysis/QueryExpressionsAliasVisitor.h b/src/Analyzer/QueryAnalysis/QueryExpressionsAliasVisitor.h index 3fca66e6eb8..96c91ffab71 100644 --- a/src/Analyzer/QueryAnalysis/QueryExpressionsAliasVisitor.h +++ b/src/Analyzer/QueryAnalysis/QueryExpressionsAliasVisitor.h @@ -1,1043 +1,12 @@ -#include +#pragma once -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include - -namespace ProfileEvents -{ - extern const Event ScalarSubqueriesGlobalCacheHit; - extern const Event ScalarSubqueriesLocalCacheHit; - extern const Event ScalarSubqueriesCacheMiss; -} +#include +#include namespace DB { -namespace ErrorCodes -{ - extern const int UNSUPPORTED_METHOD; - extern const int UNKNOWN_IDENTIFIER; - extern const int UNKNOWN_FUNCTION; - extern const int LOGICAL_ERROR; - extern const int CYCLIC_ALIASES; - extern const int INCORRECT_RESULT_OF_SCALAR_SUBQUERY; - extern const int BAD_ARGUMENTS; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int MULTIPLE_EXPRESSIONS_FOR_ALIAS; - extern const int TYPE_MISMATCH; - extern const int AMBIGUOUS_IDENTIFIER; - extern const int INVALID_WITH_FILL_EXPRESSION; - extern const int INVALID_LIMIT_EXPRESSION; - extern const int EMPTY_LIST_OF_COLUMNS_QUERIED; - extern const int TOO_DEEP_SUBQUERIES; - extern const int UNKNOWN_AGGREGATE_FUNCTION; - extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION; - extern const int TOO_MANY_ARGUMENTS_FOR_FUNCTION; - extern const int ILLEGAL_FINAL; - extern const int SAMPLING_NOT_SUPPORTED; - extern const int NO_COMMON_TYPE; - extern const int NOT_IMPLEMENTED; - extern const int ALIAS_REQUIRED; - extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; - extern const int UNKNOWN_TABLE; - extern const int ILLEGAL_COLUMN; - extern const int NUMBER_OF_COLUMNS_DOESNT_MATCH; - extern const int FUNCTION_CANNOT_HAVE_PARAMETERS; - extern const int SYNTAX_ERROR; - extern const int UNEXPECTED_EXPRESSION; - extern const int INVALID_IDENTIFIER; -} - -/** Query analyzer implementation overview. Please check documentation in QueryAnalysisPass.h first. - * And additional documentation for each method, where special cases are described in detail. - * - * Each node in query must be resolved. For each query tree node resolved state is specific. - * - * For constant node no resolve process exists, it is resolved during construction. - * - * For table node no resolve process exists, it is resolved during construction. - * - * For function node to be resolved parameters and arguments must be resolved, function node must be initialized with concrete aggregate or - * non aggregate function and with result type. - * - * For lambda node there can be 2 different cases. - * 1. Standalone: WITH (x -> x + 1) AS lambda SELECT lambda(1); Such lambdas are inlined in query tree during query analysis pass. - * 2. Function arguments: WITH (x -> x + 1) AS lambda SELECT arrayMap(lambda, [1, 2, 3]); For such lambda resolution must - * set concrete lambda arguments (initially they are identifier nodes) and resolve lambda expression body. - * - * For query node resolve process must resolve all its inner nodes. - * - * For matcher node resolve process must replace it with matched nodes. - * - * For identifier node resolve process must replace it with concrete non identifier node. This part is most complex because - * for identifier resolution scopes and identifier lookup context play important part. - * - * ClickHouse SQL support lexical scoping for identifier resolution. Scope can be defined by query node or by expression node. - * Expression nodes that can define scope are lambdas and table ALIAS columns. - * - * Identifier lookup context can be expression, function, table. - * - * Examples: WITH (x -> x + 1) as func SELECT func() FROM func; During function `func` resolution identifier lookup is performed - * in function context. - * - * If there are no information of identifier context rules are following: - * 1. Try to resolve identifier in expression context. - * 2. Try to resolve identifier in function context, if it is allowed. Example: SELECT func(arguments); Here func identifier cannot be resolved in function context - * because query projection does not support that. - * 3. Try to resolve identifier in table context, if it is allowed. Example: SELECT table; Here table identifier cannot be resolved in function context - * because query projection does not support that. - * - * TODO: This does not supported properly before, because matchers could not be resolved from aliases. - * - * Identifiers are resolved with following rules: - * Resolution starts with current scope. - * 1. Try to resolve identifier from expression scope arguments. Lambda expression arguments are greatest priority. - * 2. Try to resolve identifier from aliases. - * 3. Try to resolve identifier from join tree if scope is query, or if there are registered table columns in scope. - * Steps 2 and 3 can be changed using prefer_column_name_to_alias setting. - * 4. If it is table lookup, try to resolve identifier from CTE. - * If identifier could not be resolved in current scope, resolution must be continued in parent scopes. - * 5. Try to resolve identifier from parent scopes. - * - * Additional rules about aliases and scopes. - * 1. Parent scope cannot refer alias from child scope. - * 2. Child scope can refer to alias in parent scope. - * - * Example: SELECT arrayMap(x -> x + 1 AS a, [1,2,3]), a; Identifier a is unknown in parent scope. - * Example: SELECT a FROM (SELECT 1 as a); Here we do not refer to alias a from child query scope. But we query it projection result, similar to tables. - * Example: WITH 1 as a SELECT (SELECT a) as b; Here in child scope identifier a is resolved using alias from parent scope. - * - * Additional rules about identifier binding. - * Bind for identifier to entity means that identifier first part match some node during analysis. - * If other parts of identifier cannot be resolved in that node, exception must be thrown. - * - * Example: - * CREATE TABLE test_table (id UInt64, compound_value Tuple(value UInt64)) ENGINE=TinyLog; - * SELECT compound_value.value, 1 AS compound_value FROM test_table; - * Identifier first part compound_value bound to entity with alias compound_value, but nested identifier part cannot be resolved from entity, - * lookup should not be continued, and exception must be thrown because if lookup continues that way identifier can be resolved from join tree. - * - * TODO: This was not supported properly before analyzer because nested identifier could not be resolved from alias. - * - * More complex example: - * CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; - * WITH cast(('Value'), 'Tuple (value UInt64') AS value SELECT (SELECT value FROM test_table); - * Identifier first part value bound to test_table column value, but nested identifier part cannot be resolved from it, - * lookup should not be continued, and exception must be thrown because if lookup continues identifier can be resolved from parent scope. - * - * TODO: Update exception messages - * TODO: Table identifiers with optional UUID. - * TODO: Lookup functions arrayReduce(sum, [1, 2, 3]); - * TODO: Support function identifier resolve from parent query scope, if lambda in parent scope does not capture any columns. - */ - -namespace -{ - -/// Identifier lookup context -enum class IdentifierLookupContext : uint8_t -{ - EXPRESSION = 0, - FUNCTION, - TABLE_EXPRESSION, -}; - -const char * toString(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "EXPRESSION"; - case IdentifierLookupContext::FUNCTION: return "FUNCTION"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "TABLE_EXPRESSION"; - } -} - -const char * toStringLowercase(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "expression"; - case IdentifierLookupContext::FUNCTION: return "function"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "table expression"; - } -} - -/** Structure that represent identifier lookup during query analysis. - * Lookup can be in query expression, function, table context. - */ -struct IdentifierLookup -{ - Identifier identifier; - IdentifierLookupContext lookup_context; - - bool isExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::EXPRESSION; - } - - bool isFunctionLookup() const - { - return lookup_context == IdentifierLookupContext::FUNCTION; - } - - bool isTableExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::TABLE_EXPRESSION; - } - - String dump() const - { - return identifier.getFullName() + ' ' + toString(lookup_context); - } -}; - -inline bool operator==(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return lhs.identifier.getFullName() == rhs.identifier.getFullName() && lhs.lookup_context == rhs.lookup_context; -} - -[[maybe_unused]] inline bool operator!=(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return !(lhs == rhs); -} - -struct IdentifierLookupHash -{ - size_t operator()(const IdentifierLookup & identifier_lookup) const - { - return std::hash()(identifier_lookup.identifier.getFullName()) ^ static_cast(identifier_lookup.lookup_context); - } -}; - -enum class IdentifierResolvePlace : UInt8 -{ - NONE = 0, - EXPRESSION_ARGUMENTS, - ALIASES, - JOIN_TREE, - /// Valid only for table lookup - CTE, - /// Valid only for table lookup - DATABASE_CATALOG -}; - -const char * toString(IdentifierResolvePlace resolved_identifier_place) -{ - switch (resolved_identifier_place) - { - case IdentifierResolvePlace::NONE: return "NONE"; - case IdentifierResolvePlace::EXPRESSION_ARGUMENTS: return "EXPRESSION_ARGUMENTS"; - case IdentifierResolvePlace::ALIASES: return "ALIASES"; - case IdentifierResolvePlace::JOIN_TREE: return "JOIN_TREE"; - case IdentifierResolvePlace::CTE: return "CTE"; - case IdentifierResolvePlace::DATABASE_CATALOG: return "DATABASE_CATALOG"; - } -} - -struct IdentifierResolveResult -{ - IdentifierResolveResult() = default; - - QueryTreeNodePtr resolved_identifier; - IdentifierResolvePlace resolve_place = IdentifierResolvePlace::NONE; - bool resolved_from_parent_scopes = false; - - [[maybe_unused]] bool isResolved() const - { - return resolve_place != IdentifierResolvePlace::NONE; - } - - [[maybe_unused]] bool isResolvedFromParentScopes() const - { - return resolved_from_parent_scopes; - } - - [[maybe_unused]] bool isResolvedFromExpressionArguments() const - { - return resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - } - - [[maybe_unused]] bool isResolvedFromAliases() const - { - return resolve_place == IdentifierResolvePlace::ALIASES; - } - - [[maybe_unused]] bool isResolvedFromJoinTree() const - { - return resolve_place == IdentifierResolvePlace::JOIN_TREE; - } - - [[maybe_unused]] bool isResolvedFromCTEs() const - { - return resolve_place == IdentifierResolvePlace::CTE; - } - - void dump(WriteBuffer & buffer) const - { - if (!resolved_identifier) - { - buffer << "unresolved"; - return; - } - - buffer << resolved_identifier->formatASTForErrorMessage() << " place " << toString(resolve_place) << " resolved from parent scopes " << resolved_from_parent_scopes; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -struct IdentifierResolveState -{ - IdentifierResolveResult resolve_result; - bool cyclic_identifier_resolve = false; -}; - -struct IdentifierResolveSettings -{ - /// Allow to check join tree during identifier resolution - bool allow_to_check_join_tree = true; - - /// Allow to check CTEs during table identifier resolution - bool allow_to_check_cte = true; - - /// Allow to check parent scopes during identifier resolution - bool allow_to_check_parent_scopes = true; - - /// Allow to check database catalog during table identifier resolution - bool allow_to_check_database_catalog = true; - - /// Allow to resolve subquery during identifier resolution - bool allow_to_resolve_subquery_during_identifier_resolution = true; -}; - -struct StringTransparentHash -{ - using is_transparent = void; - using hash = std::hash; - - [[maybe_unused]] size_t operator()(const char * data) const - { - return hash()(data); - } - - size_t operator()(std::string_view data) const - { - return hash()(data); - } - - size_t operator()(const std::string & data) const - { - return hash()(data); - } -}; - -using ColumnNameToColumnNodeMap = std::unordered_map>; - -struct TableExpressionData -{ - std::string table_expression_name; - std::string table_expression_description; - std::string database_name; - std::string table_name; - bool should_qualify_columns = true; - NamesAndTypes column_names_and_types; - ColumnNameToColumnNodeMap column_name_to_column_node; - std::unordered_set subcolumn_names; /// Subset columns that are subcolumns of other columns - std::unordered_set> column_identifier_first_parts; - - bool hasFullIdentifierName(IdentifierView identifier_view) const - { - return column_name_to_column_node.contains(identifier_view.getFullName()); - } - - bool canBindIdentifier(IdentifierView identifier_view) const - { - return column_identifier_first_parts.contains(identifier_view.at(0)); - } - - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Table expression name " << table_expression_name; - - if (!table_expression_description.empty()) - buffer << " table expression description " << table_expression_description; - - if (!database_name.empty()) - buffer << " database name " << database_name; - - if (!table_name.empty()) - buffer << " table name " << table_name; - - buffer << " should qualify columns " << should_qualify_columns; - buffer << " columns size " << column_name_to_column_node.size() << '\n'; - - for (const auto & [column_name, column_node] : column_name_to_column_node) - buffer << "Column name " << column_name << " column node " << column_node->dumpTree() << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -class ExpressionsStack -{ -public: - void push(const QueryTreeNodePtr & node) - { - if (node->hasAlias()) - { - const auto & node_alias = node->getAlias(); - alias_name_to_expressions[node_alias].push_back(node); - } - - if (const auto * function = node->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - ++aggregate_functions_counter; - } - - expressions.emplace_back(node); - } - - void pop() - { - const auto & top_expression = expressions.back(); - const auto & top_expression_alias = top_expression->getAlias(); - - if (!top_expression_alias.empty()) - { - auto it = alias_name_to_expressions.find(top_expression_alias); - auto & alias_expressions = it->second; - alias_expressions.pop_back(); - - if (alias_expressions.empty()) - alias_name_to_expressions.erase(it); - } - - if (const auto * function = top_expression->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - --aggregate_functions_counter; - } - - expressions.pop_back(); - } - - [[maybe_unused]] const QueryTreeNodePtr & getRoot() const - { - return expressions.front(); - } - - const QueryTreeNodePtr & getTop() const - { - return expressions.back(); - } - - [[maybe_unused]] bool hasExpressionWithAlias(const std::string & alias) const - { - return alias_name_to_expressions.contains(alias); - } - - bool hasAggregateFunction() const - { - return aggregate_functions_counter > 0; - } - - QueryTreeNodePtr getExpressionWithAlias(const std::string & alias) const - { - auto expression_it = alias_name_to_expressions.find(alias); - if (expression_it == alias_name_to_expressions.end()) - return {}; - - return expression_it->second.front(); - } - - [[maybe_unused]] size_t size() const - { - return expressions.size(); - } - - bool empty() const - { - return expressions.empty(); - } - - void dump(WriteBuffer & buffer) const - { - buffer << expressions.size() << '\n'; - - for (const auto & expression : expressions) - { - buffer << "Expression "; - buffer << expression->formatASTForErrorMessage(); - - const auto & alias = expression->getAlias(); - if (!alias.empty()) - buffer << " alias " << alias; - - buffer << '\n'; - } - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } - -private: - QueryTreeNodes expressions; - size_t aggregate_functions_counter = 0; - std::unordered_map alias_name_to_expressions; -}; - -struct ScopeAliases -{ - /// Alias name to query expression node - std::unordered_map alias_name_to_expression_node_before_group_by; - std::unordered_map alias_name_to_expression_node_after_group_by; - - std::unordered_map * alias_name_to_expression_node = nullptr; - - /// Alias name to lambda node - std::unordered_map alias_name_to_lambda_node; - - /// Alias name to table expression node - std::unordered_map alias_name_to_table_expression_node; - - /// Expressions like `x as y` where we can't say whether it's a function, expression or table. - std::unordered_map transitive_aliases; - - /// Nodes with duplicated aliases - std::unordered_set nodes_with_duplicated_aliases; - std::vector cloned_nodes_with_duplicated_aliases; - - /// Names which are aliases from ARRAY JOIN. - /// This is needed to properly qualify columns from matchers and avoid name collision. - std::unordered_set array_join_aliases; - - std::unordered_map & getAliasMap(IdentifierLookupContext lookup_context) - { - switch (lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return *alias_name_to_expression_node; - case IdentifierLookupContext::FUNCTION: return alias_name_to_lambda_node; - case IdentifierLookupContext::TABLE_EXPRESSION: return alias_name_to_table_expression_node; - } - } - - enum class FindOption - { - FIRST_NAME, - FULL_NAME, - }; - - const std::string & getKey(const Identifier & identifier, FindOption find_option) - { - switch (find_option) - { - case FindOption::FIRST_NAME: return identifier.front(); - case FindOption::FULL_NAME: return identifier.getFullName(); - } - } - - QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) - { - auto & alias_map = getAliasMap(lookup.lookup_context); - const std::string * key = &getKey(lookup.identifier, find_option); - - auto it = alias_map.find(*key); - - if (it != alias_map.end()) - return &it->second; - - if (lookup.lookup_context == IdentifierLookupContext::TABLE_EXPRESSION) - return {}; - - while (it == alias_map.end()) - { - auto jt = transitive_aliases.find(*key); - if (jt == transitive_aliases.end()) - return {}; - - key = &(getKey(jt->second, find_option)); - it = alias_map.find(*key); - } - - return &it->second; - } - - const QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) const - { - return const_cast(this)->find(lookup, find_option); - } -}; - - -/** Projection names is name of query tree node that is used in projection part of query node. - * Example: SELECT id FROM test_table; - * `id` is projection name of column node - * - * Example: SELECT id AS id_alias FROM test_table; - * `id_alias` is projection name of column node - * - * Calculation of projection names is done during expression nodes resolution. This is done this way - * because after identifier node is resolved we lose information about identifier name. We could - * potentially save this information in query tree node itself, but that would require to clone it in some cases. - * Example: SELECT big_scalar_subquery AS a, a AS b, b AS c; - * All 3 nodes in projection are the same big_scalar_subquery, but they have different projection names. - * If we want to save it in query tree node, we have to clone subquery node that could lead to performance degradation. - * - * Possible solution is to separate query node metadata and query node content. So only node metadata could be cloned - * if we want to change projection name. This solution does not seem to be easy for client of query tree because projection - * name will be part of interface. If we potentially could hide projection names calculation in analyzer without introducing additional - * changes in query tree structure that would be preferable. - * - * Currently each resolve method returns projection names array. Resolve method must compute projection names of node. - * If node is resolved as list node this is case for `untuple` function or `matcher` result projection names array must contain projection names - * for result nodes. - * If node is not resolved as list node, projection names array contain single projection name for node. - * - * Rules for projection names: - * 1. If node has alias. It is node projection name. - * Except scenario where `untuple` function has alias. Example: SELECT untuple(expr) AS alias, alias. - * - * 2. For constant it is constant value string representation. - * - * 3. For identifier: - * If identifier is resolved from JOIN TREE, we want to remove additional identifier qualifications. - * Example: SELECT default.test_table.id FROM test_table. - * Result projection name is `id`. - * - * Example: SELECT t1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In example both test_table_1, test_table_2 have `id` column. - * In such case projection name is `t1.id` because if additional qualification is removed then column projection name `id` will be ambiguous. - * - * Example: SELECT default.test_table_1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In such case projection name is `test_table_1.id` because we remove unnecessary database qualification, but table name qualification cannot be removed - * because otherwise column projection name `id` will be ambiguous. - * - * If identifier is not resolved from JOIN TREE. Identifier name is projection name. - * Except scenario where `untuple` function resolved using identifier. Example: SELECT untuple(expr) AS alias, alias. - * Example: SELECT sum(1, 1) AS value, value. - * In such case both nodes have `value` projection names. - * - * Example: SELECT id AS value, value FROM test_table. - * In such case both nodes have have `value` projection names. - * - * Special case is `untuple` function. If `untuple` function specified with alias, then result nodes will have alias.tuple_column_name projection names. - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value) AS a; - * Result projection names are `value`, `a.id`. - * - * If `untuple` function does not have alias then result nodes will have `tupleElement(untuple_expression_projection_name, 'tuple_column_name') projection names. - * - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value); - * Result projection names are `value`, `tupleElement(value, 'id')`; - * - * 4. For function: - * Projection name consists from function_name(parameters_projection_names)(arguments_projection_names). - * Additionally if function is window function. Window node projection name is used with OVER clause. - * Example: function_name (parameters_names)(argument_projection_names) OVER window_name; - * Example: function_name (parameters_names)(argument_projection_names) OVER (PARTITION BY id ORDER BY id). - * Example: function_name (parameters_names)(argument_projection_names) OVER (window_name ORDER BY id). - * - * 5. For lambda: - * If it is standalone lambda that returns single expression, function projection name is used. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(1). - * Projection name is `lambda(1)`. - * - * If is it standalone lambda that returns list, projection names of list nodes are used. - * Example: WITH (x -> *) AS lambda SELECT lambda(1) FROM test_table; - * If test_table has two columns `id`, `value`. Then result projection names are `id`, `value`. - * - * If lambda is argument of function. - * Then projection name consists from lambda(tuple(lambda_arguments)(lambda_body_projection_name)); - * - * 6. For matcher: - * Matched nodes projection names are used as matcher projection names. - * - * Matched nodes must be qualified if needed. - * Example: SELECT * FROM test_table_1 AS t1, test_table_2 AS t2. - * In example table test_table_1 and test_table_2 both have `id`, `value` columns. - * Matched nodes after unqualified matcher resolve must be qualified to avoid ambiguous projection names. - * Result projection names must be `t1.id`, `t1.value`, `t2.id`, `t2.value`. - * - * There are special cases - * 1. For lambda inside APPLY matcher transformer: - * Example: SELECT * APPLY x -> toString(x) FROM test_table. - * In such case lambda argument projection name `x` will be replaced by matched node projection name. - * If table has two columns `id` and `value`. Then result projection names are `toString(id)`, `toString(value)`; - * - * 2. For unqualified matcher when JOIN tree contains JOIN with USING. - * Example: SELECT * FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING(id); - * Result projection names must be `id`, `t1.value`, `t2.value`. - * - * 7. For subquery: - * For subquery projection name consists of `_subquery_` prefix and implementation specific unique number suffix. - * Example: SELECT (SELECT 1), (SELECT 1 UNION DISTINCT SELECT 1); - * Result projection name can be `_subquery_1`, `subquery_2`; - * - * 8. For table: - * Table node can be used in expression context only as right argument of IN function. In that case identifier is used - * as table node projection name. - * Example: SELECT id IN test_table FROM test_table; - * Result projection name is `in(id, test_table)`. - */ -using ProjectionName = String; -using ProjectionNames = std::vector; -constexpr auto PROJECTION_NAME_PLACEHOLDER = "__projection_name_placeholder"; - -struct IdentifierResolveScope -{ - /// Construct identifier resolve scope using scope node, and parent scope - IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) - : scope_node(std::move(scope_node_)) - , parent_scope(parent_scope_) - { - if (parent_scope) - { - subquery_depth = parent_scope->subquery_depth; - context = parent_scope->context; - projection_mask_map = parent_scope->projection_mask_map; - } - else - projection_mask_map = std::make_shared>(); - - if (auto * union_node = scope_node->as()) - { - context = union_node->getContext(); - } - else if (auto * query_node = scope_node->as()) - { - context = query_node->getContext(); - group_by_use_nulls = context->getSettingsRef().group_by_use_nulls && - (query_node->isGroupByWithGroupingSets() || query_node->isGroupByWithRollup() || query_node->isGroupByWithCube()); - } - - if (context) - join_use_nulls = context->getSettingsRef().join_use_nulls; - else if (parent_scope) - join_use_nulls = parent_scope->join_use_nulls; - - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - QueryTreeNodePtr scope_node; - - IdentifierResolveScope * parent_scope = nullptr; - - ContextPtr context; - - /// Identifier lookup to result - std::unordered_map identifier_lookup_to_resolve_state; - - /// Argument can be expression like constant, column, function or table expression - std::unordered_map expression_argument_name_to_node; - - ScopeAliases aliases; - - /// Table column name to column node. Valid only during table ALIAS columns resolve. - ColumnNameToColumnNodeMap column_name_to_column_node; - - /// CTE name to query node - std::unordered_map cte_name_to_query_node; - - /// Window name to window node - std::unordered_map window_name_to_window_node; - - /// Current scope expression in resolve process stack - ExpressionsStack expressions_in_resolve_process_stack; - - /// Table expressions in resolve process - std::unordered_set table_expressions_in_resolve_process; - - /// Current scope expression - std::unordered_set non_cached_identifier_lookups_during_expression_resolve; - - /// Table expression node to data - std::unordered_map table_expression_node_to_data; - - QueryTreeNodePtrWithHashIgnoreTypesSet nullable_group_by_keys; - /// Here we count the number of nullable GROUP BY keys we met resolving expression. - /// E.g. for a query `SELECT tuple(tuple(number)) FROM numbers(10) GROUP BY (number, tuple(number)) with cube` - /// both `number` and `tuple(number)` would be in nullable_group_by_keys. - /// But when we resolve `tuple(tuple(number))` we should figure out that `tuple(number)` is already a key, - /// and we should not convert `number` to nullable. - size_t found_nullable_group_by_key_in_scope = 0; - - /** It's possible that after a JOIN, a column in the projection has a type different from the column in the source table. - * (For example, after join_use_nulls or USING column casted to supertype) - * However, the column in the projection still refers to the table as its source. - * This map is used to revert these columns back to their original columns in the source table. - */ - QueryTreeNodePtrWithHashMap join_columns_with_changed_types; - - /// Use identifier lookup to result cache - bool use_identifier_lookup_to_result_cache = true; - - /// Apply nullability to aggregation keys - bool group_by_use_nulls = false; - /// Join retutns NULLs instead of default values - bool join_use_nulls = false; - - /// JOINs count - size_t joins_count = 0; - - /// Subquery depth - size_t subquery_depth = 0; - - /** Scope join tree node for expression. - * Valid only during analysis construction for single expression. - */ - QueryTreeNodePtr expression_join_tree_node; - - /// Node hash to mask id map - std::shared_ptr> projection_mask_map; - - struct ResolvedFunctionsCache - { - FunctionOverloadResolverPtr resolver; - FunctionBasePtr function_base; - }; - - std::map functions_cache; - - [[maybe_unused]] const IdentifierResolveScope * getNearestQueryScope() const - { - const IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - IdentifierResolveScope * getNearestQueryScope() - { - IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - const TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - void pushExpressionNode(const QueryTreeNodePtr & node) - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.push(node); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - void popExpressionNode() - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.pop(); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_after_group_by; - } - - /// Dump identifier resolve scope - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Scope node " << scope_node->formatASTForErrorMessage() << '\n'; - buffer << "Identifier lookup to resolve state " << identifier_lookup_to_resolve_state.size() << '\n'; - for (const auto & [identifier, state] : identifier_lookup_to_resolve_state) - { - buffer << "Identifier " << identifier.dump() << " resolve result "; - state.resolve_result.dump(buffer); - buffer << '\n'; - } - - buffer << "Expression argument name to node " << expression_argument_name_to_node.size() << '\n'; - for (const auto & [alias_name, node] : expression_argument_name_to_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to expression node table size " << aliases.alias_name_to_expression_node->size() << '\n'; - for (const auto & [alias_name, node] : *aliases.alias_name_to_expression_node) - buffer << "Alias name " << alias_name << " expression node " << node->dumpTree() << '\n'; - - buffer << "Alias name to function node table size " << aliases.alias_name_to_lambda_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_lambda_node) - buffer << "Alias name " << alias_name << " lambda node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to table expression node table size " << aliases.alias_name_to_table_expression_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_table_expression_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "CTE name to query node table size " << cte_name_to_query_node.size() << '\n'; - for (const auto & [cte_name, node] : cte_name_to_query_node) - buffer << "CTE name " << cte_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "WINDOW name to window node table size " << window_name_to_window_node.size() << '\n'; - for (const auto & [window_name, node] : window_name_to_window_node) - buffer << "CTE name " << window_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Nodes with duplicated aliases size " << aliases.nodes_with_duplicated_aliases.size() << '\n'; - for (const auto & node : aliases.nodes_with_duplicated_aliases) - buffer << "Alias name " << node->getAlias() << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Expression resolve process stack " << '\n'; - expressions_in_resolve_process_stack.dump(buffer); - - buffer << "Table expressions in resolve process size " << table_expressions_in_resolve_process.size() << '\n'; - for (const auto & node : table_expressions_in_resolve_process) - buffer << "Table expression " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Non cached identifier lookups during expression resolve " << non_cached_identifier_lookups_during_expression_resolve.size() << '\n'; - for (const auto & identifier_lookup : non_cached_identifier_lookups_during_expression_resolve) - buffer << "Identifier lookup " << identifier_lookup.dump() << '\n'; - - buffer << "Table expression node to data " << table_expression_node_to_data.size() << '\n'; - for (const auto & [table_expression_node, table_expression_data] : table_expression_node_to_data) - buffer << "Table expression node " << table_expression_node->formatASTForErrorMessage() << " data " << table_expression_data.dump() << '\n'; - - buffer << "Use identifier lookup to result cache " << use_identifier_lookup_to_result_cache << '\n'; - buffer << "Subquery depth " << subquery_depth << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - - /** Visitor that extracts expression and function aliases from node and initialize scope tables with it. * Does not go into child lambdas and queries. * @@ -1147,7333 +116,4 @@ private: ScopeAliases & aliases; }; -class TableExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit TableExpressionsAliasVisitor(IdentifierResolveScope & scope_) - : scope(scope_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node); - } - - static bool needChildVisit(const QueryTreeNodePtr & node, const QueryTreeNodePtr & child) - { - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::ARRAY_JOIN: - { - const auto & array_join_node = node->as(); - return child.get() == array_join_node.getTableExpression().get(); - } - case QueryTreeNodeType::JOIN: - { - const auto & join_node = node->as(); - return child.get() == join_node.getLeftTableExpression().get() || child.get() == join_node.getRightTableExpression().get(); - } - default: - { - break; - } - } - - return false; - } - -private: - void updateAliasesIfNeeded(const QueryTreeNodePtr & node) - { - if (!node->hasAlias()) - return; - - const auto & node_alias = node->getAlias(); - auto [_, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(node_alias, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple table expressions with same alias {}. In scope {}", - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - IdentifierResolveScope & scope; -}; - -class QueryAnalyzer -{ -public: - explicit QueryAnalyzer(bool only_analyze_) : only_analyze(only_analyze_) {} - - void resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context) - { - IdentifierResolveScope scope(node, nullptr /*parent_scope*/); - - if (!scope.context) - scope.context = context; - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::QUERY: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For query analysis table expression must be empty"); - - resolveQuery(node, scope); - break; - } - case QueryTreeNodeType::UNION: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For union analysis table expression must be empty"); - - resolveUnion(node, scope); - break; - } - case QueryTreeNodeType::IDENTIFIER: - [[fallthrough]]; - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - [[fallthrough]]; - case QueryTreeNodeType::FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::LIST: - { - if (table_expression) - { - scope.expression_join_tree_node = table_expression; - validateTableExpressionModifiers(scope.expression_join_tree_node, scope); - initializeTableExpressionData(scope.expression_join_tree_node, scope); - } - - if (node_type == QueryTreeNodeType::LIST) - resolveExpressionNodeList(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - else - resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - QueryExpressionsAliasVisitor expressions_alias_visitor(scope.aliases); - resolveTableFunction(node, scope, expressions_alias_visitor, false /*nested_table_function*/); - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Node {} with type {} is not supported by query analyzer. " - "Supported nodes are query, union, identifier, constant, column, function, list.", - node->formatASTForErrorMessage(), - node->getNodeTypeName()); - } - } - } - -private: - /// Utility functions - - static bool isExpressionNodeType(QueryTreeNodeType node_type); - - static bool isFunctionExpressionNodeType(QueryTreeNodeType node_type); - - static bool isSubqueryNodeType(QueryTreeNodeType node_type); - - static bool isTableExpressionNodeType(QueryTreeNodeType node_type); - - static DataTypePtr getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node); - - static ProjectionName calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, - const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names); - - static ProjectionName calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name); - - static ProjectionName calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, - const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, - const ProjectionName & fill_to_expression_projection_name, - const ProjectionName & fill_step_expression_projection_name); - - static void collectCompoundExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result); - - static void collectTableExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result); - - static void collectScopeValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static void collectScopeWithParentScopesValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static std::vector collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers); - - static QueryTreeNodePtr wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path); - - QueryTreeNodePtr tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context); - - void evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & query_tree_node, IdentifierResolveScope & scope); - - static void mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope); - - void replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope); - - static void convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope); - - static void validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope); - - static std::pair recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into); - - static void expandGroupByAll(QueryNode & query_tree_node_typed); - - void expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings); - - static std::string - rewriteAggregateFunctionNameIfNeeded(const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context); - - static std::optional getColumnSideFromJoinTree(const QueryTreeNodePtr & resolved_identifier, const JoinNode & join_node) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - return {}; - - if (resolved_identifier->getNodeType() == QueryTreeNodeType::FUNCTION) - { - const auto & resolved_function = resolved_identifier->as(); - - const auto & argument_nodes = resolved_function.getArguments().getNodes(); - - std::optional result; - for (const auto & argument_node : argument_nodes) - { - auto table_side = getColumnSideFromJoinTree(argument_node, join_node); - if (table_side && result && *table_side != *result) - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Ambiguous identifier {}. In scope {}", - resolved_identifier->formatASTForErrorMessage(), - join_node.formatASTForErrorMessage()); - } - result = table_side; - } - return result; - } - - const auto * column_src = resolved_identifier->as().getColumnSource().get(); - - if (join_node.getLeftTableExpression().get() == column_src) - return JoinTableSide::Left; - if (join_node.getRightTableExpression().get() == column_src) - return JoinTableSide::Right; - return {}; - } - - static QueryTreeNodePtr convertJoinedColumnTypeToNullIfNeeded( - const QueryTreeNodePtr & resolved_identifier, - const JoinKind & join_kind, - std::optional resolved_side, - IdentifierResolveScope & scope) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && - JoinCommon::canBecomeNullable(resolved_identifier->getResultType()) && - (isFull(join_kind) || - (isLeft(join_kind) && resolved_side && *resolved_side == JoinTableSide::Right) || - (isRight(join_kind) && resolved_side && *resolved_side == JoinTableSide::Left))) - { - auto nullable_resolved_identifier = resolved_identifier->clone(); - auto & resolved_column = nullable_resolved_identifier->as(); - auto new_result_type = makeNullableOrLowCardinalityNullable(resolved_column.getColumnType()); - resolved_column.setColumnType(new_result_type); - if (resolved_column.hasExpression()) - { - auto & resolved_expression = resolved_column.getExpression(); - if (!resolved_expression->getResultType()->equals(*new_result_type)) - resolved_expression = buildCastFunction(resolved_expression, new_result_type, scope.context, true); - } - if (!nullable_resolved_identifier->isEqual(*resolved_identifier)) - scope.join_columns_with_changed_types[nullable_resolved_identifier] = resolved_identifier; - return nullable_resolved_identifier; - } - return nullptr; - } - - /// Resolve identifier functions - - static QueryTreeNodePtr tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context); - - QueryTreeNodePtr tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found = false); - - QueryTreeNodePtr tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings); - - QueryTreeNodePtr tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings = {}); - - QueryTreeNodePtr tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found = false); - - /// Resolve query tree nodes functions - - void qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static GetColumnsOptions buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context); - - using QueryTreeNodesWithNames = std::vector>; - - QueryTreeNodesWithNames getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope); - - void updateMatchedColumnsFromJoinUsing(QueryTreeNodesWithNames & result_matched_column_nodes_with_names, const QueryTreeNodePtr & source_table_expression, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionNames resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionName resolveWindow(QueryTreeNodePtr & window_node, IdentifierResolveScope & scope); - - ProjectionNames resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope); - - ProjectionNames resolveFunction(QueryTreeNodePtr & function_node, IdentifierResolveScope & scope); - - ProjectionNames resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias = false); - - ProjectionNames resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression); - - ProjectionNames resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope); - - void resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope); - - void resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope); - - void resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope); - - NamesAndTypes resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope); - - void initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope); - - void initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - void resolveTableFunction(QueryTreeNodePtr & table_function_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, bool nested_table_function); - - void resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope); - - void resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope); - - /// Lambdas that are currently in resolve process - std::unordered_set lambdas_in_resolve_process; - - /// CTEs that are currently in resolve process - std::unordered_set ctes_in_resolve_process; - - /// Function name to user defined lambda map - std::unordered_map function_name_to_user_defined_lambda; - - /// Array join expressions counter - size_t array_join_expressions_counter = 1; - - /// Subquery counter - size_t subquery_counter = 1; - - /// Global expression node to projection name map - std::unordered_map node_to_projection_name; - - /// Global resolve expression node to projection names map - std::unordered_map resolved_expressions; - - /// Global resolve expression node to tree size - std::unordered_map node_to_tree_size; - - /// Global scalar subquery to scalar value map - std::unordered_map scalar_subquery_to_scalar_value_local; - std::unordered_map scalar_subquery_to_scalar_value_global; - - const bool only_analyze; -}; - -/// Utility functions implementation - - -bool QueryAnalyzer::isExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::CONSTANT || node_type == QueryTreeNodeType::COLUMN || node_type == QueryTreeNodeType::FUNCTION - || node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isFunctionExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::LAMBDA; -} - -bool QueryAnalyzer::isSubqueryNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isTableExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::TABLE || node_type == QueryTreeNodeType::TABLE_FUNCTION || - isSubqueryNodeType(node_type); -} - -DataTypePtr QueryAnalyzer::getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node) -{ - auto node_type = query_tree_node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - { - return query_tree_node->getResultType(); - } - case QueryTreeNodeType::FUNCTION: - { - auto & function_node = query_tree_node->as(); - if (function_node.isResolved()) - return function_node.getResultType(); - break; - } - default: - { - break; - } - } - - return nullptr; -} - -ProjectionName QueryAnalyzer::calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names) -{ - const auto & function_node_typed = function_node->as(); - const auto & function_node_name = function_node_typed.getFunctionName(); - - bool is_array_function = function_node_name == "array"; - bool is_tuple_function = function_node_name == "tuple"; - - WriteBufferFromOwnString buffer; - - if (!is_array_function && !is_tuple_function) - buffer << function_node_name; - - if (!parameters_projection_names.empty()) - { - buffer << '('; - - size_t function_parameters_projection_names_size = parameters_projection_names.size(); - for (size_t i = 0; i < function_parameters_projection_names_size; ++i) - { - buffer << parameters_projection_names[i]; - - if (i + 1 != function_parameters_projection_names_size) - buffer << ", "; - } - - buffer << ')'; - } - - char open_bracket = '('; - char close_bracket = ')'; - - if (is_array_function) - { - open_bracket = '['; - close_bracket = ']'; - } - - buffer << open_bracket; - - size_t function_arguments_projection_names_size = arguments_projection_names.size(); - for (size_t i = 0; i < function_arguments_projection_names_size; ++i) - { - buffer << arguments_projection_names[i]; - - if (i + 1 != function_arguments_projection_names_size) - buffer << ", "; - } - - buffer << close_bracket; - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name) -{ - const auto & window_node_typed = window_node->as(); - const auto & window_frame = window_node_typed.getWindowFrame(); - - bool parent_window_node_has_partition_by = false; - bool parent_window_node_has_order_by = false; - - if (parent_window_node) - { - const auto & parent_window_node_typed = parent_window_node->as(); - parent_window_node_has_partition_by = parent_window_node_typed.hasPartitionBy(); - parent_window_node_has_order_by = parent_window_node_typed.hasOrderBy(); - } - - WriteBufferFromOwnString buffer; - - if (!parent_window_name.empty()) - buffer << parent_window_name; - - if (!partition_by_projection_names.empty() && !parent_window_node_has_partition_by) - { - if (!parent_window_name.empty()) - buffer << ' '; - - buffer << "PARTITION BY "; - - size_t partition_by_projection_names_size = partition_by_projection_names.size(); - for (size_t i = 0; i < partition_by_projection_names_size; ++i) - { - buffer << partition_by_projection_names[i]; - if (i + 1 != partition_by_projection_names_size) - buffer << ", "; - } - } - - if (!order_by_projection_names.empty() && !parent_window_node_has_order_by) - { - if (!partition_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << "ORDER BY "; - - size_t order_by_projection_names_size = order_by_projection_names.size(); - for (size_t i = 0; i < order_by_projection_names_size; ++i) - { - buffer << order_by_projection_names[i]; - if (i + 1 != order_by_projection_names_size) - buffer << ", "; - } - } - - if (!window_frame.is_default) - { - if (!partition_by_projection_names.empty() || !order_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << window_frame.type << " BETWEEN "; - if (window_frame.begin_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.begin_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_begin_offset_projection_name; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - - buffer << " AND "; - - if (window_frame.end_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.end_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_end_offset_projection_name; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - } - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, const ProjectionName & fill_to_expression_projection_name, const ProjectionName & fill_step_expression_projection_name) -{ - auto & sort_node_typed = sort_column_node->as(); - - WriteBufferFromOwnString sort_column_projection_name_buffer; - sort_column_projection_name_buffer << sort_expression_projection_name; - - auto sort_direction = sort_node_typed.getSortDirection(); - sort_column_projection_name_buffer << (sort_direction == SortDirection::ASCENDING ? " ASC" : " DESC"); - - auto nulls_sort_direction = sort_node_typed.getNullsSortDirection(); - - if (nulls_sort_direction) - sort_column_projection_name_buffer << " NULLS " << (nulls_sort_direction == sort_direction ? "LAST" : "FIRST"); - - if (auto collator = sort_node_typed.getCollator()) - sort_column_projection_name_buffer << " COLLATE " << collator->getLocale(); - - if (sort_node_typed.withFill()) - { - sort_column_projection_name_buffer << " WITH FILL"; - - if (sort_node_typed.hasFillFrom()) - sort_column_projection_name_buffer << " FROM " << fill_from_expression_projection_name; - - if (sort_node_typed.hasFillTo()) - sort_column_projection_name_buffer << " TO " << fill_to_expression_projection_name; - - if (sort_node_typed.hasFillStep()) - sort_column_projection_name_buffer << " STEP " << fill_step_expression_projection_name; - } - - return sort_column_projection_name_buffer.str(); -} - -/// Get valid identifiers for typo correction from compound expression -void QueryAnalyzer::collectCompoundExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result) -{ - IDataType::forEachSubcolumn([&](const auto &, const auto & name, const auto &) - { - Identifier subcolumn_indentifier(name); - size_t new_identifier_size = valid_identifier_prefix.getPartsSize() + subcolumn_indentifier.getPartsSize(); - - if (new_identifier_size == unresolved_identifier.getPartsSize()) - { - auto new_identifier = valid_identifier_prefix; - for (const auto & part : subcolumn_indentifier) - new_identifier.push_back(part); - - valid_identifiers_result.insert(std::move(new_identifier)); - } - }, ISerialization::SubstreamData(compound_expression_type->getDefaultSerialization())); -} - -/// Get valid identifiers for typo correction from table expression -void QueryAnalyzer::collectTableExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result) -{ - for (const auto & [column_name, column_node] : table_expression_data.column_name_to_column_node) - { - Identifier column_identifier(column_name); - if (unresolved_identifier.getPartsSize() == column_identifier.getPartsSize()) - valid_identifiers_result.insert(column_identifier); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier, - valid_identifiers_result); - - if (table_expression->hasAlias()) - { - Identifier column_identifier_with_alias({table_expression->getAlias()}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_alias.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_alias.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_alias); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_alias, - valid_identifiers_result); - } - - if (!table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name({table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name, - valid_identifiers_result); - } - - if (!table_expression_data.database_name.empty() && !table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name_and_database_name({table_expression_data.database_name, table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name_and_database_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name_and_database_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name_and_database_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name_and_database_name, - valid_identifiers_result); - } - } -} - -/// Get valid identifiers for typo correction from scope without looking at parent scopes -void QueryAnalyzer::collectScopeValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - bool identifier_is_short = unresolved_identifier.isShort(); - bool identifier_is_compound = unresolved_identifier.isCompound(); - - if (allow_expression_identifiers) - { - for (const auto & [name, expression] : *scope.aliases.alias_name_to_expression_node) - { - assert(expression); - auto expression_identifier = Identifier(name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - - for (const auto & [table_expression, table_expression_data] : scope.table_expression_node_to_data) - { - collectTableExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - table_expression, - table_expression_data, - valid_identifiers_result); - } - } - - if (identifier_is_short) - { - if (allow_function_identifiers) - { - for (const auto & [name, _] : *scope.aliases.alias_name_to_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - - if (allow_table_expression_identifiers) - { - for (const auto & [name, _] : scope.aliases.alias_name_to_table_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - } - - for (const auto & [argument_name, expression] : scope.expression_argument_name_to_node) - { - assert(expression); - auto expression_node_type = expression->getNodeType(); - - if (allow_expression_identifiers && isExpressionNodeType(expression_node_type)) - { - auto expression_identifier = Identifier(argument_name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - else if (identifier_is_short && allow_function_identifiers && isFunctionExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - else if (allow_table_expression_identifiers && isTableExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - } -} - -void QueryAnalyzer::collectScopeWithParentScopesValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - const IdentifierResolveScope * current_scope = &scope; - - while (current_scope) - { - collectScopeValidIdentifiersForTypoCorrection(unresolved_identifier, - *current_scope, - allow_expression_identifiers, - allow_function_identifiers, - allow_table_expression_identifiers, - valid_identifiers_result); - - current_scope = current_scope->parent_scope; - } -} - -std::vector QueryAnalyzer::collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers) -{ - std::vector prompting_strings; - prompting_strings.reserve(valid_identifiers.size()); - - for (const auto & valid_identifier : valid_identifiers) - prompting_strings.push_back(valid_identifier.getFullName()); - - return NamePrompter<1>::getHints(unresolved_identifier.getFullName(), prompting_strings); -} - -/** Wrap expression node in tuple element function calls for nested paths. - * Example: Expression node: compound_expression. Nested path: nested_path_1.nested_path_2. - * Result: tupleElement(tupleElement(compound_expression, 'nested_path_1'), 'nested_path_2'). - */ -QueryTreeNodePtr QueryAnalyzer::wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path) -{ - size_t nested_path_parts_size = nested_path.getPartsSize(); - for (size_t i = 0; i < nested_path_parts_size; ++i) - { - const auto & nested_path_part = nested_path[i]; - auto tuple_element_function = std::make_shared("tupleElement"); - - auto & tuple_element_function_arguments_nodes = tuple_element_function->getArguments().getNodes(); - tuple_element_function_arguments_nodes.reserve(2); - tuple_element_function_arguments_nodes.push_back(expression_node); - tuple_element_function_arguments_nodes.push_back(std::make_shared(nested_path_part)); - - expression_node = std::move(tuple_element_function); - } - - return expression_node; -} - -/** Try to get lambda node from sql user defined functions if sql user defined function with function name exists. - * Returns lambda node if function exists, nullptr otherwise. - */ -QueryTreeNodePtr QueryAnalyzer::tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context) -{ - auto user_defined_function = UserDefinedSQLFunctionFactory::instance().tryGet(function_name); - if (!user_defined_function) - return {}; - - auto it = function_name_to_user_defined_lambda.find(function_name); - if (it != function_name_to_user_defined_lambda.end()) - return it->second; - - const auto & create_function_query = user_defined_function->as(); - auto result_node = buildQueryTree(create_function_query->function_core, context); - if (result_node->getNodeType() != QueryTreeNodeType::LAMBDA) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "SQL user defined function {} must represent lambda expression. Actual {}", - function_name, - create_function_query->function_core->formatForErrorMessage()); - - function_name_to_user_defined_lambda.emplace(function_name, result_node); - - return result_node; -} - -bool subtreeHasViewSource(const IQueryTreeNode * node, const Context & context) -{ - if (!node) - return false; - - if (const auto * table_node = node->as()) - { - if (table_node->getStorageID().getFullNameNotQuoted() == context.getViewSource()->getStorageID().getFullNameNotQuoted()) - return true; - } - - for (const auto & child : node->getChildren()) - if (subtreeHasViewSource(child.get(), context)) - return true; - - return false; -} - -/// Evaluate scalar subquery and perform constant folding if scalar subquery does not have constant value -void QueryAnalyzer::evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - auto * query_node = node->as(); - auto * union_node = node->as(); - if (!query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node must have query or union type. Actual {} {}", - node->getNodeTypeName(), - node->formatASTForErrorMessage()); - - auto & context = scope.context; - - Block scalar_block; - - auto node_without_alias = node->clone(); - node_without_alias->removeAlias(); - - QueryTreeNodePtrWithHash node_with_hash(node_without_alias); - auto str_hash = DB::toString(node_with_hash.hash); - - bool can_use_global_scalars = !only_analyze && !(context->getViewSource() && subtreeHasViewSource(node_without_alias.get(), *context)); - - auto & scalars_cache = can_use_global_scalars ? scalar_subquery_to_scalar_value_global : scalar_subquery_to_scalar_value_local; - - if (scalars_cache.contains(node_with_hash)) - { - if (can_use_global_scalars) - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - else - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesLocalCacheHit); - - scalar_block = scalars_cache.at(node_with_hash); - } - else if (context->hasQueryContext() && can_use_global_scalars && context->getQueryContext()->hasScalar(str_hash)) - { - scalar_block = context->getQueryContext()->getScalar(str_hash); - scalar_subquery_to_scalar_value_global.emplace(node_with_hash, scalar_block); - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - } - else - { - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesCacheMiss); - auto subquery_context = Context::createCopy(context); - - Settings subquery_settings = context->getSettings(); - subquery_settings.max_result_rows = 1; - subquery_settings.extremes = false; - subquery_context->setSettings(subquery_settings); - /// When execute `INSERT INTO t WITH ... SELECT ...`, it may lead to `Unknown columns` - /// exception with this settings enabled(https://github.com/ClickHouse/ClickHouse/issues/52494). - subquery_context->setSetting("use_structure_from_insertion_table_in_table_functions", false); - - auto options = SelectQueryOptions(QueryProcessingStage::Complete, scope.subquery_depth, true /*is_subquery*/); - options.only_analyze = only_analyze; - auto interpreter = std::make_unique(node->toAST(), subquery_context, subquery_context->getViewSource(), options); - - if (only_analyze) - { - /// If query is only analyzed, then constants are not correct. - scalar_block = interpreter->getSampleBlock(); - for (auto & column : scalar_block) - { - if (column.column->empty()) - { - auto mut_col = column.column->cloneEmpty(); - mut_col->insertDefault(); - column.column = std::move(mut_col); - } - } - } - else - { - auto io = interpreter->execute(); - PullingAsyncPipelineExecutor executor(io.pipeline); - io.pipeline.setProgressCallback(context->getProgressCallback()); - io.pipeline.setProcessListElement(context->getProcessListElement()); - - Block block; - - while (block.rows() == 0 && executor.pull(block)) - { - } - - if (block.rows() == 0) - { - auto types = interpreter->getSampleBlock().getDataTypes(); - if (types.size() != 1) - types = {std::make_shared(types)}; - - auto & type = types[0]; - if (!type->isNullable()) - { - if (!type->canBeInsideNullable()) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, - "Scalar subquery returned empty result of type {} which cannot be Nullable", - type->getName()); - - type = makeNullable(type); - } - - auto scalar_column = type->createColumn(); - scalar_column->insert(Null()); - scalar_block.insert({std::move(scalar_column), type, "null"}); - } - else - { - if (block.rows() != 1) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - Block tmp_block; - while (tmp_block.rows() == 0 && executor.pull(tmp_block)) - { - } - - if (tmp_block.rows() != 0) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - block = materializeBlock(block); - size_t columns = block.columns(); - - if (columns == 1) - { - auto & column = block.getByPosition(0); - /// Here we wrap type to nullable if we can. - /// It is needed cause if subquery return no rows, it's result will be Null. - /// In case of many columns, do not check it cause tuple can't be nullable. - if (!column.type->isNullable() && column.type->canBeInsideNullable()) - { - column.type = makeNullable(column.type); - column.column = makeNullable(column.column); - } - - scalar_block = block; - } - else - { - /** Make unique column names for tuple. - * - * Example: SELECT (SELECT 2 AS x, x) - */ - makeUniqueColumnNamesInBlock(block); - - scalar_block.insert({ - ColumnTuple::create(block.getColumns()), - std::make_shared(block.getDataTypes(), block.getNames()), - "tuple"}); - } - } - } - - scalars_cache.emplace(node_with_hash, scalar_block); - if (can_use_global_scalars && context->hasQueryContext()) - context->getQueryContext()->addScalar(str_hash, scalar_block); - } - - const auto & scalar_column_with_type = scalar_block.safeGetByPosition(0); - const auto & scalar_type = scalar_column_with_type.type; - - Field scalar_value; - scalar_column_with_type.column->get(0, scalar_value); - - const auto * scalar_type_name = scalar_block.safeGetByPosition(0).type->getFamilyName(); - static const std::set useless_literal_types = {"Array", "Tuple", "AggregateFunction", "Function", "Set", "LowCardinality"}; - auto * nearest_query_scope = scope.getNearestQueryScope(); - - /// Always convert to literals when there is no query context - if (!context->getSettingsRef().enable_scalar_subquery_optimization || - !useless_literal_types.contains(scalar_type_name) || - !context->hasQueryContext() || - !nearest_query_scope) - { - auto constant_value = std::make_shared(std::move(scalar_value), scalar_type); - auto constant_node = std::make_shared(constant_value, node); - - if (constant_node->getValue().isNull()) - { - node = buildCastFunction(constant_node, constant_node->getResultType(), context); - node = std::make_shared(std::move(constant_value), node); - } - else - node = std::move(constant_node); - - return; - } - - auto & nearest_query_scope_query_node = nearest_query_scope->scope_node->as(); - auto & mutable_context = nearest_query_scope_query_node.getMutableContext(); - - auto scalar_query_hash_string = DB::toString(node_with_hash.hash) + (only_analyze ? "_analyze" : ""); - - if (mutable_context->hasQueryContext()) - mutable_context->getQueryContext()->addScalar(scalar_query_hash_string, scalar_block); - - mutable_context->addScalar(scalar_query_hash_string, scalar_block); - - std::string get_scalar_function_name = "__getScalar"; - - auto scalar_query_hash_constant_value = std::make_shared(std::move(scalar_query_hash_string), std::make_shared()); - auto scalar_query_hash_constant_node = std::make_shared(std::move(scalar_query_hash_constant_value)); - - auto get_scalar_function_node = std::make_shared(get_scalar_function_name); - get_scalar_function_node->getArguments().getNodes().push_back(std::move(scalar_query_hash_constant_node)); - - auto get_scalar_function = FunctionFactory::instance().get(get_scalar_function_name, mutable_context); - get_scalar_function_node->resolveAsFunction(get_scalar_function->build(get_scalar_function_node->getArgumentColumns())); - - node = std::move(get_scalar_function_node); -} - -void QueryAnalyzer::mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope) -{ - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - - auto & parent_window_node_typed = parent_window_node->as(); - - /** If an existing_window_name is specified it must refer to an earlier - * entry in the WINDOW list; the new window copies its partitioning clause - * from that entry, as well as its ordering clause if any. In this case - * the new window cannot specify its own PARTITION BY clause, and it can - * specify ORDER BY only if the copied window does not have one. The new - * window always uses its own frame clause; the copied window must not - * specify a frame clause. - * https://www.postgresql.org/docs/current/sql-select.html - */ - if (window_node_typed.hasPartitionBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override PARTITION BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (window_node_typed.hasOrderBy() && parent_window_node_typed.hasOrderBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override a non-empty ORDER BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (!parent_window_node_typed.getWindowFrame().is_default) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parent window '{}' is not allowed to define a frame: while processing derived window definition '{}'. In scope {}", - parent_window_name, - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - window_node_typed.getPartitionByNode() = parent_window_node_typed.getPartitionBy().clone(); - - if (parent_window_node_typed.hasOrderBy()) - window_node_typed.getOrderByNode() = parent_window_node_typed.getOrderBy().clone(); -} - -/** Replace nodes in node list with positional arguments. - * - * Example: SELECT id, value FROM test_table GROUP BY 1, 2; - * Example: SELECT id, value FROM test_table ORDER BY 1, 2; - * Example: SELECT id, value FROM test_table LIMIT 5 BY 1, 2; - */ -void QueryAnalyzer::replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope) -{ - const auto & settings = scope.context->getSettingsRef(); - if (!settings.enable_positional_arguments || scope.context->getClientInfo().query_kind != ClientInfo::QueryKind::INITIAL_QUERY) - return; - - auto & node_list_typed = node_list->as(); - - for (auto & node : node_list_typed.getNodes()) - { - auto * node_to_replace = &node; - - if (auto * sort_node = node->as()) - node_to_replace = &sort_node->getExpression(); - - auto * constant_node = (*node_to_replace)->as(); - - if (!constant_node - || (constant_node->getValue().getType() != Field::Types::UInt64 - && constant_node->getValue().getType() != Field::Types::Int64)) - continue; - - UInt64 pos; - if (constant_node->getValue().getType() == Field::Types::UInt64) - { - pos = constant_node->getValue().get(); - } - else // Int64 - { - auto value = constant_node->getValue().get(); - if (value > 0) - pos = value; - else - { - if (value < -static_cast(projection_nodes.size())) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Negative positional argument number {} is out of bounds. Expected in range [-{}, -1]. In scope {}", - value, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - pos = projection_nodes.size() + value + 1; - } - } - - if (!pos || pos > projection_nodes.size()) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Positional argument number {} is out of bounds. Expected in range [1, {}]. In scope {}", - pos, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - - --pos; - *node_to_replace = projection_nodes[pos]->clone(); - if (auto it = resolved_expressions.find(projection_nodes[pos]); it != resolved_expressions.end()) - { - resolved_expressions[*node_to_replace] = it->second; - } - } -} - -void QueryAnalyzer::convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope) -{ - const auto * limit_offset_constant_node = expression_node->as(); - if (!limit_offset_constant_node || !isNativeNumber(removeNullable(limit_offset_constant_node->getResultType()))) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} expression must be constant with numeric type. Actual {}. In scope {}", - expression_description, - expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - Field converted_value = convertFieldToType(limit_offset_constant_node->getValue(), DataTypeUInt64()); - if (converted_value.isNull()) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} numeric constant expression is not representable as UInt64", - expression_description); - - auto constant_value = std::make_shared(std::move(converted_value), std::make_shared()); - auto result_constant_node = std::make_shared(std::move(constant_value)); - result_constant_node->getSourceExpression() = limit_offset_constant_node->getSourceExpression(); - - expression_node = std::move(result_constant_node); -} - -void QueryAnalyzer::validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unexpected table expression. Expected table, table function, query or union node. Table node: {}, scope node: {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (table_node || table_function_node) - { - auto table_expression_modifiers = table_node ? table_node->getTableExpressionModifiers() : table_function_node->getTableExpressionModifiers(); - - if (table_expression_modifiers.has_value()) - { - const auto & storage = table_node ? table_node->getStorage() : table_function_node->getStorage(); - if (table_expression_modifiers->hasFinal() && !storage->supportsFinal()) - throw Exception(ErrorCodes::ILLEGAL_FINAL, - "Storage {} doesn't support FINAL", - storage->getName()); - - if (table_expression_modifiers->hasSampleSizeRatio() && !storage->supportsSampling()) - throw Exception(ErrorCodes::SAMPLING_NOT_SUPPORTED, - "Storage {} doesn't support sampling", - storage->getStorageID().getFullNameNotQuoted()); - } - } -} - -void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - bool table_expression_has_alias = table_expression_node->hasAlias(); - if (table_expression_has_alias) - return; - - if (join_node->as().getKind() == JoinKind::Paste) - return; - - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - if ((query_node && !query_node->getCTEName().empty()) || (union_node && !union_node->getCTEName().empty())) - return; - - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || - table_expression_node_type == QueryTreeNodeType::QUERY || - table_expression_node_type == QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::ALIAS_REQUIRED, - "JOIN {} no alias for subquery or table function {}. " - "In scope {} (set joined_subquery_requires_alias = 0 to disable restriction)", - join_node->formatASTForErrorMessage(), - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); -} - -std::pair QueryAnalyzer::recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into) -{ - checkStackSize(); - - if (node->as()) - { - into.push_back(node); - return {false, 1}; - } - - auto * function = node->as(); - - if (!function) - return {false, 0}; - - if (function->isAggregateFunction()) - return {true, 0}; - - UInt64 pushed_children = 0; - bool has_aggregate = false; - - for (auto & child : function->getArguments().getNodes()) - { - auto [child_has_aggregate, child_pushed_children] = recursivelyCollectMaxOrdinaryExpressions(child, into); - has_aggregate |= child_has_aggregate; - pushed_children += child_pushed_children; - } - - /// The current function is not aggregate function and there is no aggregate function in its arguments, - /// so use the current function to replace its arguments - if (!has_aggregate) - { - for (UInt64 i = 0; i < pushed_children; i++) - into.pop_back(); - - into.push_back(node); - pushed_children = 1; - } - - return {has_aggregate, pushed_children}; -} - -/** Expand GROUP BY ALL by extracting all the SELECT-ed expressions that are not aggregate functions. - * - * For a special case that if there is a function having both aggregate functions and other fields as its arguments, - * the `GROUP BY` keys will contain the maximum non-aggregate fields we can extract from it. - * - * Example: - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY ALL - * will expand as - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY substring(a, 4, 2), substring(a, 1, 2) - */ -void QueryAnalyzer::expandGroupByAll(QueryNode & query_tree_node_typed) -{ - if (!query_tree_node_typed.isGroupByAll()) - return; - - auto & group_by_nodes = query_tree_node_typed.getGroupBy().getNodes(); - auto & projection_list = query_tree_node_typed.getProjection(); - - for (auto & node : projection_list.getNodes()) - recursivelyCollectMaxOrdinaryExpressions(node, group_by_nodes); - query_tree_node_typed.setIsGroupByAll(false); -} - -void QueryAnalyzer::expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings) -{ - if (!settings.enable_order_by_all || !query_tree_node_typed.isOrderByAll()) - return; - - auto * all_node = query_tree_node_typed.getOrderBy().getNodes()[0]->as(); - if (!all_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Select analyze for not sort node."); - - auto & projection_nodes = query_tree_node_typed.getProjection().getNodes(); - auto list_node = std::make_shared(); - list_node->getNodes().reserve(projection_nodes.size()); - - for (auto & node : projection_nodes) - { - /// Detect and reject ambiguous statements: - /// E.g. for a table with columns "all", "a", "b": - /// - SELECT all, a, b ORDER BY all; -- should we sort by all columns in SELECT or by column "all"? - /// - SELECT a, b AS all ORDER BY all; -- like before but "all" as alias - /// - SELECT func(...) AS all ORDER BY all; -- like before but "all" as function - /// - SELECT a, b ORDER BY all; -- tricky in other way: does the user want to sort by columns in SELECT clause or by not SELECTed column "all"? - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - auto projection_names = resolved_expression_it->second; - if (projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected 1 projection names. Actual {}", - projection_names.size()); - if (boost::iequals(projection_names[0], "all")) - throw Exception(ErrorCodes::UNEXPECTED_EXPRESSION, - "Cannot use ORDER BY ALL to sort a column with name 'all', please disable setting `enable_order_by_all` and try again"); - } - - auto sort_node = std::make_shared(node, all_node->getSortDirection(), all_node->getNullsSortDirection()); - list_node->getNodes().push_back(sort_node); - } - - query_tree_node_typed.getOrderByNode() = list_node; - query_tree_node_typed.setIsOrderByAll(false); -} - -std::string QueryAnalyzer::rewriteAggregateFunctionNameIfNeeded( - const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context) -{ - std::string result_aggregate_function_name = aggregate_function_name; - auto aggregate_function_name_lowercase = Poco::toLower(aggregate_function_name); - - const auto & settings = context->getSettingsRef(); - - if (aggregate_function_name_lowercase == "countdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - } - else if (aggregate_function_name_lowercase == "countdistinctif" || aggregate_function_name_lowercase == "countifdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - result_aggregate_function_name += "If"; - } - - /// Replace aggregateFunctionIfDistinct into aggregateFunctionDistinctIf to make execution more optimal - if (result_aggregate_function_name.ends_with("ifdistinct")) - { - size_t prefix_length = result_aggregate_function_name.size() - strlen("ifdistinct"); - result_aggregate_function_name = result_aggregate_function_name.substr(0, prefix_length) + "DistinctIf"; - } - - bool need_add_or_null = settings.aggregate_functions_null_for_empty && !result_aggregate_function_name.ends_with("OrNull"); - if (need_add_or_null) - { - auto properties = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (!properties->returns_default_when_only_null) - result_aggregate_function_name += "OrNull"; - } - - /** Move -OrNull suffix ahead, this should execute after add -OrNull suffix. - * Used to rewrite aggregate functions with -OrNull suffix in some cases. - * Example: sumIfOrNull. - * Result: sumOrNullIf. - */ - if (result_aggregate_function_name.ends_with("OrNull")) - { - auto function_properies = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (function_properies && !function_properies->returns_default_when_only_null) - { - size_t function_name_size = result_aggregate_function_name.size(); - - static constexpr std::array suffixes_to_replace = {"MergeState", "Merge", "State", "If"}; - for (const auto & suffix : suffixes_to_replace) - { - auto suffix_string_value = String(suffix); - auto suffix_to_check = suffix_string_value + "OrNull"; - - if (!result_aggregate_function_name.ends_with(suffix_to_check)) - continue; - - result_aggregate_function_name = result_aggregate_function_name.substr(0, function_name_size - suffix_to_check.size()); - result_aggregate_function_name += "OrNull"; - result_aggregate_function_name += suffix_string_value; - - break; - } - } - } - - return result_aggregate_function_name; -} - -/// Resolve identifier functions implementation - -/// Try resolve table identifier from database catalog -QueryTreeNodePtr QueryAnalyzer::tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context) -{ - size_t parts_size = table_identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected table identifier to contain 1 or 2 parts. Actual '{}'", - table_identifier.getFullName()); - - std::string database_name; - std::string table_name; - - if (table_identifier.isCompound()) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - else - { - table_name = table_identifier[0]; - } - - StorageID storage_id(database_name, table_name); - storage_id = context->resolveStorageID(storage_id); - bool is_temporary_table = storage_id.getDatabaseName() == DatabaseCatalog::TEMPORARY_DATABASE; - - StoragePtr storage; - - if (is_temporary_table) - storage = DatabaseCatalog::instance().getTable(storage_id, context); - else - storage = DatabaseCatalog::instance().tryGetTable(storage_id, context); - - if (!storage) - return {}; - - auto storage_lock = storage->lockForShare(context->getInitialQueryId(), context->getSettingsRef().lock_acquire_timeout); - auto storage_snapshot = storage->getStorageSnapshot(storage->getInMemoryMetadataPtr(), context); - auto result = std::make_shared(std::move(storage), std::move(storage_lock), std::move(storage_snapshot)); - if (is_temporary_table) - result->setTemporaryTableName(table_name); - - return result; -} - -/// Resolve identifier from compound expression -/// If identifier cannot be resolved throw exception or return nullptr if can_be_not_found is true -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found) -{ - Identifier compound_expression_identifier; - for (size_t i = 0; i < identifier_bind_size; ++i) - compound_expression_identifier.push_back(expression_identifier[i]); - - IdentifierView nested_path(expression_identifier); - nested_path.popFirst(identifier_bind_size); - - auto expression_type = compound_expression->getResultType(); - - if (!expression_type->hasSubcolumn(nested_path.getFullName())) - { - if (auto * column = compound_expression->as()) - { - const DataTypePtr & column_type = column->getColumn().getTypeInStorage(); - if (column_type->getTypeId() == TypeIndex::Object) - { - const auto * object_type = checkAndGetDataType(column_type.get()); - if (object_type->getSchemaFormat() == "json" && object_type->hasNullableSubcolumns()) - { - QueryTreeNodePtr constant_node_null = std::make_shared(Field()); - return constant_node_null; - } - } - } - - if (can_be_not_found) - return {}; - - std::unordered_set valid_identifiers; - collectCompoundExpressionValidIdentifiersForTypoCorrection(expression_identifier, - expression_type, - compound_expression_identifier, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(expression_identifier, valid_identifiers); - - String compound_expression_from_error_message; - if (!compound_expression_source.empty()) - { - compound_expression_from_error_message += " from "; - compound_expression_from_error_message += compound_expression_source; - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier {} nested path {} cannot be resolved from type {}{}. In scope {}{}", - expression_identifier, - nested_path, - expression_type->getName(), - compound_expression_from_error_message, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - QueryTreeNodePtr get_subcolumn_function = std::make_shared("getSubcolumn"); - auto & get_subcolumn_function_arguments_nodes = get_subcolumn_function->as()->getArguments().getNodes(); - - get_subcolumn_function_arguments_nodes.reserve(2); - get_subcolumn_function_arguments_nodes.push_back(compound_expression); - get_subcolumn_function_arguments_nodes.push_back(std::make_shared(nested_path.getFullName())); - - resolveFunction(get_subcolumn_function, scope); - return get_subcolumn_function; -} - -/** Resolve identifier from expression arguments. - * - * Expression arguments can be initialized during lambda analysis or they could be provided externally. - * Expression arguments must be already resolved nodes. This is client responsibility to resolve them. - * - * Example: SELECT arrayMap(x -> x + 1, [1,2,3]); - * For lambda x -> x + 1, `x` is lambda expression argument. - * - * Resolve strategy: - * 1. Try to bind identifier to scope argument name to node map. - * 2. If identifier is binded but expression context and node type are incompatible return nullptr. - * - * It is important to support edge cases, where we lookup for table or function node, but argument has same name. - * Example: WITH (x -> x + 1) AS func, (func -> func(1) + func) AS lambda SELECT lambda(1); - * - * 3. If identifier is compound and identifier lookup is in expression context use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - auto it = scope.expression_argument_name_to_node.find(identifier_lookup.identifier.getFullName()); - bool resolve_full_identifier = it != scope.expression_argument_name_to_node.end(); - - if (!resolve_full_identifier) - { - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - it = scope.expression_argument_name_to_node.find(identifier_bind_part); - if (it == scope.expression_argument_name_to_node.end()) - return {}; - } - - auto node_type = it->second->getNodeType(); - if (identifier_lookup.isExpressionLookup() && !isExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isTableExpressionLookup() && !isTableExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isFunctionLookup() && !isFunctionExpressionNodeType(node_type)) - return {}; - - if (!resolve_full_identifier && identifier_lookup.identifier.isCompound() && identifier_lookup.isExpressionLookup()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return it->second; -} - -bool QueryAnalyzer::tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope) -{ - return scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME) != nullptr || scope.aliases.array_join_aliases.contains(identifier_lookup.identifier.front()); -} - -/** Resolve identifier from scope aliases. - * - * Resolve strategy: - * 1. If alias is registered in current expressions that are in resolve process and if top expression is not part of bottom expression with the same alias subtree - * throw cyclic aliases exception. - * Otherwise prevent cache usage for identifier lookup and return nullptr. - * - * This is special scenario where identifier has name the same as alias name in one of its parent expressions including itself. - * In such case we cannot resolve identifier from aliases because of recursion. It is client responsibility to register and deregister alias - * names during expressions resolve. - * - * We must prevent cache usage for lookup because lookup outside of expression is supposed to return other value. - * Example: SELECT (id + 1) AS id, id + 2. Lookup for id inside (id + 1) as id should return id from table, but lookup (id + 2) should return - * (id + 1) AS id. - * - * Below cases should work: - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * SELECT (id + 1) AS id FROM test_table; - * SELECT (1 + (1 + id)) AS id FROM test_table; - * - * Below cases should throw cyclic aliases exception: - * SELECT (id + b) AS id, id as b FROM test_table; - * SELECT (1 + b + 1 + id) AS id, b as c, id as b FROM test_table; - * - * 2. Depending on IdentifierLookupContext get alias name to node map from IdentifierResolveScope. - * 3. Try to bind identifier to alias name in map. If there are no such binding return nullptr. - * 4. If node in map is not resolved, resolve it. It is important in case of compound expressions. - * Example: SELECT value.a, cast('(1)', 'Tuple(a UInt64)') AS value; - * - * Special case if node is identifier node. - * Example: SELECT value, id AS value FROM test_table; - * - * Add node in current scope expressions in resolve process stack. - * Try to resolve identifier. - * If identifier is resolved, depending on lookup context, erase entry from expression or lambda map. Check QueryExpressionsAliasVisitor documentation. - * Pop node from current scope expressions in resolve process stack. - * - * 5. If identifier is compound and identifier lookup is in expression context, use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - auto * it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME); - if (it == nullptr) - return {}; - - QueryTreeNodePtr & alias_node = *it; - - if (!alias_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node with alias {} is not valid. In scope {}", - identifier_bind_part, - scope.scope_node->formatASTForErrorMessage()); - - if (auto root_expression_with_alias = scope.expressions_in_resolve_process_stack.getExpressionWithAlias(identifier_bind_part)) - { - const auto top_expression = scope.expressions_in_resolve_process_stack.getTop(); - - if (!isNodePartOfTree(top_expression.get(), root_expression_with_alias.get())) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - scope.non_cached_identifier_lookups_during_expression_resolve.insert(identifier_lookup); - return {}; - } - - auto node_type = alias_node->getNodeType(); - - /// Resolve expression if necessary - if (node_type == QueryTreeNodeType::IDENTIFIER) - { - scope.pushExpressionNode(alias_node); - - auto & alias_identifier_node = alias_node->as(); - auto identifier = alias_identifier_node.getIdentifier(); - auto lookup_result = tryResolveIdentifier(IdentifierLookup{identifier, identifier_lookup.lookup_context}, scope, identifier_resolve_settings); - if (!lookup_result.resolved_identifier) - { - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(identifier, scope, true, false, false, valid_identifiers); - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {} identifier '{}'. In scope {}{}", - toStringLowercase(identifier_lookup.lookup_context), - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - alias_node = lookup_result.resolved_identifier; - scope.popExpressionNode(); - } - else if (node_type == QueryTreeNodeType::FUNCTION) - { - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - else if (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION) - { - if (identifier_resolve_settings.allow_to_resolve_subquery_during_identifier_resolution) - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, identifier_lookup.isTableExpressionLookup() /*allow_table_expression*/); - } - - if (identifier_lookup.identifier.isCompound() && alias_node) - { - if (identifier_lookup.isExpressionLookup()) - { - return tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - 1 /*identifier_bind_size*/, - alias_node, - {} /* compound_expression_source */, - scope, - identifier_resolve_settings.allow_to_check_join_tree /* can_be_not_found */); - } - else if (identifier_lookup.isFunctionLookup() || identifier_lookup.isTableExpressionLookup()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Compound identifier '{}' cannot be resolved as {}. In scope {}", - identifier_lookup.identifier.getFullName(), - identifier_lookup.isFunctionLookup() ? "function" : "table expression", - scope.scope_node->formatASTForErrorMessage()); - } - } - - return alias_node; -} - -/** Resolve identifier from table columns. - * - * 1. If table column nodes are empty or identifier is not expression lookup return nullptr. - * 2. If identifier full name match table column use column. Save information that we resolve identifier using full name. - * 3. Else if identifier binds to table column, use column. - * 4. Try to resolve column ALIAS expression if it exists. - * 5. If identifier was compound and was not resolved using full name during step 1 use `tryResolveIdentifierFromCompoundExpression`. - * This can be the case with compound ALIAS columns. - * - * Example: - * CREATE TABLE test_table (id UInt64, value Tuple(id UInt64, value String), alias_value ALIAS value.id) ENGINE=TinyLog; - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - if (scope.column_name_to_column_node.empty() || !identifier_lookup.isExpressionLookup()) - return {}; - - const auto & identifier = identifier_lookup.identifier; - auto it = scope.column_name_to_column_node.find(identifier.getFullName()); - bool full_column_name_match = it != scope.column_name_to_column_node.end(); - - if (!full_column_name_match) - { - it = scope.column_name_to_column_node.find(identifier_lookup.identifier[0]); - if (it == scope.column_name_to_column_node.end()) - return {}; - } - - if (it->second->hasExpression()) - resolveExpressionNode(it->second->getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - QueryTreeNodePtr result = it->second; - - if (!full_column_name_match && identifier.isCompound()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return result; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - if (parts_size == 1 && path_start == table_name) - return true; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return true; - else - return false; - } - - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier)) || table_expression_data.canBindIdentifier(IdentifierView(identifier))) - return true; - - if (identifier.getPartsSize() == 1) - return false; - - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return true; - - if (identifier.getPartsSize() == 2) - return false; - - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return true; - - return false; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node_to_ignore, - const IdentifierResolveScope & scope) -{ - bool can_bind_identifier_to_table_expression = false; - - for (const auto & [table_expression_node, _] : scope.table_expression_node_to_data) - { - if (table_expression_node.get() == table_expression_node_to_ignore.get()) - continue; - - can_bind_identifier_to_table_expression = tryBindIdentifierToTableExpression(identifier_lookup, table_expression_node, scope); - if (can_bind_identifier_to_table_expression) - break; - } - - return can_bind_identifier_to_table_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found) -{ - auto identifier_without_column_qualifier = identifier; - identifier_without_column_qualifier.popFirst(identifier_column_qualifier_parts); - - /** Compound identifier cannot be resolved directly from storage if storage is not table. - * - * Example: SELECT test_table.id.value1.value2 FROM test_table; - * In table storage column test_table.id.value1.value2 will exists. - * - * Example: SELECT test_subquery.compound_expression.value FROM (SELECT compound_expression AS value) AS test_subquery; - * Here there is no column with name test_subquery.compound_expression.value, and additional wrap in tuple element is required. - */ - - QueryTreeNodePtr result_expression; - bool match_full_identifier = false; - - const auto & identifier_full_name = identifier_without_column_qualifier.getFullName(); - auto it = table_expression_data.column_name_to_column_node.find(identifier_full_name); - bool can_resolve_directly_from_storage = it != table_expression_data.column_name_to_column_node.end(); - if (can_resolve_directly_from_storage && table_expression_data.subcolumn_names.contains(identifier_full_name)) - { - /** In the case when we have an ARRAY JOIN, we should not resolve subcolumns directly from storage. - * For example, consider the following SQL query: - * SELECT ProfileEvents.Values FROM system.query_log ARRAY JOIN ProfileEvents - * In this case, ProfileEvents.Values should also be array joined, not directly resolved from storage. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - if (nearest_query_scope_query_node && nearest_query_scope_query_node->getJoinTree()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - can_resolve_directly_from_storage = false; - } - - if (can_resolve_directly_from_storage) - { - match_full_identifier = true; - result_expression = it->second; - } - else - { - it = table_expression_data.column_name_to_column_node.find(identifier_without_column_qualifier.at(0)); - if (it != table_expression_data.column_name_to_column_node.end()) - result_expression = it->second; - } - - bool clone_is_needed = true; - - String table_expression_source = table_expression_data.table_expression_description; - if (!table_expression_data.table_expression_name.empty()) - table_expression_source += " with name " + table_expression_data.table_expression_name; - - if (result_expression && !match_full_identifier && identifier_without_column_qualifier.isCompound()) - { - size_t identifier_bind_size = identifier_column_qualifier_parts + 1; - result_expression = tryResolveIdentifierFromCompoundExpression(identifier, - identifier_bind_size, - result_expression, - table_expression_source, - scope, - can_be_not_found); - if (can_be_not_found && !result_expression) - return {}; - clone_is_needed = false; - } - - if (!result_expression) - { - QueryTreeNodes nested_column_nodes; - DataTypes nested_types; - Array nested_names_array; - - for (const auto & [column_name, _] : table_expression_data.column_names_and_types) - { - Identifier column_name_identifier_without_last_part(column_name); - auto column_name_identifier_last_part = column_name_identifier_without_last_part.getParts().back(); - column_name_identifier_without_last_part.popLast(); - - if (identifier_without_column_qualifier.getFullName() != column_name_identifier_without_last_part.getFullName()) - continue; - - auto column_node_it = table_expression_data.column_name_to_column_node.find(column_name); - if (column_node_it == table_expression_data.column_name_to_column_node.end()) - continue; - - const auto & column_node = column_node_it->second; - const auto & column_type = column_node->getColumnType(); - const auto * column_type_array = typeid_cast(column_type.get()); - if (!column_type_array) - continue; - - nested_column_nodes.push_back(column_node); - nested_types.push_back(column_type_array->getNestedType()); - nested_names_array.push_back(Field(std::move(column_name_identifier_last_part))); - } - - if (!nested_types.empty()) - { - auto nested_function_node = std::make_shared("nested"); - auto & nested_function_node_arguments = nested_function_node->getArguments().getNodes(); - - auto nested_function_names_array_type = std::make_shared(std::make_shared()); - auto nested_function_names_constant_node = std::make_shared(std::move(nested_names_array), - std::move(nested_function_names_array_type)); - nested_function_node_arguments.push_back(std::move(nested_function_names_constant_node)); - nested_function_node_arguments.insert(nested_function_node_arguments.end(), - nested_column_nodes.begin(), - nested_column_nodes.end()); - - auto nested_function = FunctionFactory::instance().get(nested_function_node->getFunctionName(), scope.context); - nested_function_node->resolveAsFunction(nested_function->build(nested_function_node->getArgumentColumns())); - - clone_is_needed = false; - result_expression = std::move(nested_function_node); - } - } - - if (!result_expression) - { - if (can_be_not_found) - return {}; - std::unordered_set valid_identifiers; - collectTableExpressionValidIdentifiersForTypoCorrection(identifier, - table_expression_node, - table_expression_data, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Identifier '{}' cannot be resolved from {}. In scope {}{}", - identifier.getFullName(), - table_expression_source, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (clone_is_needed) - result_expression = result_expression->clone(); - - auto qualified_identifier = identifier; - - for (size_t i = 0; i < identifier_column_qualifier_parts; ++i) - { - auto qualified_identifier_with_removed_part = qualified_identifier; - qualified_identifier_with_removed_part.popFirst(); - - if (qualified_identifier_with_removed_part.empty()) - break; - - IdentifierLookup column_identifier_lookup = {qualified_identifier_with_removed_part, IdentifierLookupContext::EXPRESSION}; - if (tryBindIdentifierToAliases(column_identifier_lookup, scope)) - break; - - if (table_expression_data.should_qualify_columns && - tryBindIdentifierToTableExpressions(column_identifier_lookup, table_expression_node, scope)) - break; - - qualified_identifier = std::move(qualified_identifier_with_removed_part); - } - - auto qualified_identifier_full_name = qualified_identifier.getFullName(); - node_to_projection_name.emplace(result_expression, std::move(qualified_identifier_full_name)); - - return result_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (parts_size == 1 && path_start == table_name) - return table_expression_node; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return table_expression_node; - else - return {}; - } - - /** If identifier first part binds to some column start or table has full identifier name. Then we can try to find whole identifier in table. - * 1. Try to bind identifier first part to column in table, if true get full identifier from table or throw exception. - * 2. Try to bind identifier first part to table name or storage alias, if true remove first part and try to get full identifier from table or throw exception. - * Storage alias works for subquery, table function as well. - * 3. Try to bind identifier first parts to database name and table name, if true remove first two parts and try to get full identifier from table or throw exception. - */ - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier))) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/); - - if (table_expression_data.canBindIdentifier(IdentifierView(identifier))) - { - /** This check is insufficient to determine whether and identifier can be resolved from table expression. - * A further check will be performed in `tryResolveIdentifierFromStorage` to see if we have such a subcolumn. - * In cases where the subcolumn cannot be found we want to have `nullptr` instead of exception. - * So, we set `can_be_not_found = true` to have an attempt to resolve the identifier from another table expression. - * Example: `SELECT t.t from (SELECT 1 as t) AS a FULL JOIN (SELECT 1 as t) as t ON a.t = t.t;` - * Initially, we will try to resolve t.t from `a` because `t.` is bound to `1 as t`. However, as it is not a nested column, we will need to resolve it from the second table expression. - */ - auto resolved_identifier = tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/, true /*can_be_not_found*/); - if (resolved_identifier) - return resolved_identifier; - } - - if (identifier.getPartsSize() == 1) - return {}; - - const auto & table_name = table_expression_data.table_name; - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 1 /*identifier_column_qualifier_parts*/); - - if (identifier.getPartsSize() == 2) - return {}; - - const auto & database_name = table_expression_data.database_name; - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 2 /*identifier_column_qualifier_parts*/); - - return {}; -} - -QueryTreeNodePtr checkIsMissedObjectJSONSubcolumn(const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier) -{ - if (left_resolved_identifier && right_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT - && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL" && right_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (left_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (right_resolved_identifier && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & right_resolved_column = right_resolved_identifier->as(); - if (right_resolved_column.getValueStringRepresentation() == "NULL") - return right_resolved_identifier; - } - return {}; -} - -/// Used to replace columns that changed type because of JOIN to their original type -class ReplaceColumnsVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit ReplaceColumnsVisitor(const QueryTreeNodePtrWithHashMap & replacement_map_, const ContextPtr & context_) - : replacement_map(replacement_map_) - , context(context_) - {} - - /// Apply replacement transitively, because column may change it's type twice, one to have a supertype and then because of `joun_use_nulls` - static QueryTreeNodePtr findTransitiveReplacement(QueryTreeNodePtr node, const QueryTreeNodePtrWithHashMap & replacement_map_) - { - auto it = replacement_map_.find(node); - QueryTreeNodePtr result_node = nullptr; - for (; it != replacement_map_.end(); it = replacement_map_.find(result_node)) - { - if (result_node && result_node->isEqual(*it->second)) - { - Strings map_dump; - for (const auto & [k, v]: replacement_map_) - map_dump.push_back(fmt::format("{} -> {} (is_equals: {}, is_same: {})", - k.node->dumpTree(), v->dumpTree(), k.node->isEqual(*v), k.node == v)); - throw Exception(ErrorCodes::LOGICAL_ERROR, "Infinite loop in query tree replacement map: {}", fmt::join(map_dump, "; ")); - } - chassert(it->second); - - result_node = it->second; - } - return result_node; - } - - void visitImpl(QueryTreeNodePtr & node) - { - if (auto replacement_node = findTransitiveReplacement(node, replacement_map)) - node = replacement_node; - - if (auto * function_node = node->as(); function_node && function_node->isResolved()) - rerunFunctionResolve(function_node, context); - } - - /// We want to re-run resolve for function _after_ its arguments are replaced - bool shouldTraverseTopToBottom() const { return false; } - - bool needChildVisit(QueryTreeNodePtr & /* parent */, QueryTreeNodePtr & child) - { - /// Visit only expressions, but not subqueries - return child->getNodeType() == QueryTreeNodeType::IDENTIFIER - || child->getNodeType() == QueryTreeNodeType::LIST - || child->getNodeType() == QueryTreeNodeType::FUNCTION - || child->getNodeType() == QueryTreeNodeType::COLUMN; - } - -private: - const QueryTreeNodePtrWithHashMap & replacement_map; - const ContextPtr & context; -}; - -/// Compare resolved identifiers considering columns that become nullable after JOIN -bool resolvedIdenfiersFromJoinAreEquals( - const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier, - const IdentifierResolveScope & scope) -{ - auto left_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(left_resolved_identifier, scope.join_columns_with_changed_types); - const auto & left_resolved_to_compare = left_original_node ? left_original_node : left_resolved_identifier; - - auto right_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(right_resolved_identifier, scope.join_columns_with_changed_types); - const auto & right_resolved_to_compare = right_original_node ? right_original_node : right_resolved_identifier; - - return left_resolved_to_compare->isEqual(*right_resolved_to_compare, IQueryTreeNode::CompareOptions{.compare_aliases = false}); -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_join_node = table_expression_node->as(); - auto left_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getLeftTableExpression(), scope); - auto right_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getRightTableExpression(), scope); - - if (!identifier_lookup.isExpressionLookup()) - { - if (left_resolved_identifier && right_resolved_identifier) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.dump(), - scope.scope_node->formatASTForErrorMessage()); - - return left_resolved_identifier ? left_resolved_identifier : right_resolved_identifier; - } - - bool join_node_in_resolve_process = scope.table_expressions_in_resolve_process.contains(table_expression_node.get()); - - std::unordered_map join_using_column_name_to_column_node; - - if (!join_node_in_resolve_process && from_join_node.isUsingJoinExpression()) - { - auto & join_using_list = from_join_node.getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & column_node = join_using_node->as(); - join_using_column_name_to_column_node.emplace(column_node.getColumnName(), std::static_pointer_cast(join_using_node)); - } - } - - auto check_nested_column_not_in_using = [&join_using_column_name_to_column_node, &identifier_lookup](const QueryTreeNodePtr & node) - { - /** tldr: When an identifier is resolved into the function `nested` or `getSubcolumn`, and - * some column in its argument is in the USING list and its type has to be updated, we throw an error to avoid overcomplication. - * - * Identifiers can be resolved into functions in case of nested or subcolumns. - * For example `t.t.t` can be resolved into `getSubcolumn(t, 't.t')` function in case of `t` is `Tuple`. - * So, `t` in USING list is resolved from JOIN itself and has supertype of columns from left and right table. - * But `t` in `getSubcolumn` argument is still resolved from table and we need to update its type. - * - * Example: - * - * SELECT t.t FROM ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t UInt32, s1 String), s1 String) as t - * ) AS a FULL JOIN ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t Int32, s2 String), s2 String) as t - * ) AS b USING t; - * - * Result type of `t` is `Tuple(Tuple(Int64, String), String)` (different type and no names for subcolumns), - * so it may be tricky to have a correct type for `t.t` that is resolved into getSubcolumn(t, 't'). - * - * It can be more complicated in case of Nested subcolumns, in that case in query: - * SELECT t FROM ... JOIN ... USING (t.t) - * Here, `t` is resolved into function `nested(['t', 's'], t.t, t.s) so, `t.t` should be from JOIN and `t.s` should be from table. - * - * Updating type accordingly is pretty complicated, so just forbid such cases. - * - * While it still may work for storages that support selecting subcolumns directly without `getSubcolumn` function: - * SELECT t, t.t, toTypeName(t), toTypeName(t.t) FROM t1 AS a FULL JOIN t2 AS b USING t.t; - * We just support it as a best-effort: `t` will have original type from table, but `t.t` will have super-type from JOIN. - * Probably it's good to prohibit such cases as well, but it's not clear how to check it in general case. - */ - if (node->getNodeType() != QueryTreeNodeType::FUNCTION) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {}, expected function node", node->getNodeType()); - - const auto & function_argument_nodes = node->as().getArguments().getNodes(); - for (const auto & argument_node : function_argument_nodes) - { - if (argument_node->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_name = argument_node->as().getColumnName(); - if (join_using_column_name_to_column_node.contains(column_name)) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Cannot select subcolumn for identifier '{}' while joining using column '{}'", - identifier_lookup.identifier, column_name); - } - else if (argument_node->getNodeType() == QueryTreeNodeType::CONSTANT) - { - continue; - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {} for argument node in {}", - argument_node->getNodeType(), node->formatASTForErrorMessage()); - } - } - }; - - std::optional resolved_side; - QueryTreeNodePtr resolved_identifier; - - JoinKind join_kind = from_join_node.getKind(); - - /// If columns from left or right table were missed Object(Nullable('json')) subcolumns, they will be replaced - /// to ConstantNode(NULL), which can't be cast to ColumnNode, so we resolve it here. - if (auto missed_subcolumn_identifier = checkIsMissedObjectJSONSubcolumn(left_resolved_identifier, right_resolved_identifier)) - return missed_subcolumn_identifier; - - if (left_resolved_identifier && right_resolved_identifier) - { - auto using_column_node_it = join_using_column_name_to_column_node.end(); - if (left_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && right_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getColumnName() == right_resolved_column.getColumnName()) - using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - } - else - { - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(left_resolved_identifier); - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(right_resolved_identifier); - } - - if (using_column_node_it != join_using_column_name_to_column_node.end()) - { - JoinTableSide using_column_inner_column_table_side = isRight(join_kind) ? JoinTableSide::Right : JoinTableSide::Left; - auto & using_column_node = using_column_node_it->second->as(); - auto & using_expression_list = using_column_node.getExpression()->as(); - - size_t inner_column_node_index = using_column_inner_column_table_side == JoinTableSide::Left ? 0 : 1; - const auto & inner_column_node = using_expression_list.getNodes().at(inner_column_node_index); - - auto result_column_node = inner_column_node->clone(); - auto & result_column = result_column_node->as(); - result_column.setColumnType(using_column_node.getColumnType()); - - const auto & join_using_left_column = using_expression_list.getNodes().at(0); - if (!result_column_node->isEqual(*join_using_left_column)) - scope.join_columns_with_changed_types[result_column_node] = join_using_left_column; - - resolved_identifier = std::move(result_column_node); - } - else if (resolvedIdenfiersFromJoinAreEquals(left_resolved_identifier, right_resolved_identifier, scope)) - { - const auto & identifier_path_part = identifier_lookup.identifier.front(); - auto * left_resolved_identifier_column = left_resolved_identifier->as(); - auto * right_resolved_identifier_column = right_resolved_identifier->as(); - - if (left_resolved_identifier_column && right_resolved_identifier_column) - { - const auto & left_column_source_alias = left_resolved_identifier_column->getColumnSource()->getAlias(); - const auto & right_column_source_alias = right_resolved_identifier_column->getColumnSource()->getAlias(); - - /** If column from right table was resolved using alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one JOIN system.one AS A ON A.dummy = system.one.dummy; - * - * If alias is specified for left table, and alias is not specified for right table and identifier was resolved - * without using left table alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one AS A JOIN system.one ON A.dummy = system.one.dummy; - * - * Otherwise we prefer column from left table. - */ - bool column_resolved_using_right_alias = identifier_path_part == right_column_source_alias; - bool column_resolved_without_using_left_alias = !left_column_source_alias.empty() - && right_column_source_alias.empty() - && identifier_path_part != left_column_source_alias; - if (column_resolved_using_right_alias || column_resolved_without_using_left_alias) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else if (scope.joins_count == 1 && scope.context->getSettingsRef().single_join_prefer_left_table) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - else - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier '{}'. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - else if (left_resolved_identifier) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(left_resolved_identifier); - } - else - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*left_resolved_column.getColumnType())) - { - auto left_resolved_column_clone = std::static_pointer_cast(left_resolved_column.clone()); - left_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(left_resolved_column_clone); - - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - else if (right_resolved_identifier) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(right_resolved_identifier); - } - else - { - auto & right_resolved_column = right_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(right_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*right_resolved_column.getColumnType())) - { - auto right_resolved_column_clone = std::static_pointer_cast(right_resolved_column.clone()); - right_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(right_resolved_column_clone); - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - - if (join_node_in_resolve_process || !resolved_identifier) - return resolved_identifier; - - if (scope.join_use_nulls) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier); - auto nullable_resolved_identifier = convertJoinedColumnTypeToNullIfNeeded(resolved_identifier, join_kind, resolved_side, scope); - if (nullable_resolved_identifier) - { - resolved_identifier = nullable_resolved_identifier; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(resolved_identifier, projection_name_it->second); - } - } - } - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope) -{ - const auto * resolved_function = resolved_expression->as(); - if (!resolved_function || resolved_function->getFunctionName() != "getSubcolumn") - return {}; - - const auto * array_join_parent_column = array_join_column_inner_expression.get(); - - /** If both resolved and array-joined expressions are subcolumns, try to match them: - * For example, in `SELECT t.map.values FROM (SELECT * FROM tbl) ARRAY JOIN t.map` - * Identifier `t.map.values` is resolved into `getSubcolumn(t, 'map.values')` and t.map is resolved into `getSubcolumn(t, 'map')` - * Since we need to perform array join on `getSubcolumn(t, 'map')`, `t.map.values` should become `getSubcolumn(getSubcolumn(t, 'map'), 'values')` - * - * Note: It doesn't work when subcolumn in ARRAY JOIN is transformed by another expression, for example - * SELECT c.map, c.map.values FROM (SELECT * FROM tbl) ARRAY JOIN mapApply(x -> x, t.map); - */ - String array_join_subcolumn_prefix; - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "getSubcolumn") - { - const auto & argument_nodes = array_join_column_inner_expression_function->getArguments().getNodes(); - if (argument_nodes.size() == 2 && argument_nodes.at(1)->getNodeType() == QueryTreeNodeType::CONSTANT) - { - const auto & constant_node = argument_nodes.at(1)->as(); - const auto & constant_node_value = constant_node.getValue(); - if (constant_node_value.getType() == Field::Types::String) - { - array_join_subcolumn_prefix = constant_node_value.get() + "."; - array_join_parent_column = argument_nodes.at(0).get(); - } - } - } - - const auto & argument_nodes = resolved_function->getArguments().getNodes(); - if (argument_nodes.size() != 2 && !array_join_parent_column->isEqual(*argument_nodes.at(0))) - return {}; - - const auto * second_argument = argument_nodes.at(1)->as(); - if (!second_argument || second_argument->getValue().getType() != Field::Types::String) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected constant string as second argument of getSubcolumn function {}", resolved_function->dumpTree()); - - const auto & resolved_subcolumn_path = second_argument->getValue().get(); - if (!startsWith(resolved_subcolumn_path, array_join_subcolumn_prefix)) - return {}; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(array_join_column_expression_typed.getColumn(), array_join_column_expression_typed.getColumnSource())); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(resolved_subcolumn_path.substr(array_join_subcolumn_prefix.size()))); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - return function_query_node; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & array_join_node = table_expression_node->as(); - const auto & array_join_column_expressions_list = array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions_list.getNodes(); - - QueryTreeNodePtr array_join_resolved_expression; - - /** Special case when qualified or unqualified identifier point to array join expression without alias. - * - * CREATE TABLE test_table (id UInt64, value String, value_array Array(UInt8)) ENGINE=TinyLog; - * SELECT id, value, value_array, test_table.value_array, default.test_table.value_array FROM test_table ARRAY JOIN value_array; - * - * value_array, test_table.value_array, default.test_table.value_array must be resolved into array join expression. - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - if (array_join_column_expression_typed.hasAlias()) - continue; - - auto & array_join_column_inner_expression = array_join_column_expression_typed.getExpressionOrThrow(); - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "nested" && - array_join_column_inner_expression_function->getArguments().getNodes().size() > 1 && - isTuple(array_join_column_expression_typed.getResultType())) - { - const auto & nested_function_arguments = array_join_column_inner_expression_function->getArguments().getNodes(); - size_t nested_function_arguments_size = nested_function_arguments.size(); - - const auto & nested_keys_names_constant_node = nested_function_arguments[0]->as(); - const auto & nested_keys_names = nested_keys_names_constant_node.getValue().get(); - size_t nested_keys_names_size = nested_keys_names.size(); - - if (nested_keys_names_size == nested_function_arguments_size - 1) - { - for (size_t i = 1; i < nested_function_arguments_size; ++i) - { - if (!nested_function_arguments[i]->isEqual(*resolved_expression)) - continue; - - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - - const auto & nested_key_name = nested_keys_names[i - 1].get(); - Identifier nested_identifier = Identifier(nested_key_name); - auto tuple_element_function = wrapExpressionNodeInTupleElement(array_join_column, nested_identifier); - resolveFunction(tuple_element_function, scope); - - array_join_resolved_expression = std::move(tuple_element_function); - break; - } - } - } - - if (array_join_resolved_expression) - break; - - if (array_join_column_inner_expression->isEqual(*resolved_expression)) - { - array_join_resolved_expression = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - break; - } - - /// When we select subcolumn of array joined column it also should be array joined - array_join_resolved_expression = matchArrayJoinSubcolumns(array_join_column_inner_expression, array_join_column_expression_typed, resolved_expression, scope); - if (array_join_resolved_expression) - break; - } - return array_join_resolved_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_array_join_node = table_expression_node->as(); - auto resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_array_join_node.getTableExpression(), scope); - - if (scope.table_expressions_in_resolve_process.contains(table_expression_node.get()) || !identifier_lookup.isExpressionLookup()) - return resolved_identifier; - - const auto & array_join_column_expressions = from_array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions.getNodes(); - - /** Allow JOIN with USING with ARRAY JOIN. - * - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN [1,2,3] AS id INNER JOIN test_table_2 AS t2 USING (id); - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN t1.id AS id INNER JOIN test_table_2 AS t2 USING (id); - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - - IdentifierView identifier_view(identifier_lookup.identifier); - - if (identifier_view.isCompound() && from_array_join_node.hasAlias() && identifier_view.front() == from_array_join_node.getAlias()) - identifier_view.popFirst(); - - const auto & alias_or_name = array_join_column_expression_typed.hasAlias() - ? array_join_column_expression_typed.getAlias() - : array_join_column_expression_typed.getColumnName(); - - if (identifier_view.front() == alias_or_name) - identifier_view.popFirst(); - else if (identifier_view.getFullName() == alias_or_name) - identifier_view.popFirst(identifier_view.getPartsSize()); /// Clear - else - continue; - - if (identifier_view.empty()) - { - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - return array_join_column; - } - - auto compound_expr = tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - identifier_lookup.identifier.getPartsSize() - identifier_view.getPartsSize() /*identifier_bind_size*/, - array_join_column_expression, - {} /* compound_expression_source */, - scope, - true /* can_be_not_found */); - - if (compound_expr) - return compound_expr; - } - - if (!resolved_identifier) - return nullptr; - - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(resolved_identifier, table_expression_node, scope); - if (array_join_resolved_expression) - resolved_identifier = std::move(array_join_resolved_expression); - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope) -{ - auto join_tree_node_type = join_tree_node->getNodeType(); - - switch (join_tree_node_type) - { - case QueryTreeNodeType::JOIN: - return tryResolveIdentifierFromJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::ARRAY_JOIN: - return tryResolveIdentifierFromArrayJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - [[fallthrough]]; - case QueryTreeNodeType::TABLE: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - { - /** Edge case scenario when subquery in FROM node try to resolve identifier from parent scopes, when FROM is not resolved. - * SELECT subquery.b AS value FROM (SELECT value, 1 AS b) AS subquery; - * TODO: This can be supported - */ - if (scope.table_expressions_in_resolve_process.contains(join_tree_node.get())) - return {}; - - return tryResolveIdentifierFromTableExpression(identifier_lookup, join_tree_node, scope); - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Scope FROM section expected table, table function, query, union, join or array join. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } -} - -/** Resolve identifier from scope join tree. - * - * 1. If identifier is in function lookup context return nullptr. - * 2. Try to resolve identifier from table columns. - * 3. If there is no FROM section return nullptr. - * 4. If identifier is in table lookup context, check if it has 1 or 2 parts, otherwise throw exception. - * If identifier has 2 parts try to match it with database_name and table_name. - * If identifier has 1 part try to match it with table_name, then try to match it with table alias. - * 5. If identifier is in expression lookup context, we first need to bind identifier to some table column using identifier first part. - * Start with identifier first part, if it match some column name in table try to get column with full identifier name. - * TODO: Need to check if it is okay to throw exception if compound identifier first part bind to column but column is not valid. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope) -{ - if (identifier_lookup.isFunctionLookup()) - return {}; - - /// Try to resolve identifier from table columns - if (auto resolved_identifier = tryResolveIdentifierFromTableColumns(identifier_lookup, scope)) - return resolved_identifier; - - if (scope.expression_join_tree_node) - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, scope.expression_join_tree_node, scope); - - auto * query_scope_node = scope.scope_node->as(); - if (!query_scope_node || !query_scope_node->getJoinTree()) - return {}; - - const auto & join_tree_node = query_scope_node->getJoinTree(); - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_tree_node, scope); -} - -/** Try resolve identifier in current scope parent scopes. - * - * TODO: If column is matched, throw exception that nested subqueries are not supported. - * - * If initial scope is expression. Then try to resolve identifier in parent scopes until query scope is hit. - * For query scope resolve strategy is same as if initial scope if query. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - bool initial_scope_is_query = scope.scope_node->getNodeType() == QueryTreeNodeType::QUERY; - bool initial_scope_is_expression = !initial_scope_is_query; - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_parent_scopes = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - IdentifierResolveScope * scope_to_check = scope.parent_scope; - - if (initial_scope_is_expression) - { - while (scope_to_check != nullptr) - { - auto resolve_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - if (resolve_result.resolved_identifier) - return resolve_result; - - bool scope_was_query = scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY; - scope_to_check = scope_to_check->parent_scope; - - if (scope_was_query) - break; - } - } - - if (!scope.context->getSettingsRef().enable_global_with_statement) - return {}; - - /** Nested subqueries cannot access outer subqueries table expressions from JOIN tree because - * that can prevent resolution of table expression from CTE. - * - * Example: WITH a AS (SELECT number FROM numbers(1)), b AS (SELECT number FROM a) SELECT * FROM a as l, b as r; - */ - if (identifier_lookup.isTableExpressionLookup()) - identifier_resolve_settings.allow_to_check_join_tree = false; - - while (scope_to_check != nullptr) - { - auto lookup_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - const auto & resolved_identifier = lookup_result.resolved_identifier; - - scope_to_check = scope_to_check->parent_scope; - - if (resolved_identifier) - { - auto * subquery_node = resolved_identifier->as(); - auto * union_node = resolved_identifier->as(); - - bool is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - bool is_table_from_expression_arguments = lookup_result.resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS && - resolved_identifier->getNodeType() == QueryTreeNodeType::TABLE; - bool is_valid_table_expression = is_cte || is_table_from_expression_arguments; - - /** From parent scopes we can resolve table identifiers only as CTE. - * Example: SELECT (SELECT 1 FROM a) FROM test_table AS a; - * - * During child scope table identifier resolve a, table node test_table with alias a from parent scope - * is invalid. - */ - if (identifier_lookup.isTableExpressionLookup() && !is_valid_table_expression) - continue; - - if (is_valid_table_expression || resolved_identifier->as()) - { - return lookup_result; - } - else if (auto * resolved_function = resolved_identifier->as()) - { - /// Special case: scalar subquery was executed and replaced by __getScalar function. - /// Handle it as a constant. - if (resolved_function->getFunctionName() == "__getScalar") - return lookup_result; - } - - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Resolve identifier '{}' from parent scope only supported for constants and CTE. Actual {} node type {}. In scope {}", - identifier_lookup.identifier.getFullName(), - resolved_identifier->formatASTForErrorMessage(), - resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - return {}; -} - -/** Resolve identifier in scope. - * - * If identifier was resolved resolve identified lookup status will be updated. - * - * Steps: - * 1. Register identifier lookup in scope identifier lookup to resolve status table. - * If entry is already registered and is not resolved, that means that we have cyclic aliases for identifier. - * Example: SELECT a AS b, b AS a; - * Try resolve identifier in current scope: - * 3. Try resolve identifier from expression arguments. - * - * If prefer_column_name_to_alias = true. - * 4. Try to resolve identifier from join tree. - * 5. Try to resolve identifier from aliases. - * Otherwise. - * 4. Try to resolve identifier from aliases. - * 5. Try to resolve identifier from join tree. - * - * 6. If it is table identifier lookup try to lookup identifier in current scope CTEs. - * - * 7. If identifier is not resolved in current scope, try to resolve it in parent scopes. - * 8. If identifier is not resolved from parent scopes and it is table identifier lookup try to lookup identifier - * in database catalog. - * - * Same is not done for functions because function resolution is more complex, and in case of aggregate functions requires not only name - * but also argument types, it is responsibility of resolve function method to handle resolution of function name. - * - * 9. If identifier was not resolved, or identifier caching was disabled remove it from identifier lookup to resolve status table. - * - * It is okay for identifier to be not resolved, in case we want first try to lookup identifier in one context, - * then if there is no identifier in this context, try to lookup in another context. - * Example: Try to lookup identifier as expression, if it is not found, lookup as function. - * Example: Try to lookup identifier as expression, if it is not found, lookup as table. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - auto it = scope.identifier_lookup_to_resolve_state.find(identifier_lookup); - if (it != scope.identifier_lookup_to_resolve_state.end()) - { - if (it->second.cyclic_identifier_resolve) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (!it->second.resolve_result.isResolved()) - it->second.cyclic_identifier_resolve = true; - - if (it->second.resolve_result.isResolved() && - scope.use_identifier_lookup_to_result_cache && - !scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) && - (!it->second.resolve_result.isResolvedFromCTEs() || !ctes_in_resolve_process.contains(identifier_lookup.identifier.getFullName()))) - return it->second.resolve_result; - } - else - { - auto [insert_it, _] = scope.identifier_lookup_to_resolve_state.insert({identifier_lookup, IdentifierResolveState()}); - it = insert_it; - } - - /// Resolve identifier from current scope - - IdentifierResolveResult resolve_result; - resolve_result.resolved_identifier = tryResolveIdentifierFromExpressionArguments(identifier_lookup, scope); - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - - if (!resolve_result.resolved_identifier) - { - bool prefer_column_name_to_alias = scope.context->getSettingsRef().prefer_column_name_to_alias; - - if (identifier_lookup.isExpressionLookup()) - { - /* For aliases from ARRAY JOIN we prefer column from join tree: - * SELECT id FROM ( SELECT ... ) AS subquery ARRAY JOIN [0] AS id INNER JOIN second_table USING (id) - * In the example, identifier `id` should be resolved into one from USING (id) column. - */ - - auto * alias_it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FULL_NAME); - if (alias_it && (*alias_it)->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_node = (*alias_it)->as(); - if (column_node.getColumnSource()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - prefer_column_name_to_alias = true; - } - } - - if (unlikely(prefer_column_name_to_alias)) - { - if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - - if (!resolve_result.resolved_identifier) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - } - else - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - { - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - else if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - } - } - - if (!resolve_result.resolved_identifier && identifier_lookup.isTableExpressionLookup()) - { - auto full_name = identifier_lookup.identifier.getFullName(); - auto cte_query_node_it = scope.cte_name_to_query_node.find(full_name); - - /// CTE may reference table expressions with the same name, e.g.: - /// - /// WITH test1 AS (SELECT * FROM test1) SELECT * FROM test1; - /// - /// Since we don't support recursive CTEs, `test1` identifier inside of CTE - /// references to table .test1. - /// This means that the example above is equivalent to the following query: - /// - /// SELECT * FROM test1; - /// - /// To accomplish this behaviour it's not allowed to resolve identifiers to - /// CTE that is being resolved. - if (cte_query_node_it != scope.cte_name_to_query_node.end() - && !ctes_in_resolve_process.contains(full_name)) - { - resolve_result.resolved_identifier = cte_query_node_it->second; - resolve_result.resolve_place = IdentifierResolvePlace::CTE; - } - } - - /// Try to resolve identifier from parent scopes - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_parent_scopes) - { - resolve_result = tryResolveIdentifierInParentScopes(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolved_from_parent_scopes = true; - } - - /// Try to resolve table identifier from database catalog - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_database_catalog && identifier_lookup.isTableExpressionLookup()) - { - resolve_result.resolved_identifier = tryResolveTableIdentifierFromDatabaseCatalog(identifier_lookup.identifier, scope.context); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::DATABASE_CATALOG; - } - - bool was_cyclic_identifier_resolve = it->second.cyclic_identifier_resolve; - if (!was_cyclic_identifier_resolve) - it->second.resolve_result = resolve_result; - it->second.cyclic_identifier_resolve = false; - - /** If identifier was not resolved, or during expression resolution identifier was explicitly added into non cached set, - * or identifier caching was disabled in resolve scope we remove identifier lookup result from identifier lookup to result table. - */ - if (!was_cyclic_identifier_resolve && (!resolve_result.resolved_identifier || - scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) || - !scope.use_identifier_lookup_to_result_cache)) - scope.identifier_lookup_to_resolve_state.erase(it); - - return resolve_result; -} - -/// Resolve query tree nodes functions implementation - -/** Qualify column nodes with projection names. - * - * Example: SELECT * FROM test_table AS t1, test_table AS t2; - */ -void QueryAnalyzer::qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - /// Build additional column qualification parts array - std::vector additional_column_qualification_parts; - - if (table_expression_node->hasAlias()) - additional_column_qualification_parts = {table_expression_node->getAlias()}; - else if (auto * table_node = table_expression_node->as()) - additional_column_qualification_parts = {table_node->getStorageID().getDatabaseName(), table_node->getStorageID().getTableName()}; - - size_t additional_column_qualification_parts_size = additional_column_qualification_parts.size(); - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - /** For each matched column node iterate over additional column qualifications and apply them if column needs to be qualified. - * To check if column needs to be qualified we check if column name can bind to any other table expression in scope or to scope aliases. - */ - std::vector column_qualified_identifier_parts; - - for (const auto & column_node : column_nodes) - { - const auto & column_name = column_node->as().getColumnName(); - column_qualified_identifier_parts = Identifier(column_name).getParts(); - - /// Iterate over additional column qualifications and apply them if needed - for (size_t i = 0; i < additional_column_qualification_parts_size; ++i) - { - auto identifier_to_check = Identifier(column_qualified_identifier_parts); - IdentifierLookup identifier_lookup{identifier_to_check, IdentifierLookupContext::EXPRESSION}; - bool need_to_qualify = table_expression_data.should_qualify_columns; - if (need_to_qualify) - need_to_qualify = tryBindIdentifierToTableExpressions(identifier_lookup, table_expression_node, scope); - - if (tryBindIdentifierToAliases(identifier_lookup, scope)) - need_to_qualify = true; - - if (need_to_qualify) - { - /** Add last qualification part that was not used into column qualified identifier. - * If additional column qualification parts consists from [database_name, table_name]. - * On first iteration if column is needed to be qualified to qualify it with table_name. - * On second iteration if column is needed to be qualified to qualify it with database_name. - */ - size_t part_index_to_use_for_qualification = additional_column_qualification_parts_size - i - 1; - const auto & part_to_use = additional_column_qualification_parts[part_index_to_use_for_qualification]; - column_qualified_identifier_parts.insert(column_qualified_identifier_parts.begin(), part_to_use); - } - else - { - break; - } - } - - auto qualified_node_name = Identifier(column_qualified_identifier_parts).getFullName(); - node_to_projection_name.emplace(column_node, qualified_node_name); - } -} - -/// Build get columns options for matcher -GetColumnsOptions QueryAnalyzer::buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context) -{ - auto & matcher_node_typed = matcher_node->as(); - UInt8 get_columns_options_kind = GetColumnsOptions::AllPhysicalAndAliases; - - if (matcher_node_typed.isAsteriskMatcher()) - { - get_columns_options_kind = GetColumnsOptions::Ordinary; - - const auto & settings = context->getSettingsRef(); - - if (settings.asterisk_include_alias_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Aliases; - - if (settings.asterisk_include_materialized_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Materialized; - } - - return GetColumnsOptions(static_cast(get_columns_options_kind)); -} - -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - /** Use resolved columns from table expression data in nearest query scope if available. - * It is important for ALIAS columns to use column nodes with resolved ALIAS expression. - */ - const TableExpressionData * table_expression_data = nullptr; - const auto * nearest_query_scope = scope.getNearestQueryScope(); - if (nearest_query_scope) - table_expression_data = &nearest_query_scope->getTableExpressionDataOrThrow(table_expression_node); - - QueryTreeNodes matched_column_nodes; - - for (const auto & column : matched_columns) - { - const auto & column_name = column.name; - if (!matcher_node_typed.isMatchingColumn(column_name)) - continue; - - if (table_expression_data) - { - auto column_node_it = table_expression_data->column_name_to_column_node.find(column_name); - if (column_node_it != table_expression_data->column_name_to_column_node.end()) - { - matched_column_nodes.emplace_back(column_node_it->second); - continue; - } - } - - matched_column_nodes.emplace_back(std::make_shared(column, table_expression_node)); - } - - const auto & qualify_matched_column_nodes_scope = nearest_query_scope ? *nearest_query_scope : scope; - qualifyColumnNodesWithProjectionNames(matched_column_nodes, table_expression_node, qualify_matched_column_nodes_scope); - - QueryAnalyzer::QueryTreeNodesWithNames matched_column_nodes_with_names; - matched_column_nodes_with_names.reserve(matched_column_nodes.size()); - - for (auto && matched_column_node : matched_column_nodes) - { - auto column_name = matched_column_node->as().getColumnName(); - matched_column_nodes_with_names.emplace_back(std::move(matched_column_node), std::move(column_name)); - } - - return matched_column_nodes_with_names; -} - -bool hasTableExpressionInJoinTree(const QueryTreeNodePtr & join_tree_node, const QueryTreeNodePtr & table_expression) -{ - QueryTreeNodes nodes_to_process; - nodes_to_process.push_back(join_tree_node); - - while (!nodes_to_process.empty()) - { - auto node_to_process = std::move(nodes_to_process.back()); - nodes_to_process.pop_back(); - if (node_to_process == table_expression) - return true; - - if (node_to_process->getNodeType() == QueryTreeNodeType::JOIN) - { - const auto & join_node = node_to_process->as(); - nodes_to_process.push_back(join_node.getLeftTableExpression()); - nodes_to_process.push_back(join_node.getRightTableExpression()); - } - } - return false; -} - -/// Columns that resolved from matcher can also match columns from JOIN USING. -/// In that case we update type to type of column in USING section. -/// TODO: It's not completely correct for qualified matchers, so t1.* should be resolved to left table column type. -/// But in planner we do not distinguish such cases. -void QueryAnalyzer::updateMatchedColumnsFromJoinUsing( - QueryTreeNodesWithNames & result_matched_column_nodes_with_names, - const QueryTreeNodePtr & source_table_expression, - IdentifierResolveScope & scope) -{ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "There are no table sources. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - const auto & join_tree = nearest_query_scope_query_node->getJoinTree(); - - const auto * join_node = join_tree->as(); - if (join_node && join_node->isUsingJoinExpression()) - { - const auto & join_using_list = join_node->getJoinExpression()->as(); - const auto & join_using_nodes = join_using_list.getNodes(); - - for (auto & [matched_column_node, _] : result_matched_column_nodes_with_names) - { - auto & matched_column_node_typed = matched_column_node->as(); - const auto & matched_column_name = matched_column_node_typed.getColumnName(); - - for (const auto & join_using_node : join_using_nodes) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (matched_column_name != join_using_column_name) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - auto it = node_to_projection_name.find(matched_column_node); - - if (hasTableExpressionInJoinTree(join_node->getLeftTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(0); - else if (hasTableExpressionInJoinTree(join_node->getRightTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(1); - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Cannot find column {} in JOIN USING section {}", - matched_column_node->dumpTree(), join_node->dumpTree()); - - matched_column_node = matched_column_node->clone(); - if (it != node_to_projection_name.end()) - node_to_projection_name.emplace(matched_column_node, it->second); - - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - } - } - } -} - -/** Resolve qualified tree matcher. - * - * First try to match qualified identifier to expression. If qualified identifier matched expression node then - * if expression is compound match it column names using matcher `isMatchingColumn` method, if expression is not compound, throw exception. - * If qualified identifier did not match expression in query tree, try to lookup qualified identifier in table context. - */ -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isQualified()); - - auto expression_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::EXPRESSION}; - auto expression_identifier_resolve_result = tryResolveIdentifier(expression_identifier_lookup, scope); - auto expression_query_tree_node = expression_identifier_resolve_result.resolved_identifier; - - /// Try to resolve unqualified matcher for query expression - - if (expression_query_tree_node) - { - auto result_type = expression_query_tree_node->getResultType(); - - while (true) - { - if (const auto * array_type = typeid_cast(result_type.get())) - result_type = array_type->getNestedType(); - else if (const auto * map_type = typeid_cast(result_type.get())) - result_type = map_type->getNestedType(); - else - break; - } - - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Qualified matcher {} find non compound expression {} with type {}. Expected tuple or array of tuples. In scope {}", - matcher_node->formatASTForErrorMessage(), - expression_query_tree_node->formatASTForErrorMessage(), - expression_query_tree_node->getResultType()->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - auto qualified_matcher_element_identifier = matcher_node_typed.getQualifiedIdentifier(); - for (const auto & element_name : element_names) - { - if (!matcher_node_typed.isMatchingColumn(element_name)) - continue; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back(expression_query_tree_node); - get_subcolumn_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - qualified_matcher_element_identifier.push_back(element_name); - node_to_projection_name.emplace(function_query_node, qualified_matcher_element_identifier.getFullName()); - qualified_matcher_element_identifier.pop_back(); - - matched_expression_nodes_with_column_names.emplace_back(std::move(function_query_node), element_name); - } - - return matched_expression_nodes_with_column_names; - } - - /// Try to resolve qualified matcher for table expression - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_cte = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - auto table_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, identifier_resolve_settings); - auto table_expression_node = table_identifier_resolve_result.resolved_identifier; - - if (!table_expression_node) - { - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Qualified matcher {} does not find table. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - NamesAndTypes matched_columns; - - auto * table_expression_query_node = table_expression_node->as(); - auto * table_expression_union_node = table_expression_node->as(); - auto * table_expression_table_node = table_expression_node->as(); - auto * table_expression_table_function_node = table_expression_node->as(); - - if (table_expression_query_node || table_expression_union_node) - { - matched_columns = table_expression_query_node ? table_expression_query_node->getProjectionColumns() - : table_expression_union_node->computeProjectionColumns(); - } - else if (table_expression_table_node || table_expression_table_function_node) - { - const auto & storage_snapshot = table_expression_table_node ? table_expression_table_node->getStorageSnapshot() - : table_expression_table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - matched_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Invalid table expression node {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto result_matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression_node, - matched_columns, - scope); - - updateMatchedColumnsFromJoinUsing(result_matched_column_nodes_with_names, table_expression_node, scope); - - return result_matched_column_nodes_with_names; -} - -/// Resolve non qualified matcher, using scope join tree node. -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isUnqualified()); - - /** There can be edge case if matcher is inside lambda expression. - * Try to find parent query expression using parent scopes. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unqualified matcher {} cannot be resolved. There are no table sources. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** For unqualifited matcher resolve we build table expressions stack from JOIN tree and then process it. - * For table, table function, query, union table expressions add matched columns into table expressions columns stack. - * For array join continue processing. - * For join node combine last left and right table expressions columns on stack together. It is important that if JOIN has USING - * we must add USING columns before combining left and right table expressions columns. Columns from left and right table - * expressions that have same names as columns in USING clause must be skipped. - */ - - auto table_expressions_stack = buildTableExpressionsStack(nearest_query_scope_query_node->getJoinTree()); - std::vector table_expressions_column_nodes_with_names_stack; - - std::unordered_set table_expression_column_names_to_skip; - - QueryTreeNodesWithNames result; - - if (matcher_node_typed.getMatcherType() == MatcherNodeType::COLUMNS_LIST) - { - auto identifiers = matcher_node_typed.getColumnsIdentifiers(); - result.reserve(identifiers.size()); - - for (const auto & identifier : identifiers) - { - auto resolve_result = tryResolveIdentifier(IdentifierLookup{identifier, IdentifierLookupContext::EXPRESSION}, scope); - if (!resolve_result.isResolved()) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Unknown identifier '{}' inside COLUMNS matcher. In scope {}", - identifier.getFullName(), scope.dump()); - - // TODO: Introduce IdentifierLookupContext::COLUMN and get rid of this check - auto * resolved_column = resolve_result.resolved_identifier->as(); - if (!resolved_column) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier '{}' inside COLUMNS matcher must resolve into a column, but got {}. In scope {}", - identifier.getFullName(), - resolve_result.resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - result.emplace_back(resolve_result.resolved_identifier, resolved_column->getColumnName()); - } - return result; - } - - result.resize(matcher_node_typed.getColumnsIdentifiers().size()); - - for (auto & table_expression : table_expressions_stack) - { - bool table_expression_in_resolve_process = nearest_query_scope->table_expressions_in_resolve_process.contains(table_expression.get()); - - if (auto * array_join_node = table_expression->as()) - { - if (table_expressions_column_nodes_with_names_stack.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 1 table expressions on stack before ARRAY JOIN processing"); - - if (table_expression_in_resolve_process) - continue; - - auto & table_expression_column_nodes_with_names = table_expressions_column_nodes_with_names_stack.back(); - - for (auto & [table_expression_column_node, _] : table_expression_column_nodes_with_names) - { - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(table_expression_column_node, - table_expression, - scope); - if (array_join_resolved_expression) - table_expression_column_node = std::move(array_join_resolved_expression); - } - - continue; - } - - auto * join_node = table_expression->as(); - - if (join_node) - { - size_t table_expressions_column_nodes_with_names_stack_size = table_expressions_column_nodes_with_names_stack.size(); - if (table_expressions_column_nodes_with_names_stack_size < 2) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 2 table expressions on stack before JOIN processing. Actual {}", - table_expressions_column_nodes_with_names_stack_size); - - auto right_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - auto left_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - table_expression_column_names_to_skip.clear(); - - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - /** If there is JOIN with USING we need to match only single USING column and do not use left table expression - * and right table expression column with same name. - * - * Example: SELECT id FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING (id); - */ - if (!table_expression_in_resolve_process && join_node->isUsingJoinExpression()) - { - auto & join_using_list = join_node->getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (!matcher_node_typed.isMatchingColumn(join_using_column_name)) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - /** If column doesn't exists in the table, then do not match column from USING clause. - * Example: SELECT a + 1 AS id, * FROM (SELECT 1 AS a) AS t1 JOIN (SELECT 2 AS id) AS t2 USING (id); - * In this case `id` is not present in the left table expression, - * so asterisk should return `id` from the right table expression. - */ - auto is_column_from_parent_scope = [&scope](const QueryTreeNodePtr & using_node_from_table) - { - const auto & using_column_from_table = using_node_from_table->as(); - auto table_expression_data_it = scope.table_expression_node_to_data.find(using_column_from_table.getColumnSource()); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - { - const auto & table_expression_data = table_expression_data_it->second; - const auto & column_name = using_column_from_table.getColumnName(); - return !table_expression_data.column_name_to_column_node.contains(column_name); - } - return false; - }; - - if (is_column_from_parent_scope(join_using_column_nodes.at(0)) || - is_column_from_parent_scope(join_using_column_nodes.at(1))) - continue; - - QueryTreeNodePtr matched_column_node; - - if (isRight(join_node->getKind())) - matched_column_node = join_using_column_nodes.at(1); - else - matched_column_node = join_using_column_nodes.at(0); - - matched_column_node = matched_column_node->clone(); - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - - table_expression_column_names_to_skip.insert(join_using_column_name); - matched_expression_nodes_with_column_names.emplace_back(std::move(matched_column_node), join_using_column_name); - } - } - - for (auto && left_table_column_with_name : left_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(left_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(left_table_column_with_name)); - } - - for (auto && right_table_column_with_name : right_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(right_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(right_table_column_with_name)); - } - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_expression_nodes_with_column_names)); - continue; - } - - if (table_expression_in_resolve_process) - { - table_expressions_column_nodes_with_names_stack.emplace_back(); - continue; - } - - auto * table_node = table_expression->as(); - auto * table_function_node = table_expression->as(); - auto * query_node = table_expression->as(); - auto * union_node = table_expression->as(); - - NamesAndTypes table_expression_columns; - - if (query_node || union_node) - { - table_expression_columns = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - } - else if (table_node || table_function_node) - { - const auto & storage_snapshot - = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - table_expression_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unqualified matcher {} resolve unexpected table expression. In scope {}", - matcher_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression, - table_expression_columns, - scope); - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_column_nodes_with_names)); - } - - for (auto & table_expression_column_nodes_with_names : table_expressions_column_nodes_with_names_stack) - { - for (auto && table_expression_column_node_with_name : table_expression_column_nodes_with_names) - result.push_back(std::move(table_expression_column_node_with_name)); - } - - return result; -} - - -/** Resolve query tree matcher. Check MatcherNode.h for detailed matcher description. Check ColumnTransformers.h for detailed transformers description. - * - * 1. Populate matched expression nodes resolving qualified or unqualified matcher. - * 2. Apply column transformers to matched expression nodes. For strict column transformers save used column names. - * 3. Validate strict column transformers. - */ -ProjectionNames QueryAnalyzer::resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - QueryTreeNodesWithNames matched_expression_nodes_with_names; - - if (matcher_node_typed.isQualified()) - matched_expression_nodes_with_names = resolveQualifiedMatcher(matcher_node, scope); - else - matched_expression_nodes_with_names = resolveUnqualifiedMatcher(matcher_node, scope); - - if (scope.join_use_nulls) - { - /** If we are resolving matcher came from the result of JOIN and `join_use_nulls` is set, - * we need to convert joined column type to Nullable. - * We are taking the nearest JoinNode to check to which table column belongs, - * because for LEFT/RIGHT join, we convert only the corresponding side. - */ - const auto * nearest_query_scope = scope.getNearestQueryScope(); - const QueryNode * nearest_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - const QueryTreeNodePtr & nearest_scope_join_tree = nearest_scope_query_node ? nearest_scope_query_node->getJoinTree() : nullptr; - const JoinNode * nearest_scope_join_node = nearest_scope_join_tree ? nearest_scope_join_tree->as() : nullptr; - if (nearest_scope_join_node) - { - for (auto & [node, node_name] : matched_expression_nodes_with_names) - { - auto join_identifier_side = getColumnSideFromJoinTree(node, *nearest_scope_join_node); - auto projection_name_it = node_to_projection_name.find(node); - auto nullable_node = convertJoinedColumnTypeToNullIfNeeded(node, nearest_scope_join_node->getKind(), join_identifier_side, scope); - if (nullable_node) - { - node = nullable_node; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(node, projection_name_it->second); - } - } - } - } - } - - if (!scope.expressions_in_resolve_process_stack.hasAggregateFunction()) - { - for (auto & [node, _] : matched_expression_nodes_with_names) - { - auto it = scope.nullable_group_by_keys.find(node); - if (it != scope.nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - } - } - } - - std::unordered_map> strict_transformer_to_used_column_names; - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - auto * except_transformer = transformer->as(); - auto * replace_transformer = transformer->as(); - - if (except_transformer && except_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(except_transformer, std::unordered_set()); - else if (replace_transformer && replace_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(replace_transformer, std::unordered_set()); - } - - ListNodePtr list = std::make_shared(); - ProjectionNames result_projection_names; - ProjectionNames node_projection_names; - - for (auto & [node, column_name] : matched_expression_nodes_with_names) - { - bool apply_transformer_was_used = false; - bool replace_transformer_was_used = false; - bool execute_apply_transformer = false; - bool execute_replace_transformer = false; - - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - else - result_projection_names.push_back(column_name); - - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - if (auto * apply_transformer = transformer->as()) - { - const auto & expression_node = apply_transformer->getExpressionNode(); - apply_transformer_was_used = true; - - if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::LAMBDA) - { - auto lambda_expression_to_resolve = expression_node->clone(); - IdentifierResolveScope lambda_scope(expression_node, &scope /*parent_scope*/); - node_projection_names = resolveLambda(expression_node, lambda_expression_to_resolve, {node}, lambda_scope); - auto & lambda_expression_to_resolve_typed = lambda_expression_to_resolve->as(); - node = lambda_expression_to_resolve_typed.getExpression(); - } - else if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::FUNCTION) - { - auto function_to_resolve_untyped = expression_node->clone(); - auto & function_to_resolve_typed = function_to_resolve_untyped->as(); - function_to_resolve_typed.getArguments().getNodes().push_back(node); - node_projection_names = resolveFunction(function_to_resolve_untyped, scope); - node = function_to_resolve_untyped; - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unsupported apply matcher expression type. Expected lambda or function apply transformer. Actual {}. In scope {}", - transformer->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - execute_apply_transformer = true; - } - else if (auto * except_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - if (except_transformer->isColumnMatching(column_name)) - { - if (except_transformer->isStrict()) - strict_transformer_to_used_column_names[except_transformer].insert(column_name); - - node = {}; - break; - } - } - else if (auto * replace_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - auto replace_expression = replace_transformer->findReplacementExpression(column_name); - if (!replace_expression) - continue; - - replace_transformer_was_used = true; - - if (replace_transformer->isStrict()) - strict_transformer_to_used_column_names[replace_transformer].insert(column_name); - - node = replace_expression->clone(); - node_projection_names = resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** If replace expression resolved as single node, we want to use replace column name as result projection name, instead - * of using replace expression projection name. - * - * Example: SELECT * REPLACE id + 5 AS id FROM test_table; - */ - if (node_projection_names.size() == 1) - node_projection_names[0] = column_name; - - execute_replace_transformer = true; - } - - if (execute_apply_transformer || execute_replace_transformer) - { - if (auto * node_list = node->as()) - { - auto & node_list_nodes = node_list->getNodes(); - size_t node_list_nodes_size = node_list_nodes.size(); - - if (node_list_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "{} transformer {} resolved as list node with size {}. Expected 1. In scope {}", - execute_apply_transformer ? "APPLY" : "REPLACE", - transformer->formatASTForErrorMessage(), - node_list_nodes_size, - scope.scope_node->formatASTForErrorMessage()); - - node = node_list_nodes[0]; - } - - if (node_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Matcher node expected 1 projection name. Actual {}", node_projection_names.size()); - - result_projection_names.back() = std::move(node_projection_names[0]); - node_to_projection_name.emplace(node, result_projection_names.back()); - node_projection_names.clear(); - } - } - - if (node) - list->getNodes().push_back(node); - else - result_projection_names.pop_back(); - } - - for (auto & [strict_transformer, used_column_names] : strict_transformer_to_used_column_names) - { - auto strict_transformer_type = strict_transformer->getTransformerType(); - const Names * strict_transformer_column_names = nullptr; - - switch (strict_transformer_type) - { - case ColumnTransfomerType::EXCEPT: - { - const auto * except_transformer = static_cast(strict_transformer); - const auto & except_names = except_transformer->getExceptColumnNames(); - - if (except_names.size() != used_column_names.size()) - strict_transformer_column_names = &except_transformer->getExceptColumnNames(); - - break; - } - case ColumnTransfomerType::REPLACE: - { - const auto * replace_transformer = static_cast(strict_transformer); - const auto & replacement_names = replace_transformer->getReplacementsNames(); - - if (replacement_names.size() != used_column_names.size()) - strict_transformer_column_names = &replace_transformer->getReplacementsNames(); - - break; - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected strict EXCEPT or REPLACE column transformer. Actual type {}. In scope {}", - toString(strict_transformer_type), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (!strict_transformer_column_names) - continue; - - Names non_matched_column_names; - size_t strict_transformer_column_names_size = strict_transformer_column_names->size(); - for (size_t i = 0; i < strict_transformer_column_names_size; ++i) - { - const auto & column_name = (*strict_transformer_column_names)[i]; - if (used_column_names.find(column_name) == used_column_names.end()) - non_matched_column_names.push_back(column_name); - } - - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Strict {} column transformer {} expects following column(s) : {}. In scope {}", - toString(strict_transformer_type), - strict_transformer->formatASTForErrorMessage(), - fmt::join(non_matched_column_names, ", "), - scope.scope_node->formatASTForErrorMessage()); - } - - auto original_ast = matcher_node->getOriginalAST(); - matcher_node = std::move(list); - if (original_ast) - matcher_node->setOriginalAST(original_ast); - - return result_projection_names; -} - -/** Resolve window function window node. - * - * Node can be identifier or window node. - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - * Example: SELECT count(*) OVER (PARTITION BY id); - * - * If node has parent window name specified, then parent window definition is searched in nearest query scope WINDOW section. - * If node is identifier, than node is replaced with window definition. - * If node is window, that window node is merged with parent window node. - * - * Window node PARTITION BY and ORDER BY parts are resolved. - * If window node has frame begin OFFSET or frame end OFFSET specified, they are resolved, and window node frame constants are updated. - * Window node frame is validated. - */ -ProjectionName QueryAnalyzer::resolveWindow(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - std::string parent_window_name; - auto * identifier_node = node->as(); - - ProjectionName result_projection_name; - QueryTreeNodePtr parent_window_node; - - if (identifier_node) - parent_window_name = identifier_node->getIdentifier().getFullName(); - else if (auto * window_node = node->as()) - parent_window_name = window_node->getParentWindowName(); - - if (!parent_window_name.empty()) - { - auto * nearest_query_scope = scope.getNearestQueryScope(); - - if (!nearest_query_scope) - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Window '{}' does not exist.", parent_window_name); - - auto & scope_window_name_to_window_node = nearest_query_scope->window_name_to_window_node; - - auto window_node_it = scope_window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope_window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - nearest_query_scope->scope_node->formatASTForErrorMessage()); - - parent_window_node = window_node_it->second; - - if (identifier_node) - { - node = parent_window_node->clone(); - result_projection_name = parent_window_name; - } - else - { - mergeWindowWithParentWindow(node, parent_window_node, scope); - } - } - - auto & window_node = node->as(); - window_node.setParentWindowName({}); - - ProjectionNames partition_by_projection_names = resolveExpressionNodeList(window_node.getPartitionByNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - ProjectionNames order_by_projection_names = resolveSortNodeList(window_node.getOrderByNode(), scope); - - ProjectionNames frame_begin_offset_projection_names; - ProjectionNames frame_end_offset_projection_names; - - if (window_node.hasFrameBeginOffset()) - { - frame_begin_offset_projection_names = resolveExpressionNode(window_node.getFrameBeginOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_begin_constant_node = window_node.getFrameBeginOffsetNode()->as(); - if (!window_frame_begin_constant_node || !isNativeNumber(removeNullable(window_frame_begin_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameBeginOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().begin_offset = window_frame_begin_constant_node->getValue(); - if (frame_begin_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_begin_offset_projection_names.size()); - } - - if (window_node.hasFrameEndOffset()) - { - frame_end_offset_projection_names = resolveExpressionNode(window_node.getFrameEndOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_end_constant_node = window_node.getFrameEndOffsetNode()->as(); - if (!window_frame_end_constant_node || !isNativeNumber(removeNullable(window_frame_end_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameEndOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().end_offset = window_frame_end_constant_node->getValue(); - if (frame_end_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_end_offset_projection_names.size()); - } - - window_node.getWindowFrame().checkValid(); - - if (result_projection_name.empty()) - { - result_projection_name = calculateWindowProjectionName(node, - parent_window_node, - parent_window_name, - partition_by_projection_names, - order_by_projection_names, - frame_begin_offset_projection_names.empty() ? "" : frame_begin_offset_projection_names.front(), - frame_end_offset_projection_names.empty() ? "" : frame_end_offset_projection_names.front()); - } - - return result_projection_name; -} - -/** Resolve lambda function. - * This function modified lambda_node during resolve. It is caller responsibility to clone lambda before resolve - * if it is needed for later use. - * - * Lambda body expression result projection names is used as lambda projection names. - * - * Lambda expression can be resolved into list node. It is caller responsibility to handle it properly. - * - * lambda_node - node that must have LambdaNode type. - * lambda_node_to_resolve - lambda node to resolve that must have LambdaNode type. - * arguments - lambda arguments. - * scope - lambda scope. It is client responsibility to create it. - * - * Resolve steps: - * 1. Validate arguments. - * 2. Register lambda node in lambdas in resolve process. This is necessary to prevent recursive lambda resolving. - * 3. Initialize scope with lambda aliases. - * 4. Validate lambda argument names, and scope expressions. - * 5. Resolve lambda body expression. - * 6. Deregister lambda node from lambdas in resolve process. - */ -ProjectionNames QueryAnalyzer::resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope) -{ - auto & lambda_to_resolve = lambda_node_to_resolve->as(); - auto & lambda_arguments_nodes = lambda_to_resolve.getArguments().getNodes(); - size_t lambda_arguments_nodes_size = lambda_arguments_nodes.size(); - - /** Register lambda as being resolved, to prevent recursive lambdas resolution. - * Example: WITH (x -> x + lambda_2(x)) AS lambda_1, (x -> x + lambda_1(x)) AS lambda_2 SELECT 1; - */ - auto it = lambdas_in_resolve_process.find(lambda_node.get()); - if (it != lambdas_in_resolve_process.end()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive lambda {}. In scope {}", - lambda_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - lambdas_in_resolve_process.emplace(lambda_node.get()); - - size_t arguments_size = lambda_arguments.size(); - if (lambda_arguments_nodes_size != arguments_size) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} expect {} arguments. Actual {}. In scope {}", - lambda_to_resolve.formatASTForErrorMessage(), - lambda_arguments_nodes_size, - arguments_size, - scope.scope_node->formatASTForErrorMessage()); - - /// Initialize aliases in lambda scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - visitor.visit(lambda_to_resolve.getExpression()); - - /** Replace lambda arguments with new arguments. - * Additionally validate that there are no aliases with same name as lambda arguments. - * Arguments are registered in current scope expression_argument_name_to_node map. - */ - QueryTreeNodes lambda_new_arguments_nodes; - lambda_new_arguments_nodes.reserve(lambda_arguments_nodes_size); - - for (size_t i = 0; i < lambda_arguments_nodes_size; ++i) - { - auto & lambda_argument_node = lambda_arguments_nodes[i]; - const auto * lambda_argument_identifier = lambda_argument_node->as(); - const auto * lambda_argument_column = lambda_argument_node->as(); - if (!lambda_argument_identifier && !lambda_argument_column) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected IDENTIFIER or COLUMN as lambda argument, got {}", lambda_node->dumpTree()); - const auto & lambda_argument_name = lambda_argument_identifier ? lambda_argument_identifier->getIdentifier().getFullName() - : lambda_argument_column->getColumnName(); - - bool has_expression_node = scope.aliases.alias_name_to_expression_node->contains(lambda_argument_name); - bool has_alias_node = scope.aliases.alias_name_to_lambda_node.contains(lambda_argument_name); - - if (has_expression_node || has_alias_node) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Alias name '{}' inside lambda {} cannot have same name as lambda argument. In scope {}", - lambda_argument_name, - lambda_argument_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - scope.expression_argument_name_to_node.emplace(lambda_argument_name, lambda_arguments[i]); - lambda_new_arguments_nodes.push_back(lambda_arguments[i]); - } - - lambda_to_resolve.getArguments().getNodes() = std::move(lambda_new_arguments_nodes); - - /// Lambda body expression is resolved as standard query expression node. - auto result_projection_names = resolveExpressionNode(lambda_to_resolve.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - lambdas_in_resolve_process.erase(lambda_node.get()); - - return result_projection_names; -} - -namespace -{ -void checkFunctionNodeHasEmptyNullsAction(FunctionNode const & node) -{ - if (node.getNullsAction() != NullsAction::EMPTY) - throw Exception( - ErrorCodes::SYNTAX_ERROR, - "Function with name '{}' cannot use {} NULLS", - node.getFunctionName(), - node.getNullsAction() == NullsAction::IGNORE_NULLS ? "IGNORE" : "RESPECT"); -} -} - -/** Resolve function node in scope. - * During function node resolve, function node can be replaced with another expression (if it match lambda or sql user defined function), - * with constant (if it allow constant folding), or with expression list. It is caller responsibility to handle such cases appropriately. - * - * Steps: - * 1. Resolve function parameters. Validate that each function parameter must be constant node. - * 2. Try to lookup function as lambda in current scope. If it is lambda we can skip `in` and `count` special handling. - * 3. If function is count function, that take unqualified ASTERISK matcher, remove it from its arguments. Example: SELECT count(*) FROM test_table; - * 4. If function is `IN` function, then right part of `IN` function is replaced as subquery. - * 5. Resolve function arguments list, lambda expressions are allowed as function arguments. - * For `IN` function table expressions are allowed as function arguments. - * 6. Initialize argument_columns, argument_types, function_lambda_arguments_indexes arrays from function arguments. - * 7. If function name identifier was not resolved as function in current scope, try to lookup lambda from sql user defined functions factory. - * 8. If function was resolve as lambda from step 2 or 7, then resolve lambda using function arguments and replace function node with lambda result. - * After than function node is resolved. - * 9. If function was not resolved during step 6 as lambda, then try to resolve function as window function or executable user defined function - * or ordinary function or aggregate function. - * - * If function is resolved as window function or executable user defined function or aggregate function, function node is resolved - * no additional special handling is required. - * - * 8. If function was resolved as non aggregate function. Then if some of function arguments are lambda expressions, their result types need to be initialized and - * they must be resolved. - * 9. If function is suitable for constant folding, try to perform constant folding for function node. - */ -ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - FunctionNodePtr function_node_ptr = std::static_pointer_cast(node); - auto function_name = function_node_ptr->getFunctionName(); - - /// Resolve function parameters - - auto parameters_projection_names = resolveExpressionNodeList(function_node_ptr->getParametersNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - /// Convert function parameters into constant parameters array - - Array parameters; - - auto & parameters_nodes = function_node_ptr->getParameters().getNodes(); - parameters.reserve(parameters_nodes.size()); - - for (auto & parameter_node : parameters_nodes) - { - const auto * constant_node = parameter_node->as(); - if (!constant_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parameter for function '{}' expected to have constant value. Actual {}. In scope {}", - function_name, - parameter_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - parameters.push_back(constant_node->getValue()); - } - - //// If function node is not window function try to lookup function node name as lambda identifier. - QueryTreeNodePtr lambda_expression_untyped; - if (!function_node_ptr->isWindowFunction()) - { - auto function_lookup_result = tryResolveIdentifier({Identifier{function_name}, IdentifierLookupContext::FUNCTION}, scope); - lambda_expression_untyped = function_lookup_result.resolved_identifier; - } - - bool is_special_function_in = false; - bool is_special_function_dict_get = false; - bool is_special_function_join_get = false; - bool is_special_function_exists = false; - bool is_special_function_if = false; - - if (!lambda_expression_untyped) - { - is_special_function_in = isNameOfInFunction(function_name); - is_special_function_dict_get = functionIsDictGet(function_name); - is_special_function_join_get = functionIsJoinGet(function_name); - is_special_function_exists = function_name == "exists"; - is_special_function_if = function_name == "if"; - - auto function_name_lowercase = Poco::toLower(function_name); - - /** Special handling for count and countState functions. - * - * Example: SELECT count(*) FROM test_table - * Example: SELECT countState(*) FROM test_table; - */ - if (function_node_ptr->getArguments().getNodes().size() == 1 && - (function_name_lowercase == "count" || function_name_lowercase == "countstate")) - { - auto * matcher_node = function_node_ptr->getArguments().getNodes().front()->as(); - if (matcher_node && matcher_node->isUnqualified()) - function_node_ptr->getArguments().getNodes().clear(); - } - } - - /** Special functions dictGet and its variations and joinGet can be executed when first argument is identifier. - * Example: SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Try to resolve identifier as expression identifier and if it is resolved use it. - * Example: WITH 'dict_name' AS identifier SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Otherwise replace identifier with identifier full name constant. - * Validation that dictionary exists or table exists will be performed during function `getReturnType` method call. - */ - if ((is_special_function_dict_get || is_special_function_join_get) && - !function_node_ptr->getArguments().getNodes().empty() && - function_node_ptr->getArguments().getNodes()[0]->getNodeType() == QueryTreeNodeType::IDENTIFIER) - { - auto & first_argument = function_node_ptr->getArguments().getNodes()[0]; - auto & first_argument_identifier = first_argument->as(); - auto identifier = first_argument_identifier.getIdentifier(); - - IdentifierLookup identifier_lookup{identifier, IdentifierLookupContext::EXPRESSION}; - auto resolve_result = tryResolveIdentifier(identifier_lookup, scope); - - if (resolve_result.isResolved()) - { - first_argument = std::move(resolve_result.resolved_identifier); - } - else - { - size_t parts_size = identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected {} function first argument identifier to contain 1 or 2 parts. Actual '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_special_function_dict_get) - { - scope.context->getExternalDictionariesLoader().assertDictionaryStructureExists(identifier.getFullName(), scope.context); - } - else - { - auto table_node = tryResolveTableIdentifierFromDatabaseCatalog(identifier, scope.context); - if (!table_node) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} first argument expected table identifier '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node_typed = table_node->as(); - if (!std::dynamic_pointer_cast(table_node_typed.getStorage())) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} table '{}' should have engine StorageJoin. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - first_argument = std::make_shared(identifier.getFullName()); - } - } - - if (is_special_function_exists) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /// Rewrite EXISTS (subquery) into 1 IN (SELECT 1 FROM (subquery) LIMIT 1). - auto & exists_subquery_argument = function_node_ptr->getArguments().getNodes().at(0); - - auto constant_data_type = std::make_shared(); - - auto in_subquery = std::make_shared(Context::createCopy(scope.context)); - in_subquery->setIsSubquery(true); - in_subquery->getProjection().getNodes().push_back(std::make_shared(1UL, constant_data_type)); - in_subquery->getJoinTree() = exists_subquery_argument; - in_subquery->getLimit() = std::make_shared(1UL, constant_data_type); - - function_node_ptr = std::make_shared("in"); - function_node_ptr->getArguments().getNodes() = {std::make_shared(1UL, constant_data_type), in_subquery}; - node = function_node_ptr; - function_name = "in"; - is_special_function_in = true; - } - - if (is_special_function_if && !function_node_ptr->getArguments().getNodes().empty()) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /** Handle special case with constant If function, even if some of the arguments are invalid. - * - * SELECT if(hasColumnInTable('system', 'numbers', 'not_existing_column'), not_existing_column, 5) FROM system.numbers; - */ - auto & if_function_arguments = function_node_ptr->getArguments().getNodes(); - auto if_function_condition = if_function_arguments[0]; - resolveExpressionNode(if_function_condition, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto constant_condition = tryExtractConstantFromConditionNode(if_function_condition); - - if (constant_condition.has_value() && if_function_arguments.size() == 3) - { - QueryTreeNodePtr constant_if_result_node; - QueryTreeNodePtr possibly_invalid_argument_node; - - if (*constant_condition) - { - possibly_invalid_argument_node = if_function_arguments[2]; - constant_if_result_node = if_function_arguments[1]; - } - else - { - possibly_invalid_argument_node = if_function_arguments[1]; - constant_if_result_node = if_function_arguments[2]; - } - - bool apply_constant_if_optimization = false; - - try - { - resolveExpressionNode(possibly_invalid_argument_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - } - catch (...) - { - apply_constant_if_optimization = true; - } - - if (apply_constant_if_optimization) - { - auto result_projection_names = resolveExpressionNode(constant_if_result_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - node = std::move(constant_if_result_node); - return result_projection_names; - } - } - } - - /// Resolve function arguments - bool allow_table_expressions = is_special_function_in; - auto arguments_projection_names = resolveExpressionNodeList(function_node_ptr->getArgumentsNode(), - scope, - true /*allow_lambda_expression*/, - allow_table_expressions /*allow_table_expression*/); - - /// Mask arguments if needed - if (!scope.context->getSettingsRef().format_display_secrets_in_show_and_select) - { - if (FunctionSecretArgumentsFinder::Result secret_arguments = FunctionSecretArgumentsFinderTreeNode(*function_node_ptr).getResult(); secret_arguments.count) - { - auto & argument_nodes = function_node_ptr->getArgumentsNode()->as().getNodes(); - - for (size_t n = secret_arguments.start; n < secret_arguments.start + secret_arguments.count; ++n) - { - if (auto * constant = argument_nodes[n]->as()) - { - auto mask = scope.projection_mask_map->insert({constant->getTreeHash(), scope.projection_mask_map->size() + 1}).first->second; - constant->setMaskId(mask); - arguments_projection_names[n] = "[HIDDEN id: " + std::to_string(mask) + "]"; - } - } - } - } - - auto & function_node = *function_node_ptr; - - /// Replace right IN function argument if it is table or table function with subquery that read ordinary columns - if (is_special_function_in) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - if (scope.context->getSettingsRef().transform_null_in) - { - static constexpr std::array, 4> in_function_to_replace_null_in_function_map = - {{ - {"in", "nullIn"}, - {"notIn", "notNullIn"}, - {"globalIn", "globalNullIn"}, - {"globalNotIn", "globalNotNullIn"}, - }}; - - for (const auto & [in_function_name, in_function_name_to_replace] : in_function_to_replace_null_in_function_map) - { - if (function_name == in_function_name) - { - function_name = in_function_name_to_replace; - break; - } - } - } - - auto & function_in_arguments_nodes = function_node.getArguments().getNodes(); - if (function_in_arguments_nodes.size() != 2) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function '{}' expects 2 arguments", function_name); - - auto & in_second_argument = function_in_arguments_nodes[1]; - auto * table_node = in_second_argument->as(); - auto * table_function_node = in_second_argument->as(); - - if (table_node) - { - /// If table is already prepared set, we do not replace it with subquery. - /// If table is not a StorageSet, we'll create plan to build set in the Planner. - } - else if (table_function_node) - { - const auto & storage_snapshot = table_function_node->getStorageSnapshot(); - auto columns_to_select = storage_snapshot->getColumns(GetColumnsOptions(GetColumnsOptions::Ordinary)); - - size_t columns_to_select_size = columns_to_select.size(); - - auto column_nodes_to_select = std::make_shared(); - column_nodes_to_select->getNodes().reserve(columns_to_select_size); - - NamesAndTypes projection_columns; - projection_columns.reserve(columns_to_select_size); - - for (auto & column : columns_to_select) - { - column_nodes_to_select->getNodes().emplace_back(std::make_shared(column, in_second_argument)); - projection_columns.emplace_back(column.name, column.type); - } - - auto in_second_argument_query_node = std::make_shared(Context::createCopy(scope.context)); - in_second_argument_query_node->setIsSubquery(true); - in_second_argument_query_node->getProjectionNode() = std::move(column_nodes_to_select); - in_second_argument_query_node->getJoinTree() = std::move(in_second_argument); - in_second_argument_query_node->resolveProjectionColumns(std::move(projection_columns)); - - in_second_argument = std::move(in_second_argument_query_node); - } - else - { - /// Replace storage with values storage of insertion block - if (StoragePtr storage = scope.context->getViewSource()) - { - QueryTreeNodePtr table_expression; - /// Process possibly nested sub-selects - for (auto * query_node = in_second_argument->as(); query_node; query_node = table_expression->as()) - table_expression = extractLeftTableExpression(query_node->getJoinTree()); - - if (table_expression) - { - if (auto * query_table_node = table_expression->as()) - { - if (query_table_node->getStorageID().getFullNameNotQuoted() == storage->getStorageID().getFullNameNotQuoted()) - { - auto replacement_table_expression = std::make_shared(storage, scope.context); - if (std::optional table_expression_modifiers = query_table_node->getTableExpressionModifiers()) - replacement_table_expression->setTableExpressionModifiers(*table_expression_modifiers); - in_second_argument = in_second_argument->cloneAndReplace(table_expression, std::move(replacement_table_expression)); - } - } - } - } - - resolveExpressionNode(in_second_argument, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - } - } - - /// Initialize function argument columns - - ColumnsWithTypeAndName argument_columns; - DataTypes argument_types; - bool all_arguments_constants = true; - std::vector function_lambda_arguments_indexes; - - auto & function_arguments = function_node.getArguments().getNodes(); - size_t function_arguments_size = function_arguments.size(); - - for (size_t function_argument_index = 0; function_argument_index < function_arguments_size; ++function_argument_index) - { - auto & function_argument = function_arguments[function_argument_index]; - - ColumnWithTypeAndName argument_column; - argument_column.name = arguments_projection_names[function_argument_index]; - - /** If function argument is lambda, save lambda argument index and initialize argument type as DataTypeFunction - * where function argument types are initialized with empty array of lambda arguments size. - */ - if (const auto * lambda_node = function_argument->as()) - { - size_t lambda_arguments_size = lambda_node->getArguments().getNodes().size(); - argument_column.type = std::make_shared(DataTypes(lambda_arguments_size, nullptr), nullptr); - function_lambda_arguments_indexes.push_back(function_argument_index); - } - else if (is_special_function_in && function_argument_index == 1) - { - argument_column.type = std::make_shared(); - } - else - { - argument_column.type = function_argument->getResultType(); - } - - if (!argument_column.type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' argument is not resolved. In scope {}", - function_name, - scope.scope_node->formatASTForErrorMessage()); - - bool argument_is_constant = false; - const auto * constant_node = function_argument->as(); - if (constant_node) - { - argument_column.column = constant_node->getResultType()->createColumnConst(1, constant_node->getValue()); - argument_column.type = constant_node->getResultType(); - argument_is_constant = true; - } - else if (const auto * get_scalar_function_node = function_argument->as(); - get_scalar_function_node && get_scalar_function_node->getFunctionName() == "__getScalar") - { - /// Allow constant folding through getScalar - const auto * get_scalar_const_arg = get_scalar_function_node->getArguments().getNodes().at(0)->as(); - if (get_scalar_const_arg && scope.context->hasQueryContext()) - { - auto query_context = scope.context->getQueryContext(); - auto scalar_string = toString(get_scalar_const_arg->getValue()); - if (query_context->hasScalar(scalar_string)) - { - auto scalar = query_context->getScalar(scalar_string); - argument_column.column = ColumnConst::create(scalar.getByPosition(0).column, 1); - argument_column.type = get_scalar_function_node->getResultType(); - argument_is_constant = true; - } - } - } - - all_arguments_constants &= argument_is_constant; - - argument_types.push_back(argument_column.type); - argument_columns.emplace_back(std::move(argument_column)); - } - - /// Calculate function projection name - ProjectionNames result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - - /** Try to resolve function as - * 1. Lambda function in current scope. Example: WITH (x -> x + 1) AS lambda SELECT lambda(1); - * 2. Lambda function from sql user defined functions. - * 3. Special `untuple` function. - * 4. Special `grouping` function. - * 5. Window function. - * 6. Executable user defined function. - * 7. Ordinary function. - * 8. Aggregate function. - * - * TODO: Provide better error hints. - */ - if (!function_node.isWindowFunction()) - { - if (!lambda_expression_untyped) - lambda_expression_untyped = tryGetLambdaFromSQLUserDefinedFunctions(function_node.getFunctionName(), scope.context); - - /** If function is resolved as lambda. - * Clone lambda before resolve. - * Initialize lambda arguments as function arguments. - * Resolve lambda and then replace function node with resolved lambda expression body. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(value) FROM test_table; - * Result: SELECT value + 1 FROM test_table; - */ - if (lambda_expression_untyped) - { - auto * lambda_expression = lambda_expression_untyped->as(); - if (!lambda_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function identifier '{}' must be resolved as lambda. Actual {}. In scope {}", - function_node.getFunctionName(), - lambda_expression_untyped->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - if (!parameters.empty()) - { - throw Exception( - ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_node.formatASTForErrorMessage()); - } - - auto lambda_expression_clone = lambda_expression_untyped->clone(); - - IdentifierResolveScope lambda_scope(lambda_expression_clone, &scope /*parent_scope*/); - ProjectionNames lambda_projection_names = resolveLambda(lambda_expression_untyped, lambda_expression_clone, function_arguments, lambda_scope); - - auto & resolved_lambda = lambda_expression_clone->as(); - node = resolved_lambda.getExpression(); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(lambda_projection_names); - - return result_projection_names; - } - - if (function_name == "untuple") - { - /// Special handling of `untuple` function - - if (function_arguments.size() != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' must have 1 argument. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - const auto & untuple_argument = function_arguments[0]; - /// Handle this special case first as `getResultType()` might return nullptr - if (untuple_argument->as()) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Function untuple can't have lambda-expressions as arguments"); - - auto result_type = untuple_argument->getResultType(); - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' argument must have compound type. Actual type {}. In scope {}", - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - - auto result_list = std::make_shared(); - result_list->getNodes().reserve(element_names.size()); - - for (const auto & element_name : element_names) - { - auto tuple_element_function = std::make_shared("tupleElement"); - tuple_element_function->getArguments().getNodes().push_back(untuple_argument); - tuple_element_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = tuple_element_function; - resolveFunction(function_query_node, scope); - - result_list->getNodes().push_back(std::move(function_query_node)); - } - - auto untuple_argument_projection_name = arguments_projection_names.at(0); - result_projection_names.clear(); - - for (const auto & element_name : element_names) - { - if (node->hasAlias()) - result_projection_names.push_back(node->getAlias() + '.' + element_name); - else - result_projection_names.push_back(fmt::format("tupleElement({}, '{}')", untuple_argument_projection_name, element_name)); - } - - node = std::move(result_list); - return result_projection_names; - } - else if (function_name == "grouping") - { - /// It is responsibility of planner to perform additional handling of grouping function - if (function_arguments_size == 0) - throw Exception(ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING expects at least one argument"); - else if (function_arguments_size > 64) - throw Exception(ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING can have up to 64 arguments, but {} provided", - function_arguments_size); - checkFunctionNodeHasEmptyNullsAction(function_node); - - bool force_grouping_standard_compatibility = scope.context->getSettingsRef().force_grouping_standard_compatibility; - auto grouping_function = std::make_shared(force_grouping_standard_compatibility); - auto grouping_function_adaptor = std::make_shared(std::move(grouping_function)); - function_node.resolveAsFunction(grouping_function_adaptor->build(argument_columns)); - - return result_projection_names; - } - } - - if (function_node.isWindowFunction()) - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - throw Exception(ErrorCodes::UNKNOWN_AGGREGATE_FUNCTION, "Aggregate function with name '{}' does not exist. In scope {}{}", - function_name, scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(AggregateFunctionFactory::instance().getHints(function_name))); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Window function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsWindowFunction(std::move(aggregate_function)); - - bool window_node_is_identifier = function_node.getWindowNode()->getNodeType() == QueryTreeNodeType::IDENTIFIER; - ProjectionName window_projection_name = resolveWindow(function_node.getWindowNode(), scope); - - if (window_node_is_identifier) - result_projection_names[0] += " OVER " + window_projection_name; - else - result_projection_names[0] += " OVER (" + window_projection_name + ')'; - - return result_projection_names; - } - - FunctionOverloadResolverPtr function = UserDefinedExecutableFunctionFactory::instance().tryGet(function_name, scope.context, parameters); /// NOLINT(readability-static-accessed-through-instance) - bool is_executable_udf = true; - - IdentifierResolveScope::ResolvedFunctionsCache * function_cache = nullptr; - - if (!function) - { - /// This is a hack to allow a query like `select randConstant(), randConstant(), randConstant()`. - /// Function randConstant() would return the same value for the same arguments (in scope). - - auto hash = function_node_ptr->getTreeHash(); - function_cache = &scope.functions_cache[hash]; - if (!function_cache->resolver) - function_cache->resolver = FunctionFactory::instance().tryGet(function_name, scope.context); - - function = function_cache->resolver; - - is_executable_udf = false; - } - - if (function) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - } - else - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - std::vector possible_function_names; - - auto function_names = UserDefinedExecutableFunctionFactory::instance().getRegisteredNames(scope.context); /// NOLINT(readability-static-accessed-through-instance) - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = UserDefinedSQLFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = FunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = AggregateFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - for (auto & [name, lambda_node] : scope.aliases.alias_name_to_lambda_node) - { - if (lambda_node->getNodeType() == QueryTreeNodeType::LAMBDA) - possible_function_names.push_back(name); - } - - auto hints = NamePrompter<2>::getHints(function_name, possible_function_names); - - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Function with name '{}' does not exist. In scope {}{}", - function_name, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Aggregate function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsAggregateFunction(std::move(aggregate_function)); - - return result_projection_names; - } - - /// Executable UDFs may have parameters. They are checked in UserDefinedExecutableFunctionFactory. - if (!parameters.empty() && !is_executable_udf) - { - throw Exception(ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_name); - } - - /** For lambda arguments we need to initialize lambda argument types DataTypeFunction using `getLambdaArgumentTypes` function. - * Then each lambda arguments are initialized with columns, where column source is lambda. - * This information is important for later steps of query processing. - * Example: SELECT arrayMap(x -> x + 1, [1, 2, 3]). - * lambda node x -> x + 1 identifier x is resolved as column where source is lambda node. - */ - bool has_lambda_arguments = !function_lambda_arguments_indexes.empty(); - if (has_lambda_arguments) - { - function->getLambdaArgumentTypes(argument_types); - - ProjectionNames lambda_projection_names; - for (auto & function_lambda_argument_index : function_lambda_arguments_indexes) - { - auto & lambda_argument = function_arguments[function_lambda_argument_index]; - auto lambda_to_resolve = lambda_argument->clone(); - auto & lambda_to_resolve_typed = lambda_to_resolve->as(); - - const auto & lambda_argument_names = lambda_to_resolve_typed.getArgumentNames(); - size_t lambda_arguments_size = lambda_to_resolve_typed.getArguments().getNodes().size(); - - const auto * function_data_type = typeid_cast(argument_types[function_lambda_argument_index].get()); - if (!function_data_type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' expected function data type for lambda argument with index {}. Actual {}. In scope {}", - function_name, - function_lambda_argument_index, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & function_data_type_argument_types = function_data_type->getArgumentTypes(); - size_t function_data_type_arguments_size = function_data_type_argument_types.size(); - if (function_data_type_arguments_size != lambda_arguments_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}" - "' function data type for lambda argument with index {} arguments size mismatch. " - "Actual {}. Expected {}. In scope {}", - function_name, - function_data_type_arguments_size, - lambda_arguments_size, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - QueryTreeNodes lambda_arguments; - lambda_arguments.reserve(lambda_arguments_size); - - for (size_t i = 0; i < lambda_arguments_size; ++i) - { - const auto & argument_type = function_data_type_argument_types[i]; - auto column_name_and_type = NameAndTypePair{lambda_argument_names[i], argument_type}; - lambda_arguments.push_back(std::make_shared(std::move(column_name_and_type), lambda_to_resolve)); - } - - IdentifierResolveScope lambda_scope(lambda_to_resolve, &scope /*parent_scope*/); - lambda_projection_names = resolveLambda(lambda_argument, lambda_to_resolve, lambda_arguments, lambda_scope); - - if (auto * lambda_list_node_result = lambda_to_resolve_typed.getExpression()->as()) - { - size_t lambda_list_node_result_nodes_size = lambda_list_node_result->getNodes().size(); - - if (lambda_list_node_result_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Lambda as function argument resolved as list node with size {}. Expected 1. In scope {}", - lambda_list_node_result_nodes_size, - lambda_to_resolve->formatASTForErrorMessage()); - - lambda_to_resolve_typed.getExpression() = lambda_list_node_result->getNodes().front(); - } - - if (arguments_projection_names.at(function_lambda_argument_index) == PROJECTION_NAME_PLACEHOLDER) - { - size_t lambda_projection_names_size =lambda_projection_names.size(); - if (lambda_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Lambda argument inside function expected to have 1 projection name. Actual {}", - lambda_projection_names_size); - - WriteBufferFromOwnString lambda_argument_projection_name_buffer; - lambda_argument_projection_name_buffer << "lambda("; - lambda_argument_projection_name_buffer << "tuple("; - - size_t lambda_argument_names_size = lambda_argument_names.size(); - - for (size_t i = 0; i < lambda_argument_names_size; ++i) - { - const auto & lambda_argument_name = lambda_argument_names[i]; - lambda_argument_projection_name_buffer << lambda_argument_name; - - if (i + 1 != lambda_argument_names_size) - lambda_argument_projection_name_buffer << ", "; - } - - lambda_argument_projection_name_buffer << "), "; - lambda_argument_projection_name_buffer << lambda_projection_names[0]; - lambda_argument_projection_name_buffer << ")"; - - lambda_projection_names.clear(); - - arguments_projection_names[function_lambda_argument_index] = lambda_argument_projection_name_buffer.str(); - } - - auto lambda_resolved_type = std::make_shared(function_data_type_argument_types, lambda_to_resolve_typed.getExpression()->getResultType()); - lambda_to_resolve_typed.resolve(lambda_resolved_type); - - argument_types[function_lambda_argument_index] = lambda_resolved_type; - argument_columns[function_lambda_argument_index].type = lambda_resolved_type; - function_arguments[function_lambda_argument_index] = std::move(lambda_to_resolve); - } - - /// Recalculate function projection name after lambda resolution - result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - } - - /** Create SET column for special function IN to allow constant folding - * if left and right arguments are constants. - * - * Example: SELECT * FROM test_table LIMIT 1 IN 1; - */ - if (is_special_function_in) - { - const auto * first_argument_constant_node = function_arguments[0]->as(); - const auto * second_argument_constant_node = function_arguments[1]->as(); - - if (first_argument_constant_node && second_argument_constant_node) - { - const auto & first_argument_constant_type = first_argument_constant_node->getResultType(); - const auto & second_argument_constant_literal = second_argument_constant_node->getValue(); - const auto & second_argument_constant_type = second_argument_constant_node->getResultType(); - - const auto & settings = scope.context->getSettingsRef(); - - auto result_block = getSetElementsForConstantValue(first_argument_constant_type, - second_argument_constant_literal, - second_argument_constant_type, - settings.transform_null_in); - - SizeLimits size_limits_for_set = {settings.max_rows_in_set, settings.max_bytes_in_set, settings.set_overflow_mode}; - - auto set = std::make_shared(size_limits_for_set, 0, settings.transform_null_in); - - set->setHeader(result_block.cloneEmpty().getColumnsWithTypeAndName()); - set->insertFromBlock(result_block.getColumnsWithTypeAndName()); - set->finishInsert(); - - auto future_set = std::make_shared(std::move(set)); - - /// Create constant set column for constant folding - - auto column_set = ColumnSet::create(1, std::move(future_set)); - argument_columns[1].column = ColumnConst::create(std::move(column_set), 1); - } - - argument_columns[1].type = std::make_shared(); - } - - std::shared_ptr constant_value; - - try - { - FunctionBasePtr function_base; - if (function_cache) - { - auto & cached_function = function_cache->function_base; - if (!cached_function) - cached_function = function->build(argument_columns); - - function_base = cached_function; - } - else - function_base = function->build(argument_columns); - - /// Do not constant fold get scalar functions - bool disable_constant_folding = function_name == "__getScalar" || function_name == "shardNum" || - function_name == "shardCount" || function_name == "hostName" || function_name == "tcpPort"; - - /** If function is suitable for constant folding try to convert it to constant. - * Example: SELECT plus(1, 1); - * Result: SELECT 2; - */ - if (function_base->isSuitableForConstantFolding() && !disable_constant_folding) - { - auto result_type = function_base->getResultType(); - auto executable_function = function_base->prepare(argument_columns); - - ColumnPtr column; - - if (all_arguments_constants) - { - size_t num_rows = function_arguments.empty() ? 0 : argument_columns.front().column->size(); - column = executable_function->execute(argument_columns, result_type, num_rows, true); - } - else - { - column = function_base->getConstantResultForNonConstArguments(argument_columns, result_type); - } - - if (column && column->getDataType() != result_type->getColumnType()) - throw Exception( - ErrorCodes::LOGICAL_ERROR, - "Unexpected return type from {}. Expected {}. Got {}", - function->getName(), - result_type->getColumnType(), - column->getDataType()); - - /** Do not perform constant folding if there are aggregate or arrayJoin functions inside function. - * Example: SELECT toTypeName(sum(number)) FROM numbers(10); - */ - if (column && isColumnConst(*column) && !typeid_cast(column.get())->getDataColumn().isDummy() && - !hasAggregateFunctionNodes(node) && !hasFunctionNode(node, "arrayJoin") && - /// Sanity check: do not convert large columns to constants - column->byteSize() < 1_MiB) - { - /// Replace function node with result constant node - Field column_constant_value; - column->get(0, column_constant_value); - constant_value = std::make_shared(std::move(column_constant_value), result_type); - } - } - - function_node.resolveAsFunction(std::move(function_base)); - } - catch (Exception & e) - { - e.addMessage("In scope {}", scope.scope_node->formatASTForErrorMessage()); - throw; - } - - if (constant_value) - node = std::make_shared(std::move(constant_value), node); - - return result_projection_names; -} - -/** Resolve expression node. - * Argument node can be replaced with different node, or even with list node in case of matcher resolution. - * Example: SELECT * FROM test_table; - * * - is matcher node, and it can be resolved into ListNode. - * - * Steps: - * 1. If node has alias, replace node with its value in scope alias map. Register alias in expression_aliases_in_resolve_process, to prevent resolving identifier - * which can bind to expression alias name. Check tryResolveIdentifierFromAliases documentation for additional explanation. - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * - * 2. Call specific resolve method depending on node type. - * - * If allow_table_expression = true and node is query node, then it is not evaluated as scalar subquery. - * Although if node is identifier that is resolved into query node that query is evaluated as scalar subquery. - * SELECT id, (SELECT 1) AS c FROM test_table WHERE a IN c; - * SELECT id, FROM test_table WHERE a IN (SELECT 1); - * - * 3. Special case identifier node. - * Try resolve it as expression identifier. - * Then if allow_lambda_expression = true try to resolve it as function. - * Then if allow_table_expression = true try to resolve it as table expression. - * - * 4. If node has alias, update its value in scope alias map. Deregister alias from expression_aliases_in_resolve_process. - */ -ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias) -{ - checkStackSize(); - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - /** There can be edge case, when subquery for IN function is resolved multiple times in different context. - * SELECT id IN (subquery AS value), value FROM test_table; - * When we start to resolve `value` identifier, subquery is already resolved but constant folding is not performed. - */ - auto node_type = node->getNodeType(); - if (!allow_table_expression && (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION)) - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - } - - return resolved_expression_it->second; - } - - String node_alias = node->getAlias(); - ProjectionNames result_projection_names; - - if (node_alias.empty()) - { - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - else - { - result_projection_names.push_back(node_alias); - } - - bool is_duplicated_alias = scope.aliases.nodes_with_duplicated_aliases.contains(node); - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.insert({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - /** Do not use alias table if node has alias same as some other node. - * Example: WITH x -> x + 1 AS lambda SELECT 1 AS lambda; - * During 1 AS lambda resolve if we use alias table we replace node with x -> x + 1 AS lambda. - * - * Do not use alias table if allow_table_expression = true and we resolve query node directly. - * Example: SELECT a FROM test_table WHERE id IN (SELECT 1) AS a; - * To support both (SELECT 1) AS expression in projection and (SELECT 1) as subquery in IN, do not use - * alias table because in alias table subquery could be evaluated as scalar. - */ - bool use_alias_table = !ignore_alias; - if (is_duplicated_alias || (allow_table_expression && isSubqueryNodeType(node->getNodeType()))) - use_alias_table = false; - - if (!node_alias.empty() && use_alias_table) - { - /** Node could be potentially resolved by resolving other nodes. - * SELECT b, a as b FROM test_table; - * - * To resolve b we need to resolve a. - */ - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - node = it->second; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - node = it->second; - } - } - - scope.pushExpressionNode(node); - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & identifier_node = node->as(); - auto unresolved_identifier = identifier_node.getIdentifier(); - auto resolve_identifier_expression_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier_node = resolve_identifier_expression_result.resolved_identifier; - - if (resolved_identifier_node && result_projection_names.empty() && - (resolve_identifier_expression_result.isResolvedFromJoinTree() || resolve_identifier_expression_result.isResolvedFromExpressionArguments())) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier_node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - - if (!resolved_identifier_node && allow_lambda_expression) - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::FUNCTION}, scope).resolved_identifier; - - if (!resolved_identifier_node && allow_table_expression) - { - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::TABLE_EXPRESSION}, scope).resolved_identifier; - - if (resolved_identifier_node) - { - /// If table identifier is resolved as CTE clone it and resolve - auto * subquery_node = resolved_identifier_node->as(); - auto * union_node = resolved_identifier_node->as(); - bool resolved_as_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - - if (resolved_as_cte) - { - resolved_identifier_node = resolved_identifier_node->clone(); - subquery_node = resolved_identifier_node->as(); - union_node = resolved_identifier_node->as(); - - std::string_view cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - if (subquery_node) - subquery_node->setIsCTE(false); - else - union_node->setIsCTE(false); - - IdentifierResolveScope subquery_scope(resolved_identifier_node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - /// CTE is being resolved, it's required to forbid to resolve to it again - /// because recursive CTEs are not supported, e.g.: - /// - /// WITH test1 AS (SELECT i + 1, j + 1 FROM test1) SELECT toInt64(4) i, toInt64(5) j FROM numbers(3) WHERE (i, j) IN test1; - /// - /// In this example argument of function `in` is being resolve here. If CTE `test1` is not forbidden, - /// `test1` is resolved to CTE (not to the table) in `initializeQueryJoinTreeNode` function. - ctes_in_resolve_process.insert(cte_name); - - if (subquery_node) - resolveQuery(resolved_identifier_node, subquery_scope); - else - resolveUnion(resolved_identifier_node, subquery_scope); - - ctes_in_resolve_process.erase(cte_name); - } - } - } - - if (!resolved_identifier_node) - { - std::string message_clarification; - if (allow_lambda_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::FUNCTION); - - if (allow_table_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::TABLE_EXPRESSION); - - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(unresolved_identifier, - scope, - true, - allow_lambda_expression, - allow_table_expression, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(unresolved_identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {}{} identifier '{}' in scope {}{}", - toStringLowercase(IdentifierLookupContext::EXPRESSION), - message_clarification, - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - node = std::move(resolved_identifier_node); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - { - result_projection_names.clear(); - resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - return resolved_expression_it->second; - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier '{}' resolve into list node and list node projection names are not initialized. In scope {}", - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_projection_names.empty()) - result_projection_names.push_back(unresolved_identifier.getFullName()); - - break; - } - case QueryTreeNodeType::MATCHER: - { - result_projection_names = resolveMatcher(node, scope); - break; - } - case QueryTreeNodeType::LIST: - { - /** Edge case if list expression has alias. - * Matchers cannot have aliases, but `untuple` function can. - * Example: SELECT a, untuple(CAST(('hello', 1) AS Tuple(name String, count UInt32))) AS a; - * During resolveFunction `untuple` function is replaced by list of 2 constants 'hello', 1. - */ - result_projection_names = resolveExpressionNodeList(node, scope, allow_lambda_expression, allow_lambda_expression); - break; - } - case QueryTreeNodeType::CONSTANT: - { - if (result_projection_names.empty()) - { - const auto & constant_node = node->as(); - result_projection_names.push_back(constant_node.getValueStringRepresentation()); - } - - /// Already resolved - break; - } - case QueryTreeNodeType::COLUMN: - { - auto & column_node = node->as(); - if (column_node.hasExpression()) - resolveExpressionNode(column_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (result_projection_names.empty()) - result_projection_names.push_back(column_node.getColumnName()); - - break; - } - case QueryTreeNodeType::FUNCTION: - { - auto function_projection_names = resolveFunction(node, scope); - - if (result_projection_names.empty() || node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(function_projection_names); - - break; - } - case QueryTreeNodeType::LAMBDA: - { - if (!allow_lambda_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (result_projection_names.empty()) - result_projection_names.push_back(PROJECTION_NAME_PLACEHOLDER); - - /// Lambda must be resolved by caller - break; - } - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - std::string projection_name = "_subquery_" + std::to_string(subquery_counter); - ++subquery_counter; - - if (node_type == QueryTreeNodeType::QUERY) - resolveQuery(node, subquery_scope); - else - resolveUnion(node, subquery_scope); - - if (!allow_table_expression) - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - - if (result_projection_names.empty()) - result_projection_names.push_back(std::move(projection_name)); - - break; - } - case QueryTreeNodeType::TABLE: - { - if (!allow_table_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Table {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node = node->as(); - result_projection_names.push_back(table_node.getStorageID().getFullNameNotQuoted()); - - break; - } - case QueryTreeNodeType::TRANSFORMER: - [[fallthrough]]; - case QueryTreeNodeType::SORT: - [[fallthrough]]; - case QueryTreeNodeType::INTERPOLATE: - [[fallthrough]]; - case QueryTreeNodeType::WINDOW: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::ARRAY_JOIN: - [[fallthrough]]; - case QueryTreeNodeType::JOIN: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "{} {} is not allowed in expression context. In scope {}", - node->getNodeType(), - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - validateTreeSize(node, scope.context->getSettingsRef().max_expanded_ast_elements, node_to_tree_size); - - /// Lambda can be inside the aggregate function, so we should check parent scopes. - /// Most likely only the root scope can have an arrgegate function, but let's check all just in case. - bool in_aggregate_function_scope = false; - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - in_aggregate_function_scope = in_aggregate_function_scope || scope_ptr->expressions_in_resolve_process_stack.hasAggregateFunction(); - - if (!in_aggregate_function_scope) - { - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - { - auto it = scope_ptr->nullable_group_by_keys.find(node); - if (it != scope_ptr->nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - break; - } - } - } - - /** Update aliases after expression node was resolved. - * Do not update node in alias table if we resolve it for duplicate alias. - */ - if (!node_alias.empty() && use_alias_table && !scope.group_by_use_nulls) - { - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - it->second = node; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - it->second = node; - } - } - - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.erase({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - if (!ignore_alias) - resolved_expressions.emplace(node, result_projection_names); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - return result_projection_names; -} - -/** Resolve expression node list. - * If expression is CTE subquery node it is skipped. - * If expression is resolved in list, it is flattened into initial node list. - * - * Such examples must work: - * Example: CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; SELECT plus(*) FROM test_table; - * Example: SELECT *** FROM system.one; - */ -ProjectionNames QueryAnalyzer::resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression) -{ - auto & node_list_typed = node_list->as(); - size_t node_list_size = node_list_typed.getNodes().size(); - - QueryTreeNodes result_nodes; - result_nodes.reserve(node_list_size); - - ProjectionNames result_projection_names; - - for (auto & node : node_list_typed.getNodes()) - { - auto node_to_resolve = node; - auto expression_node_projection_names = resolveExpressionNode(node_to_resolve, scope, allow_lambda_expression, allow_table_expression); - size_t expected_projection_names_size = 1; - if (auto * expression_list = node_to_resolve->as()) - { - expected_projection_names_size = expression_list->getNodes().size(); - for (auto & expression_list_node : expression_list->getNodes()) - result_nodes.push_back(expression_list_node); - } - else - { - result_nodes.push_back(std::move(node_to_resolve)); - } - - if (expression_node_projection_names.size() != expected_projection_names_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected {} projection names. Actual {}", - expected_projection_names_size, - expression_node_projection_names.size()); - - result_projection_names.insert(result_projection_names.end(), expression_node_projection_names.begin(), expression_node_projection_names.end()); - expression_node_projection_names.clear(); - } - - node_list_typed.getNodes() = std::move(result_nodes); - - return result_projection_names; -} - -/** Resolve sort columns nodes list. - */ -ProjectionNames QueryAnalyzer::resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames result_projection_names; - ProjectionNames sort_expression_projection_names; - ProjectionNames fill_from_expression_projection_names; - ProjectionNames fill_to_expression_projection_names; - ProjectionNames fill_step_expression_projection_names; - - auto & sort_node_list_typed = sort_node_list->as(); - for (auto & node : sort_node_list_typed.getNodes()) - { - auto & sort_node = node->as(); - sort_expression_projection_names = resolveExpressionNode(sort_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (auto * sort_column_list_node = sort_node.getExpression()->as()) - { - size_t sort_column_list_node_size = sort_column_list_node->getNodes().size(); - if (sort_column_list_node_size != 1) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Sort column node expression resolved into list with size {}. Expected 1. In scope {}", - sort_column_list_node_size, - scope.scope_node->formatASTForErrorMessage()); - } - - sort_node.getExpression() = sort_column_list_node->getNodes().front(); - } - - size_t sort_expression_projection_names_size = sort_expression_projection_names.size(); - if (sort_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort expression expected 1 projection name. Actual {}", - sort_expression_projection_names_size); - - if (sort_node.hasFillFrom()) - { - fill_from_expression_projection_names = resolveExpressionNode(sort_node.getFillFrom(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillFrom()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL FROM expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_from_expression_projection_names_size = fill_from_expression_projection_names.size(); - if (fill_from_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL FROM expression expected 1 projection name. Actual {}", - fill_from_expression_projection_names_size); - } - - if (sort_node.hasFillTo()) - { - fill_to_expression_projection_names = resolveExpressionNode(sort_node.getFillTo(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillTo()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL TO expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_to_expression_projection_names_size = fill_to_expression_projection_names.size(); - if (fill_to_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL TO expression expected 1 projection name. Actual {}", - fill_to_expression_projection_names_size); - } - - if (sort_node.hasFillStep()) - { - fill_step_expression_projection_names = resolveExpressionNode(sort_node.getFillStep(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillStep()->as(); - if (!constant_node) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - bool is_number = isColumnedAsNumber(constant_node->getResultType()); - bool is_interval = WhichDataType(constant_node->getResultType()).isInterval(); - if (!is_number && !is_interval) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_step_expression_projection_names_size = fill_step_expression_projection_names.size(); - if (fill_step_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort FILL STEP expression expected 1 projection name. Actual {}", - fill_step_expression_projection_names_size); - } - - auto sort_column_projection_name = calculateSortColumnProjectionName(node, - sort_expression_projection_names[0], - fill_from_expression_projection_names.empty() ? "" : fill_from_expression_projection_names.front(), - fill_to_expression_projection_names.empty() ? "" : fill_to_expression_projection_names.front(), - fill_step_expression_projection_names.empty() ? "" : fill_step_expression_projection_names.front()); - - result_projection_names.push_back(std::move(sort_column_projection_name)); - - sort_expression_projection_names.clear(); - fill_from_expression_projection_names.clear(); - fill_to_expression_projection_names.clear(); - fill_step_expression_projection_names.clear(); - } - - return result_projection_names; -} - -namespace -{ - -void expandTuplesInList(QueryTreeNodes & key_list) -{ - QueryTreeNodes expanded_keys; - expanded_keys.reserve(key_list.size()); - for (auto const & key : key_list) - { - if (auto * function = key->as(); function != nullptr && function->getFunctionName() == "tuple") - { - std::copy(function->getArguments().begin(), function->getArguments().end(), std::back_inserter(expanded_keys)); - } - else - expanded_keys.push_back(key); - } - key_list = std::move(expanded_keys); -} - -} - -/** Resolve GROUP BY clause. - */ -void QueryAnalyzer::resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope) -{ - if (query_node_typed.isGroupByWithGroupingSets()) - { - for (auto & grouping_sets_keys_list_node : query_node_typed.getGroupBy().getNodes()) - { - replaceNodesWithPositionalArguments(grouping_sets_keys_list_node, query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(grouping_sets_keys_list_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = grouping_sets_keys_list_node->as().getNodes(); - expandTuplesInList(group_by_list); - } - - if (scope.group_by_use_nulls) - { - for (const auto & grouping_set : query_node_typed.getGroupBy().getNodes()) - { - for (const auto & group_by_elem : grouping_set->as()->getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } - } - else - { - replaceNodesWithPositionalArguments(query_node_typed.getGroupByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getGroupByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = query_node_typed.getGroupBy().getNodes(); - expandTuplesInList(group_by_list); - - if (scope.group_by_use_nulls) - { - for (const auto & group_by_elem : query_node_typed.getGroupBy().getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } -} - -/** Resolve interpolate columns nodes list. - */ -void QueryAnalyzer::resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope) -{ - auto & interpolate_node_list_typed = interpolate_node_list->as(); - - for (auto & interpolate_node : interpolate_node_list_typed.getNodes()) - { - auto & interpolate_node_typed = interpolate_node->as(); - - auto * column_to_interpolate = interpolate_node_typed.getExpression()->as(); - if (!column_to_interpolate) - throw Exception(ErrorCodes::LOGICAL_ERROR, "INTERPOLATE can work only for indentifiers, but {} is found", - interpolate_node_typed.getExpression()->formatASTForErrorMessage()); - auto column_to_interpolate_name = column_to_interpolate->getIdentifier().getFullName(); - - resolveExpressionNode(interpolate_node_typed.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool is_column_constant = interpolate_node_typed.getExpression()->getNodeType() == QueryTreeNodeType::CONSTANT; - - auto & interpolation_to_resolve = interpolate_node_typed.getInterpolateExpression(); - IdentifierResolveScope interpolate_scope(interpolation_to_resolve, &scope /*parent_scope*/); - - auto fake_column_node = std::make_shared(NameAndTypePair(column_to_interpolate_name, interpolate_node_typed.getExpression()->getResultType()), interpolate_node_typed.getExpression()); - if (is_column_constant) - interpolate_scope.expression_argument_name_to_node.emplace(column_to_interpolate_name, fake_column_node); - - resolveExpressionNode(interpolation_to_resolve, interpolate_scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (is_column_constant) - interpolation_to_resolve = interpolation_to_resolve->cloneAndReplace(fake_column_node, interpolate_node_typed.getExpression()); - } -} - -/** Resolve window nodes list. - */ -void QueryAnalyzer::resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope) -{ - auto & window_node_list_typed = window_node_list->as(); - for (auto & node : window_node_list_typed.getNodes()) - resolveWindow(node, scope); -} - -NamesAndTypes QueryAnalyzer::resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames projection_names = resolveExpressionNodeList(projection_node_list, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto projection_nodes = projection_node_list->as().getNodes(); - size_t projection_nodes_size = projection_nodes.size(); - - NamesAndTypes projection_columns; - projection_columns.reserve(projection_nodes_size); - - for (size_t i = 0; i < projection_nodes_size; ++i) - { - auto projection_node = projection_nodes[i]; - - if (!isExpressionNodeType(projection_node->getNodeType())) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Projection node must be constant, function, column, query or union"); - - projection_columns.emplace_back(projection_names[i], projection_node->getResultType()); - } - - return projection_columns; -} - -/** Initialize query join tree node. - * - * 1. Resolve identifiers. - * 2. Register table, table function, query, union, join, array join nodes in scope table expressions in resolve process. - */ -void QueryAnalyzer::initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope) -{ - std::deque join_tree_node_ptrs_to_process_queue; - join_tree_node_ptrs_to_process_queue.push_back(&join_tree_node); - - while (!join_tree_node_ptrs_to_process_queue.empty()) - { - auto * current_join_tree_node_ptr = join_tree_node_ptrs_to_process_queue.front(); - join_tree_node_ptrs_to_process_queue.pop_front(); - - auto & current_join_tree_node = *current_join_tree_node_ptr; - auto current_join_tree_node_type = current_join_tree_node->getNodeType(); - - switch (current_join_tree_node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & from_table_identifier = current_join_tree_node->as(); - auto table_identifier_lookup = IdentifierLookup{from_table_identifier.getIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - - auto from_table_identifier_alias = from_table_identifier.getAlias(); - - IdentifierResolveSettings resolve_settings; - /// In join tree initialization ignore join tree as identifier lookup source - resolve_settings.allow_to_check_join_tree = false; - /** Disable resolve of subquery during identifier resolution. - * Example: SELECT * FROM (SELECT 1) AS t1, t1; - * During `t1` identifier resolution we resolve it into subquery SELECT 1, but we want to disable - * subquery resolution at this stage, because JOIN TREE of parent query is not resolved. - */ - resolve_settings.allow_to_resolve_subquery_during_identifier_resolution = false; - - scope.pushExpressionNode(current_join_tree_node); - - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, resolve_settings); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - auto resolved_identifier = table_identifier_resolve_result.resolved_identifier; - - if (!resolved_identifier) - throw Exception(ErrorCodes::UNKNOWN_TABLE, - "Unknown table expression identifier '{}' in scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - resolved_identifier = resolved_identifier->clone(); - - /// Update alias name to table expression map - auto table_expression_it = scope.aliases.alias_name_to_table_expression_node.find(from_table_identifier_alias); - if (table_expression_it != scope.aliases.alias_name_to_table_expression_node.end()) - table_expression_it->second = resolved_identifier; - - auto table_expression_modifiers = from_table_identifier.getTableExpressionModifiers(); - - auto * resolved_identifier_query_node = resolved_identifier->as(); - auto * resolved_identifier_union_node = resolved_identifier->as(); - - if (resolved_identifier_query_node || resolved_identifier_union_node) - { - if (table_expression_modifiers.has_value()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Table expression modifiers {} are not supported for subquery {}", - table_expression_modifiers->formatForErrorMessage(), - resolved_identifier->formatASTForErrorMessage()); - } - } - else if (auto * resolved_identifier_table_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else if (auto * resolved_identifier_table_function_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_function_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier in JOIN TREE '{}' resolved into unexpected table expression. In scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto current_join_tree_node_alias = current_join_tree_node->getAlias(); - resolved_identifier->setAlias(current_join_tree_node_alias); - current_join_tree_node = resolved_identifier; - - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::QUERY: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::UNION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - auto & array_join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&array_join.getTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::JOIN: - { - auto & join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&join.getLeftTableExpression()); - join_tree_node_ptrs_to_process_queue.push_back(&join.getRightTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - ++scope.joins_count; - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, UNION, ARRAY JOIN or JOIN. Actual {} {}. In scope {}", - current_join_tree_node->getNodeTypeName(), - current_join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - } -} - -/// Initialize table expression data for table expression node -void QueryAnalyzer::initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto table_expression_data_it = scope.table_expression_node_to_data.find(table_expression_node); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - return; - - TableExpressionData table_expression_data; - - if (table_node) - { - if (!table_node->getTemporaryTableName().empty()) - { - table_expression_data.table_name = table_node->getTemporaryTableName(); - table_expression_data.table_expression_name = table_node->getTemporaryTableName(); - } - else - { - const auto & table_storage_id = table_node->getStorageID(); - table_expression_data.database_name = table_storage_id.database_name; - table_expression_data.table_name = table_storage_id.table_name; - table_expression_data.table_expression_name = table_storage_id.getFullNameNotQuoted(); - } - - table_expression_data.table_expression_description = "table"; - } - else if (query_node || union_node) - { - table_expression_data.table_name = query_node ? query_node->getCTEName() : union_node->getCTEName(); - table_expression_data.table_expression_description = "subquery"; - } - else if (table_function_node) - { - table_expression_data.table_expression_description = "table_function"; - } - - if (table_expression_node->hasAlias()) - table_expression_data.table_expression_name = table_expression_node->getAlias(); - - if (table_node || table_function_node) - { - const auto & storage_snapshot = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - - auto get_column_options = GetColumnsOptions(GetColumnsOptions::All).withExtendedObjects().withVirtuals(); - if (storage_snapshot->storage.supportsSubcolumns()) - get_column_options.withSubcolumns(); - - auto column_names_and_types = storage_snapshot->getColumns(get_column_options); - table_expression_data.column_names_and_types = NamesAndTypes(column_names_and_types.begin(), column_names_and_types.end()); - - const auto & columns_description = storage_snapshot->metadata->getColumns(); - - std::vector> alias_columns_to_resolve; - ColumnNameToColumnNodeMap column_name_to_column_node; - column_name_to_column_node.reserve(column_names_and_types.size()); - - /** For ALIAS columns in table we must additionally analyze ALIAS expressions. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + 5); - * - * To do that we collect alias columns and build table column name to column node map. - * For each alias column we build identifier resolve scope, initialize it with table column name to node map - * and resolve alias column. - */ - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - for (const auto & subcolumn : columns_description.getSubcolumns(column_name_and_type.name)) - table_expression_data.subcolumn_names.insert(subcolumn.name); - const auto & column_default = columns_description.getDefault(column_name_and_type.name); - - if (column_default && column_default->kind == ColumnDefaultKind::Alias) - { - auto alias_expression = buildQueryTree(column_default->expression, scope.context); - auto column_node = std::make_shared(column_name_and_type, std::move(alias_expression), table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - alias_columns_to_resolve.emplace_back(column_name_and_type.name, column_node); - } - else - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - for (auto & [alias_column_to_resolve_name, alias_column_to_resolve] : alias_columns_to_resolve) - { - /** Alias column could be potentially resolved during resolve of other ALIAS column. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + alias_value_2, alias_value_2 ALIAS id + 5) ENGINE=TinyLog; - * - * During resolve of alias_value_1, alias_value_2 column will be resolved. - */ - alias_column_to_resolve = column_name_to_column_node[alias_column_to_resolve_name]; - - IdentifierResolveScope alias_column_resolve_scope(alias_column_to_resolve, nullptr /*parent_scope*/); - alias_column_resolve_scope.column_name_to_column_node = std::move(column_name_to_column_node); - alias_column_resolve_scope.context = scope.context; - - /// Initialize aliases in alias column scope - QueryExpressionsAliasVisitor visitor(alias_column_resolve_scope.aliases); - visitor.visit(alias_column_to_resolve->getExpression()); - - resolveExpressionNode(alias_column_resolve_scope.scope_node, - alias_column_resolve_scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - auto & resolved_expression = alias_column_to_resolve->getExpression(); - if (!resolved_expression->getResultType()->equals(*alias_column_to_resolve->getResultType())) - resolved_expression = buildCastFunction(resolved_expression, alias_column_to_resolve->getResultType(), scope.context, true); - column_name_to_column_node = std::move(alias_column_resolve_scope.column_name_to_column_node); - column_name_to_column_node[alias_column_to_resolve_name] = alias_column_to_resolve; - } - - table_expression_data.column_name_to_column_node = std::move(column_name_to_column_node); - } - else if (query_node || union_node) - { - table_expression_data.column_names_and_types = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - table_expression_data.column_name_to_column_node.reserve(table_expression_data.column_names_and_types.size()); - - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - table_expression_data.column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - table_expression_data.column_identifier_first_parts.reserve(table_expression_data.column_name_to_column_node.size()); - - for (auto & [column_name, _] : table_expression_data.column_name_to_column_node) - { - Identifier column_name_identifier(column_name); - table_expression_data.column_identifier_first_parts.insert(column_name_identifier.at(0)); - } - - if (auto * scope_query_node = scope.scope_node->as()) - { - auto left_table_expression = extractLeftTableExpression(scope_query_node->getJoinTree()); - if (table_expression_node.get() == left_table_expression.get() && - scope.joins_count == 1 && - scope.context->getSettingsRef().single_join_prefer_left_table) - table_expression_data.should_qualify_columns = false; - } - - scope.table_expression_node_to_data.emplace(table_expression_node, std::move(table_expression_data)); -} - -bool findIdentifier(const FunctionNode & function) -{ - for (const auto & argument : function.getArguments()) - { - if (argument->as()) - return true; - if (const auto * f = argument->as(); f && findIdentifier(*f)) - return true; - } - return false; -} - -/// Resolve table function node in scope -void QueryAnalyzer::resolveTableFunction(QueryTreeNodePtr & table_function_node, - IdentifierResolveScope & scope, - QueryExpressionsAliasVisitor & expressions_visitor, - bool nested_table_function) -{ - auto & table_function_node_typed = table_function_node->as(); - - if (!nested_table_function) - expressions_visitor.visit(table_function_node_typed.getArgumentsNode()); - - const auto & table_function_name = table_function_node_typed.getTableFunctionName(); - - auto & scope_context = scope.context; - - TableFunctionPtr table_function_ptr = TableFunctionFactory::instance().tryGet(table_function_name, scope_context); - if (!table_function_ptr) - { - String database_name = scope_context->getCurrentDatabase(); - String table_name; - - auto function_ast = table_function_node->toAST(); - Identifier table_identifier{table_function_name}; - if (table_identifier.getPartsSize() == 1) - { - table_name = table_identifier[0]; - } - else if (table_identifier.getPartsSize() == 2) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - - auto parametrized_view_storage = scope_context->getQueryContext()->buildParametrizedViewStorage(function_ast, database_name, table_name); - if (parametrized_view_storage) - { - auto fake_table_node = std::make_shared(parametrized_view_storage, scope_context); - fake_table_node->setAlias(table_function_node->getAlias()); - table_function_node = fake_table_node; - return; - } - - auto hints = TableFunctionFactory::instance().getHints(table_function_name); - if (!hints.empty()) - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}. Maybe you meant: {}", - table_function_name, - DB::toString(hints)); - else - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}", - table_function_name); - } - - QueryTreeNodes result_table_function_arguments; - - auto skip_analysis_arguments_indexes = table_function_ptr->skipAnalysisForArguments(table_function_node, scope_context); - - auto & table_function_arguments = table_function_node_typed.getArguments().getNodes(); - size_t table_function_arguments_size = table_function_arguments.size(); - - for (size_t table_function_argument_index = 0; table_function_argument_index < table_function_arguments_size; ++table_function_argument_index) - { - auto & table_function_argument = table_function_arguments[table_function_argument_index]; - - auto skip_argument_index_it = std::find(skip_analysis_arguments_indexes.begin(), - skip_analysis_arguments_indexes.end(), - table_function_argument_index); - if (skip_argument_index_it != skip_analysis_arguments_indexes.end()) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - if (auto * identifier_node = table_function_argument->as()) - { - const auto & unresolved_identifier = identifier_node->getIdentifier(); - auto identifier_resolve_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier = std::move(identifier_resolve_result.resolved_identifier); - - if (resolved_identifier && resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - result_table_function_arguments.push_back(std::move(resolved_identifier)); - else - result_table_function_arguments.push_back(table_function_argument); - - continue; - } - else if (auto * table_function_argument_function = table_function_argument->as()) - { - const auto & table_function_argument_function_name = table_function_argument_function->getFunctionName(); - if (TableFunctionFactory::instance().isTableFunctionName(table_function_argument_function_name)) - { - auto table_function_node_to_resolve_typed = std::make_shared(table_function_argument_function_name); - table_function_node_to_resolve_typed->getArgumentsNode() = table_function_argument_function->getArgumentsNode(); - - QueryTreeNodePtr table_function_node_to_resolve = std::move(table_function_node_to_resolve_typed); - resolveTableFunction(table_function_node_to_resolve, scope, expressions_visitor, true /*nested_table_function*/); - - result_table_function_arguments.push_back(std::move(table_function_node_to_resolve)); - continue; - } - } - - /** Table functions arguments can contain expressions with invalid identifiers. - * We cannot skip analysis for such arguments, because some table functions cannot provide - * information if analysis for argument should be skipped until other arguments will be resolved. - * - * Example: SELECT key from remote('127.0.0.{1,2}', view(select number AS key from numbers(2)), cityHash64(key)); - * Example: SELECT id from remote('127.0.0.{1,2}', 'default', 'test_table', cityHash64(id)); - */ - try - { - resolveExpressionNode(table_function_argument, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - catch (const Exception & exception) - { - if (exception.code() == ErrorCodes::UNKNOWN_IDENTIFIER) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - throw; - } - - if (auto * expression_list = table_function_argument->as()) - { - for (auto & expression_list_node : expression_list->getNodes()) - result_table_function_arguments.push_back(expression_list_node); - } - else - { - result_table_function_arguments.push_back(table_function_argument); - } - } - - table_function_node_typed.getArguments().getNodes() = std::move(result_table_function_arguments); - - auto table_function_ast = table_function_node_typed.toAST(); - table_function_ptr->parseArguments(table_function_ast, scope_context); - - - uint64_t use_structure_from_insertion_table_in_table_functions = scope_context->getSettingsRef().use_structure_from_insertion_table_in_table_functions; - if (!nested_table_function && - use_structure_from_insertion_table_in_table_functions && - scope_context->hasInsertionTable() && - table_function_ptr->needStructureHint()) - { - const auto & insertion_table = scope_context->getInsertionTable(); - if (!insertion_table.empty()) - { - const auto & insert_columns = DatabaseCatalog::instance() - .getTable(insertion_table, scope_context) - ->getInMemoryMetadataPtr() - ->getColumns(); - const auto & insert_column_names = scope_context->hasInsertionTableColumnNames() ? *scope_context->getInsertionTableColumnNames() : insert_columns.getOrdinary().getNames(); - DB::ColumnsDescription structure_hint; - - bool use_columns_from_insert_query = true; - - /// Insert table matches columns against SELECT expression by position, so we want to map - /// insert table columns to table function columns through names from SELECT expression. - - auto insert_column_name_it = insert_column_names.begin(); - auto insert_column_names_end = insert_column_names.end(); /// end iterator of the range covered by possible asterisk - auto virtual_column_names = table_function_ptr->getVirtualsToCheckBeforeUsingStructureHint(); - bool asterisk = false; - const auto & expression_list = scope.scope_node->as().getProjection(); - auto expression = expression_list.begin(); - - /// We want to go through SELECT expression list and correspond each expression to column in insert table - /// which type will be used as a hint for the file structure inference. - for (; expression != expression_list.end() && insert_column_name_it != insert_column_names_end; ++expression) - { - if (auto * identifier_node = (*expression)->as()) - { - - if (!virtual_column_names.contains(identifier_node->getIdentifier().getFullName())) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - ColumnDescription column = insert_columns.get(*insert_column_name_it); - column.name = identifier_node->getIdentifier().getFullName(); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else if (auto * matcher_node = (*expression)->as(); matcher_node && matcher_node->getMatcherType() == MatcherNodeType::ASTERISK) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Only one asterisk can be used in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - if (!structure_hint.empty()) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - asterisk = true; - } - else if (auto * function = (*expression)->as()) - { - if (use_structure_from_insertion_table_in_table_functions == 2 && findIdentifier(*function)) - { - use_columns_from_insert_query = false; - break; - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else - { - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - } - - if (use_structure_from_insertion_table_in_table_functions == 2 && !asterisk) - { - /// For input function we should check if input format supports reading subset of columns. - if (table_function_ptr->getName() == "input") - use_columns_from_insert_query = FormatFactory::instance().checkIfFormatSupportsSubsetOfColumns(scope.context->getInsertFormat(), scope.context); - else - use_columns_from_insert_query = table_function_ptr->supportsReadingSubsetOfColumns(scope.context); - } - - if (use_columns_from_insert_query) - { - if (expression == expression_list.end()) - { - /// Append tail of insert structure to the hint - if (asterisk) - { - for (; insert_column_name_it != insert_column_names_end; ++insert_column_name_it) - { - ColumnDescription column = insert_columns.get(*insert_column_name_it); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - } - - if (!structure_hint.empty()) - table_function_ptr->setStructureHint(structure_hint); - - } else if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::NUMBER_OF_COLUMNS_DOESNT_MATCH, "Number of columns in insert table less than required by SELECT expression."); - } - } - } - - auto table_function_storage = scope_context->getQueryContext()->executeTableFunction(table_function_ast, table_function_ptr); - table_function_node_typed.resolve(std::move(table_function_ptr), std::move(table_function_storage), scope_context, std::move(skip_analysis_arguments_indexes)); -} - -/// Resolve array join node in scope -void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & array_join_node_typed = array_join_node->as(); - resolveQueryJoinTreeNode(array_join_node_typed.getTableExpression(), scope, expressions_visitor); - - std::unordered_set array_join_column_names; - - /// Wrap array join expressions into column nodes, where array join expression is inner expression - - auto & array_join_nodes = array_join_node_typed.getJoinExpressions().getNodes(); - size_t array_join_nodes_size = array_join_nodes.size(); - - if (array_join_nodes_size == 0) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, - "ARRAY JOIN requires at least single expression"); - - std::vector array_join_column_expressions; - array_join_column_expressions.reserve(array_join_nodes_size); - - for (auto & array_join_expression : array_join_nodes) - { - auto array_join_expression_alias = array_join_expression->getAlias(); - - for (const auto & elem : array_join_nodes) - { - if (elem->hasAlias()) - scope.aliases.array_join_aliases.insert(elem->getAlias()); - - for (auto & child : elem->getChildren()) - { - if (child) - expressions_visitor.visit(child); - } - } - - std::string identifier_full_name; - - if (auto * identifier_node = array_join_expression->as()) - identifier_full_name = identifier_node->getIdentifier().getFullName(); - - resolveExpressionNode(array_join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/, true /*ignore_alias*/); - - auto process_array_join_expression = [&](QueryTreeNodePtr & expression) - { - auto result_type = expression->getResultType(); - bool is_array_type = isArray(result_type); - bool is_map_type = isMap(result_type); - - if (!is_array_type && !is_map_type) - throw Exception(ErrorCodes::TYPE_MISMATCH, - "ARRAY JOIN {} requires expression {} with Array or Map type. Actual {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - expression->formatASTForErrorMessage(), - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_map_type) - result_type = assert_cast(*result_type).getNestedType(); - - result_type = assert_cast(*result_type).getNestedType(); - - String array_join_column_name; - - if (!array_join_expression_alias.empty()) - { - array_join_column_name = array_join_expression_alias; - } - else if (auto * array_join_expression_inner_column = array_join_expression->as()) - { - array_join_column_name = array_join_expression_inner_column->getColumnName(); - } - else if (!identifier_full_name.empty()) - { - array_join_column_name = identifier_full_name; - } - else - { - array_join_column_name = "__array_join_expression_" + std::to_string(array_join_expressions_counter); - ++array_join_expressions_counter; - } - - if (array_join_column_names.contains(array_join_column_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "ARRAY JOIN {} multiple columns with name {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - array_join_column_name, - scope.scope_node->formatASTForErrorMessage()); - array_join_column_names.emplace(array_join_column_name); - - NameAndTypePair array_join_column(array_join_column_name, result_type); - auto array_join_column_node = std::make_shared(std::move(array_join_column), expression, array_join_node); - array_join_column_node->setAlias(array_join_expression_alias); - array_join_column_expressions.push_back(std::move(array_join_column_node)); - }; - - // Support ARRAY JOIN COLUMNS(...). COLUMNS transformer is resolved to list of columns. - if (auto * columns_list = array_join_expression->as()) - { - for (auto & array_join_subexpression : columns_list->getNodes()) - process_array_join_expression(array_join_subexpression); - } - else - { - process_array_join_expression(array_join_expression); - } - } - - array_join_nodes = std::move(array_join_column_expressions); -} - -void QueryAnalyzer::checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope) -{ - Names column_names; - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - if (join_node->as().getKind() != JoinKind::Paste) - return; - - auto * left_node = left_table_expr->as(); - auto * right_node = right_table_expr->as(); - - if (!left_node && !right_node) - return; - - if (left_node) - for (const auto & name_and_type : left_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - if (right_node) - for (const auto & name_and_type : right_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - - if (column_names.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of projection columns cannot be empty"); - - std::sort(column_names.begin(), column_names.end()); - for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is no any duplicates because it will lead to broken result - if (column_names[i] == column_names[i+1]) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add/change aliases to avoid duplication)" - "While processing '{}'", join_node->formatASTForErrorMessage()); -} - -/// Resolve join node in scope -void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & join_node_typed = join_node->as(); - - resolveQueryJoinTreeNode(join_node_typed.getLeftTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getLeftTableExpression(), scope); - - resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); - - if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) - checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope); - - if (join_node_typed.isOnJoinExpression()) - { - expressions_visitor.visit(join_node_typed.getJoinExpression()); - auto join_expression = join_node_typed.getJoinExpression(); - resolveExpressionNode(join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - join_node_typed.getJoinExpression() = std::move(join_expression); - } - else if (join_node_typed.isUsingJoinExpression()) - { - auto & join_using_list = join_node_typed.getJoinExpression()->as(); - std::unordered_set join_using_identifiers; - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto * identifier_node = join_using_node->as(); - if (!identifier_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} USING clause expected identifier. Actual {}", - join_node_typed.formatASTForErrorMessage(), - join_using_node->formatASTForErrorMessage()); - - const auto & identifier_full_name = identifier_node->getIdentifier().getFullName(); - - if (join_using_identifiers.contains(identifier_full_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} identifier '{}' appears more than once in USING clause", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name); - - join_using_identifiers.insert(identifier_full_name); - - const auto & settings = scope.context->getSettingsRef(); - - /** While resolving JOIN USING identifier, try to resolve identifier from parent subquery projection. - * Example: SELECT a + 1 AS b FROM (SELECT 1 AS a) t1 JOIN (SELECT 2 AS b) USING b - * In this case `b` is not in the left table expression, but it is in the parent subquery projection. - */ - auto try_resolve_identifier_from_query_projection = [this](const String & identifier_full_name_, - const QueryTreeNodePtr & left_table_expression, - const IdentifierResolveScope & scope_) -> QueryTreeNodePtr - { - const QueryNode * query_node = scope_.scope_node ? scope_.scope_node->as() : nullptr; - if (!query_node) - return nullptr; - - const auto & projection_list = query_node->getProjection(); - for (const auto & projection_node : projection_list.getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name_ == projection_node->getAlias()) - { - auto left_subquery = std::make_shared(query_node->getMutableContext()); - left_subquery->getProjection().getNodes().push_back(projection_node->clone()); - left_subquery->getJoinTree() = left_table_expression; - - IdentifierResolveScope left_subquery_scope(left_subquery, nullptr /*parent_scope*/); - resolveQuery(left_subquery, left_subquery_scope); - - const auto & resolved_nodes = left_subquery->getProjection().getNodes(); - if (resolved_nodes.size() == 1) - { - /// Create ColumnNode with expression from parent projection - return std::make_shared( - NameAndTypePair{identifier_full_name_, resolved_nodes.front()->getResultType()}, - resolved_nodes.front(), left_table_expression); - } - } - } - return nullptr; - }; - - QueryTreeNodePtr result_left_table_expression = nullptr; - /** With `analyzer_compatibility_join_using_top_level_identifier` alias in projection has higher priority than column from left table. - * But if aliased expression cannot be resolved from left table, we get UNKNOW_IDENTIFIER error, - * despite the fact that column from USING could be resolved from left table. - * It's compatibility with a default behavior for old analyzer. - */ - if (settings.analyzer_compatibility_join_using_top_level_identifier) - result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - IdentifierLookup identifier_lookup{identifier_node->getIdentifier(), IdentifierLookupContext::EXPRESSION}; - if (!result_left_table_expression) - result_left_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getLeftTableExpression(), scope); - - /** Here we may try to resolve identifier from projection in case it's not resolved from left table expression - * and analyzer_compatibility_join_using_top_level_identifier is disabled. - * For now we do not do this, because not all corner cases are clear. - * But let's at least mention it in error message - */ - /// if (!settings.analyzer_compatibility_join_using_top_level_identifier && !result_left_table_expression) - /// result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - if (!result_left_table_expression) - { - String extra_message; - const QueryNode * query_node = scope.scope_node ? scope.scope_node->as() : nullptr; - if (settings.analyzer_compatibility_join_using_top_level_identifier && query_node) - { - for (const auto & projection_node : query_node->getProjection().getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name == projection_node->getAlias()) - { - extra_message = fmt::format( - ", but alias '{}' is present in SELECT list." - " You may try to SET analyzer_compatibility_join_using_top_level_identifier = 1, to allow to use it in USING clause", - projection_node->formatASTForErrorMessage()); - break; - } - } - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from left table expression{}. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - extra_message, - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_left_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from left table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto result_right_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getRightTableExpression(), scope); - if (!result_right_table_expression) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - if (result_right_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto expression_types = DataTypes{result_left_table_expression->getResultType(), result_right_table_expression->getResultType()}; - DataTypePtr common_type = tryGetLeastSupertype(expression_types); - - if (!common_type) - throw Exception(ErrorCodes::NO_COMMON_TYPE, - "JOIN {} cannot infer common type for {} and {} in USING for identifier '{}'. In scope {}", - join_node_typed.formatASTForErrorMessage(), - result_left_table_expression->getResultType()->getName(), - result_right_table_expression->getResultType()->getName(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - NameAndTypePair join_using_column(identifier_full_name, common_type); - ListNodePtr join_using_expression = std::make_shared(QueryTreeNodes{result_left_table_expression, result_right_table_expression}); - auto join_using_column_node = std::make_shared(std::move(join_using_column), std::move(join_using_expression), join_node); - join_using_node = std::move(join_using_column_node); - } - } -} - -/** Resolve query join tree. - * - * Query join tree must be initialized before calling this function. - */ -void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto from_node_type = join_tree_node->getNodeType(); - - switch (from_node_type) - { - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - resolveExpressionNode(join_tree_node, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - resolveTableFunction(join_tree_node, scope, expressions_visitor, false /*nested_table_function*/); - break; - } - case QueryTreeNodeType::TABLE: - { - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - resolveArrayJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::JOIN: - { - resolveJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::IDENTIFIER: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifiers in FROM section must be already resolved. Node {}, scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, ARRAY JOIN or JOIN. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - auto join_tree_node_type = join_tree_node->getNodeType(); - if (isTableExpressionNodeType(join_tree_node_type)) - { - validateTableExpressionModifiers(join_tree_node, scope); - initializeTableExpressionData(join_tree_node, scope); - - auto & query_node = scope.scope_node->as(); - auto & mutable_context = query_node.getMutableContext(); - - if (!mutable_context->isDistributed()) - { - bool is_distributed = false; - - if (auto * table_node = join_tree_node->as()) - is_distributed = table_node->getStorage()->isRemote(); - else if (auto * table_function_node = join_tree_node->as()) - is_distributed = table_function_node->getStorage()->isRemote(); - - mutable_context->setDistributed(is_distributed); - } - } - - auto add_table_expression_alias_into_scope = [&](const QueryTreeNodePtr & table_expression_node) - { - const auto & alias_name = table_expression_node->getAlias(); - if (alias_name.empty()) - return; - - auto [it, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(alias_name, table_expression_node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Duplicate aliases {} for table expressions in FROM section are not allowed. Try to register {}. Already registered {}.", - alias_name, - table_expression_node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage()); - }; - - add_table_expression_alias_into_scope(join_tree_node); - scope.table_expressions_in_resolve_process.erase(join_tree_node.get()); -} - -/** Resolve query. - * This function modifies query node during resolve. It is caller responsibility to clone query node before resolve - * if it is needed for later use. - * - * query_node - query_tree_node that must have QueryNode type. - * scope - query scope. It is caller responsibility to create it. - * - * Resolve steps: - * 1. Validate subqueries depth, perform GROUP BY validation that does not depend on information about aggregate functions. - * 2. Initialize query scope with aliases. - * 3. Register CTE subqueries from WITH section in scope and remove them from WITH section. - * 4. Resolve JOIN TREE. - * 5. Resolve projection columns. - * 6. Resolve expressions in other query parts. - * 7. Validate nodes with duplicate aliases. - * 8. Validate aggregate functions, GROUPING function, window functions. - * 9. Remove WITH and WINDOW sections from query. - * 10. Remove aliases from expression and lambda nodes. - * 11. Resolve query tree node with projection columns. - */ -void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope) -{ - size_t max_subquery_depth = scope.context->getSettingsRef().max_subquery_depth; - if (max_subquery_depth && scope.subquery_depth > max_subquery_depth) - throw Exception(ErrorCodes::TOO_DEEP_SUBQUERIES, - "Too deep subqueries. Maximum: {}", - max_subquery_depth); - - auto & query_node_typed = query_node->as(); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.insert(query_node_typed.getCTEName()); - - bool is_rollup_or_cube = query_node_typed.isGroupByWithRollup() || query_node_typed.isGroupByWithCube(); - - if (query_node_typed.isGroupByWithGroupingSets() - && query_node_typed.isGroupByWithTotals() - && query_node_typed.getGroupBy().getNodes().size() != 1) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and GROUPING SETS are not supported together"); - - if (query_node_typed.isGroupByWithGroupingSets() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "GROUPING SETS are not supported together with ROLLUP and CUBE"); - - if (query_node_typed.isGroupByWithRollup() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithCube())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "ROLLUP is not supported together with GROUPING SETS and CUBE"); - - if (query_node_typed.isGroupByWithCube() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithRollup())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "CUBE is not supported together with GROUPING SETS and ROLLUP"); - - if (query_node_typed.hasHaving() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of HAVING"); - - if (query_node_typed.hasQualify() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of QUALIFY"); - - /// Initialize aliases in query node scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - - if (query_node_typed.hasWith()) - visitor.visit(query_node_typed.getWithNode()); - - if (!query_node_typed.getProjection().getNodes().empty()) - visitor.visit(query_node_typed.getProjectionNode()); - - if (query_node_typed.getPrewhere()) - visitor.visit(query_node_typed.getPrewhere()); - - if (query_node_typed.getWhere()) - visitor.visit(query_node_typed.getWhere()); - - if (query_node_typed.hasGroupBy()) - visitor.visit(query_node_typed.getGroupByNode()); - - if (query_node_typed.hasHaving()) - visitor.visit(query_node_typed.getHaving()); - - if (query_node_typed.hasWindow()) - visitor.visit(query_node_typed.getWindowNode()); - - if (query_node_typed.hasQualify()) - visitor.visit(query_node_typed.getQualify()); - - if (query_node_typed.hasOrderBy()) - visitor.visit(query_node_typed.getOrderByNode()); - - if (query_node_typed.hasInterpolate()) - visitor.visit(query_node_typed.getInterpolate()); - - if (query_node_typed.hasLimitByLimit()) - visitor.visit(query_node_typed.getLimitByLimit()); - - if (query_node_typed.hasLimitByOffset()) - visitor.visit(query_node_typed.getLimitByOffset()); - - if (query_node_typed.hasLimitBy()) - visitor.visit(query_node_typed.getLimitByNode()); - - if (query_node_typed.hasLimit()) - visitor.visit(query_node_typed.getLimit()); - - if (query_node_typed.hasOffset()) - visitor.visit(query_node_typed.getOffset()); - - /// Register CTE subqueries and remove them from WITH section - - auto & with_nodes = query_node_typed.getWith().getNodes(); - - for (auto & node : with_nodes) - { - auto * subquery_node = node->as(); - auto * union_node = node->as(); - - bool subquery_is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - if (!subquery_is_cte) - continue; - - const auto & cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - auto [_, inserted] = scope.cte_name_to_query_node.emplace(cte_name, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "CTE with name {} already exists. In scope {}", - cte_name, - scope.scope_node->formatASTForErrorMessage()); - } - - /** WITH section can be safely removed, because WITH section only can provide aliases to query expressions - * and CTE for other sections to use. - * - * Example: WITH 1 AS constant, (x -> x + 1) AS lambda, a AS (SELECT * FROM test_table); - */ - query_node_typed.getWith().getNodes().clear(); - - for (auto & window_node : query_node_typed.getWindow().getNodes()) - { - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - if (!parent_window_name.empty()) - { - auto window_node_it = scope.window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope.window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - scope.scope_node->formatASTForErrorMessage()); - - mergeWindowWithParentWindow(window_node, window_node_it->second, scope); - window_node_typed.setParentWindowName({}); - } - - auto [_, inserted] = scope.window_name_to_window_node.emplace(window_node_typed.getAlias(), window_node); - if (!inserted) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' is already defined. In scope {}", - window_node_typed.getAlias(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** Disable identifier cache during JOIN TREE resolve. - * Depending on JOIN expression section, identifier with same name - * can be resolved in different columns. - * - * Example: SELECT id FROM test_table AS t1 INNER JOIN test_table AS t2 ON t1.id = t2.id INNER JOIN test_table AS t3 ON t1.id = t3.id - * In first join expression ON t1.id = t2.id t1.id is resolved into test_table.id column. - * In second join expression ON t1.id = t3.id t1.id must be resolved into test_table.id column after first JOIN. - */ - scope.use_identifier_lookup_to_result_cache = false; - - if (query_node_typed.getJoinTree()) - { - TableExpressionsAliasVisitor table_expressions_visitor(scope); - table_expressions_visitor.visit(query_node_typed.getJoinTree()); - - initializeQueryJoinTreeNode(query_node_typed.getJoinTree(), scope); - scope.aliases.alias_name_to_table_expression_node.clear(); - - resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor); - } - - if (!scope.group_by_use_nulls) - scope.use_identifier_lookup_to_result_cache = true; - - /// Resolve query node sections. - - NamesAndTypes projection_columns; - - if (!scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - if (auto & prewhere_node = query_node_typed.getPrewhere()) - { - resolveExpressionNode(prewhere_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** Expressions in PREWHERE with JOIN should not change their type. - * Example: SELECT * FROM t1 JOIN t2 USING (a) PREWHERE a = 1 - * Column `a` in PREWHERE should be resolved from the left table - * and should not change its type to Nullable or to the supertype of `a` from t1 and t2. - * Here's a more complicated example where the column is somewhere inside an expression: - * SELECT a + 1 as b FROM t1 JOIN t2 USING (id) PREWHERE b = 1 - * The expression `a + 1 as b` in the projection and in PREWHERE should have different `a`. - */ - prewhere_node = prewhere_node->clone(); - ReplaceColumnsVisitor replace_visitor(scope.join_columns_with_changed_types, scope.context); - replace_visitor.visit(prewhere_node); - } - - if (query_node_typed.getWhere()) - resolveExpressionNode(query_node_typed.getWhere(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasGroupBy()) - resolveGroupByNode(query_node_typed, scope); - - if (scope.group_by_use_nulls) - { - resolved_expressions.clear(); - /// Clone is needed cause aliases share subtrees. - /// If not clone, the same (shared) subtree could be resolved again with different (Nullable) type - /// See 03023_group_by_use_nulls_analyzer_crashes - for (auto & [key, node] : scope.aliases.alias_name_to_expression_node_before_group_by) - scope.aliases.alias_name_to_expression_node_after_group_by[key] = node->clone(); - - scope.aliases.alias_name_to_expression_node = &scope.aliases.alias_name_to_expression_node_after_group_by; - } - - if (query_node_typed.hasHaving()) - resolveExpressionNode(query_node_typed.getHaving(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasWindow()) - resolveWindowNodeList(query_node_typed.getWindowNode(), scope); - - if (query_node_typed.hasQualify()) - resolveExpressionNode(query_node_typed.getQualify(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasOrderBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getOrderByNode(), query_node_typed.getProjection().getNodes(), scope); - - const auto & settings = scope.context->getSettingsRef(); - - expandOrderByAll(query_node_typed, settings); - resolveSortNodeList(query_node_typed.getOrderByNode(), scope); - } - - if (query_node_typed.hasInterpolate()) - resolveInterpolateColumnsNodeList(query_node_typed.getInterpolate(), scope); - - if (query_node_typed.hasLimitByLimit()) - { - resolveExpressionNode(query_node_typed.getLimitByLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByLimit(), "LIMIT BY LIMIT", scope); - } - - if (query_node_typed.hasLimitByOffset()) - { - resolveExpressionNode(query_node_typed.getLimitByOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByOffset(), "LIMIT BY OFFSET", scope); - } - - if (query_node_typed.hasLimitBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getLimitByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getLimitByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - - if (query_node_typed.hasLimit()) - { - resolveExpressionNode(query_node_typed.getLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimit(), "LIMIT", scope); - } - - if (query_node_typed.hasOffset()) - { - resolveExpressionNode(query_node_typed.getOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getOffset(), "OFFSET", scope); - } - - if (scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - /** Resolve nodes with duplicate aliases. - * Table expressions cannot have duplicate aliases. - * - * Such nodes during scope aliases collection are placed into duplicated array. - * After scope nodes are resolved, we can compare node with duplicate alias with - * node from scope alias table. - */ - for (const auto & node_with_duplicated_alias : scope.aliases.cloned_nodes_with_duplicated_aliases) - { - auto node = node_with_duplicated_alias; - auto node_alias = node->getAlias(); - - /// Add current alias to non cached set, because in case of cyclic alias identifier should not be substituted from cache. - /// See 02896_cyclic_aliases_crash. - resolveExpressionNode(node, scope, true /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool has_node_in_alias_table = false; - - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - if (!has_node_in_alias_table) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node {} with duplicate alias {} does not exist in alias table. In scope {}", - node->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - - node->removeAlias(); - } - - expandGroupByAll(query_node_typed); - - validateFilters(query_node); - validateAggregates(query_node, { .group_by_use_nulls = scope.group_by_use_nulls }); - - for (const auto & column : projection_columns) - { - if (isNotCreatable(column.type)) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Invalid projection column with type {}. In scope {}", - column.type->getName(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** WINDOW section can be safely removed, because WINDOW section can only provide window definition to window functions. - * - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - */ - query_node_typed.getWindow().getNodes().clear(); - - /// Remove aliases from expression and lambda nodes - - for (auto & [_, node] : *scope.aliases.alias_name_to_expression_node) - node->removeAlias(); - - for (auto & [_, node] : scope.aliases.alias_name_to_lambda_node) - node->removeAlias(); - - query_node_typed.resolveProjectionColumns(std::move(projection_columns)); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.erase(query_node_typed.getCTEName()); -} - -void QueryAnalyzer::resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope) -{ - auto & union_node_typed = union_node->as(); - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.insert(union_node_typed.getCTEName()); - - auto & queries_nodes = union_node_typed.getQueries().getNodes(); - - std::optional recursive_cte_table; - TableNodePtr recursive_cte_table_node; - - if (union_node_typed.isCTE() && union_node_typed.isRecursiveCTE()) - { - auto & non_recursive_query = queries_nodes[0]; - bool non_recursive_query_is_query_node = non_recursive_query->getNodeType() == QueryTreeNodeType::QUERY; - auto & non_recursive_query_mutable_context = non_recursive_query_is_query_node ? non_recursive_query->as().getMutableContext() - : non_recursive_query->as().getMutableContext(); - - IdentifierResolveScope non_recursive_subquery_scope(non_recursive_query, &scope /*parent_scope*/); - non_recursive_subquery_scope.subquery_depth = scope.subquery_depth + 1; - - if (non_recursive_query_is_query_node) - resolveQuery(non_recursive_query, non_recursive_subquery_scope); - else - resolveUnion(non_recursive_query, non_recursive_subquery_scope); - - auto temporary_table_columns = non_recursive_query_is_query_node - ? non_recursive_query->as().getProjectionColumns() - : non_recursive_query->as().computeProjectionColumns(); - - auto temporary_table_holder = std::make_shared( - non_recursive_query_mutable_context, - ColumnsDescription{NamesAndTypesList{temporary_table_columns.begin(), temporary_table_columns.end()}}, - ConstraintsDescription{}, - nullptr /*query*/, - true /*create_for_global_subquery*/); - auto temporary_table_storage = temporary_table_holder->getTable(); - - recursive_cte_table_node = std::make_shared(temporary_table_storage, non_recursive_query_mutable_context); - recursive_cte_table_node->setTemporaryTableName(union_node_typed.getCTEName()); - - recursive_cte_table.emplace(std::move(temporary_table_holder), std::move(temporary_table_storage), std::move(temporary_table_columns)); - } - - size_t queries_nodes_size = queries_nodes.size(); - for (size_t i = recursive_cte_table.has_value(); i < queries_nodes_size; ++i) - { - auto & query_node = queries_nodes[i]; - - IdentifierResolveScope subquery_scope(query_node, &scope /*parent_scope*/); - - if (recursive_cte_table_node) - subquery_scope.expression_argument_name_to_node[union_node_typed.getCTEName()] = recursive_cte_table_node; - - auto query_node_type = query_node->getNodeType(); - - if (query_node_type == QueryTreeNodeType::QUERY) - { - resolveQuery(query_node, subquery_scope); - } - else if (query_node_type == QueryTreeNodeType::UNION) - { - resolveUnion(query_node, subquery_scope); - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "UNION unsupported node {}. In scope {}", - query_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (recursive_cte_table && isStorageUsedInTree(recursive_cte_table->storage, union_node.get())) - { - if (union_node_typed.getUnionMode() != SelectUnionMode::UNION_ALL) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive CTE subquery {} with {} union mode is unsupported, only UNION ALL union mode is supported", - union_node_typed.formatASTForErrorMessage(), - toString(union_node_typed.getUnionMode())); - - union_node_typed.setRecursiveCTETable(std::move(*recursive_cte_table)); - } - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.erase(union_node_typed.getCTEName()); -} - -} - -QueryAnalysisPass::QueryAnalysisPass(QueryTreeNodePtr table_expression_, bool only_analyze_) - : table_expression(std::move(table_expression_)) - , only_analyze(only_analyze_) -{} - -QueryAnalysisPass::QueryAnalysisPass(bool only_analyze_) : only_analyze(only_analyze_) {} - -void QueryAnalysisPass::run(QueryTreeNodePtr & query_tree_node, ContextPtr context) -{ - QueryAnalyzer analyzer(only_analyze); - analyzer.resolve(query_tree_node, table_expression, context); - createUniqueTableAliases(query_tree_node, table_expression, context); -} - } diff --git a/src/Analyzer/QueryAnalysis/ScopeAliases.h b/src/Analyzer/QueryAnalysis/ScopeAliases.h index 3fca66e6eb8..370ffc65625 100644 --- a/src/Analyzer/QueryAnalysis/ScopeAliases.h +++ b/src/Analyzer/QueryAnalysis/ScopeAliases.h @@ -1,591 +1,11 @@ -#include +#pragma once -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include - -namespace ProfileEvents -{ - extern const Event ScalarSubqueriesGlobalCacheHit; - extern const Event ScalarSubqueriesLocalCacheHit; - extern const Event ScalarSubqueriesCacheMiss; -} +#include namespace DB { -namespace ErrorCodes -{ - extern const int UNSUPPORTED_METHOD; - extern const int UNKNOWN_IDENTIFIER; - extern const int UNKNOWN_FUNCTION; - extern const int LOGICAL_ERROR; - extern const int CYCLIC_ALIASES; - extern const int INCORRECT_RESULT_OF_SCALAR_SUBQUERY; - extern const int BAD_ARGUMENTS; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int MULTIPLE_EXPRESSIONS_FOR_ALIAS; - extern const int TYPE_MISMATCH; - extern const int AMBIGUOUS_IDENTIFIER; - extern const int INVALID_WITH_FILL_EXPRESSION; - extern const int INVALID_LIMIT_EXPRESSION; - extern const int EMPTY_LIST_OF_COLUMNS_QUERIED; - extern const int TOO_DEEP_SUBQUERIES; - extern const int UNKNOWN_AGGREGATE_FUNCTION; - extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION; - extern const int TOO_MANY_ARGUMENTS_FOR_FUNCTION; - extern const int ILLEGAL_FINAL; - extern const int SAMPLING_NOT_SUPPORTED; - extern const int NO_COMMON_TYPE; - extern const int NOT_IMPLEMENTED; - extern const int ALIAS_REQUIRED; - extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; - extern const int UNKNOWN_TABLE; - extern const int ILLEGAL_COLUMN; - extern const int NUMBER_OF_COLUMNS_DOESNT_MATCH; - extern const int FUNCTION_CANNOT_HAVE_PARAMETERS; - extern const int SYNTAX_ERROR; - extern const int UNEXPECTED_EXPRESSION; - extern const int INVALID_IDENTIFIER; -} - -/** Query analyzer implementation overview. Please check documentation in QueryAnalysisPass.h first. - * And additional documentation for each method, where special cases are described in detail. - * - * Each node in query must be resolved. For each query tree node resolved state is specific. - * - * For constant node no resolve process exists, it is resolved during construction. - * - * For table node no resolve process exists, it is resolved during construction. - * - * For function node to be resolved parameters and arguments must be resolved, function node must be initialized with concrete aggregate or - * non aggregate function and with result type. - * - * For lambda node there can be 2 different cases. - * 1. Standalone: WITH (x -> x + 1) AS lambda SELECT lambda(1); Such lambdas are inlined in query tree during query analysis pass. - * 2. Function arguments: WITH (x -> x + 1) AS lambda SELECT arrayMap(lambda, [1, 2, 3]); For such lambda resolution must - * set concrete lambda arguments (initially they are identifier nodes) and resolve lambda expression body. - * - * For query node resolve process must resolve all its inner nodes. - * - * For matcher node resolve process must replace it with matched nodes. - * - * For identifier node resolve process must replace it with concrete non identifier node. This part is most complex because - * for identifier resolution scopes and identifier lookup context play important part. - * - * ClickHouse SQL support lexical scoping for identifier resolution. Scope can be defined by query node or by expression node. - * Expression nodes that can define scope are lambdas and table ALIAS columns. - * - * Identifier lookup context can be expression, function, table. - * - * Examples: WITH (x -> x + 1) as func SELECT func() FROM func; During function `func` resolution identifier lookup is performed - * in function context. - * - * If there are no information of identifier context rules are following: - * 1. Try to resolve identifier in expression context. - * 2. Try to resolve identifier in function context, if it is allowed. Example: SELECT func(arguments); Here func identifier cannot be resolved in function context - * because query projection does not support that. - * 3. Try to resolve identifier in table context, if it is allowed. Example: SELECT table; Here table identifier cannot be resolved in function context - * because query projection does not support that. - * - * TODO: This does not supported properly before, because matchers could not be resolved from aliases. - * - * Identifiers are resolved with following rules: - * Resolution starts with current scope. - * 1. Try to resolve identifier from expression scope arguments. Lambda expression arguments are greatest priority. - * 2. Try to resolve identifier from aliases. - * 3. Try to resolve identifier from join tree if scope is query, or if there are registered table columns in scope. - * Steps 2 and 3 can be changed using prefer_column_name_to_alias setting. - * 4. If it is table lookup, try to resolve identifier from CTE. - * If identifier could not be resolved in current scope, resolution must be continued in parent scopes. - * 5. Try to resolve identifier from parent scopes. - * - * Additional rules about aliases and scopes. - * 1. Parent scope cannot refer alias from child scope. - * 2. Child scope can refer to alias in parent scope. - * - * Example: SELECT arrayMap(x -> x + 1 AS a, [1,2,3]), a; Identifier a is unknown in parent scope. - * Example: SELECT a FROM (SELECT 1 as a); Here we do not refer to alias a from child query scope. But we query it projection result, similar to tables. - * Example: WITH 1 as a SELECT (SELECT a) as b; Here in child scope identifier a is resolved using alias from parent scope. - * - * Additional rules about identifier binding. - * Bind for identifier to entity means that identifier first part match some node during analysis. - * If other parts of identifier cannot be resolved in that node, exception must be thrown. - * - * Example: - * CREATE TABLE test_table (id UInt64, compound_value Tuple(value UInt64)) ENGINE=TinyLog; - * SELECT compound_value.value, 1 AS compound_value FROM test_table; - * Identifier first part compound_value bound to entity with alias compound_value, but nested identifier part cannot be resolved from entity, - * lookup should not be continued, and exception must be thrown because if lookup continues that way identifier can be resolved from join tree. - * - * TODO: This was not supported properly before analyzer because nested identifier could not be resolved from alias. - * - * More complex example: - * CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; - * WITH cast(('Value'), 'Tuple (value UInt64') AS value SELECT (SELECT value FROM test_table); - * Identifier first part value bound to test_table column value, but nested identifier part cannot be resolved from it, - * lookup should not be continued, and exception must be thrown because if lookup continues identifier can be resolved from parent scope. - * - * TODO: Update exception messages - * TODO: Table identifiers with optional UUID. - * TODO: Lookup functions arrayReduce(sum, [1, 2, 3]); - * TODO: Support function identifier resolve from parent query scope, if lambda in parent scope does not capture any columns. - */ - -namespace -{ - -/// Identifier lookup context -enum class IdentifierLookupContext : uint8_t -{ - EXPRESSION = 0, - FUNCTION, - TABLE_EXPRESSION, -}; - -const char * toString(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "EXPRESSION"; - case IdentifierLookupContext::FUNCTION: return "FUNCTION"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "TABLE_EXPRESSION"; - } -} - -const char * toStringLowercase(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "expression"; - case IdentifierLookupContext::FUNCTION: return "function"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "table expression"; - } -} - -/** Structure that represent identifier lookup during query analysis. - * Lookup can be in query expression, function, table context. - */ -struct IdentifierLookup -{ - Identifier identifier; - IdentifierLookupContext lookup_context; - - bool isExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::EXPRESSION; - } - - bool isFunctionLookup() const - { - return lookup_context == IdentifierLookupContext::FUNCTION; - } - - bool isTableExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::TABLE_EXPRESSION; - } - - String dump() const - { - return identifier.getFullName() + ' ' + toString(lookup_context); - } -}; - -inline bool operator==(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return lhs.identifier.getFullName() == rhs.identifier.getFullName() && lhs.lookup_context == rhs.lookup_context; -} - -[[maybe_unused]] inline bool operator!=(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return !(lhs == rhs); -} - -struct IdentifierLookupHash -{ - size_t operator()(const IdentifierLookup & identifier_lookup) const - { - return std::hash()(identifier_lookup.identifier.getFullName()) ^ static_cast(identifier_lookup.lookup_context); - } -}; - -enum class IdentifierResolvePlace : UInt8 -{ - NONE = 0, - EXPRESSION_ARGUMENTS, - ALIASES, - JOIN_TREE, - /// Valid only for table lookup - CTE, - /// Valid only for table lookup - DATABASE_CATALOG -}; - -const char * toString(IdentifierResolvePlace resolved_identifier_place) -{ - switch (resolved_identifier_place) - { - case IdentifierResolvePlace::NONE: return "NONE"; - case IdentifierResolvePlace::EXPRESSION_ARGUMENTS: return "EXPRESSION_ARGUMENTS"; - case IdentifierResolvePlace::ALIASES: return "ALIASES"; - case IdentifierResolvePlace::JOIN_TREE: return "JOIN_TREE"; - case IdentifierResolvePlace::CTE: return "CTE"; - case IdentifierResolvePlace::DATABASE_CATALOG: return "DATABASE_CATALOG"; - } -} - -struct IdentifierResolveResult -{ - IdentifierResolveResult() = default; - - QueryTreeNodePtr resolved_identifier; - IdentifierResolvePlace resolve_place = IdentifierResolvePlace::NONE; - bool resolved_from_parent_scopes = false; - - [[maybe_unused]] bool isResolved() const - { - return resolve_place != IdentifierResolvePlace::NONE; - } - - [[maybe_unused]] bool isResolvedFromParentScopes() const - { - return resolved_from_parent_scopes; - } - - [[maybe_unused]] bool isResolvedFromExpressionArguments() const - { - return resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - } - - [[maybe_unused]] bool isResolvedFromAliases() const - { - return resolve_place == IdentifierResolvePlace::ALIASES; - } - - [[maybe_unused]] bool isResolvedFromJoinTree() const - { - return resolve_place == IdentifierResolvePlace::JOIN_TREE; - } - - [[maybe_unused]] bool isResolvedFromCTEs() const - { - return resolve_place == IdentifierResolvePlace::CTE; - } - - void dump(WriteBuffer & buffer) const - { - if (!resolved_identifier) - { - buffer << "unresolved"; - return; - } - - buffer << resolved_identifier->formatASTForErrorMessage() << " place " << toString(resolve_place) << " resolved from parent scopes " << resolved_from_parent_scopes; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -struct IdentifierResolveState -{ - IdentifierResolveResult resolve_result; - bool cyclic_identifier_resolve = false; -}; - -struct IdentifierResolveSettings -{ - /// Allow to check join tree during identifier resolution - bool allow_to_check_join_tree = true; - - /// Allow to check CTEs during table identifier resolution - bool allow_to_check_cte = true; - - /// Allow to check parent scopes during identifier resolution - bool allow_to_check_parent_scopes = true; - - /// Allow to check database catalog during table identifier resolution - bool allow_to_check_database_catalog = true; - - /// Allow to resolve subquery during identifier resolution - bool allow_to_resolve_subquery_during_identifier_resolution = true; -}; - -struct StringTransparentHash -{ - using is_transparent = void; - using hash = std::hash; - - [[maybe_unused]] size_t operator()(const char * data) const - { - return hash()(data); - } - - size_t operator()(std::string_view data) const - { - return hash()(data); - } - - size_t operator()(const std::string & data) const - { - return hash()(data); - } -}; - -using ColumnNameToColumnNodeMap = std::unordered_map>; - -struct TableExpressionData -{ - std::string table_expression_name; - std::string table_expression_description; - std::string database_name; - std::string table_name; - bool should_qualify_columns = true; - NamesAndTypes column_names_and_types; - ColumnNameToColumnNodeMap column_name_to_column_node; - std::unordered_set subcolumn_names; /// Subset columns that are subcolumns of other columns - std::unordered_set> column_identifier_first_parts; - - bool hasFullIdentifierName(IdentifierView identifier_view) const - { - return column_name_to_column_node.contains(identifier_view.getFullName()); - } - - bool canBindIdentifier(IdentifierView identifier_view) const - { - return column_identifier_first_parts.contains(identifier_view.at(0)); - } - - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Table expression name " << table_expression_name; - - if (!table_expression_description.empty()) - buffer << " table expression description " << table_expression_description; - - if (!database_name.empty()) - buffer << " database name " << database_name; - - if (!table_name.empty()) - buffer << " table name " << table_name; - - buffer << " should qualify columns " << should_qualify_columns; - buffer << " columns size " << column_name_to_column_node.size() << '\n'; - - for (const auto & [column_name, column_node] : column_name_to_column_node) - buffer << "Column name " << column_name << " column node " << column_node->dumpTree() << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -class ExpressionsStack -{ -public: - void push(const QueryTreeNodePtr & node) - { - if (node->hasAlias()) - { - const auto & node_alias = node->getAlias(); - alias_name_to_expressions[node_alias].push_back(node); - } - - if (const auto * function = node->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - ++aggregate_functions_counter; - } - - expressions.emplace_back(node); - } - - void pop() - { - const auto & top_expression = expressions.back(); - const auto & top_expression_alias = top_expression->getAlias(); - - if (!top_expression_alias.empty()) - { - auto it = alias_name_to_expressions.find(top_expression_alias); - auto & alias_expressions = it->second; - alias_expressions.pop_back(); - - if (alias_expressions.empty()) - alias_name_to_expressions.erase(it); - } - - if (const auto * function = top_expression->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - --aggregate_functions_counter; - } - - expressions.pop_back(); - } - - [[maybe_unused]] const QueryTreeNodePtr & getRoot() const - { - return expressions.front(); - } - - const QueryTreeNodePtr & getTop() const - { - return expressions.back(); - } - - [[maybe_unused]] bool hasExpressionWithAlias(const std::string & alias) const - { - return alias_name_to_expressions.contains(alias); - } - - bool hasAggregateFunction() const - { - return aggregate_functions_counter > 0; - } - - QueryTreeNodePtr getExpressionWithAlias(const std::string & alias) const - { - auto expression_it = alias_name_to_expressions.find(alias); - if (expression_it == alias_name_to_expressions.end()) - return {}; - - return expression_it->second.front(); - } - - [[maybe_unused]] size_t size() const - { - return expressions.size(); - } - - bool empty() const - { - return expressions.empty(); - } - - void dump(WriteBuffer & buffer) const - { - buffer << expressions.size() << '\n'; - - for (const auto & expression : expressions) - { - buffer << "Expression "; - buffer << expression->formatASTForErrorMessage(); - - const auto & alias = expression->getAlias(); - if (!alias.empty()) - buffer << " alias " << alias; - - buffer << '\n'; - } - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } - -private: - QueryTreeNodes expressions; - size_t aggregate_functions_counter = 0; - std::unordered_map alias_name_to_expressions; -}; - struct ScopeAliases { /// Alias name to query expression node @@ -668,7812 +88,4 @@ struct ScopeAliases } }; - -/** Projection names is name of query tree node that is used in projection part of query node. - * Example: SELECT id FROM test_table; - * `id` is projection name of column node - * - * Example: SELECT id AS id_alias FROM test_table; - * `id_alias` is projection name of column node - * - * Calculation of projection names is done during expression nodes resolution. This is done this way - * because after identifier node is resolved we lose information about identifier name. We could - * potentially save this information in query tree node itself, but that would require to clone it in some cases. - * Example: SELECT big_scalar_subquery AS a, a AS b, b AS c; - * All 3 nodes in projection are the same big_scalar_subquery, but they have different projection names. - * If we want to save it in query tree node, we have to clone subquery node that could lead to performance degradation. - * - * Possible solution is to separate query node metadata and query node content. So only node metadata could be cloned - * if we want to change projection name. This solution does not seem to be easy for client of query tree because projection - * name will be part of interface. If we potentially could hide projection names calculation in analyzer without introducing additional - * changes in query tree structure that would be preferable. - * - * Currently each resolve method returns projection names array. Resolve method must compute projection names of node. - * If node is resolved as list node this is case for `untuple` function or `matcher` result projection names array must contain projection names - * for result nodes. - * If node is not resolved as list node, projection names array contain single projection name for node. - * - * Rules for projection names: - * 1. If node has alias. It is node projection name. - * Except scenario where `untuple` function has alias. Example: SELECT untuple(expr) AS alias, alias. - * - * 2. For constant it is constant value string representation. - * - * 3. For identifier: - * If identifier is resolved from JOIN TREE, we want to remove additional identifier qualifications. - * Example: SELECT default.test_table.id FROM test_table. - * Result projection name is `id`. - * - * Example: SELECT t1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In example both test_table_1, test_table_2 have `id` column. - * In such case projection name is `t1.id` because if additional qualification is removed then column projection name `id` will be ambiguous. - * - * Example: SELECT default.test_table_1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In such case projection name is `test_table_1.id` because we remove unnecessary database qualification, but table name qualification cannot be removed - * because otherwise column projection name `id` will be ambiguous. - * - * If identifier is not resolved from JOIN TREE. Identifier name is projection name. - * Except scenario where `untuple` function resolved using identifier. Example: SELECT untuple(expr) AS alias, alias. - * Example: SELECT sum(1, 1) AS value, value. - * In such case both nodes have `value` projection names. - * - * Example: SELECT id AS value, value FROM test_table. - * In such case both nodes have have `value` projection names. - * - * Special case is `untuple` function. If `untuple` function specified with alias, then result nodes will have alias.tuple_column_name projection names. - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value) AS a; - * Result projection names are `value`, `a.id`. - * - * If `untuple` function does not have alias then result nodes will have `tupleElement(untuple_expression_projection_name, 'tuple_column_name') projection names. - * - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value); - * Result projection names are `value`, `tupleElement(value, 'id')`; - * - * 4. For function: - * Projection name consists from function_name(parameters_projection_names)(arguments_projection_names). - * Additionally if function is window function. Window node projection name is used with OVER clause. - * Example: function_name (parameters_names)(argument_projection_names) OVER window_name; - * Example: function_name (parameters_names)(argument_projection_names) OVER (PARTITION BY id ORDER BY id). - * Example: function_name (parameters_names)(argument_projection_names) OVER (window_name ORDER BY id). - * - * 5. For lambda: - * If it is standalone lambda that returns single expression, function projection name is used. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(1). - * Projection name is `lambda(1)`. - * - * If is it standalone lambda that returns list, projection names of list nodes are used. - * Example: WITH (x -> *) AS lambda SELECT lambda(1) FROM test_table; - * If test_table has two columns `id`, `value`. Then result projection names are `id`, `value`. - * - * If lambda is argument of function. - * Then projection name consists from lambda(tuple(lambda_arguments)(lambda_body_projection_name)); - * - * 6. For matcher: - * Matched nodes projection names are used as matcher projection names. - * - * Matched nodes must be qualified if needed. - * Example: SELECT * FROM test_table_1 AS t1, test_table_2 AS t2. - * In example table test_table_1 and test_table_2 both have `id`, `value` columns. - * Matched nodes after unqualified matcher resolve must be qualified to avoid ambiguous projection names. - * Result projection names must be `t1.id`, `t1.value`, `t2.id`, `t2.value`. - * - * There are special cases - * 1. For lambda inside APPLY matcher transformer: - * Example: SELECT * APPLY x -> toString(x) FROM test_table. - * In such case lambda argument projection name `x` will be replaced by matched node projection name. - * If table has two columns `id` and `value`. Then result projection names are `toString(id)`, `toString(value)`; - * - * 2. For unqualified matcher when JOIN tree contains JOIN with USING. - * Example: SELECT * FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING(id); - * Result projection names must be `id`, `t1.value`, `t2.value`. - * - * 7. For subquery: - * For subquery projection name consists of `_subquery_` prefix and implementation specific unique number suffix. - * Example: SELECT (SELECT 1), (SELECT 1 UNION DISTINCT SELECT 1); - * Result projection name can be `_subquery_1`, `subquery_2`; - * - * 8. For table: - * Table node can be used in expression context only as right argument of IN function. In that case identifier is used - * as table node projection name. - * Example: SELECT id IN test_table FROM test_table; - * Result projection name is `in(id, test_table)`. - */ -using ProjectionName = String; -using ProjectionNames = std::vector; -constexpr auto PROJECTION_NAME_PLACEHOLDER = "__projection_name_placeholder"; - -struct IdentifierResolveScope -{ - /// Construct identifier resolve scope using scope node, and parent scope - IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) - : scope_node(std::move(scope_node_)) - , parent_scope(parent_scope_) - { - if (parent_scope) - { - subquery_depth = parent_scope->subquery_depth; - context = parent_scope->context; - projection_mask_map = parent_scope->projection_mask_map; - } - else - projection_mask_map = std::make_shared>(); - - if (auto * union_node = scope_node->as()) - { - context = union_node->getContext(); - } - else if (auto * query_node = scope_node->as()) - { - context = query_node->getContext(); - group_by_use_nulls = context->getSettingsRef().group_by_use_nulls && - (query_node->isGroupByWithGroupingSets() || query_node->isGroupByWithRollup() || query_node->isGroupByWithCube()); - } - - if (context) - join_use_nulls = context->getSettingsRef().join_use_nulls; - else if (parent_scope) - join_use_nulls = parent_scope->join_use_nulls; - - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - QueryTreeNodePtr scope_node; - - IdentifierResolveScope * parent_scope = nullptr; - - ContextPtr context; - - /// Identifier lookup to result - std::unordered_map identifier_lookup_to_resolve_state; - - /// Argument can be expression like constant, column, function or table expression - std::unordered_map expression_argument_name_to_node; - - ScopeAliases aliases; - - /// Table column name to column node. Valid only during table ALIAS columns resolve. - ColumnNameToColumnNodeMap column_name_to_column_node; - - /// CTE name to query node - std::unordered_map cte_name_to_query_node; - - /// Window name to window node - std::unordered_map window_name_to_window_node; - - /// Current scope expression in resolve process stack - ExpressionsStack expressions_in_resolve_process_stack; - - /// Table expressions in resolve process - std::unordered_set table_expressions_in_resolve_process; - - /// Current scope expression - std::unordered_set non_cached_identifier_lookups_during_expression_resolve; - - /// Table expression node to data - std::unordered_map table_expression_node_to_data; - - QueryTreeNodePtrWithHashIgnoreTypesSet nullable_group_by_keys; - /// Here we count the number of nullable GROUP BY keys we met resolving expression. - /// E.g. for a query `SELECT tuple(tuple(number)) FROM numbers(10) GROUP BY (number, tuple(number)) with cube` - /// both `number` and `tuple(number)` would be in nullable_group_by_keys. - /// But when we resolve `tuple(tuple(number))` we should figure out that `tuple(number)` is already a key, - /// and we should not convert `number` to nullable. - size_t found_nullable_group_by_key_in_scope = 0; - - /** It's possible that after a JOIN, a column in the projection has a type different from the column in the source table. - * (For example, after join_use_nulls or USING column casted to supertype) - * However, the column in the projection still refers to the table as its source. - * This map is used to revert these columns back to their original columns in the source table. - */ - QueryTreeNodePtrWithHashMap join_columns_with_changed_types; - - /// Use identifier lookup to result cache - bool use_identifier_lookup_to_result_cache = true; - - /// Apply nullability to aggregation keys - bool group_by_use_nulls = false; - /// Join retutns NULLs instead of default values - bool join_use_nulls = false; - - /// JOINs count - size_t joins_count = 0; - - /// Subquery depth - size_t subquery_depth = 0; - - /** Scope join tree node for expression. - * Valid only during analysis construction for single expression. - */ - QueryTreeNodePtr expression_join_tree_node; - - /// Node hash to mask id map - std::shared_ptr> projection_mask_map; - - struct ResolvedFunctionsCache - { - FunctionOverloadResolverPtr resolver; - FunctionBasePtr function_base; - }; - - std::map functions_cache; - - [[maybe_unused]] const IdentifierResolveScope * getNearestQueryScope() const - { - const IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - IdentifierResolveScope * getNearestQueryScope() - { - IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - const TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - void pushExpressionNode(const QueryTreeNodePtr & node) - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.push(node); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - void popExpressionNode() - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.pop(); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_after_group_by; - } - - /// Dump identifier resolve scope - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Scope node " << scope_node->formatASTForErrorMessage() << '\n'; - buffer << "Identifier lookup to resolve state " << identifier_lookup_to_resolve_state.size() << '\n'; - for (const auto & [identifier, state] : identifier_lookup_to_resolve_state) - { - buffer << "Identifier " << identifier.dump() << " resolve result "; - state.resolve_result.dump(buffer); - buffer << '\n'; - } - - buffer << "Expression argument name to node " << expression_argument_name_to_node.size() << '\n'; - for (const auto & [alias_name, node] : expression_argument_name_to_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to expression node table size " << aliases.alias_name_to_expression_node->size() << '\n'; - for (const auto & [alias_name, node] : *aliases.alias_name_to_expression_node) - buffer << "Alias name " << alias_name << " expression node " << node->dumpTree() << '\n'; - - buffer << "Alias name to function node table size " << aliases.alias_name_to_lambda_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_lambda_node) - buffer << "Alias name " << alias_name << " lambda node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to table expression node table size " << aliases.alias_name_to_table_expression_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_table_expression_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "CTE name to query node table size " << cte_name_to_query_node.size() << '\n'; - for (const auto & [cte_name, node] : cte_name_to_query_node) - buffer << "CTE name " << cte_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "WINDOW name to window node table size " << window_name_to_window_node.size() << '\n'; - for (const auto & [window_name, node] : window_name_to_window_node) - buffer << "CTE name " << window_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Nodes with duplicated aliases size " << aliases.nodes_with_duplicated_aliases.size() << '\n'; - for (const auto & node : aliases.nodes_with_duplicated_aliases) - buffer << "Alias name " << node->getAlias() << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Expression resolve process stack " << '\n'; - expressions_in_resolve_process_stack.dump(buffer); - - buffer << "Table expressions in resolve process size " << table_expressions_in_resolve_process.size() << '\n'; - for (const auto & node : table_expressions_in_resolve_process) - buffer << "Table expression " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Non cached identifier lookups during expression resolve " << non_cached_identifier_lookups_during_expression_resolve.size() << '\n'; - for (const auto & identifier_lookup : non_cached_identifier_lookups_during_expression_resolve) - buffer << "Identifier lookup " << identifier_lookup.dump() << '\n'; - - buffer << "Table expression node to data " << table_expression_node_to_data.size() << '\n'; - for (const auto & [table_expression_node, table_expression_data] : table_expression_node_to_data) - buffer << "Table expression node " << table_expression_node->formatASTForErrorMessage() << " data " << table_expression_data.dump() << '\n'; - - buffer << "Use identifier lookup to result cache " << use_identifier_lookup_to_result_cache << '\n'; - buffer << "Subquery depth " << subquery_depth << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - - -/** Visitor that extracts expression and function aliases from node and initialize scope tables with it. - * Does not go into child lambdas and queries. - * - * Important: - * Identifier nodes with aliases are added both in alias to expression and alias to function map. - * - * These is necessary because identifier with alias can give alias name to any query tree node. - * - * Example: - * WITH (x -> x + 1) AS id, id AS value SELECT value(1); - * In this example id as value is identifier node that has alias, during scope initialization we cannot derive - * that id is actually lambda or expression. - * - * There are no easy solution here, without trying to make full featured expression resolution at this stage. - * Example: - * WITH (x -> x + 1) AS id, id AS id_1, id_1 AS id_2 SELECT id_2(1); - * Example: SELECT a, b AS a, b AS c, 1 AS c; - * - * It is client responsibility after resolving identifier node with alias, make following actions: - * 1. If identifier node was resolved in function scope, remove alias from scope expression map. - * 2. If identifier node was resolved in expression scope, remove alias from scope function map. - * - * That way we separate alias map initialization and expressions resolution. - */ -class QueryExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit QueryExpressionsAliasVisitor(ScopeAliases & aliases_) - : aliases(aliases_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node, false /*is_lambda_node*/); - } - - bool needChildVisit(const QueryTreeNodePtr &, const QueryTreeNodePtr & child) - { - if (auto * lambda_node = child->as()) - { - updateAliasesIfNeeded(child, true /*is_lambda_node*/); - return false; - } - else if (auto * query_tree_node = child->as()) - { - if (query_tree_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - else if (auto * union_node = child->as()) - { - if (union_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - - return true; - } -private: - void addDuplicatingAlias(const QueryTreeNodePtr & node) - { - aliases.nodes_with_duplicated_aliases.emplace(node); - auto cloned_node = node->clone(); - aliases.cloned_nodes_with_duplicated_aliases.emplace_back(cloned_node); - aliases.nodes_with_duplicated_aliases.emplace(cloned_node); - } - - void updateAliasesIfNeeded(const QueryTreeNodePtr & node, bool is_lambda_node) - { - if (!node->hasAlias()) - return; - - // We should not resolve expressions to WindowNode - if (node->getNodeType() == QueryTreeNodeType::WINDOW) - return; - - const auto & alias = node->getAlias(); - - if (is_lambda_node) - { - if (aliases.alias_name_to_expression_node->contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_lambda_node.insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - return; - } - - if (aliases.alias_name_to_lambda_node.contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_expression_node->insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - /// If node is identifier put it into transitive aliases map. - if (const auto * identifier = typeid_cast(node.get())) - aliases.transitive_aliases.insert(std::make_pair(alias, identifier->getIdentifier())); - } - - ScopeAliases & aliases; -}; - -class TableExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit TableExpressionsAliasVisitor(IdentifierResolveScope & scope_) - : scope(scope_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node); - } - - static bool needChildVisit(const QueryTreeNodePtr & node, const QueryTreeNodePtr & child) - { - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::ARRAY_JOIN: - { - const auto & array_join_node = node->as(); - return child.get() == array_join_node.getTableExpression().get(); - } - case QueryTreeNodeType::JOIN: - { - const auto & join_node = node->as(); - return child.get() == join_node.getLeftTableExpression().get() || child.get() == join_node.getRightTableExpression().get(); - } - default: - { - break; - } - } - - return false; - } - -private: - void updateAliasesIfNeeded(const QueryTreeNodePtr & node) - { - if (!node->hasAlias()) - return; - - const auto & node_alias = node->getAlias(); - auto [_, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(node_alias, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple table expressions with same alias {}. In scope {}", - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - IdentifierResolveScope & scope; -}; - -class QueryAnalyzer -{ -public: - explicit QueryAnalyzer(bool only_analyze_) : only_analyze(only_analyze_) {} - - void resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context) - { - IdentifierResolveScope scope(node, nullptr /*parent_scope*/); - - if (!scope.context) - scope.context = context; - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::QUERY: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For query analysis table expression must be empty"); - - resolveQuery(node, scope); - break; - } - case QueryTreeNodeType::UNION: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For union analysis table expression must be empty"); - - resolveUnion(node, scope); - break; - } - case QueryTreeNodeType::IDENTIFIER: - [[fallthrough]]; - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - [[fallthrough]]; - case QueryTreeNodeType::FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::LIST: - { - if (table_expression) - { - scope.expression_join_tree_node = table_expression; - validateTableExpressionModifiers(scope.expression_join_tree_node, scope); - initializeTableExpressionData(scope.expression_join_tree_node, scope); - } - - if (node_type == QueryTreeNodeType::LIST) - resolveExpressionNodeList(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - else - resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - QueryExpressionsAliasVisitor expressions_alias_visitor(scope.aliases); - resolveTableFunction(node, scope, expressions_alias_visitor, false /*nested_table_function*/); - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Node {} with type {} is not supported by query analyzer. " - "Supported nodes are query, union, identifier, constant, column, function, list.", - node->formatASTForErrorMessage(), - node->getNodeTypeName()); - } - } - } - -private: - /// Utility functions - - static bool isExpressionNodeType(QueryTreeNodeType node_type); - - static bool isFunctionExpressionNodeType(QueryTreeNodeType node_type); - - static bool isSubqueryNodeType(QueryTreeNodeType node_type); - - static bool isTableExpressionNodeType(QueryTreeNodeType node_type); - - static DataTypePtr getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node); - - static ProjectionName calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, - const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names); - - static ProjectionName calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name); - - static ProjectionName calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, - const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, - const ProjectionName & fill_to_expression_projection_name, - const ProjectionName & fill_step_expression_projection_name); - - static void collectCompoundExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result); - - static void collectTableExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result); - - static void collectScopeValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static void collectScopeWithParentScopesValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static std::vector collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers); - - static QueryTreeNodePtr wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path); - - QueryTreeNodePtr tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context); - - void evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & query_tree_node, IdentifierResolveScope & scope); - - static void mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope); - - void replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope); - - static void convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope); - - static void validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope); - - static std::pair recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into); - - static void expandGroupByAll(QueryNode & query_tree_node_typed); - - void expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings); - - static std::string - rewriteAggregateFunctionNameIfNeeded(const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context); - - static std::optional getColumnSideFromJoinTree(const QueryTreeNodePtr & resolved_identifier, const JoinNode & join_node) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - return {}; - - if (resolved_identifier->getNodeType() == QueryTreeNodeType::FUNCTION) - { - const auto & resolved_function = resolved_identifier->as(); - - const auto & argument_nodes = resolved_function.getArguments().getNodes(); - - std::optional result; - for (const auto & argument_node : argument_nodes) - { - auto table_side = getColumnSideFromJoinTree(argument_node, join_node); - if (table_side && result && *table_side != *result) - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Ambiguous identifier {}. In scope {}", - resolved_identifier->formatASTForErrorMessage(), - join_node.formatASTForErrorMessage()); - } - result = table_side; - } - return result; - } - - const auto * column_src = resolved_identifier->as().getColumnSource().get(); - - if (join_node.getLeftTableExpression().get() == column_src) - return JoinTableSide::Left; - if (join_node.getRightTableExpression().get() == column_src) - return JoinTableSide::Right; - return {}; - } - - static QueryTreeNodePtr convertJoinedColumnTypeToNullIfNeeded( - const QueryTreeNodePtr & resolved_identifier, - const JoinKind & join_kind, - std::optional resolved_side, - IdentifierResolveScope & scope) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && - JoinCommon::canBecomeNullable(resolved_identifier->getResultType()) && - (isFull(join_kind) || - (isLeft(join_kind) && resolved_side && *resolved_side == JoinTableSide::Right) || - (isRight(join_kind) && resolved_side && *resolved_side == JoinTableSide::Left))) - { - auto nullable_resolved_identifier = resolved_identifier->clone(); - auto & resolved_column = nullable_resolved_identifier->as(); - auto new_result_type = makeNullableOrLowCardinalityNullable(resolved_column.getColumnType()); - resolved_column.setColumnType(new_result_type); - if (resolved_column.hasExpression()) - { - auto & resolved_expression = resolved_column.getExpression(); - if (!resolved_expression->getResultType()->equals(*new_result_type)) - resolved_expression = buildCastFunction(resolved_expression, new_result_type, scope.context, true); - } - if (!nullable_resolved_identifier->isEqual(*resolved_identifier)) - scope.join_columns_with_changed_types[nullable_resolved_identifier] = resolved_identifier; - return nullable_resolved_identifier; - } - return nullptr; - } - - /// Resolve identifier functions - - static QueryTreeNodePtr tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context); - - QueryTreeNodePtr tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found = false); - - QueryTreeNodePtr tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings); - - QueryTreeNodePtr tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings = {}); - - QueryTreeNodePtr tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found = false); - - /// Resolve query tree nodes functions - - void qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static GetColumnsOptions buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context); - - using QueryTreeNodesWithNames = std::vector>; - - QueryTreeNodesWithNames getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope); - - void updateMatchedColumnsFromJoinUsing(QueryTreeNodesWithNames & result_matched_column_nodes_with_names, const QueryTreeNodePtr & source_table_expression, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionNames resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionName resolveWindow(QueryTreeNodePtr & window_node, IdentifierResolveScope & scope); - - ProjectionNames resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope); - - ProjectionNames resolveFunction(QueryTreeNodePtr & function_node, IdentifierResolveScope & scope); - - ProjectionNames resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias = false); - - ProjectionNames resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression); - - ProjectionNames resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope); - - void resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope); - - void resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope); - - void resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope); - - NamesAndTypes resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope); - - void initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope); - - void initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - void resolveTableFunction(QueryTreeNodePtr & table_function_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, bool nested_table_function); - - void resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope); - - void resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope); - - /// Lambdas that are currently in resolve process - std::unordered_set lambdas_in_resolve_process; - - /// CTEs that are currently in resolve process - std::unordered_set ctes_in_resolve_process; - - /// Function name to user defined lambda map - std::unordered_map function_name_to_user_defined_lambda; - - /// Array join expressions counter - size_t array_join_expressions_counter = 1; - - /// Subquery counter - size_t subquery_counter = 1; - - /// Global expression node to projection name map - std::unordered_map node_to_projection_name; - - /// Global resolve expression node to projection names map - std::unordered_map resolved_expressions; - - /// Global resolve expression node to tree size - std::unordered_map node_to_tree_size; - - /// Global scalar subquery to scalar value map - std::unordered_map scalar_subquery_to_scalar_value_local; - std::unordered_map scalar_subquery_to_scalar_value_global; - - const bool only_analyze; -}; - -/// Utility functions implementation - - -bool QueryAnalyzer::isExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::CONSTANT || node_type == QueryTreeNodeType::COLUMN || node_type == QueryTreeNodeType::FUNCTION - || node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isFunctionExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::LAMBDA; -} - -bool QueryAnalyzer::isSubqueryNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isTableExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::TABLE || node_type == QueryTreeNodeType::TABLE_FUNCTION || - isSubqueryNodeType(node_type); -} - -DataTypePtr QueryAnalyzer::getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node) -{ - auto node_type = query_tree_node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - { - return query_tree_node->getResultType(); - } - case QueryTreeNodeType::FUNCTION: - { - auto & function_node = query_tree_node->as(); - if (function_node.isResolved()) - return function_node.getResultType(); - break; - } - default: - { - break; - } - } - - return nullptr; -} - -ProjectionName QueryAnalyzer::calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names) -{ - const auto & function_node_typed = function_node->as(); - const auto & function_node_name = function_node_typed.getFunctionName(); - - bool is_array_function = function_node_name == "array"; - bool is_tuple_function = function_node_name == "tuple"; - - WriteBufferFromOwnString buffer; - - if (!is_array_function && !is_tuple_function) - buffer << function_node_name; - - if (!parameters_projection_names.empty()) - { - buffer << '('; - - size_t function_parameters_projection_names_size = parameters_projection_names.size(); - for (size_t i = 0; i < function_parameters_projection_names_size; ++i) - { - buffer << parameters_projection_names[i]; - - if (i + 1 != function_parameters_projection_names_size) - buffer << ", "; - } - - buffer << ')'; - } - - char open_bracket = '('; - char close_bracket = ')'; - - if (is_array_function) - { - open_bracket = '['; - close_bracket = ']'; - } - - buffer << open_bracket; - - size_t function_arguments_projection_names_size = arguments_projection_names.size(); - for (size_t i = 0; i < function_arguments_projection_names_size; ++i) - { - buffer << arguments_projection_names[i]; - - if (i + 1 != function_arguments_projection_names_size) - buffer << ", "; - } - - buffer << close_bracket; - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name) -{ - const auto & window_node_typed = window_node->as(); - const auto & window_frame = window_node_typed.getWindowFrame(); - - bool parent_window_node_has_partition_by = false; - bool parent_window_node_has_order_by = false; - - if (parent_window_node) - { - const auto & parent_window_node_typed = parent_window_node->as(); - parent_window_node_has_partition_by = parent_window_node_typed.hasPartitionBy(); - parent_window_node_has_order_by = parent_window_node_typed.hasOrderBy(); - } - - WriteBufferFromOwnString buffer; - - if (!parent_window_name.empty()) - buffer << parent_window_name; - - if (!partition_by_projection_names.empty() && !parent_window_node_has_partition_by) - { - if (!parent_window_name.empty()) - buffer << ' '; - - buffer << "PARTITION BY "; - - size_t partition_by_projection_names_size = partition_by_projection_names.size(); - for (size_t i = 0; i < partition_by_projection_names_size; ++i) - { - buffer << partition_by_projection_names[i]; - if (i + 1 != partition_by_projection_names_size) - buffer << ", "; - } - } - - if (!order_by_projection_names.empty() && !parent_window_node_has_order_by) - { - if (!partition_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << "ORDER BY "; - - size_t order_by_projection_names_size = order_by_projection_names.size(); - for (size_t i = 0; i < order_by_projection_names_size; ++i) - { - buffer << order_by_projection_names[i]; - if (i + 1 != order_by_projection_names_size) - buffer << ", "; - } - } - - if (!window_frame.is_default) - { - if (!partition_by_projection_names.empty() || !order_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << window_frame.type << " BETWEEN "; - if (window_frame.begin_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.begin_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_begin_offset_projection_name; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - - buffer << " AND "; - - if (window_frame.end_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.end_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_end_offset_projection_name; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - } - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, const ProjectionName & fill_to_expression_projection_name, const ProjectionName & fill_step_expression_projection_name) -{ - auto & sort_node_typed = sort_column_node->as(); - - WriteBufferFromOwnString sort_column_projection_name_buffer; - sort_column_projection_name_buffer << sort_expression_projection_name; - - auto sort_direction = sort_node_typed.getSortDirection(); - sort_column_projection_name_buffer << (sort_direction == SortDirection::ASCENDING ? " ASC" : " DESC"); - - auto nulls_sort_direction = sort_node_typed.getNullsSortDirection(); - - if (nulls_sort_direction) - sort_column_projection_name_buffer << " NULLS " << (nulls_sort_direction == sort_direction ? "LAST" : "FIRST"); - - if (auto collator = sort_node_typed.getCollator()) - sort_column_projection_name_buffer << " COLLATE " << collator->getLocale(); - - if (sort_node_typed.withFill()) - { - sort_column_projection_name_buffer << " WITH FILL"; - - if (sort_node_typed.hasFillFrom()) - sort_column_projection_name_buffer << " FROM " << fill_from_expression_projection_name; - - if (sort_node_typed.hasFillTo()) - sort_column_projection_name_buffer << " TO " << fill_to_expression_projection_name; - - if (sort_node_typed.hasFillStep()) - sort_column_projection_name_buffer << " STEP " << fill_step_expression_projection_name; - } - - return sort_column_projection_name_buffer.str(); -} - -/// Get valid identifiers for typo correction from compound expression -void QueryAnalyzer::collectCompoundExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result) -{ - IDataType::forEachSubcolumn([&](const auto &, const auto & name, const auto &) - { - Identifier subcolumn_indentifier(name); - size_t new_identifier_size = valid_identifier_prefix.getPartsSize() + subcolumn_indentifier.getPartsSize(); - - if (new_identifier_size == unresolved_identifier.getPartsSize()) - { - auto new_identifier = valid_identifier_prefix; - for (const auto & part : subcolumn_indentifier) - new_identifier.push_back(part); - - valid_identifiers_result.insert(std::move(new_identifier)); - } - }, ISerialization::SubstreamData(compound_expression_type->getDefaultSerialization())); -} - -/// Get valid identifiers for typo correction from table expression -void QueryAnalyzer::collectTableExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result) -{ - for (const auto & [column_name, column_node] : table_expression_data.column_name_to_column_node) - { - Identifier column_identifier(column_name); - if (unresolved_identifier.getPartsSize() == column_identifier.getPartsSize()) - valid_identifiers_result.insert(column_identifier); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier, - valid_identifiers_result); - - if (table_expression->hasAlias()) - { - Identifier column_identifier_with_alias({table_expression->getAlias()}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_alias.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_alias.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_alias); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_alias, - valid_identifiers_result); - } - - if (!table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name({table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name, - valid_identifiers_result); - } - - if (!table_expression_data.database_name.empty() && !table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name_and_database_name({table_expression_data.database_name, table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name_and_database_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name_and_database_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name_and_database_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name_and_database_name, - valid_identifiers_result); - } - } -} - -/// Get valid identifiers for typo correction from scope without looking at parent scopes -void QueryAnalyzer::collectScopeValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - bool identifier_is_short = unresolved_identifier.isShort(); - bool identifier_is_compound = unresolved_identifier.isCompound(); - - if (allow_expression_identifiers) - { - for (const auto & [name, expression] : *scope.aliases.alias_name_to_expression_node) - { - assert(expression); - auto expression_identifier = Identifier(name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - - for (const auto & [table_expression, table_expression_data] : scope.table_expression_node_to_data) - { - collectTableExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - table_expression, - table_expression_data, - valid_identifiers_result); - } - } - - if (identifier_is_short) - { - if (allow_function_identifiers) - { - for (const auto & [name, _] : *scope.aliases.alias_name_to_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - - if (allow_table_expression_identifiers) - { - for (const auto & [name, _] : scope.aliases.alias_name_to_table_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - } - - for (const auto & [argument_name, expression] : scope.expression_argument_name_to_node) - { - assert(expression); - auto expression_node_type = expression->getNodeType(); - - if (allow_expression_identifiers && isExpressionNodeType(expression_node_type)) - { - auto expression_identifier = Identifier(argument_name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - else if (identifier_is_short && allow_function_identifiers && isFunctionExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - else if (allow_table_expression_identifiers && isTableExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - } -} - -void QueryAnalyzer::collectScopeWithParentScopesValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - const IdentifierResolveScope * current_scope = &scope; - - while (current_scope) - { - collectScopeValidIdentifiersForTypoCorrection(unresolved_identifier, - *current_scope, - allow_expression_identifiers, - allow_function_identifiers, - allow_table_expression_identifiers, - valid_identifiers_result); - - current_scope = current_scope->parent_scope; - } -} - -std::vector QueryAnalyzer::collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers) -{ - std::vector prompting_strings; - prompting_strings.reserve(valid_identifiers.size()); - - for (const auto & valid_identifier : valid_identifiers) - prompting_strings.push_back(valid_identifier.getFullName()); - - return NamePrompter<1>::getHints(unresolved_identifier.getFullName(), prompting_strings); -} - -/** Wrap expression node in tuple element function calls for nested paths. - * Example: Expression node: compound_expression. Nested path: nested_path_1.nested_path_2. - * Result: tupleElement(tupleElement(compound_expression, 'nested_path_1'), 'nested_path_2'). - */ -QueryTreeNodePtr QueryAnalyzer::wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path) -{ - size_t nested_path_parts_size = nested_path.getPartsSize(); - for (size_t i = 0; i < nested_path_parts_size; ++i) - { - const auto & nested_path_part = nested_path[i]; - auto tuple_element_function = std::make_shared("tupleElement"); - - auto & tuple_element_function_arguments_nodes = tuple_element_function->getArguments().getNodes(); - tuple_element_function_arguments_nodes.reserve(2); - tuple_element_function_arguments_nodes.push_back(expression_node); - tuple_element_function_arguments_nodes.push_back(std::make_shared(nested_path_part)); - - expression_node = std::move(tuple_element_function); - } - - return expression_node; -} - -/** Try to get lambda node from sql user defined functions if sql user defined function with function name exists. - * Returns lambda node if function exists, nullptr otherwise. - */ -QueryTreeNodePtr QueryAnalyzer::tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context) -{ - auto user_defined_function = UserDefinedSQLFunctionFactory::instance().tryGet(function_name); - if (!user_defined_function) - return {}; - - auto it = function_name_to_user_defined_lambda.find(function_name); - if (it != function_name_to_user_defined_lambda.end()) - return it->second; - - const auto & create_function_query = user_defined_function->as(); - auto result_node = buildQueryTree(create_function_query->function_core, context); - if (result_node->getNodeType() != QueryTreeNodeType::LAMBDA) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "SQL user defined function {} must represent lambda expression. Actual {}", - function_name, - create_function_query->function_core->formatForErrorMessage()); - - function_name_to_user_defined_lambda.emplace(function_name, result_node); - - return result_node; -} - -bool subtreeHasViewSource(const IQueryTreeNode * node, const Context & context) -{ - if (!node) - return false; - - if (const auto * table_node = node->as()) - { - if (table_node->getStorageID().getFullNameNotQuoted() == context.getViewSource()->getStorageID().getFullNameNotQuoted()) - return true; - } - - for (const auto & child : node->getChildren()) - if (subtreeHasViewSource(child.get(), context)) - return true; - - return false; -} - -/// Evaluate scalar subquery and perform constant folding if scalar subquery does not have constant value -void QueryAnalyzer::evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - auto * query_node = node->as(); - auto * union_node = node->as(); - if (!query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node must have query or union type. Actual {} {}", - node->getNodeTypeName(), - node->formatASTForErrorMessage()); - - auto & context = scope.context; - - Block scalar_block; - - auto node_without_alias = node->clone(); - node_without_alias->removeAlias(); - - QueryTreeNodePtrWithHash node_with_hash(node_without_alias); - auto str_hash = DB::toString(node_with_hash.hash); - - bool can_use_global_scalars = !only_analyze && !(context->getViewSource() && subtreeHasViewSource(node_without_alias.get(), *context)); - - auto & scalars_cache = can_use_global_scalars ? scalar_subquery_to_scalar_value_global : scalar_subquery_to_scalar_value_local; - - if (scalars_cache.contains(node_with_hash)) - { - if (can_use_global_scalars) - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - else - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesLocalCacheHit); - - scalar_block = scalars_cache.at(node_with_hash); - } - else if (context->hasQueryContext() && can_use_global_scalars && context->getQueryContext()->hasScalar(str_hash)) - { - scalar_block = context->getQueryContext()->getScalar(str_hash); - scalar_subquery_to_scalar_value_global.emplace(node_with_hash, scalar_block); - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - } - else - { - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesCacheMiss); - auto subquery_context = Context::createCopy(context); - - Settings subquery_settings = context->getSettings(); - subquery_settings.max_result_rows = 1; - subquery_settings.extremes = false; - subquery_context->setSettings(subquery_settings); - /// When execute `INSERT INTO t WITH ... SELECT ...`, it may lead to `Unknown columns` - /// exception with this settings enabled(https://github.com/ClickHouse/ClickHouse/issues/52494). - subquery_context->setSetting("use_structure_from_insertion_table_in_table_functions", false); - - auto options = SelectQueryOptions(QueryProcessingStage::Complete, scope.subquery_depth, true /*is_subquery*/); - options.only_analyze = only_analyze; - auto interpreter = std::make_unique(node->toAST(), subquery_context, subquery_context->getViewSource(), options); - - if (only_analyze) - { - /// If query is only analyzed, then constants are not correct. - scalar_block = interpreter->getSampleBlock(); - for (auto & column : scalar_block) - { - if (column.column->empty()) - { - auto mut_col = column.column->cloneEmpty(); - mut_col->insertDefault(); - column.column = std::move(mut_col); - } - } - } - else - { - auto io = interpreter->execute(); - PullingAsyncPipelineExecutor executor(io.pipeline); - io.pipeline.setProgressCallback(context->getProgressCallback()); - io.pipeline.setProcessListElement(context->getProcessListElement()); - - Block block; - - while (block.rows() == 0 && executor.pull(block)) - { - } - - if (block.rows() == 0) - { - auto types = interpreter->getSampleBlock().getDataTypes(); - if (types.size() != 1) - types = {std::make_shared(types)}; - - auto & type = types[0]; - if (!type->isNullable()) - { - if (!type->canBeInsideNullable()) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, - "Scalar subquery returned empty result of type {} which cannot be Nullable", - type->getName()); - - type = makeNullable(type); - } - - auto scalar_column = type->createColumn(); - scalar_column->insert(Null()); - scalar_block.insert({std::move(scalar_column), type, "null"}); - } - else - { - if (block.rows() != 1) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - Block tmp_block; - while (tmp_block.rows() == 0 && executor.pull(tmp_block)) - { - } - - if (tmp_block.rows() != 0) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - block = materializeBlock(block); - size_t columns = block.columns(); - - if (columns == 1) - { - auto & column = block.getByPosition(0); - /// Here we wrap type to nullable if we can. - /// It is needed cause if subquery return no rows, it's result will be Null. - /// In case of many columns, do not check it cause tuple can't be nullable. - if (!column.type->isNullable() && column.type->canBeInsideNullable()) - { - column.type = makeNullable(column.type); - column.column = makeNullable(column.column); - } - - scalar_block = block; - } - else - { - /** Make unique column names for tuple. - * - * Example: SELECT (SELECT 2 AS x, x) - */ - makeUniqueColumnNamesInBlock(block); - - scalar_block.insert({ - ColumnTuple::create(block.getColumns()), - std::make_shared(block.getDataTypes(), block.getNames()), - "tuple"}); - } - } - } - - scalars_cache.emplace(node_with_hash, scalar_block); - if (can_use_global_scalars && context->hasQueryContext()) - context->getQueryContext()->addScalar(str_hash, scalar_block); - } - - const auto & scalar_column_with_type = scalar_block.safeGetByPosition(0); - const auto & scalar_type = scalar_column_with_type.type; - - Field scalar_value; - scalar_column_with_type.column->get(0, scalar_value); - - const auto * scalar_type_name = scalar_block.safeGetByPosition(0).type->getFamilyName(); - static const std::set useless_literal_types = {"Array", "Tuple", "AggregateFunction", "Function", "Set", "LowCardinality"}; - auto * nearest_query_scope = scope.getNearestQueryScope(); - - /// Always convert to literals when there is no query context - if (!context->getSettingsRef().enable_scalar_subquery_optimization || - !useless_literal_types.contains(scalar_type_name) || - !context->hasQueryContext() || - !nearest_query_scope) - { - auto constant_value = std::make_shared(std::move(scalar_value), scalar_type); - auto constant_node = std::make_shared(constant_value, node); - - if (constant_node->getValue().isNull()) - { - node = buildCastFunction(constant_node, constant_node->getResultType(), context); - node = std::make_shared(std::move(constant_value), node); - } - else - node = std::move(constant_node); - - return; - } - - auto & nearest_query_scope_query_node = nearest_query_scope->scope_node->as(); - auto & mutable_context = nearest_query_scope_query_node.getMutableContext(); - - auto scalar_query_hash_string = DB::toString(node_with_hash.hash) + (only_analyze ? "_analyze" : ""); - - if (mutable_context->hasQueryContext()) - mutable_context->getQueryContext()->addScalar(scalar_query_hash_string, scalar_block); - - mutable_context->addScalar(scalar_query_hash_string, scalar_block); - - std::string get_scalar_function_name = "__getScalar"; - - auto scalar_query_hash_constant_value = std::make_shared(std::move(scalar_query_hash_string), std::make_shared()); - auto scalar_query_hash_constant_node = std::make_shared(std::move(scalar_query_hash_constant_value)); - - auto get_scalar_function_node = std::make_shared(get_scalar_function_name); - get_scalar_function_node->getArguments().getNodes().push_back(std::move(scalar_query_hash_constant_node)); - - auto get_scalar_function = FunctionFactory::instance().get(get_scalar_function_name, mutable_context); - get_scalar_function_node->resolveAsFunction(get_scalar_function->build(get_scalar_function_node->getArgumentColumns())); - - node = std::move(get_scalar_function_node); -} - -void QueryAnalyzer::mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope) -{ - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - - auto & parent_window_node_typed = parent_window_node->as(); - - /** If an existing_window_name is specified it must refer to an earlier - * entry in the WINDOW list; the new window copies its partitioning clause - * from that entry, as well as its ordering clause if any. In this case - * the new window cannot specify its own PARTITION BY clause, and it can - * specify ORDER BY only if the copied window does not have one. The new - * window always uses its own frame clause; the copied window must not - * specify a frame clause. - * https://www.postgresql.org/docs/current/sql-select.html - */ - if (window_node_typed.hasPartitionBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override PARTITION BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (window_node_typed.hasOrderBy() && parent_window_node_typed.hasOrderBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override a non-empty ORDER BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (!parent_window_node_typed.getWindowFrame().is_default) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parent window '{}' is not allowed to define a frame: while processing derived window definition '{}'. In scope {}", - parent_window_name, - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - window_node_typed.getPartitionByNode() = parent_window_node_typed.getPartitionBy().clone(); - - if (parent_window_node_typed.hasOrderBy()) - window_node_typed.getOrderByNode() = parent_window_node_typed.getOrderBy().clone(); -} - -/** Replace nodes in node list with positional arguments. - * - * Example: SELECT id, value FROM test_table GROUP BY 1, 2; - * Example: SELECT id, value FROM test_table ORDER BY 1, 2; - * Example: SELECT id, value FROM test_table LIMIT 5 BY 1, 2; - */ -void QueryAnalyzer::replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope) -{ - const auto & settings = scope.context->getSettingsRef(); - if (!settings.enable_positional_arguments || scope.context->getClientInfo().query_kind != ClientInfo::QueryKind::INITIAL_QUERY) - return; - - auto & node_list_typed = node_list->as(); - - for (auto & node : node_list_typed.getNodes()) - { - auto * node_to_replace = &node; - - if (auto * sort_node = node->as()) - node_to_replace = &sort_node->getExpression(); - - auto * constant_node = (*node_to_replace)->as(); - - if (!constant_node - || (constant_node->getValue().getType() != Field::Types::UInt64 - && constant_node->getValue().getType() != Field::Types::Int64)) - continue; - - UInt64 pos; - if (constant_node->getValue().getType() == Field::Types::UInt64) - { - pos = constant_node->getValue().get(); - } - else // Int64 - { - auto value = constant_node->getValue().get(); - if (value > 0) - pos = value; - else - { - if (value < -static_cast(projection_nodes.size())) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Negative positional argument number {} is out of bounds. Expected in range [-{}, -1]. In scope {}", - value, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - pos = projection_nodes.size() + value + 1; - } - } - - if (!pos || pos > projection_nodes.size()) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Positional argument number {} is out of bounds. Expected in range [1, {}]. In scope {}", - pos, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - - --pos; - *node_to_replace = projection_nodes[pos]->clone(); - if (auto it = resolved_expressions.find(projection_nodes[pos]); it != resolved_expressions.end()) - { - resolved_expressions[*node_to_replace] = it->second; - } - } -} - -void QueryAnalyzer::convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope) -{ - const auto * limit_offset_constant_node = expression_node->as(); - if (!limit_offset_constant_node || !isNativeNumber(removeNullable(limit_offset_constant_node->getResultType()))) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} expression must be constant with numeric type. Actual {}. In scope {}", - expression_description, - expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - Field converted_value = convertFieldToType(limit_offset_constant_node->getValue(), DataTypeUInt64()); - if (converted_value.isNull()) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} numeric constant expression is not representable as UInt64", - expression_description); - - auto constant_value = std::make_shared(std::move(converted_value), std::make_shared()); - auto result_constant_node = std::make_shared(std::move(constant_value)); - result_constant_node->getSourceExpression() = limit_offset_constant_node->getSourceExpression(); - - expression_node = std::move(result_constant_node); -} - -void QueryAnalyzer::validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unexpected table expression. Expected table, table function, query or union node. Table node: {}, scope node: {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (table_node || table_function_node) - { - auto table_expression_modifiers = table_node ? table_node->getTableExpressionModifiers() : table_function_node->getTableExpressionModifiers(); - - if (table_expression_modifiers.has_value()) - { - const auto & storage = table_node ? table_node->getStorage() : table_function_node->getStorage(); - if (table_expression_modifiers->hasFinal() && !storage->supportsFinal()) - throw Exception(ErrorCodes::ILLEGAL_FINAL, - "Storage {} doesn't support FINAL", - storage->getName()); - - if (table_expression_modifiers->hasSampleSizeRatio() && !storage->supportsSampling()) - throw Exception(ErrorCodes::SAMPLING_NOT_SUPPORTED, - "Storage {} doesn't support sampling", - storage->getStorageID().getFullNameNotQuoted()); - } - } -} - -void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - bool table_expression_has_alias = table_expression_node->hasAlias(); - if (table_expression_has_alias) - return; - - if (join_node->as().getKind() == JoinKind::Paste) - return; - - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - if ((query_node && !query_node->getCTEName().empty()) || (union_node && !union_node->getCTEName().empty())) - return; - - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || - table_expression_node_type == QueryTreeNodeType::QUERY || - table_expression_node_type == QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::ALIAS_REQUIRED, - "JOIN {} no alias for subquery or table function {}. " - "In scope {} (set joined_subquery_requires_alias = 0 to disable restriction)", - join_node->formatASTForErrorMessage(), - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); -} - -std::pair QueryAnalyzer::recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into) -{ - checkStackSize(); - - if (node->as()) - { - into.push_back(node); - return {false, 1}; - } - - auto * function = node->as(); - - if (!function) - return {false, 0}; - - if (function->isAggregateFunction()) - return {true, 0}; - - UInt64 pushed_children = 0; - bool has_aggregate = false; - - for (auto & child : function->getArguments().getNodes()) - { - auto [child_has_aggregate, child_pushed_children] = recursivelyCollectMaxOrdinaryExpressions(child, into); - has_aggregate |= child_has_aggregate; - pushed_children += child_pushed_children; - } - - /// The current function is not aggregate function and there is no aggregate function in its arguments, - /// so use the current function to replace its arguments - if (!has_aggregate) - { - for (UInt64 i = 0; i < pushed_children; i++) - into.pop_back(); - - into.push_back(node); - pushed_children = 1; - } - - return {has_aggregate, pushed_children}; -} - -/** Expand GROUP BY ALL by extracting all the SELECT-ed expressions that are not aggregate functions. - * - * For a special case that if there is a function having both aggregate functions and other fields as its arguments, - * the `GROUP BY` keys will contain the maximum non-aggregate fields we can extract from it. - * - * Example: - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY ALL - * will expand as - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY substring(a, 4, 2), substring(a, 1, 2) - */ -void QueryAnalyzer::expandGroupByAll(QueryNode & query_tree_node_typed) -{ - if (!query_tree_node_typed.isGroupByAll()) - return; - - auto & group_by_nodes = query_tree_node_typed.getGroupBy().getNodes(); - auto & projection_list = query_tree_node_typed.getProjection(); - - for (auto & node : projection_list.getNodes()) - recursivelyCollectMaxOrdinaryExpressions(node, group_by_nodes); - query_tree_node_typed.setIsGroupByAll(false); -} - -void QueryAnalyzer::expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings) -{ - if (!settings.enable_order_by_all || !query_tree_node_typed.isOrderByAll()) - return; - - auto * all_node = query_tree_node_typed.getOrderBy().getNodes()[0]->as(); - if (!all_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Select analyze for not sort node."); - - auto & projection_nodes = query_tree_node_typed.getProjection().getNodes(); - auto list_node = std::make_shared(); - list_node->getNodes().reserve(projection_nodes.size()); - - for (auto & node : projection_nodes) - { - /// Detect and reject ambiguous statements: - /// E.g. for a table with columns "all", "a", "b": - /// - SELECT all, a, b ORDER BY all; -- should we sort by all columns in SELECT or by column "all"? - /// - SELECT a, b AS all ORDER BY all; -- like before but "all" as alias - /// - SELECT func(...) AS all ORDER BY all; -- like before but "all" as function - /// - SELECT a, b ORDER BY all; -- tricky in other way: does the user want to sort by columns in SELECT clause or by not SELECTed column "all"? - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - auto projection_names = resolved_expression_it->second; - if (projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected 1 projection names. Actual {}", - projection_names.size()); - if (boost::iequals(projection_names[0], "all")) - throw Exception(ErrorCodes::UNEXPECTED_EXPRESSION, - "Cannot use ORDER BY ALL to sort a column with name 'all', please disable setting `enable_order_by_all` and try again"); - } - - auto sort_node = std::make_shared(node, all_node->getSortDirection(), all_node->getNullsSortDirection()); - list_node->getNodes().push_back(sort_node); - } - - query_tree_node_typed.getOrderByNode() = list_node; - query_tree_node_typed.setIsOrderByAll(false); -} - -std::string QueryAnalyzer::rewriteAggregateFunctionNameIfNeeded( - const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context) -{ - std::string result_aggregate_function_name = aggregate_function_name; - auto aggregate_function_name_lowercase = Poco::toLower(aggregate_function_name); - - const auto & settings = context->getSettingsRef(); - - if (aggregate_function_name_lowercase == "countdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - } - else if (aggregate_function_name_lowercase == "countdistinctif" || aggregate_function_name_lowercase == "countifdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - result_aggregate_function_name += "If"; - } - - /// Replace aggregateFunctionIfDistinct into aggregateFunctionDistinctIf to make execution more optimal - if (result_aggregate_function_name.ends_with("ifdistinct")) - { - size_t prefix_length = result_aggregate_function_name.size() - strlen("ifdistinct"); - result_aggregate_function_name = result_aggregate_function_name.substr(0, prefix_length) + "DistinctIf"; - } - - bool need_add_or_null = settings.aggregate_functions_null_for_empty && !result_aggregate_function_name.ends_with("OrNull"); - if (need_add_or_null) - { - auto properties = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (!properties->returns_default_when_only_null) - result_aggregate_function_name += "OrNull"; - } - - /** Move -OrNull suffix ahead, this should execute after add -OrNull suffix. - * Used to rewrite aggregate functions with -OrNull suffix in some cases. - * Example: sumIfOrNull. - * Result: sumOrNullIf. - */ - if (result_aggregate_function_name.ends_with("OrNull")) - { - auto function_properies = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (function_properies && !function_properies->returns_default_when_only_null) - { - size_t function_name_size = result_aggregate_function_name.size(); - - static constexpr std::array suffixes_to_replace = {"MergeState", "Merge", "State", "If"}; - for (const auto & suffix : suffixes_to_replace) - { - auto suffix_string_value = String(suffix); - auto suffix_to_check = suffix_string_value + "OrNull"; - - if (!result_aggregate_function_name.ends_with(suffix_to_check)) - continue; - - result_aggregate_function_name = result_aggregate_function_name.substr(0, function_name_size - suffix_to_check.size()); - result_aggregate_function_name += "OrNull"; - result_aggregate_function_name += suffix_string_value; - - break; - } - } - } - - return result_aggregate_function_name; -} - -/// Resolve identifier functions implementation - -/// Try resolve table identifier from database catalog -QueryTreeNodePtr QueryAnalyzer::tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context) -{ - size_t parts_size = table_identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected table identifier to contain 1 or 2 parts. Actual '{}'", - table_identifier.getFullName()); - - std::string database_name; - std::string table_name; - - if (table_identifier.isCompound()) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - else - { - table_name = table_identifier[0]; - } - - StorageID storage_id(database_name, table_name); - storage_id = context->resolveStorageID(storage_id); - bool is_temporary_table = storage_id.getDatabaseName() == DatabaseCatalog::TEMPORARY_DATABASE; - - StoragePtr storage; - - if (is_temporary_table) - storage = DatabaseCatalog::instance().getTable(storage_id, context); - else - storage = DatabaseCatalog::instance().tryGetTable(storage_id, context); - - if (!storage) - return {}; - - auto storage_lock = storage->lockForShare(context->getInitialQueryId(), context->getSettingsRef().lock_acquire_timeout); - auto storage_snapshot = storage->getStorageSnapshot(storage->getInMemoryMetadataPtr(), context); - auto result = std::make_shared(std::move(storage), std::move(storage_lock), std::move(storage_snapshot)); - if (is_temporary_table) - result->setTemporaryTableName(table_name); - - return result; -} - -/// Resolve identifier from compound expression -/// If identifier cannot be resolved throw exception or return nullptr if can_be_not_found is true -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found) -{ - Identifier compound_expression_identifier; - for (size_t i = 0; i < identifier_bind_size; ++i) - compound_expression_identifier.push_back(expression_identifier[i]); - - IdentifierView nested_path(expression_identifier); - nested_path.popFirst(identifier_bind_size); - - auto expression_type = compound_expression->getResultType(); - - if (!expression_type->hasSubcolumn(nested_path.getFullName())) - { - if (auto * column = compound_expression->as()) - { - const DataTypePtr & column_type = column->getColumn().getTypeInStorage(); - if (column_type->getTypeId() == TypeIndex::Object) - { - const auto * object_type = checkAndGetDataType(column_type.get()); - if (object_type->getSchemaFormat() == "json" && object_type->hasNullableSubcolumns()) - { - QueryTreeNodePtr constant_node_null = std::make_shared(Field()); - return constant_node_null; - } - } - } - - if (can_be_not_found) - return {}; - - std::unordered_set valid_identifiers; - collectCompoundExpressionValidIdentifiersForTypoCorrection(expression_identifier, - expression_type, - compound_expression_identifier, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(expression_identifier, valid_identifiers); - - String compound_expression_from_error_message; - if (!compound_expression_source.empty()) - { - compound_expression_from_error_message += " from "; - compound_expression_from_error_message += compound_expression_source; - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier {} nested path {} cannot be resolved from type {}{}. In scope {}{}", - expression_identifier, - nested_path, - expression_type->getName(), - compound_expression_from_error_message, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - QueryTreeNodePtr get_subcolumn_function = std::make_shared("getSubcolumn"); - auto & get_subcolumn_function_arguments_nodes = get_subcolumn_function->as()->getArguments().getNodes(); - - get_subcolumn_function_arguments_nodes.reserve(2); - get_subcolumn_function_arguments_nodes.push_back(compound_expression); - get_subcolumn_function_arguments_nodes.push_back(std::make_shared(nested_path.getFullName())); - - resolveFunction(get_subcolumn_function, scope); - return get_subcolumn_function; -} - -/** Resolve identifier from expression arguments. - * - * Expression arguments can be initialized during lambda analysis or they could be provided externally. - * Expression arguments must be already resolved nodes. This is client responsibility to resolve them. - * - * Example: SELECT arrayMap(x -> x + 1, [1,2,3]); - * For lambda x -> x + 1, `x` is lambda expression argument. - * - * Resolve strategy: - * 1. Try to bind identifier to scope argument name to node map. - * 2. If identifier is binded but expression context and node type are incompatible return nullptr. - * - * It is important to support edge cases, where we lookup for table or function node, but argument has same name. - * Example: WITH (x -> x + 1) AS func, (func -> func(1) + func) AS lambda SELECT lambda(1); - * - * 3. If identifier is compound and identifier lookup is in expression context use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - auto it = scope.expression_argument_name_to_node.find(identifier_lookup.identifier.getFullName()); - bool resolve_full_identifier = it != scope.expression_argument_name_to_node.end(); - - if (!resolve_full_identifier) - { - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - it = scope.expression_argument_name_to_node.find(identifier_bind_part); - if (it == scope.expression_argument_name_to_node.end()) - return {}; - } - - auto node_type = it->second->getNodeType(); - if (identifier_lookup.isExpressionLookup() && !isExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isTableExpressionLookup() && !isTableExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isFunctionLookup() && !isFunctionExpressionNodeType(node_type)) - return {}; - - if (!resolve_full_identifier && identifier_lookup.identifier.isCompound() && identifier_lookup.isExpressionLookup()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return it->second; -} - -bool QueryAnalyzer::tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope) -{ - return scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME) != nullptr || scope.aliases.array_join_aliases.contains(identifier_lookup.identifier.front()); -} - -/** Resolve identifier from scope aliases. - * - * Resolve strategy: - * 1. If alias is registered in current expressions that are in resolve process and if top expression is not part of bottom expression with the same alias subtree - * throw cyclic aliases exception. - * Otherwise prevent cache usage for identifier lookup and return nullptr. - * - * This is special scenario where identifier has name the same as alias name in one of its parent expressions including itself. - * In such case we cannot resolve identifier from aliases because of recursion. It is client responsibility to register and deregister alias - * names during expressions resolve. - * - * We must prevent cache usage for lookup because lookup outside of expression is supposed to return other value. - * Example: SELECT (id + 1) AS id, id + 2. Lookup for id inside (id + 1) as id should return id from table, but lookup (id + 2) should return - * (id + 1) AS id. - * - * Below cases should work: - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * SELECT (id + 1) AS id FROM test_table; - * SELECT (1 + (1 + id)) AS id FROM test_table; - * - * Below cases should throw cyclic aliases exception: - * SELECT (id + b) AS id, id as b FROM test_table; - * SELECT (1 + b + 1 + id) AS id, b as c, id as b FROM test_table; - * - * 2. Depending on IdentifierLookupContext get alias name to node map from IdentifierResolveScope. - * 3. Try to bind identifier to alias name in map. If there are no such binding return nullptr. - * 4. If node in map is not resolved, resolve it. It is important in case of compound expressions. - * Example: SELECT value.a, cast('(1)', 'Tuple(a UInt64)') AS value; - * - * Special case if node is identifier node. - * Example: SELECT value, id AS value FROM test_table; - * - * Add node in current scope expressions in resolve process stack. - * Try to resolve identifier. - * If identifier is resolved, depending on lookup context, erase entry from expression or lambda map. Check QueryExpressionsAliasVisitor documentation. - * Pop node from current scope expressions in resolve process stack. - * - * 5. If identifier is compound and identifier lookup is in expression context, use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - auto * it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME); - if (it == nullptr) - return {}; - - QueryTreeNodePtr & alias_node = *it; - - if (!alias_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node with alias {} is not valid. In scope {}", - identifier_bind_part, - scope.scope_node->formatASTForErrorMessage()); - - if (auto root_expression_with_alias = scope.expressions_in_resolve_process_stack.getExpressionWithAlias(identifier_bind_part)) - { - const auto top_expression = scope.expressions_in_resolve_process_stack.getTop(); - - if (!isNodePartOfTree(top_expression.get(), root_expression_with_alias.get())) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - scope.non_cached_identifier_lookups_during_expression_resolve.insert(identifier_lookup); - return {}; - } - - auto node_type = alias_node->getNodeType(); - - /// Resolve expression if necessary - if (node_type == QueryTreeNodeType::IDENTIFIER) - { - scope.pushExpressionNode(alias_node); - - auto & alias_identifier_node = alias_node->as(); - auto identifier = alias_identifier_node.getIdentifier(); - auto lookup_result = tryResolveIdentifier(IdentifierLookup{identifier, identifier_lookup.lookup_context}, scope, identifier_resolve_settings); - if (!lookup_result.resolved_identifier) - { - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(identifier, scope, true, false, false, valid_identifiers); - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {} identifier '{}'. In scope {}{}", - toStringLowercase(identifier_lookup.lookup_context), - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - alias_node = lookup_result.resolved_identifier; - scope.popExpressionNode(); - } - else if (node_type == QueryTreeNodeType::FUNCTION) - { - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - else if (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION) - { - if (identifier_resolve_settings.allow_to_resolve_subquery_during_identifier_resolution) - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, identifier_lookup.isTableExpressionLookup() /*allow_table_expression*/); - } - - if (identifier_lookup.identifier.isCompound() && alias_node) - { - if (identifier_lookup.isExpressionLookup()) - { - return tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - 1 /*identifier_bind_size*/, - alias_node, - {} /* compound_expression_source */, - scope, - identifier_resolve_settings.allow_to_check_join_tree /* can_be_not_found */); - } - else if (identifier_lookup.isFunctionLookup() || identifier_lookup.isTableExpressionLookup()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Compound identifier '{}' cannot be resolved as {}. In scope {}", - identifier_lookup.identifier.getFullName(), - identifier_lookup.isFunctionLookup() ? "function" : "table expression", - scope.scope_node->formatASTForErrorMessage()); - } - } - - return alias_node; -} - -/** Resolve identifier from table columns. - * - * 1. If table column nodes are empty or identifier is not expression lookup return nullptr. - * 2. If identifier full name match table column use column. Save information that we resolve identifier using full name. - * 3. Else if identifier binds to table column, use column. - * 4. Try to resolve column ALIAS expression if it exists. - * 5. If identifier was compound and was not resolved using full name during step 1 use `tryResolveIdentifierFromCompoundExpression`. - * This can be the case with compound ALIAS columns. - * - * Example: - * CREATE TABLE test_table (id UInt64, value Tuple(id UInt64, value String), alias_value ALIAS value.id) ENGINE=TinyLog; - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - if (scope.column_name_to_column_node.empty() || !identifier_lookup.isExpressionLookup()) - return {}; - - const auto & identifier = identifier_lookup.identifier; - auto it = scope.column_name_to_column_node.find(identifier.getFullName()); - bool full_column_name_match = it != scope.column_name_to_column_node.end(); - - if (!full_column_name_match) - { - it = scope.column_name_to_column_node.find(identifier_lookup.identifier[0]); - if (it == scope.column_name_to_column_node.end()) - return {}; - } - - if (it->second->hasExpression()) - resolveExpressionNode(it->second->getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - QueryTreeNodePtr result = it->second; - - if (!full_column_name_match && identifier.isCompound()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return result; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - if (parts_size == 1 && path_start == table_name) - return true; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return true; - else - return false; - } - - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier)) || table_expression_data.canBindIdentifier(IdentifierView(identifier))) - return true; - - if (identifier.getPartsSize() == 1) - return false; - - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return true; - - if (identifier.getPartsSize() == 2) - return false; - - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return true; - - return false; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node_to_ignore, - const IdentifierResolveScope & scope) -{ - bool can_bind_identifier_to_table_expression = false; - - for (const auto & [table_expression_node, _] : scope.table_expression_node_to_data) - { - if (table_expression_node.get() == table_expression_node_to_ignore.get()) - continue; - - can_bind_identifier_to_table_expression = tryBindIdentifierToTableExpression(identifier_lookup, table_expression_node, scope); - if (can_bind_identifier_to_table_expression) - break; - } - - return can_bind_identifier_to_table_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found) -{ - auto identifier_without_column_qualifier = identifier; - identifier_without_column_qualifier.popFirst(identifier_column_qualifier_parts); - - /** Compound identifier cannot be resolved directly from storage if storage is not table. - * - * Example: SELECT test_table.id.value1.value2 FROM test_table; - * In table storage column test_table.id.value1.value2 will exists. - * - * Example: SELECT test_subquery.compound_expression.value FROM (SELECT compound_expression AS value) AS test_subquery; - * Here there is no column with name test_subquery.compound_expression.value, and additional wrap in tuple element is required. - */ - - QueryTreeNodePtr result_expression; - bool match_full_identifier = false; - - const auto & identifier_full_name = identifier_without_column_qualifier.getFullName(); - auto it = table_expression_data.column_name_to_column_node.find(identifier_full_name); - bool can_resolve_directly_from_storage = it != table_expression_data.column_name_to_column_node.end(); - if (can_resolve_directly_from_storage && table_expression_data.subcolumn_names.contains(identifier_full_name)) - { - /** In the case when we have an ARRAY JOIN, we should not resolve subcolumns directly from storage. - * For example, consider the following SQL query: - * SELECT ProfileEvents.Values FROM system.query_log ARRAY JOIN ProfileEvents - * In this case, ProfileEvents.Values should also be array joined, not directly resolved from storage. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - if (nearest_query_scope_query_node && nearest_query_scope_query_node->getJoinTree()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - can_resolve_directly_from_storage = false; - } - - if (can_resolve_directly_from_storage) - { - match_full_identifier = true; - result_expression = it->second; - } - else - { - it = table_expression_data.column_name_to_column_node.find(identifier_without_column_qualifier.at(0)); - if (it != table_expression_data.column_name_to_column_node.end()) - result_expression = it->second; - } - - bool clone_is_needed = true; - - String table_expression_source = table_expression_data.table_expression_description; - if (!table_expression_data.table_expression_name.empty()) - table_expression_source += " with name " + table_expression_data.table_expression_name; - - if (result_expression && !match_full_identifier && identifier_without_column_qualifier.isCompound()) - { - size_t identifier_bind_size = identifier_column_qualifier_parts + 1; - result_expression = tryResolveIdentifierFromCompoundExpression(identifier, - identifier_bind_size, - result_expression, - table_expression_source, - scope, - can_be_not_found); - if (can_be_not_found && !result_expression) - return {}; - clone_is_needed = false; - } - - if (!result_expression) - { - QueryTreeNodes nested_column_nodes; - DataTypes nested_types; - Array nested_names_array; - - for (const auto & [column_name, _] : table_expression_data.column_names_and_types) - { - Identifier column_name_identifier_without_last_part(column_name); - auto column_name_identifier_last_part = column_name_identifier_without_last_part.getParts().back(); - column_name_identifier_without_last_part.popLast(); - - if (identifier_without_column_qualifier.getFullName() != column_name_identifier_without_last_part.getFullName()) - continue; - - auto column_node_it = table_expression_data.column_name_to_column_node.find(column_name); - if (column_node_it == table_expression_data.column_name_to_column_node.end()) - continue; - - const auto & column_node = column_node_it->second; - const auto & column_type = column_node->getColumnType(); - const auto * column_type_array = typeid_cast(column_type.get()); - if (!column_type_array) - continue; - - nested_column_nodes.push_back(column_node); - nested_types.push_back(column_type_array->getNestedType()); - nested_names_array.push_back(Field(std::move(column_name_identifier_last_part))); - } - - if (!nested_types.empty()) - { - auto nested_function_node = std::make_shared("nested"); - auto & nested_function_node_arguments = nested_function_node->getArguments().getNodes(); - - auto nested_function_names_array_type = std::make_shared(std::make_shared()); - auto nested_function_names_constant_node = std::make_shared(std::move(nested_names_array), - std::move(nested_function_names_array_type)); - nested_function_node_arguments.push_back(std::move(nested_function_names_constant_node)); - nested_function_node_arguments.insert(nested_function_node_arguments.end(), - nested_column_nodes.begin(), - nested_column_nodes.end()); - - auto nested_function = FunctionFactory::instance().get(nested_function_node->getFunctionName(), scope.context); - nested_function_node->resolveAsFunction(nested_function->build(nested_function_node->getArgumentColumns())); - - clone_is_needed = false; - result_expression = std::move(nested_function_node); - } - } - - if (!result_expression) - { - if (can_be_not_found) - return {}; - std::unordered_set valid_identifiers; - collectTableExpressionValidIdentifiersForTypoCorrection(identifier, - table_expression_node, - table_expression_data, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Identifier '{}' cannot be resolved from {}. In scope {}{}", - identifier.getFullName(), - table_expression_source, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (clone_is_needed) - result_expression = result_expression->clone(); - - auto qualified_identifier = identifier; - - for (size_t i = 0; i < identifier_column_qualifier_parts; ++i) - { - auto qualified_identifier_with_removed_part = qualified_identifier; - qualified_identifier_with_removed_part.popFirst(); - - if (qualified_identifier_with_removed_part.empty()) - break; - - IdentifierLookup column_identifier_lookup = {qualified_identifier_with_removed_part, IdentifierLookupContext::EXPRESSION}; - if (tryBindIdentifierToAliases(column_identifier_lookup, scope)) - break; - - if (table_expression_data.should_qualify_columns && - tryBindIdentifierToTableExpressions(column_identifier_lookup, table_expression_node, scope)) - break; - - qualified_identifier = std::move(qualified_identifier_with_removed_part); - } - - auto qualified_identifier_full_name = qualified_identifier.getFullName(); - node_to_projection_name.emplace(result_expression, std::move(qualified_identifier_full_name)); - - return result_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (parts_size == 1 && path_start == table_name) - return table_expression_node; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return table_expression_node; - else - return {}; - } - - /** If identifier first part binds to some column start or table has full identifier name. Then we can try to find whole identifier in table. - * 1. Try to bind identifier first part to column in table, if true get full identifier from table or throw exception. - * 2. Try to bind identifier first part to table name or storage alias, if true remove first part and try to get full identifier from table or throw exception. - * Storage alias works for subquery, table function as well. - * 3. Try to bind identifier first parts to database name and table name, if true remove first two parts and try to get full identifier from table or throw exception. - */ - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier))) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/); - - if (table_expression_data.canBindIdentifier(IdentifierView(identifier))) - { - /** This check is insufficient to determine whether and identifier can be resolved from table expression. - * A further check will be performed in `tryResolveIdentifierFromStorage` to see if we have such a subcolumn. - * In cases where the subcolumn cannot be found we want to have `nullptr` instead of exception. - * So, we set `can_be_not_found = true` to have an attempt to resolve the identifier from another table expression. - * Example: `SELECT t.t from (SELECT 1 as t) AS a FULL JOIN (SELECT 1 as t) as t ON a.t = t.t;` - * Initially, we will try to resolve t.t from `a` because `t.` is bound to `1 as t`. However, as it is not a nested column, we will need to resolve it from the second table expression. - */ - auto resolved_identifier = tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/, true /*can_be_not_found*/); - if (resolved_identifier) - return resolved_identifier; - } - - if (identifier.getPartsSize() == 1) - return {}; - - const auto & table_name = table_expression_data.table_name; - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 1 /*identifier_column_qualifier_parts*/); - - if (identifier.getPartsSize() == 2) - return {}; - - const auto & database_name = table_expression_data.database_name; - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 2 /*identifier_column_qualifier_parts*/); - - return {}; -} - -QueryTreeNodePtr checkIsMissedObjectJSONSubcolumn(const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier) -{ - if (left_resolved_identifier && right_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT - && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL" && right_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (left_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (right_resolved_identifier && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & right_resolved_column = right_resolved_identifier->as(); - if (right_resolved_column.getValueStringRepresentation() == "NULL") - return right_resolved_identifier; - } - return {}; -} - -/// Used to replace columns that changed type because of JOIN to their original type -class ReplaceColumnsVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit ReplaceColumnsVisitor(const QueryTreeNodePtrWithHashMap & replacement_map_, const ContextPtr & context_) - : replacement_map(replacement_map_) - , context(context_) - {} - - /// Apply replacement transitively, because column may change it's type twice, one to have a supertype and then because of `joun_use_nulls` - static QueryTreeNodePtr findTransitiveReplacement(QueryTreeNodePtr node, const QueryTreeNodePtrWithHashMap & replacement_map_) - { - auto it = replacement_map_.find(node); - QueryTreeNodePtr result_node = nullptr; - for (; it != replacement_map_.end(); it = replacement_map_.find(result_node)) - { - if (result_node && result_node->isEqual(*it->second)) - { - Strings map_dump; - for (const auto & [k, v]: replacement_map_) - map_dump.push_back(fmt::format("{} -> {} (is_equals: {}, is_same: {})", - k.node->dumpTree(), v->dumpTree(), k.node->isEqual(*v), k.node == v)); - throw Exception(ErrorCodes::LOGICAL_ERROR, "Infinite loop in query tree replacement map: {}", fmt::join(map_dump, "; ")); - } - chassert(it->second); - - result_node = it->second; - } - return result_node; - } - - void visitImpl(QueryTreeNodePtr & node) - { - if (auto replacement_node = findTransitiveReplacement(node, replacement_map)) - node = replacement_node; - - if (auto * function_node = node->as(); function_node && function_node->isResolved()) - rerunFunctionResolve(function_node, context); - } - - /// We want to re-run resolve for function _after_ its arguments are replaced - bool shouldTraverseTopToBottom() const { return false; } - - bool needChildVisit(QueryTreeNodePtr & /* parent */, QueryTreeNodePtr & child) - { - /// Visit only expressions, but not subqueries - return child->getNodeType() == QueryTreeNodeType::IDENTIFIER - || child->getNodeType() == QueryTreeNodeType::LIST - || child->getNodeType() == QueryTreeNodeType::FUNCTION - || child->getNodeType() == QueryTreeNodeType::COLUMN; - } - -private: - const QueryTreeNodePtrWithHashMap & replacement_map; - const ContextPtr & context; -}; - -/// Compare resolved identifiers considering columns that become nullable after JOIN -bool resolvedIdenfiersFromJoinAreEquals( - const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier, - const IdentifierResolveScope & scope) -{ - auto left_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(left_resolved_identifier, scope.join_columns_with_changed_types); - const auto & left_resolved_to_compare = left_original_node ? left_original_node : left_resolved_identifier; - - auto right_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(right_resolved_identifier, scope.join_columns_with_changed_types); - const auto & right_resolved_to_compare = right_original_node ? right_original_node : right_resolved_identifier; - - return left_resolved_to_compare->isEqual(*right_resolved_to_compare, IQueryTreeNode::CompareOptions{.compare_aliases = false}); -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_join_node = table_expression_node->as(); - auto left_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getLeftTableExpression(), scope); - auto right_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getRightTableExpression(), scope); - - if (!identifier_lookup.isExpressionLookup()) - { - if (left_resolved_identifier && right_resolved_identifier) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.dump(), - scope.scope_node->formatASTForErrorMessage()); - - return left_resolved_identifier ? left_resolved_identifier : right_resolved_identifier; - } - - bool join_node_in_resolve_process = scope.table_expressions_in_resolve_process.contains(table_expression_node.get()); - - std::unordered_map join_using_column_name_to_column_node; - - if (!join_node_in_resolve_process && from_join_node.isUsingJoinExpression()) - { - auto & join_using_list = from_join_node.getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & column_node = join_using_node->as(); - join_using_column_name_to_column_node.emplace(column_node.getColumnName(), std::static_pointer_cast(join_using_node)); - } - } - - auto check_nested_column_not_in_using = [&join_using_column_name_to_column_node, &identifier_lookup](const QueryTreeNodePtr & node) - { - /** tldr: When an identifier is resolved into the function `nested` or `getSubcolumn`, and - * some column in its argument is in the USING list and its type has to be updated, we throw an error to avoid overcomplication. - * - * Identifiers can be resolved into functions in case of nested or subcolumns. - * For example `t.t.t` can be resolved into `getSubcolumn(t, 't.t')` function in case of `t` is `Tuple`. - * So, `t` in USING list is resolved from JOIN itself and has supertype of columns from left and right table. - * But `t` in `getSubcolumn` argument is still resolved from table and we need to update its type. - * - * Example: - * - * SELECT t.t FROM ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t UInt32, s1 String), s1 String) as t - * ) AS a FULL JOIN ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t Int32, s2 String), s2 String) as t - * ) AS b USING t; - * - * Result type of `t` is `Tuple(Tuple(Int64, String), String)` (different type and no names for subcolumns), - * so it may be tricky to have a correct type for `t.t` that is resolved into getSubcolumn(t, 't'). - * - * It can be more complicated in case of Nested subcolumns, in that case in query: - * SELECT t FROM ... JOIN ... USING (t.t) - * Here, `t` is resolved into function `nested(['t', 's'], t.t, t.s) so, `t.t` should be from JOIN and `t.s` should be from table. - * - * Updating type accordingly is pretty complicated, so just forbid such cases. - * - * While it still may work for storages that support selecting subcolumns directly without `getSubcolumn` function: - * SELECT t, t.t, toTypeName(t), toTypeName(t.t) FROM t1 AS a FULL JOIN t2 AS b USING t.t; - * We just support it as a best-effort: `t` will have original type from table, but `t.t` will have super-type from JOIN. - * Probably it's good to prohibit such cases as well, but it's not clear how to check it in general case. - */ - if (node->getNodeType() != QueryTreeNodeType::FUNCTION) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {}, expected function node", node->getNodeType()); - - const auto & function_argument_nodes = node->as().getArguments().getNodes(); - for (const auto & argument_node : function_argument_nodes) - { - if (argument_node->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_name = argument_node->as().getColumnName(); - if (join_using_column_name_to_column_node.contains(column_name)) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Cannot select subcolumn for identifier '{}' while joining using column '{}'", - identifier_lookup.identifier, column_name); - } - else if (argument_node->getNodeType() == QueryTreeNodeType::CONSTANT) - { - continue; - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {} for argument node in {}", - argument_node->getNodeType(), node->formatASTForErrorMessage()); - } - } - }; - - std::optional resolved_side; - QueryTreeNodePtr resolved_identifier; - - JoinKind join_kind = from_join_node.getKind(); - - /// If columns from left or right table were missed Object(Nullable('json')) subcolumns, they will be replaced - /// to ConstantNode(NULL), which can't be cast to ColumnNode, so we resolve it here. - if (auto missed_subcolumn_identifier = checkIsMissedObjectJSONSubcolumn(left_resolved_identifier, right_resolved_identifier)) - return missed_subcolumn_identifier; - - if (left_resolved_identifier && right_resolved_identifier) - { - auto using_column_node_it = join_using_column_name_to_column_node.end(); - if (left_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && right_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getColumnName() == right_resolved_column.getColumnName()) - using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - } - else - { - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(left_resolved_identifier); - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(right_resolved_identifier); - } - - if (using_column_node_it != join_using_column_name_to_column_node.end()) - { - JoinTableSide using_column_inner_column_table_side = isRight(join_kind) ? JoinTableSide::Right : JoinTableSide::Left; - auto & using_column_node = using_column_node_it->second->as(); - auto & using_expression_list = using_column_node.getExpression()->as(); - - size_t inner_column_node_index = using_column_inner_column_table_side == JoinTableSide::Left ? 0 : 1; - const auto & inner_column_node = using_expression_list.getNodes().at(inner_column_node_index); - - auto result_column_node = inner_column_node->clone(); - auto & result_column = result_column_node->as(); - result_column.setColumnType(using_column_node.getColumnType()); - - const auto & join_using_left_column = using_expression_list.getNodes().at(0); - if (!result_column_node->isEqual(*join_using_left_column)) - scope.join_columns_with_changed_types[result_column_node] = join_using_left_column; - - resolved_identifier = std::move(result_column_node); - } - else if (resolvedIdenfiersFromJoinAreEquals(left_resolved_identifier, right_resolved_identifier, scope)) - { - const auto & identifier_path_part = identifier_lookup.identifier.front(); - auto * left_resolved_identifier_column = left_resolved_identifier->as(); - auto * right_resolved_identifier_column = right_resolved_identifier->as(); - - if (left_resolved_identifier_column && right_resolved_identifier_column) - { - const auto & left_column_source_alias = left_resolved_identifier_column->getColumnSource()->getAlias(); - const auto & right_column_source_alias = right_resolved_identifier_column->getColumnSource()->getAlias(); - - /** If column from right table was resolved using alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one JOIN system.one AS A ON A.dummy = system.one.dummy; - * - * If alias is specified for left table, and alias is not specified for right table and identifier was resolved - * without using left table alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one AS A JOIN system.one ON A.dummy = system.one.dummy; - * - * Otherwise we prefer column from left table. - */ - bool column_resolved_using_right_alias = identifier_path_part == right_column_source_alias; - bool column_resolved_without_using_left_alias = !left_column_source_alias.empty() - && right_column_source_alias.empty() - && identifier_path_part != left_column_source_alias; - if (column_resolved_using_right_alias || column_resolved_without_using_left_alias) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else if (scope.joins_count == 1 && scope.context->getSettingsRef().single_join_prefer_left_table) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - else - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier '{}'. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - else if (left_resolved_identifier) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(left_resolved_identifier); - } - else - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*left_resolved_column.getColumnType())) - { - auto left_resolved_column_clone = std::static_pointer_cast(left_resolved_column.clone()); - left_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(left_resolved_column_clone); - - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - else if (right_resolved_identifier) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(right_resolved_identifier); - } - else - { - auto & right_resolved_column = right_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(right_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*right_resolved_column.getColumnType())) - { - auto right_resolved_column_clone = std::static_pointer_cast(right_resolved_column.clone()); - right_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(right_resolved_column_clone); - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - - if (join_node_in_resolve_process || !resolved_identifier) - return resolved_identifier; - - if (scope.join_use_nulls) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier); - auto nullable_resolved_identifier = convertJoinedColumnTypeToNullIfNeeded(resolved_identifier, join_kind, resolved_side, scope); - if (nullable_resolved_identifier) - { - resolved_identifier = nullable_resolved_identifier; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(resolved_identifier, projection_name_it->second); - } - } - } - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope) -{ - const auto * resolved_function = resolved_expression->as(); - if (!resolved_function || resolved_function->getFunctionName() != "getSubcolumn") - return {}; - - const auto * array_join_parent_column = array_join_column_inner_expression.get(); - - /** If both resolved and array-joined expressions are subcolumns, try to match them: - * For example, in `SELECT t.map.values FROM (SELECT * FROM tbl) ARRAY JOIN t.map` - * Identifier `t.map.values` is resolved into `getSubcolumn(t, 'map.values')` and t.map is resolved into `getSubcolumn(t, 'map')` - * Since we need to perform array join on `getSubcolumn(t, 'map')`, `t.map.values` should become `getSubcolumn(getSubcolumn(t, 'map'), 'values')` - * - * Note: It doesn't work when subcolumn in ARRAY JOIN is transformed by another expression, for example - * SELECT c.map, c.map.values FROM (SELECT * FROM tbl) ARRAY JOIN mapApply(x -> x, t.map); - */ - String array_join_subcolumn_prefix; - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "getSubcolumn") - { - const auto & argument_nodes = array_join_column_inner_expression_function->getArguments().getNodes(); - if (argument_nodes.size() == 2 && argument_nodes.at(1)->getNodeType() == QueryTreeNodeType::CONSTANT) - { - const auto & constant_node = argument_nodes.at(1)->as(); - const auto & constant_node_value = constant_node.getValue(); - if (constant_node_value.getType() == Field::Types::String) - { - array_join_subcolumn_prefix = constant_node_value.get() + "."; - array_join_parent_column = argument_nodes.at(0).get(); - } - } - } - - const auto & argument_nodes = resolved_function->getArguments().getNodes(); - if (argument_nodes.size() != 2 && !array_join_parent_column->isEqual(*argument_nodes.at(0))) - return {}; - - const auto * second_argument = argument_nodes.at(1)->as(); - if (!second_argument || second_argument->getValue().getType() != Field::Types::String) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected constant string as second argument of getSubcolumn function {}", resolved_function->dumpTree()); - - const auto & resolved_subcolumn_path = second_argument->getValue().get(); - if (!startsWith(resolved_subcolumn_path, array_join_subcolumn_prefix)) - return {}; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(array_join_column_expression_typed.getColumn(), array_join_column_expression_typed.getColumnSource())); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(resolved_subcolumn_path.substr(array_join_subcolumn_prefix.size()))); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - return function_query_node; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & array_join_node = table_expression_node->as(); - const auto & array_join_column_expressions_list = array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions_list.getNodes(); - - QueryTreeNodePtr array_join_resolved_expression; - - /** Special case when qualified or unqualified identifier point to array join expression without alias. - * - * CREATE TABLE test_table (id UInt64, value String, value_array Array(UInt8)) ENGINE=TinyLog; - * SELECT id, value, value_array, test_table.value_array, default.test_table.value_array FROM test_table ARRAY JOIN value_array; - * - * value_array, test_table.value_array, default.test_table.value_array must be resolved into array join expression. - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - if (array_join_column_expression_typed.hasAlias()) - continue; - - auto & array_join_column_inner_expression = array_join_column_expression_typed.getExpressionOrThrow(); - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "nested" && - array_join_column_inner_expression_function->getArguments().getNodes().size() > 1 && - isTuple(array_join_column_expression_typed.getResultType())) - { - const auto & nested_function_arguments = array_join_column_inner_expression_function->getArguments().getNodes(); - size_t nested_function_arguments_size = nested_function_arguments.size(); - - const auto & nested_keys_names_constant_node = nested_function_arguments[0]->as(); - const auto & nested_keys_names = nested_keys_names_constant_node.getValue().get(); - size_t nested_keys_names_size = nested_keys_names.size(); - - if (nested_keys_names_size == nested_function_arguments_size - 1) - { - for (size_t i = 1; i < nested_function_arguments_size; ++i) - { - if (!nested_function_arguments[i]->isEqual(*resolved_expression)) - continue; - - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - - const auto & nested_key_name = nested_keys_names[i - 1].get(); - Identifier nested_identifier = Identifier(nested_key_name); - auto tuple_element_function = wrapExpressionNodeInTupleElement(array_join_column, nested_identifier); - resolveFunction(tuple_element_function, scope); - - array_join_resolved_expression = std::move(tuple_element_function); - break; - } - } - } - - if (array_join_resolved_expression) - break; - - if (array_join_column_inner_expression->isEqual(*resolved_expression)) - { - array_join_resolved_expression = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - break; - } - - /// When we select subcolumn of array joined column it also should be array joined - array_join_resolved_expression = matchArrayJoinSubcolumns(array_join_column_inner_expression, array_join_column_expression_typed, resolved_expression, scope); - if (array_join_resolved_expression) - break; - } - return array_join_resolved_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_array_join_node = table_expression_node->as(); - auto resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_array_join_node.getTableExpression(), scope); - - if (scope.table_expressions_in_resolve_process.contains(table_expression_node.get()) || !identifier_lookup.isExpressionLookup()) - return resolved_identifier; - - const auto & array_join_column_expressions = from_array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions.getNodes(); - - /** Allow JOIN with USING with ARRAY JOIN. - * - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN [1,2,3] AS id INNER JOIN test_table_2 AS t2 USING (id); - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN t1.id AS id INNER JOIN test_table_2 AS t2 USING (id); - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - - IdentifierView identifier_view(identifier_lookup.identifier); - - if (identifier_view.isCompound() && from_array_join_node.hasAlias() && identifier_view.front() == from_array_join_node.getAlias()) - identifier_view.popFirst(); - - const auto & alias_or_name = array_join_column_expression_typed.hasAlias() - ? array_join_column_expression_typed.getAlias() - : array_join_column_expression_typed.getColumnName(); - - if (identifier_view.front() == alias_or_name) - identifier_view.popFirst(); - else if (identifier_view.getFullName() == alias_or_name) - identifier_view.popFirst(identifier_view.getPartsSize()); /// Clear - else - continue; - - if (identifier_view.empty()) - { - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - return array_join_column; - } - - auto compound_expr = tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - identifier_lookup.identifier.getPartsSize() - identifier_view.getPartsSize() /*identifier_bind_size*/, - array_join_column_expression, - {} /* compound_expression_source */, - scope, - true /* can_be_not_found */); - - if (compound_expr) - return compound_expr; - } - - if (!resolved_identifier) - return nullptr; - - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(resolved_identifier, table_expression_node, scope); - if (array_join_resolved_expression) - resolved_identifier = std::move(array_join_resolved_expression); - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope) -{ - auto join_tree_node_type = join_tree_node->getNodeType(); - - switch (join_tree_node_type) - { - case QueryTreeNodeType::JOIN: - return tryResolveIdentifierFromJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::ARRAY_JOIN: - return tryResolveIdentifierFromArrayJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - [[fallthrough]]; - case QueryTreeNodeType::TABLE: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - { - /** Edge case scenario when subquery in FROM node try to resolve identifier from parent scopes, when FROM is not resolved. - * SELECT subquery.b AS value FROM (SELECT value, 1 AS b) AS subquery; - * TODO: This can be supported - */ - if (scope.table_expressions_in_resolve_process.contains(join_tree_node.get())) - return {}; - - return tryResolveIdentifierFromTableExpression(identifier_lookup, join_tree_node, scope); - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Scope FROM section expected table, table function, query, union, join or array join. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } -} - -/** Resolve identifier from scope join tree. - * - * 1. If identifier is in function lookup context return nullptr. - * 2. Try to resolve identifier from table columns. - * 3. If there is no FROM section return nullptr. - * 4. If identifier is in table lookup context, check if it has 1 or 2 parts, otherwise throw exception. - * If identifier has 2 parts try to match it with database_name and table_name. - * If identifier has 1 part try to match it with table_name, then try to match it with table alias. - * 5. If identifier is in expression lookup context, we first need to bind identifier to some table column using identifier first part. - * Start with identifier first part, if it match some column name in table try to get column with full identifier name. - * TODO: Need to check if it is okay to throw exception if compound identifier first part bind to column but column is not valid. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope) -{ - if (identifier_lookup.isFunctionLookup()) - return {}; - - /// Try to resolve identifier from table columns - if (auto resolved_identifier = tryResolveIdentifierFromTableColumns(identifier_lookup, scope)) - return resolved_identifier; - - if (scope.expression_join_tree_node) - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, scope.expression_join_tree_node, scope); - - auto * query_scope_node = scope.scope_node->as(); - if (!query_scope_node || !query_scope_node->getJoinTree()) - return {}; - - const auto & join_tree_node = query_scope_node->getJoinTree(); - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_tree_node, scope); -} - -/** Try resolve identifier in current scope parent scopes. - * - * TODO: If column is matched, throw exception that nested subqueries are not supported. - * - * If initial scope is expression. Then try to resolve identifier in parent scopes until query scope is hit. - * For query scope resolve strategy is same as if initial scope if query. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - bool initial_scope_is_query = scope.scope_node->getNodeType() == QueryTreeNodeType::QUERY; - bool initial_scope_is_expression = !initial_scope_is_query; - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_parent_scopes = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - IdentifierResolveScope * scope_to_check = scope.parent_scope; - - if (initial_scope_is_expression) - { - while (scope_to_check != nullptr) - { - auto resolve_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - if (resolve_result.resolved_identifier) - return resolve_result; - - bool scope_was_query = scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY; - scope_to_check = scope_to_check->parent_scope; - - if (scope_was_query) - break; - } - } - - if (!scope.context->getSettingsRef().enable_global_with_statement) - return {}; - - /** Nested subqueries cannot access outer subqueries table expressions from JOIN tree because - * that can prevent resolution of table expression from CTE. - * - * Example: WITH a AS (SELECT number FROM numbers(1)), b AS (SELECT number FROM a) SELECT * FROM a as l, b as r; - */ - if (identifier_lookup.isTableExpressionLookup()) - identifier_resolve_settings.allow_to_check_join_tree = false; - - while (scope_to_check != nullptr) - { - auto lookup_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - const auto & resolved_identifier = lookup_result.resolved_identifier; - - scope_to_check = scope_to_check->parent_scope; - - if (resolved_identifier) - { - auto * subquery_node = resolved_identifier->as(); - auto * union_node = resolved_identifier->as(); - - bool is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - bool is_table_from_expression_arguments = lookup_result.resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS && - resolved_identifier->getNodeType() == QueryTreeNodeType::TABLE; - bool is_valid_table_expression = is_cte || is_table_from_expression_arguments; - - /** From parent scopes we can resolve table identifiers only as CTE. - * Example: SELECT (SELECT 1 FROM a) FROM test_table AS a; - * - * During child scope table identifier resolve a, table node test_table with alias a from parent scope - * is invalid. - */ - if (identifier_lookup.isTableExpressionLookup() && !is_valid_table_expression) - continue; - - if (is_valid_table_expression || resolved_identifier->as()) - { - return lookup_result; - } - else if (auto * resolved_function = resolved_identifier->as()) - { - /// Special case: scalar subquery was executed and replaced by __getScalar function. - /// Handle it as a constant. - if (resolved_function->getFunctionName() == "__getScalar") - return lookup_result; - } - - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Resolve identifier '{}' from parent scope only supported for constants and CTE. Actual {} node type {}. In scope {}", - identifier_lookup.identifier.getFullName(), - resolved_identifier->formatASTForErrorMessage(), - resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - return {}; -} - -/** Resolve identifier in scope. - * - * If identifier was resolved resolve identified lookup status will be updated. - * - * Steps: - * 1. Register identifier lookup in scope identifier lookup to resolve status table. - * If entry is already registered and is not resolved, that means that we have cyclic aliases for identifier. - * Example: SELECT a AS b, b AS a; - * Try resolve identifier in current scope: - * 3. Try resolve identifier from expression arguments. - * - * If prefer_column_name_to_alias = true. - * 4. Try to resolve identifier from join tree. - * 5. Try to resolve identifier from aliases. - * Otherwise. - * 4. Try to resolve identifier from aliases. - * 5. Try to resolve identifier from join tree. - * - * 6. If it is table identifier lookup try to lookup identifier in current scope CTEs. - * - * 7. If identifier is not resolved in current scope, try to resolve it in parent scopes. - * 8. If identifier is not resolved from parent scopes and it is table identifier lookup try to lookup identifier - * in database catalog. - * - * Same is not done for functions because function resolution is more complex, and in case of aggregate functions requires not only name - * but also argument types, it is responsibility of resolve function method to handle resolution of function name. - * - * 9. If identifier was not resolved, or identifier caching was disabled remove it from identifier lookup to resolve status table. - * - * It is okay for identifier to be not resolved, in case we want first try to lookup identifier in one context, - * then if there is no identifier in this context, try to lookup in another context. - * Example: Try to lookup identifier as expression, if it is not found, lookup as function. - * Example: Try to lookup identifier as expression, if it is not found, lookup as table. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - auto it = scope.identifier_lookup_to_resolve_state.find(identifier_lookup); - if (it != scope.identifier_lookup_to_resolve_state.end()) - { - if (it->second.cyclic_identifier_resolve) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (!it->second.resolve_result.isResolved()) - it->second.cyclic_identifier_resolve = true; - - if (it->second.resolve_result.isResolved() && - scope.use_identifier_lookup_to_result_cache && - !scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) && - (!it->second.resolve_result.isResolvedFromCTEs() || !ctes_in_resolve_process.contains(identifier_lookup.identifier.getFullName()))) - return it->second.resolve_result; - } - else - { - auto [insert_it, _] = scope.identifier_lookup_to_resolve_state.insert({identifier_lookup, IdentifierResolveState()}); - it = insert_it; - } - - /// Resolve identifier from current scope - - IdentifierResolveResult resolve_result; - resolve_result.resolved_identifier = tryResolveIdentifierFromExpressionArguments(identifier_lookup, scope); - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - - if (!resolve_result.resolved_identifier) - { - bool prefer_column_name_to_alias = scope.context->getSettingsRef().prefer_column_name_to_alias; - - if (identifier_lookup.isExpressionLookup()) - { - /* For aliases from ARRAY JOIN we prefer column from join tree: - * SELECT id FROM ( SELECT ... ) AS subquery ARRAY JOIN [0] AS id INNER JOIN second_table USING (id) - * In the example, identifier `id` should be resolved into one from USING (id) column. - */ - - auto * alias_it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FULL_NAME); - if (alias_it && (*alias_it)->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_node = (*alias_it)->as(); - if (column_node.getColumnSource()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - prefer_column_name_to_alias = true; - } - } - - if (unlikely(prefer_column_name_to_alias)) - { - if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - - if (!resolve_result.resolved_identifier) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - } - else - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - { - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - else if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - } - } - - if (!resolve_result.resolved_identifier && identifier_lookup.isTableExpressionLookup()) - { - auto full_name = identifier_lookup.identifier.getFullName(); - auto cte_query_node_it = scope.cte_name_to_query_node.find(full_name); - - /// CTE may reference table expressions with the same name, e.g.: - /// - /// WITH test1 AS (SELECT * FROM test1) SELECT * FROM test1; - /// - /// Since we don't support recursive CTEs, `test1` identifier inside of CTE - /// references to table .test1. - /// This means that the example above is equivalent to the following query: - /// - /// SELECT * FROM test1; - /// - /// To accomplish this behaviour it's not allowed to resolve identifiers to - /// CTE that is being resolved. - if (cte_query_node_it != scope.cte_name_to_query_node.end() - && !ctes_in_resolve_process.contains(full_name)) - { - resolve_result.resolved_identifier = cte_query_node_it->second; - resolve_result.resolve_place = IdentifierResolvePlace::CTE; - } - } - - /// Try to resolve identifier from parent scopes - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_parent_scopes) - { - resolve_result = tryResolveIdentifierInParentScopes(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolved_from_parent_scopes = true; - } - - /// Try to resolve table identifier from database catalog - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_database_catalog && identifier_lookup.isTableExpressionLookup()) - { - resolve_result.resolved_identifier = tryResolveTableIdentifierFromDatabaseCatalog(identifier_lookup.identifier, scope.context); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::DATABASE_CATALOG; - } - - bool was_cyclic_identifier_resolve = it->second.cyclic_identifier_resolve; - if (!was_cyclic_identifier_resolve) - it->second.resolve_result = resolve_result; - it->second.cyclic_identifier_resolve = false; - - /** If identifier was not resolved, or during expression resolution identifier was explicitly added into non cached set, - * or identifier caching was disabled in resolve scope we remove identifier lookup result from identifier lookup to result table. - */ - if (!was_cyclic_identifier_resolve && (!resolve_result.resolved_identifier || - scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) || - !scope.use_identifier_lookup_to_result_cache)) - scope.identifier_lookup_to_resolve_state.erase(it); - - return resolve_result; -} - -/// Resolve query tree nodes functions implementation - -/** Qualify column nodes with projection names. - * - * Example: SELECT * FROM test_table AS t1, test_table AS t2; - */ -void QueryAnalyzer::qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - /// Build additional column qualification parts array - std::vector additional_column_qualification_parts; - - if (table_expression_node->hasAlias()) - additional_column_qualification_parts = {table_expression_node->getAlias()}; - else if (auto * table_node = table_expression_node->as()) - additional_column_qualification_parts = {table_node->getStorageID().getDatabaseName(), table_node->getStorageID().getTableName()}; - - size_t additional_column_qualification_parts_size = additional_column_qualification_parts.size(); - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - /** For each matched column node iterate over additional column qualifications and apply them if column needs to be qualified. - * To check if column needs to be qualified we check if column name can bind to any other table expression in scope or to scope aliases. - */ - std::vector column_qualified_identifier_parts; - - for (const auto & column_node : column_nodes) - { - const auto & column_name = column_node->as().getColumnName(); - column_qualified_identifier_parts = Identifier(column_name).getParts(); - - /// Iterate over additional column qualifications and apply them if needed - for (size_t i = 0; i < additional_column_qualification_parts_size; ++i) - { - auto identifier_to_check = Identifier(column_qualified_identifier_parts); - IdentifierLookup identifier_lookup{identifier_to_check, IdentifierLookupContext::EXPRESSION}; - bool need_to_qualify = table_expression_data.should_qualify_columns; - if (need_to_qualify) - need_to_qualify = tryBindIdentifierToTableExpressions(identifier_lookup, table_expression_node, scope); - - if (tryBindIdentifierToAliases(identifier_lookup, scope)) - need_to_qualify = true; - - if (need_to_qualify) - { - /** Add last qualification part that was not used into column qualified identifier. - * If additional column qualification parts consists from [database_name, table_name]. - * On first iteration if column is needed to be qualified to qualify it with table_name. - * On second iteration if column is needed to be qualified to qualify it with database_name. - */ - size_t part_index_to_use_for_qualification = additional_column_qualification_parts_size - i - 1; - const auto & part_to_use = additional_column_qualification_parts[part_index_to_use_for_qualification]; - column_qualified_identifier_parts.insert(column_qualified_identifier_parts.begin(), part_to_use); - } - else - { - break; - } - } - - auto qualified_node_name = Identifier(column_qualified_identifier_parts).getFullName(); - node_to_projection_name.emplace(column_node, qualified_node_name); - } -} - -/// Build get columns options for matcher -GetColumnsOptions QueryAnalyzer::buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context) -{ - auto & matcher_node_typed = matcher_node->as(); - UInt8 get_columns_options_kind = GetColumnsOptions::AllPhysicalAndAliases; - - if (matcher_node_typed.isAsteriskMatcher()) - { - get_columns_options_kind = GetColumnsOptions::Ordinary; - - const auto & settings = context->getSettingsRef(); - - if (settings.asterisk_include_alias_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Aliases; - - if (settings.asterisk_include_materialized_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Materialized; - } - - return GetColumnsOptions(static_cast(get_columns_options_kind)); -} - -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - /** Use resolved columns from table expression data in nearest query scope if available. - * It is important for ALIAS columns to use column nodes with resolved ALIAS expression. - */ - const TableExpressionData * table_expression_data = nullptr; - const auto * nearest_query_scope = scope.getNearestQueryScope(); - if (nearest_query_scope) - table_expression_data = &nearest_query_scope->getTableExpressionDataOrThrow(table_expression_node); - - QueryTreeNodes matched_column_nodes; - - for (const auto & column : matched_columns) - { - const auto & column_name = column.name; - if (!matcher_node_typed.isMatchingColumn(column_name)) - continue; - - if (table_expression_data) - { - auto column_node_it = table_expression_data->column_name_to_column_node.find(column_name); - if (column_node_it != table_expression_data->column_name_to_column_node.end()) - { - matched_column_nodes.emplace_back(column_node_it->second); - continue; - } - } - - matched_column_nodes.emplace_back(std::make_shared(column, table_expression_node)); - } - - const auto & qualify_matched_column_nodes_scope = nearest_query_scope ? *nearest_query_scope : scope; - qualifyColumnNodesWithProjectionNames(matched_column_nodes, table_expression_node, qualify_matched_column_nodes_scope); - - QueryAnalyzer::QueryTreeNodesWithNames matched_column_nodes_with_names; - matched_column_nodes_with_names.reserve(matched_column_nodes.size()); - - for (auto && matched_column_node : matched_column_nodes) - { - auto column_name = matched_column_node->as().getColumnName(); - matched_column_nodes_with_names.emplace_back(std::move(matched_column_node), std::move(column_name)); - } - - return matched_column_nodes_with_names; -} - -bool hasTableExpressionInJoinTree(const QueryTreeNodePtr & join_tree_node, const QueryTreeNodePtr & table_expression) -{ - QueryTreeNodes nodes_to_process; - nodes_to_process.push_back(join_tree_node); - - while (!nodes_to_process.empty()) - { - auto node_to_process = std::move(nodes_to_process.back()); - nodes_to_process.pop_back(); - if (node_to_process == table_expression) - return true; - - if (node_to_process->getNodeType() == QueryTreeNodeType::JOIN) - { - const auto & join_node = node_to_process->as(); - nodes_to_process.push_back(join_node.getLeftTableExpression()); - nodes_to_process.push_back(join_node.getRightTableExpression()); - } - } - return false; -} - -/// Columns that resolved from matcher can also match columns from JOIN USING. -/// In that case we update type to type of column in USING section. -/// TODO: It's not completely correct for qualified matchers, so t1.* should be resolved to left table column type. -/// But in planner we do not distinguish such cases. -void QueryAnalyzer::updateMatchedColumnsFromJoinUsing( - QueryTreeNodesWithNames & result_matched_column_nodes_with_names, - const QueryTreeNodePtr & source_table_expression, - IdentifierResolveScope & scope) -{ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "There are no table sources. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - const auto & join_tree = nearest_query_scope_query_node->getJoinTree(); - - const auto * join_node = join_tree->as(); - if (join_node && join_node->isUsingJoinExpression()) - { - const auto & join_using_list = join_node->getJoinExpression()->as(); - const auto & join_using_nodes = join_using_list.getNodes(); - - for (auto & [matched_column_node, _] : result_matched_column_nodes_with_names) - { - auto & matched_column_node_typed = matched_column_node->as(); - const auto & matched_column_name = matched_column_node_typed.getColumnName(); - - for (const auto & join_using_node : join_using_nodes) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (matched_column_name != join_using_column_name) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - auto it = node_to_projection_name.find(matched_column_node); - - if (hasTableExpressionInJoinTree(join_node->getLeftTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(0); - else if (hasTableExpressionInJoinTree(join_node->getRightTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(1); - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Cannot find column {} in JOIN USING section {}", - matched_column_node->dumpTree(), join_node->dumpTree()); - - matched_column_node = matched_column_node->clone(); - if (it != node_to_projection_name.end()) - node_to_projection_name.emplace(matched_column_node, it->second); - - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - } - } - } -} - -/** Resolve qualified tree matcher. - * - * First try to match qualified identifier to expression. If qualified identifier matched expression node then - * if expression is compound match it column names using matcher `isMatchingColumn` method, if expression is not compound, throw exception. - * If qualified identifier did not match expression in query tree, try to lookup qualified identifier in table context. - */ -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isQualified()); - - auto expression_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::EXPRESSION}; - auto expression_identifier_resolve_result = tryResolveIdentifier(expression_identifier_lookup, scope); - auto expression_query_tree_node = expression_identifier_resolve_result.resolved_identifier; - - /// Try to resolve unqualified matcher for query expression - - if (expression_query_tree_node) - { - auto result_type = expression_query_tree_node->getResultType(); - - while (true) - { - if (const auto * array_type = typeid_cast(result_type.get())) - result_type = array_type->getNestedType(); - else if (const auto * map_type = typeid_cast(result_type.get())) - result_type = map_type->getNestedType(); - else - break; - } - - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Qualified matcher {} find non compound expression {} with type {}. Expected tuple or array of tuples. In scope {}", - matcher_node->formatASTForErrorMessage(), - expression_query_tree_node->formatASTForErrorMessage(), - expression_query_tree_node->getResultType()->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - auto qualified_matcher_element_identifier = matcher_node_typed.getQualifiedIdentifier(); - for (const auto & element_name : element_names) - { - if (!matcher_node_typed.isMatchingColumn(element_name)) - continue; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back(expression_query_tree_node); - get_subcolumn_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - qualified_matcher_element_identifier.push_back(element_name); - node_to_projection_name.emplace(function_query_node, qualified_matcher_element_identifier.getFullName()); - qualified_matcher_element_identifier.pop_back(); - - matched_expression_nodes_with_column_names.emplace_back(std::move(function_query_node), element_name); - } - - return matched_expression_nodes_with_column_names; - } - - /// Try to resolve qualified matcher for table expression - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_cte = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - auto table_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, identifier_resolve_settings); - auto table_expression_node = table_identifier_resolve_result.resolved_identifier; - - if (!table_expression_node) - { - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Qualified matcher {} does not find table. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - NamesAndTypes matched_columns; - - auto * table_expression_query_node = table_expression_node->as(); - auto * table_expression_union_node = table_expression_node->as(); - auto * table_expression_table_node = table_expression_node->as(); - auto * table_expression_table_function_node = table_expression_node->as(); - - if (table_expression_query_node || table_expression_union_node) - { - matched_columns = table_expression_query_node ? table_expression_query_node->getProjectionColumns() - : table_expression_union_node->computeProjectionColumns(); - } - else if (table_expression_table_node || table_expression_table_function_node) - { - const auto & storage_snapshot = table_expression_table_node ? table_expression_table_node->getStorageSnapshot() - : table_expression_table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - matched_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Invalid table expression node {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto result_matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression_node, - matched_columns, - scope); - - updateMatchedColumnsFromJoinUsing(result_matched_column_nodes_with_names, table_expression_node, scope); - - return result_matched_column_nodes_with_names; -} - -/// Resolve non qualified matcher, using scope join tree node. -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isUnqualified()); - - /** There can be edge case if matcher is inside lambda expression. - * Try to find parent query expression using parent scopes. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unqualified matcher {} cannot be resolved. There are no table sources. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** For unqualifited matcher resolve we build table expressions stack from JOIN tree and then process it. - * For table, table function, query, union table expressions add matched columns into table expressions columns stack. - * For array join continue processing. - * For join node combine last left and right table expressions columns on stack together. It is important that if JOIN has USING - * we must add USING columns before combining left and right table expressions columns. Columns from left and right table - * expressions that have same names as columns in USING clause must be skipped. - */ - - auto table_expressions_stack = buildTableExpressionsStack(nearest_query_scope_query_node->getJoinTree()); - std::vector table_expressions_column_nodes_with_names_stack; - - std::unordered_set table_expression_column_names_to_skip; - - QueryTreeNodesWithNames result; - - if (matcher_node_typed.getMatcherType() == MatcherNodeType::COLUMNS_LIST) - { - auto identifiers = matcher_node_typed.getColumnsIdentifiers(); - result.reserve(identifiers.size()); - - for (const auto & identifier : identifiers) - { - auto resolve_result = tryResolveIdentifier(IdentifierLookup{identifier, IdentifierLookupContext::EXPRESSION}, scope); - if (!resolve_result.isResolved()) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Unknown identifier '{}' inside COLUMNS matcher. In scope {}", - identifier.getFullName(), scope.dump()); - - // TODO: Introduce IdentifierLookupContext::COLUMN and get rid of this check - auto * resolved_column = resolve_result.resolved_identifier->as(); - if (!resolved_column) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier '{}' inside COLUMNS matcher must resolve into a column, but got {}. In scope {}", - identifier.getFullName(), - resolve_result.resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - result.emplace_back(resolve_result.resolved_identifier, resolved_column->getColumnName()); - } - return result; - } - - result.resize(matcher_node_typed.getColumnsIdentifiers().size()); - - for (auto & table_expression : table_expressions_stack) - { - bool table_expression_in_resolve_process = nearest_query_scope->table_expressions_in_resolve_process.contains(table_expression.get()); - - if (auto * array_join_node = table_expression->as()) - { - if (table_expressions_column_nodes_with_names_stack.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 1 table expressions on stack before ARRAY JOIN processing"); - - if (table_expression_in_resolve_process) - continue; - - auto & table_expression_column_nodes_with_names = table_expressions_column_nodes_with_names_stack.back(); - - for (auto & [table_expression_column_node, _] : table_expression_column_nodes_with_names) - { - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(table_expression_column_node, - table_expression, - scope); - if (array_join_resolved_expression) - table_expression_column_node = std::move(array_join_resolved_expression); - } - - continue; - } - - auto * join_node = table_expression->as(); - - if (join_node) - { - size_t table_expressions_column_nodes_with_names_stack_size = table_expressions_column_nodes_with_names_stack.size(); - if (table_expressions_column_nodes_with_names_stack_size < 2) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 2 table expressions on stack before JOIN processing. Actual {}", - table_expressions_column_nodes_with_names_stack_size); - - auto right_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - auto left_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - table_expression_column_names_to_skip.clear(); - - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - /** If there is JOIN with USING we need to match only single USING column and do not use left table expression - * and right table expression column with same name. - * - * Example: SELECT id FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING (id); - */ - if (!table_expression_in_resolve_process && join_node->isUsingJoinExpression()) - { - auto & join_using_list = join_node->getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (!matcher_node_typed.isMatchingColumn(join_using_column_name)) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - /** If column doesn't exists in the table, then do not match column from USING clause. - * Example: SELECT a + 1 AS id, * FROM (SELECT 1 AS a) AS t1 JOIN (SELECT 2 AS id) AS t2 USING (id); - * In this case `id` is not present in the left table expression, - * so asterisk should return `id` from the right table expression. - */ - auto is_column_from_parent_scope = [&scope](const QueryTreeNodePtr & using_node_from_table) - { - const auto & using_column_from_table = using_node_from_table->as(); - auto table_expression_data_it = scope.table_expression_node_to_data.find(using_column_from_table.getColumnSource()); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - { - const auto & table_expression_data = table_expression_data_it->second; - const auto & column_name = using_column_from_table.getColumnName(); - return !table_expression_data.column_name_to_column_node.contains(column_name); - } - return false; - }; - - if (is_column_from_parent_scope(join_using_column_nodes.at(0)) || - is_column_from_parent_scope(join_using_column_nodes.at(1))) - continue; - - QueryTreeNodePtr matched_column_node; - - if (isRight(join_node->getKind())) - matched_column_node = join_using_column_nodes.at(1); - else - matched_column_node = join_using_column_nodes.at(0); - - matched_column_node = matched_column_node->clone(); - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - - table_expression_column_names_to_skip.insert(join_using_column_name); - matched_expression_nodes_with_column_names.emplace_back(std::move(matched_column_node), join_using_column_name); - } - } - - for (auto && left_table_column_with_name : left_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(left_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(left_table_column_with_name)); - } - - for (auto && right_table_column_with_name : right_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(right_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(right_table_column_with_name)); - } - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_expression_nodes_with_column_names)); - continue; - } - - if (table_expression_in_resolve_process) - { - table_expressions_column_nodes_with_names_stack.emplace_back(); - continue; - } - - auto * table_node = table_expression->as(); - auto * table_function_node = table_expression->as(); - auto * query_node = table_expression->as(); - auto * union_node = table_expression->as(); - - NamesAndTypes table_expression_columns; - - if (query_node || union_node) - { - table_expression_columns = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - } - else if (table_node || table_function_node) - { - const auto & storage_snapshot - = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - table_expression_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unqualified matcher {} resolve unexpected table expression. In scope {}", - matcher_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression, - table_expression_columns, - scope); - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_column_nodes_with_names)); - } - - for (auto & table_expression_column_nodes_with_names : table_expressions_column_nodes_with_names_stack) - { - for (auto && table_expression_column_node_with_name : table_expression_column_nodes_with_names) - result.push_back(std::move(table_expression_column_node_with_name)); - } - - return result; -} - - -/** Resolve query tree matcher. Check MatcherNode.h for detailed matcher description. Check ColumnTransformers.h for detailed transformers description. - * - * 1. Populate matched expression nodes resolving qualified or unqualified matcher. - * 2. Apply column transformers to matched expression nodes. For strict column transformers save used column names. - * 3. Validate strict column transformers. - */ -ProjectionNames QueryAnalyzer::resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - QueryTreeNodesWithNames matched_expression_nodes_with_names; - - if (matcher_node_typed.isQualified()) - matched_expression_nodes_with_names = resolveQualifiedMatcher(matcher_node, scope); - else - matched_expression_nodes_with_names = resolveUnqualifiedMatcher(matcher_node, scope); - - if (scope.join_use_nulls) - { - /** If we are resolving matcher came from the result of JOIN and `join_use_nulls` is set, - * we need to convert joined column type to Nullable. - * We are taking the nearest JoinNode to check to which table column belongs, - * because for LEFT/RIGHT join, we convert only the corresponding side. - */ - const auto * nearest_query_scope = scope.getNearestQueryScope(); - const QueryNode * nearest_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - const QueryTreeNodePtr & nearest_scope_join_tree = nearest_scope_query_node ? nearest_scope_query_node->getJoinTree() : nullptr; - const JoinNode * nearest_scope_join_node = nearest_scope_join_tree ? nearest_scope_join_tree->as() : nullptr; - if (nearest_scope_join_node) - { - for (auto & [node, node_name] : matched_expression_nodes_with_names) - { - auto join_identifier_side = getColumnSideFromJoinTree(node, *nearest_scope_join_node); - auto projection_name_it = node_to_projection_name.find(node); - auto nullable_node = convertJoinedColumnTypeToNullIfNeeded(node, nearest_scope_join_node->getKind(), join_identifier_side, scope); - if (nullable_node) - { - node = nullable_node; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(node, projection_name_it->second); - } - } - } - } - } - - if (!scope.expressions_in_resolve_process_stack.hasAggregateFunction()) - { - for (auto & [node, _] : matched_expression_nodes_with_names) - { - auto it = scope.nullable_group_by_keys.find(node); - if (it != scope.nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - } - } - } - - std::unordered_map> strict_transformer_to_used_column_names; - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - auto * except_transformer = transformer->as(); - auto * replace_transformer = transformer->as(); - - if (except_transformer && except_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(except_transformer, std::unordered_set()); - else if (replace_transformer && replace_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(replace_transformer, std::unordered_set()); - } - - ListNodePtr list = std::make_shared(); - ProjectionNames result_projection_names; - ProjectionNames node_projection_names; - - for (auto & [node, column_name] : matched_expression_nodes_with_names) - { - bool apply_transformer_was_used = false; - bool replace_transformer_was_used = false; - bool execute_apply_transformer = false; - bool execute_replace_transformer = false; - - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - else - result_projection_names.push_back(column_name); - - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - if (auto * apply_transformer = transformer->as()) - { - const auto & expression_node = apply_transformer->getExpressionNode(); - apply_transformer_was_used = true; - - if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::LAMBDA) - { - auto lambda_expression_to_resolve = expression_node->clone(); - IdentifierResolveScope lambda_scope(expression_node, &scope /*parent_scope*/); - node_projection_names = resolveLambda(expression_node, lambda_expression_to_resolve, {node}, lambda_scope); - auto & lambda_expression_to_resolve_typed = lambda_expression_to_resolve->as(); - node = lambda_expression_to_resolve_typed.getExpression(); - } - else if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::FUNCTION) - { - auto function_to_resolve_untyped = expression_node->clone(); - auto & function_to_resolve_typed = function_to_resolve_untyped->as(); - function_to_resolve_typed.getArguments().getNodes().push_back(node); - node_projection_names = resolveFunction(function_to_resolve_untyped, scope); - node = function_to_resolve_untyped; - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unsupported apply matcher expression type. Expected lambda or function apply transformer. Actual {}. In scope {}", - transformer->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - execute_apply_transformer = true; - } - else if (auto * except_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - if (except_transformer->isColumnMatching(column_name)) - { - if (except_transformer->isStrict()) - strict_transformer_to_used_column_names[except_transformer].insert(column_name); - - node = {}; - break; - } - } - else if (auto * replace_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - auto replace_expression = replace_transformer->findReplacementExpression(column_name); - if (!replace_expression) - continue; - - replace_transformer_was_used = true; - - if (replace_transformer->isStrict()) - strict_transformer_to_used_column_names[replace_transformer].insert(column_name); - - node = replace_expression->clone(); - node_projection_names = resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** If replace expression resolved as single node, we want to use replace column name as result projection name, instead - * of using replace expression projection name. - * - * Example: SELECT * REPLACE id + 5 AS id FROM test_table; - */ - if (node_projection_names.size() == 1) - node_projection_names[0] = column_name; - - execute_replace_transformer = true; - } - - if (execute_apply_transformer || execute_replace_transformer) - { - if (auto * node_list = node->as()) - { - auto & node_list_nodes = node_list->getNodes(); - size_t node_list_nodes_size = node_list_nodes.size(); - - if (node_list_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "{} transformer {} resolved as list node with size {}. Expected 1. In scope {}", - execute_apply_transformer ? "APPLY" : "REPLACE", - transformer->formatASTForErrorMessage(), - node_list_nodes_size, - scope.scope_node->formatASTForErrorMessage()); - - node = node_list_nodes[0]; - } - - if (node_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Matcher node expected 1 projection name. Actual {}", node_projection_names.size()); - - result_projection_names.back() = std::move(node_projection_names[0]); - node_to_projection_name.emplace(node, result_projection_names.back()); - node_projection_names.clear(); - } - } - - if (node) - list->getNodes().push_back(node); - else - result_projection_names.pop_back(); - } - - for (auto & [strict_transformer, used_column_names] : strict_transformer_to_used_column_names) - { - auto strict_transformer_type = strict_transformer->getTransformerType(); - const Names * strict_transformer_column_names = nullptr; - - switch (strict_transformer_type) - { - case ColumnTransfomerType::EXCEPT: - { - const auto * except_transformer = static_cast(strict_transformer); - const auto & except_names = except_transformer->getExceptColumnNames(); - - if (except_names.size() != used_column_names.size()) - strict_transformer_column_names = &except_transformer->getExceptColumnNames(); - - break; - } - case ColumnTransfomerType::REPLACE: - { - const auto * replace_transformer = static_cast(strict_transformer); - const auto & replacement_names = replace_transformer->getReplacementsNames(); - - if (replacement_names.size() != used_column_names.size()) - strict_transformer_column_names = &replace_transformer->getReplacementsNames(); - - break; - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected strict EXCEPT or REPLACE column transformer. Actual type {}. In scope {}", - toString(strict_transformer_type), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (!strict_transformer_column_names) - continue; - - Names non_matched_column_names; - size_t strict_transformer_column_names_size = strict_transformer_column_names->size(); - for (size_t i = 0; i < strict_transformer_column_names_size; ++i) - { - const auto & column_name = (*strict_transformer_column_names)[i]; - if (used_column_names.find(column_name) == used_column_names.end()) - non_matched_column_names.push_back(column_name); - } - - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Strict {} column transformer {} expects following column(s) : {}. In scope {}", - toString(strict_transformer_type), - strict_transformer->formatASTForErrorMessage(), - fmt::join(non_matched_column_names, ", "), - scope.scope_node->formatASTForErrorMessage()); - } - - auto original_ast = matcher_node->getOriginalAST(); - matcher_node = std::move(list); - if (original_ast) - matcher_node->setOriginalAST(original_ast); - - return result_projection_names; -} - -/** Resolve window function window node. - * - * Node can be identifier or window node. - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - * Example: SELECT count(*) OVER (PARTITION BY id); - * - * If node has parent window name specified, then parent window definition is searched in nearest query scope WINDOW section. - * If node is identifier, than node is replaced with window definition. - * If node is window, that window node is merged with parent window node. - * - * Window node PARTITION BY and ORDER BY parts are resolved. - * If window node has frame begin OFFSET or frame end OFFSET specified, they are resolved, and window node frame constants are updated. - * Window node frame is validated. - */ -ProjectionName QueryAnalyzer::resolveWindow(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - std::string parent_window_name; - auto * identifier_node = node->as(); - - ProjectionName result_projection_name; - QueryTreeNodePtr parent_window_node; - - if (identifier_node) - parent_window_name = identifier_node->getIdentifier().getFullName(); - else if (auto * window_node = node->as()) - parent_window_name = window_node->getParentWindowName(); - - if (!parent_window_name.empty()) - { - auto * nearest_query_scope = scope.getNearestQueryScope(); - - if (!nearest_query_scope) - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Window '{}' does not exist.", parent_window_name); - - auto & scope_window_name_to_window_node = nearest_query_scope->window_name_to_window_node; - - auto window_node_it = scope_window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope_window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - nearest_query_scope->scope_node->formatASTForErrorMessage()); - - parent_window_node = window_node_it->second; - - if (identifier_node) - { - node = parent_window_node->clone(); - result_projection_name = parent_window_name; - } - else - { - mergeWindowWithParentWindow(node, parent_window_node, scope); - } - } - - auto & window_node = node->as(); - window_node.setParentWindowName({}); - - ProjectionNames partition_by_projection_names = resolveExpressionNodeList(window_node.getPartitionByNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - ProjectionNames order_by_projection_names = resolveSortNodeList(window_node.getOrderByNode(), scope); - - ProjectionNames frame_begin_offset_projection_names; - ProjectionNames frame_end_offset_projection_names; - - if (window_node.hasFrameBeginOffset()) - { - frame_begin_offset_projection_names = resolveExpressionNode(window_node.getFrameBeginOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_begin_constant_node = window_node.getFrameBeginOffsetNode()->as(); - if (!window_frame_begin_constant_node || !isNativeNumber(removeNullable(window_frame_begin_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameBeginOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().begin_offset = window_frame_begin_constant_node->getValue(); - if (frame_begin_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_begin_offset_projection_names.size()); - } - - if (window_node.hasFrameEndOffset()) - { - frame_end_offset_projection_names = resolveExpressionNode(window_node.getFrameEndOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_end_constant_node = window_node.getFrameEndOffsetNode()->as(); - if (!window_frame_end_constant_node || !isNativeNumber(removeNullable(window_frame_end_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameEndOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().end_offset = window_frame_end_constant_node->getValue(); - if (frame_end_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_end_offset_projection_names.size()); - } - - window_node.getWindowFrame().checkValid(); - - if (result_projection_name.empty()) - { - result_projection_name = calculateWindowProjectionName(node, - parent_window_node, - parent_window_name, - partition_by_projection_names, - order_by_projection_names, - frame_begin_offset_projection_names.empty() ? "" : frame_begin_offset_projection_names.front(), - frame_end_offset_projection_names.empty() ? "" : frame_end_offset_projection_names.front()); - } - - return result_projection_name; -} - -/** Resolve lambda function. - * This function modified lambda_node during resolve. It is caller responsibility to clone lambda before resolve - * if it is needed for later use. - * - * Lambda body expression result projection names is used as lambda projection names. - * - * Lambda expression can be resolved into list node. It is caller responsibility to handle it properly. - * - * lambda_node - node that must have LambdaNode type. - * lambda_node_to_resolve - lambda node to resolve that must have LambdaNode type. - * arguments - lambda arguments. - * scope - lambda scope. It is client responsibility to create it. - * - * Resolve steps: - * 1. Validate arguments. - * 2. Register lambda node in lambdas in resolve process. This is necessary to prevent recursive lambda resolving. - * 3. Initialize scope with lambda aliases. - * 4. Validate lambda argument names, and scope expressions. - * 5. Resolve lambda body expression. - * 6. Deregister lambda node from lambdas in resolve process. - */ -ProjectionNames QueryAnalyzer::resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope) -{ - auto & lambda_to_resolve = lambda_node_to_resolve->as(); - auto & lambda_arguments_nodes = lambda_to_resolve.getArguments().getNodes(); - size_t lambda_arguments_nodes_size = lambda_arguments_nodes.size(); - - /** Register lambda as being resolved, to prevent recursive lambdas resolution. - * Example: WITH (x -> x + lambda_2(x)) AS lambda_1, (x -> x + lambda_1(x)) AS lambda_2 SELECT 1; - */ - auto it = lambdas_in_resolve_process.find(lambda_node.get()); - if (it != lambdas_in_resolve_process.end()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive lambda {}. In scope {}", - lambda_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - lambdas_in_resolve_process.emplace(lambda_node.get()); - - size_t arguments_size = lambda_arguments.size(); - if (lambda_arguments_nodes_size != arguments_size) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} expect {} arguments. Actual {}. In scope {}", - lambda_to_resolve.formatASTForErrorMessage(), - lambda_arguments_nodes_size, - arguments_size, - scope.scope_node->formatASTForErrorMessage()); - - /// Initialize aliases in lambda scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - visitor.visit(lambda_to_resolve.getExpression()); - - /** Replace lambda arguments with new arguments. - * Additionally validate that there are no aliases with same name as lambda arguments. - * Arguments are registered in current scope expression_argument_name_to_node map. - */ - QueryTreeNodes lambda_new_arguments_nodes; - lambda_new_arguments_nodes.reserve(lambda_arguments_nodes_size); - - for (size_t i = 0; i < lambda_arguments_nodes_size; ++i) - { - auto & lambda_argument_node = lambda_arguments_nodes[i]; - const auto * lambda_argument_identifier = lambda_argument_node->as(); - const auto * lambda_argument_column = lambda_argument_node->as(); - if (!lambda_argument_identifier && !lambda_argument_column) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected IDENTIFIER or COLUMN as lambda argument, got {}", lambda_node->dumpTree()); - const auto & lambda_argument_name = lambda_argument_identifier ? lambda_argument_identifier->getIdentifier().getFullName() - : lambda_argument_column->getColumnName(); - - bool has_expression_node = scope.aliases.alias_name_to_expression_node->contains(lambda_argument_name); - bool has_alias_node = scope.aliases.alias_name_to_lambda_node.contains(lambda_argument_name); - - if (has_expression_node || has_alias_node) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Alias name '{}' inside lambda {} cannot have same name as lambda argument. In scope {}", - lambda_argument_name, - lambda_argument_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - scope.expression_argument_name_to_node.emplace(lambda_argument_name, lambda_arguments[i]); - lambda_new_arguments_nodes.push_back(lambda_arguments[i]); - } - - lambda_to_resolve.getArguments().getNodes() = std::move(lambda_new_arguments_nodes); - - /// Lambda body expression is resolved as standard query expression node. - auto result_projection_names = resolveExpressionNode(lambda_to_resolve.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - lambdas_in_resolve_process.erase(lambda_node.get()); - - return result_projection_names; -} - -namespace -{ -void checkFunctionNodeHasEmptyNullsAction(FunctionNode const & node) -{ - if (node.getNullsAction() != NullsAction::EMPTY) - throw Exception( - ErrorCodes::SYNTAX_ERROR, - "Function with name '{}' cannot use {} NULLS", - node.getFunctionName(), - node.getNullsAction() == NullsAction::IGNORE_NULLS ? "IGNORE" : "RESPECT"); -} -} - -/** Resolve function node in scope. - * During function node resolve, function node can be replaced with another expression (if it match lambda or sql user defined function), - * with constant (if it allow constant folding), or with expression list. It is caller responsibility to handle such cases appropriately. - * - * Steps: - * 1. Resolve function parameters. Validate that each function parameter must be constant node. - * 2. Try to lookup function as lambda in current scope. If it is lambda we can skip `in` and `count` special handling. - * 3. If function is count function, that take unqualified ASTERISK matcher, remove it from its arguments. Example: SELECT count(*) FROM test_table; - * 4. If function is `IN` function, then right part of `IN` function is replaced as subquery. - * 5. Resolve function arguments list, lambda expressions are allowed as function arguments. - * For `IN` function table expressions are allowed as function arguments. - * 6. Initialize argument_columns, argument_types, function_lambda_arguments_indexes arrays from function arguments. - * 7. If function name identifier was not resolved as function in current scope, try to lookup lambda from sql user defined functions factory. - * 8. If function was resolve as lambda from step 2 or 7, then resolve lambda using function arguments and replace function node with lambda result. - * After than function node is resolved. - * 9. If function was not resolved during step 6 as lambda, then try to resolve function as window function or executable user defined function - * or ordinary function or aggregate function. - * - * If function is resolved as window function or executable user defined function or aggregate function, function node is resolved - * no additional special handling is required. - * - * 8. If function was resolved as non aggregate function. Then if some of function arguments are lambda expressions, their result types need to be initialized and - * they must be resolved. - * 9. If function is suitable for constant folding, try to perform constant folding for function node. - */ -ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - FunctionNodePtr function_node_ptr = std::static_pointer_cast(node); - auto function_name = function_node_ptr->getFunctionName(); - - /// Resolve function parameters - - auto parameters_projection_names = resolveExpressionNodeList(function_node_ptr->getParametersNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - /// Convert function parameters into constant parameters array - - Array parameters; - - auto & parameters_nodes = function_node_ptr->getParameters().getNodes(); - parameters.reserve(parameters_nodes.size()); - - for (auto & parameter_node : parameters_nodes) - { - const auto * constant_node = parameter_node->as(); - if (!constant_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parameter for function '{}' expected to have constant value. Actual {}. In scope {}", - function_name, - parameter_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - parameters.push_back(constant_node->getValue()); - } - - //// If function node is not window function try to lookup function node name as lambda identifier. - QueryTreeNodePtr lambda_expression_untyped; - if (!function_node_ptr->isWindowFunction()) - { - auto function_lookup_result = tryResolveIdentifier({Identifier{function_name}, IdentifierLookupContext::FUNCTION}, scope); - lambda_expression_untyped = function_lookup_result.resolved_identifier; - } - - bool is_special_function_in = false; - bool is_special_function_dict_get = false; - bool is_special_function_join_get = false; - bool is_special_function_exists = false; - bool is_special_function_if = false; - - if (!lambda_expression_untyped) - { - is_special_function_in = isNameOfInFunction(function_name); - is_special_function_dict_get = functionIsDictGet(function_name); - is_special_function_join_get = functionIsJoinGet(function_name); - is_special_function_exists = function_name == "exists"; - is_special_function_if = function_name == "if"; - - auto function_name_lowercase = Poco::toLower(function_name); - - /** Special handling for count and countState functions. - * - * Example: SELECT count(*) FROM test_table - * Example: SELECT countState(*) FROM test_table; - */ - if (function_node_ptr->getArguments().getNodes().size() == 1 && - (function_name_lowercase == "count" || function_name_lowercase == "countstate")) - { - auto * matcher_node = function_node_ptr->getArguments().getNodes().front()->as(); - if (matcher_node && matcher_node->isUnqualified()) - function_node_ptr->getArguments().getNodes().clear(); - } - } - - /** Special functions dictGet and its variations and joinGet can be executed when first argument is identifier. - * Example: SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Try to resolve identifier as expression identifier and if it is resolved use it. - * Example: WITH 'dict_name' AS identifier SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Otherwise replace identifier with identifier full name constant. - * Validation that dictionary exists or table exists will be performed during function `getReturnType` method call. - */ - if ((is_special_function_dict_get || is_special_function_join_get) && - !function_node_ptr->getArguments().getNodes().empty() && - function_node_ptr->getArguments().getNodes()[0]->getNodeType() == QueryTreeNodeType::IDENTIFIER) - { - auto & first_argument = function_node_ptr->getArguments().getNodes()[0]; - auto & first_argument_identifier = first_argument->as(); - auto identifier = first_argument_identifier.getIdentifier(); - - IdentifierLookup identifier_lookup{identifier, IdentifierLookupContext::EXPRESSION}; - auto resolve_result = tryResolveIdentifier(identifier_lookup, scope); - - if (resolve_result.isResolved()) - { - first_argument = std::move(resolve_result.resolved_identifier); - } - else - { - size_t parts_size = identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected {} function first argument identifier to contain 1 or 2 parts. Actual '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_special_function_dict_get) - { - scope.context->getExternalDictionariesLoader().assertDictionaryStructureExists(identifier.getFullName(), scope.context); - } - else - { - auto table_node = tryResolveTableIdentifierFromDatabaseCatalog(identifier, scope.context); - if (!table_node) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} first argument expected table identifier '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node_typed = table_node->as(); - if (!std::dynamic_pointer_cast(table_node_typed.getStorage())) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} table '{}' should have engine StorageJoin. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - first_argument = std::make_shared(identifier.getFullName()); - } - } - - if (is_special_function_exists) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /// Rewrite EXISTS (subquery) into 1 IN (SELECT 1 FROM (subquery) LIMIT 1). - auto & exists_subquery_argument = function_node_ptr->getArguments().getNodes().at(0); - - auto constant_data_type = std::make_shared(); - - auto in_subquery = std::make_shared(Context::createCopy(scope.context)); - in_subquery->setIsSubquery(true); - in_subquery->getProjection().getNodes().push_back(std::make_shared(1UL, constant_data_type)); - in_subquery->getJoinTree() = exists_subquery_argument; - in_subquery->getLimit() = std::make_shared(1UL, constant_data_type); - - function_node_ptr = std::make_shared("in"); - function_node_ptr->getArguments().getNodes() = {std::make_shared(1UL, constant_data_type), in_subquery}; - node = function_node_ptr; - function_name = "in"; - is_special_function_in = true; - } - - if (is_special_function_if && !function_node_ptr->getArguments().getNodes().empty()) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /** Handle special case with constant If function, even if some of the arguments are invalid. - * - * SELECT if(hasColumnInTable('system', 'numbers', 'not_existing_column'), not_existing_column, 5) FROM system.numbers; - */ - auto & if_function_arguments = function_node_ptr->getArguments().getNodes(); - auto if_function_condition = if_function_arguments[0]; - resolveExpressionNode(if_function_condition, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto constant_condition = tryExtractConstantFromConditionNode(if_function_condition); - - if (constant_condition.has_value() && if_function_arguments.size() == 3) - { - QueryTreeNodePtr constant_if_result_node; - QueryTreeNodePtr possibly_invalid_argument_node; - - if (*constant_condition) - { - possibly_invalid_argument_node = if_function_arguments[2]; - constant_if_result_node = if_function_arguments[1]; - } - else - { - possibly_invalid_argument_node = if_function_arguments[1]; - constant_if_result_node = if_function_arguments[2]; - } - - bool apply_constant_if_optimization = false; - - try - { - resolveExpressionNode(possibly_invalid_argument_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - } - catch (...) - { - apply_constant_if_optimization = true; - } - - if (apply_constant_if_optimization) - { - auto result_projection_names = resolveExpressionNode(constant_if_result_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - node = std::move(constant_if_result_node); - return result_projection_names; - } - } - } - - /// Resolve function arguments - bool allow_table_expressions = is_special_function_in; - auto arguments_projection_names = resolveExpressionNodeList(function_node_ptr->getArgumentsNode(), - scope, - true /*allow_lambda_expression*/, - allow_table_expressions /*allow_table_expression*/); - - /// Mask arguments if needed - if (!scope.context->getSettingsRef().format_display_secrets_in_show_and_select) - { - if (FunctionSecretArgumentsFinder::Result secret_arguments = FunctionSecretArgumentsFinderTreeNode(*function_node_ptr).getResult(); secret_arguments.count) - { - auto & argument_nodes = function_node_ptr->getArgumentsNode()->as().getNodes(); - - for (size_t n = secret_arguments.start; n < secret_arguments.start + secret_arguments.count; ++n) - { - if (auto * constant = argument_nodes[n]->as()) - { - auto mask = scope.projection_mask_map->insert({constant->getTreeHash(), scope.projection_mask_map->size() + 1}).first->second; - constant->setMaskId(mask); - arguments_projection_names[n] = "[HIDDEN id: " + std::to_string(mask) + "]"; - } - } - } - } - - auto & function_node = *function_node_ptr; - - /// Replace right IN function argument if it is table or table function with subquery that read ordinary columns - if (is_special_function_in) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - if (scope.context->getSettingsRef().transform_null_in) - { - static constexpr std::array, 4> in_function_to_replace_null_in_function_map = - {{ - {"in", "nullIn"}, - {"notIn", "notNullIn"}, - {"globalIn", "globalNullIn"}, - {"globalNotIn", "globalNotNullIn"}, - }}; - - for (const auto & [in_function_name, in_function_name_to_replace] : in_function_to_replace_null_in_function_map) - { - if (function_name == in_function_name) - { - function_name = in_function_name_to_replace; - break; - } - } - } - - auto & function_in_arguments_nodes = function_node.getArguments().getNodes(); - if (function_in_arguments_nodes.size() != 2) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function '{}' expects 2 arguments", function_name); - - auto & in_second_argument = function_in_arguments_nodes[1]; - auto * table_node = in_second_argument->as(); - auto * table_function_node = in_second_argument->as(); - - if (table_node) - { - /// If table is already prepared set, we do not replace it with subquery. - /// If table is not a StorageSet, we'll create plan to build set in the Planner. - } - else if (table_function_node) - { - const auto & storage_snapshot = table_function_node->getStorageSnapshot(); - auto columns_to_select = storage_snapshot->getColumns(GetColumnsOptions(GetColumnsOptions::Ordinary)); - - size_t columns_to_select_size = columns_to_select.size(); - - auto column_nodes_to_select = std::make_shared(); - column_nodes_to_select->getNodes().reserve(columns_to_select_size); - - NamesAndTypes projection_columns; - projection_columns.reserve(columns_to_select_size); - - for (auto & column : columns_to_select) - { - column_nodes_to_select->getNodes().emplace_back(std::make_shared(column, in_second_argument)); - projection_columns.emplace_back(column.name, column.type); - } - - auto in_second_argument_query_node = std::make_shared(Context::createCopy(scope.context)); - in_second_argument_query_node->setIsSubquery(true); - in_second_argument_query_node->getProjectionNode() = std::move(column_nodes_to_select); - in_second_argument_query_node->getJoinTree() = std::move(in_second_argument); - in_second_argument_query_node->resolveProjectionColumns(std::move(projection_columns)); - - in_second_argument = std::move(in_second_argument_query_node); - } - else - { - /// Replace storage with values storage of insertion block - if (StoragePtr storage = scope.context->getViewSource()) - { - QueryTreeNodePtr table_expression; - /// Process possibly nested sub-selects - for (auto * query_node = in_second_argument->as(); query_node; query_node = table_expression->as()) - table_expression = extractLeftTableExpression(query_node->getJoinTree()); - - if (table_expression) - { - if (auto * query_table_node = table_expression->as()) - { - if (query_table_node->getStorageID().getFullNameNotQuoted() == storage->getStorageID().getFullNameNotQuoted()) - { - auto replacement_table_expression = std::make_shared(storage, scope.context); - if (std::optional table_expression_modifiers = query_table_node->getTableExpressionModifiers()) - replacement_table_expression->setTableExpressionModifiers(*table_expression_modifiers); - in_second_argument = in_second_argument->cloneAndReplace(table_expression, std::move(replacement_table_expression)); - } - } - } - } - - resolveExpressionNode(in_second_argument, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - } - } - - /// Initialize function argument columns - - ColumnsWithTypeAndName argument_columns; - DataTypes argument_types; - bool all_arguments_constants = true; - std::vector function_lambda_arguments_indexes; - - auto & function_arguments = function_node.getArguments().getNodes(); - size_t function_arguments_size = function_arguments.size(); - - for (size_t function_argument_index = 0; function_argument_index < function_arguments_size; ++function_argument_index) - { - auto & function_argument = function_arguments[function_argument_index]; - - ColumnWithTypeAndName argument_column; - argument_column.name = arguments_projection_names[function_argument_index]; - - /** If function argument is lambda, save lambda argument index and initialize argument type as DataTypeFunction - * where function argument types are initialized with empty array of lambda arguments size. - */ - if (const auto * lambda_node = function_argument->as()) - { - size_t lambda_arguments_size = lambda_node->getArguments().getNodes().size(); - argument_column.type = std::make_shared(DataTypes(lambda_arguments_size, nullptr), nullptr); - function_lambda_arguments_indexes.push_back(function_argument_index); - } - else if (is_special_function_in && function_argument_index == 1) - { - argument_column.type = std::make_shared(); - } - else - { - argument_column.type = function_argument->getResultType(); - } - - if (!argument_column.type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' argument is not resolved. In scope {}", - function_name, - scope.scope_node->formatASTForErrorMessage()); - - bool argument_is_constant = false; - const auto * constant_node = function_argument->as(); - if (constant_node) - { - argument_column.column = constant_node->getResultType()->createColumnConst(1, constant_node->getValue()); - argument_column.type = constant_node->getResultType(); - argument_is_constant = true; - } - else if (const auto * get_scalar_function_node = function_argument->as(); - get_scalar_function_node && get_scalar_function_node->getFunctionName() == "__getScalar") - { - /// Allow constant folding through getScalar - const auto * get_scalar_const_arg = get_scalar_function_node->getArguments().getNodes().at(0)->as(); - if (get_scalar_const_arg && scope.context->hasQueryContext()) - { - auto query_context = scope.context->getQueryContext(); - auto scalar_string = toString(get_scalar_const_arg->getValue()); - if (query_context->hasScalar(scalar_string)) - { - auto scalar = query_context->getScalar(scalar_string); - argument_column.column = ColumnConst::create(scalar.getByPosition(0).column, 1); - argument_column.type = get_scalar_function_node->getResultType(); - argument_is_constant = true; - } - } - } - - all_arguments_constants &= argument_is_constant; - - argument_types.push_back(argument_column.type); - argument_columns.emplace_back(std::move(argument_column)); - } - - /// Calculate function projection name - ProjectionNames result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - - /** Try to resolve function as - * 1. Lambda function in current scope. Example: WITH (x -> x + 1) AS lambda SELECT lambda(1); - * 2. Lambda function from sql user defined functions. - * 3. Special `untuple` function. - * 4. Special `grouping` function. - * 5. Window function. - * 6. Executable user defined function. - * 7. Ordinary function. - * 8. Aggregate function. - * - * TODO: Provide better error hints. - */ - if (!function_node.isWindowFunction()) - { - if (!lambda_expression_untyped) - lambda_expression_untyped = tryGetLambdaFromSQLUserDefinedFunctions(function_node.getFunctionName(), scope.context); - - /** If function is resolved as lambda. - * Clone lambda before resolve. - * Initialize lambda arguments as function arguments. - * Resolve lambda and then replace function node with resolved lambda expression body. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(value) FROM test_table; - * Result: SELECT value + 1 FROM test_table; - */ - if (lambda_expression_untyped) - { - auto * lambda_expression = lambda_expression_untyped->as(); - if (!lambda_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function identifier '{}' must be resolved as lambda. Actual {}. In scope {}", - function_node.getFunctionName(), - lambda_expression_untyped->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - if (!parameters.empty()) - { - throw Exception( - ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_node.formatASTForErrorMessage()); - } - - auto lambda_expression_clone = lambda_expression_untyped->clone(); - - IdentifierResolveScope lambda_scope(lambda_expression_clone, &scope /*parent_scope*/); - ProjectionNames lambda_projection_names = resolveLambda(lambda_expression_untyped, lambda_expression_clone, function_arguments, lambda_scope); - - auto & resolved_lambda = lambda_expression_clone->as(); - node = resolved_lambda.getExpression(); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(lambda_projection_names); - - return result_projection_names; - } - - if (function_name == "untuple") - { - /// Special handling of `untuple` function - - if (function_arguments.size() != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' must have 1 argument. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - const auto & untuple_argument = function_arguments[0]; - /// Handle this special case first as `getResultType()` might return nullptr - if (untuple_argument->as()) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Function untuple can't have lambda-expressions as arguments"); - - auto result_type = untuple_argument->getResultType(); - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' argument must have compound type. Actual type {}. In scope {}", - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - - auto result_list = std::make_shared(); - result_list->getNodes().reserve(element_names.size()); - - for (const auto & element_name : element_names) - { - auto tuple_element_function = std::make_shared("tupleElement"); - tuple_element_function->getArguments().getNodes().push_back(untuple_argument); - tuple_element_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = tuple_element_function; - resolveFunction(function_query_node, scope); - - result_list->getNodes().push_back(std::move(function_query_node)); - } - - auto untuple_argument_projection_name = arguments_projection_names.at(0); - result_projection_names.clear(); - - for (const auto & element_name : element_names) - { - if (node->hasAlias()) - result_projection_names.push_back(node->getAlias() + '.' + element_name); - else - result_projection_names.push_back(fmt::format("tupleElement({}, '{}')", untuple_argument_projection_name, element_name)); - } - - node = std::move(result_list); - return result_projection_names; - } - else if (function_name == "grouping") - { - /// It is responsibility of planner to perform additional handling of grouping function - if (function_arguments_size == 0) - throw Exception(ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING expects at least one argument"); - else if (function_arguments_size > 64) - throw Exception(ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING can have up to 64 arguments, but {} provided", - function_arguments_size); - checkFunctionNodeHasEmptyNullsAction(function_node); - - bool force_grouping_standard_compatibility = scope.context->getSettingsRef().force_grouping_standard_compatibility; - auto grouping_function = std::make_shared(force_grouping_standard_compatibility); - auto grouping_function_adaptor = std::make_shared(std::move(grouping_function)); - function_node.resolveAsFunction(grouping_function_adaptor->build(argument_columns)); - - return result_projection_names; - } - } - - if (function_node.isWindowFunction()) - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - throw Exception(ErrorCodes::UNKNOWN_AGGREGATE_FUNCTION, "Aggregate function with name '{}' does not exist. In scope {}{}", - function_name, scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(AggregateFunctionFactory::instance().getHints(function_name))); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Window function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsWindowFunction(std::move(aggregate_function)); - - bool window_node_is_identifier = function_node.getWindowNode()->getNodeType() == QueryTreeNodeType::IDENTIFIER; - ProjectionName window_projection_name = resolveWindow(function_node.getWindowNode(), scope); - - if (window_node_is_identifier) - result_projection_names[0] += " OVER " + window_projection_name; - else - result_projection_names[0] += " OVER (" + window_projection_name + ')'; - - return result_projection_names; - } - - FunctionOverloadResolverPtr function = UserDefinedExecutableFunctionFactory::instance().tryGet(function_name, scope.context, parameters); /// NOLINT(readability-static-accessed-through-instance) - bool is_executable_udf = true; - - IdentifierResolveScope::ResolvedFunctionsCache * function_cache = nullptr; - - if (!function) - { - /// This is a hack to allow a query like `select randConstant(), randConstant(), randConstant()`. - /// Function randConstant() would return the same value for the same arguments (in scope). - - auto hash = function_node_ptr->getTreeHash(); - function_cache = &scope.functions_cache[hash]; - if (!function_cache->resolver) - function_cache->resolver = FunctionFactory::instance().tryGet(function_name, scope.context); - - function = function_cache->resolver; - - is_executable_udf = false; - } - - if (function) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - } - else - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - std::vector possible_function_names; - - auto function_names = UserDefinedExecutableFunctionFactory::instance().getRegisteredNames(scope.context); /// NOLINT(readability-static-accessed-through-instance) - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = UserDefinedSQLFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = FunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = AggregateFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - for (auto & [name, lambda_node] : scope.aliases.alias_name_to_lambda_node) - { - if (lambda_node->getNodeType() == QueryTreeNodeType::LAMBDA) - possible_function_names.push_back(name); - } - - auto hints = NamePrompter<2>::getHints(function_name, possible_function_names); - - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Function with name '{}' does not exist. In scope {}{}", - function_name, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Aggregate function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsAggregateFunction(std::move(aggregate_function)); - - return result_projection_names; - } - - /// Executable UDFs may have parameters. They are checked in UserDefinedExecutableFunctionFactory. - if (!parameters.empty() && !is_executable_udf) - { - throw Exception(ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_name); - } - - /** For lambda arguments we need to initialize lambda argument types DataTypeFunction using `getLambdaArgumentTypes` function. - * Then each lambda arguments are initialized with columns, where column source is lambda. - * This information is important for later steps of query processing. - * Example: SELECT arrayMap(x -> x + 1, [1, 2, 3]). - * lambda node x -> x + 1 identifier x is resolved as column where source is lambda node. - */ - bool has_lambda_arguments = !function_lambda_arguments_indexes.empty(); - if (has_lambda_arguments) - { - function->getLambdaArgumentTypes(argument_types); - - ProjectionNames lambda_projection_names; - for (auto & function_lambda_argument_index : function_lambda_arguments_indexes) - { - auto & lambda_argument = function_arguments[function_lambda_argument_index]; - auto lambda_to_resolve = lambda_argument->clone(); - auto & lambda_to_resolve_typed = lambda_to_resolve->as(); - - const auto & lambda_argument_names = lambda_to_resolve_typed.getArgumentNames(); - size_t lambda_arguments_size = lambda_to_resolve_typed.getArguments().getNodes().size(); - - const auto * function_data_type = typeid_cast(argument_types[function_lambda_argument_index].get()); - if (!function_data_type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' expected function data type for lambda argument with index {}. Actual {}. In scope {}", - function_name, - function_lambda_argument_index, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & function_data_type_argument_types = function_data_type->getArgumentTypes(); - size_t function_data_type_arguments_size = function_data_type_argument_types.size(); - if (function_data_type_arguments_size != lambda_arguments_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}" - "' function data type for lambda argument with index {} arguments size mismatch. " - "Actual {}. Expected {}. In scope {}", - function_name, - function_data_type_arguments_size, - lambda_arguments_size, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - QueryTreeNodes lambda_arguments; - lambda_arguments.reserve(lambda_arguments_size); - - for (size_t i = 0; i < lambda_arguments_size; ++i) - { - const auto & argument_type = function_data_type_argument_types[i]; - auto column_name_and_type = NameAndTypePair{lambda_argument_names[i], argument_type}; - lambda_arguments.push_back(std::make_shared(std::move(column_name_and_type), lambda_to_resolve)); - } - - IdentifierResolveScope lambda_scope(lambda_to_resolve, &scope /*parent_scope*/); - lambda_projection_names = resolveLambda(lambda_argument, lambda_to_resolve, lambda_arguments, lambda_scope); - - if (auto * lambda_list_node_result = lambda_to_resolve_typed.getExpression()->as()) - { - size_t lambda_list_node_result_nodes_size = lambda_list_node_result->getNodes().size(); - - if (lambda_list_node_result_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Lambda as function argument resolved as list node with size {}. Expected 1. In scope {}", - lambda_list_node_result_nodes_size, - lambda_to_resolve->formatASTForErrorMessage()); - - lambda_to_resolve_typed.getExpression() = lambda_list_node_result->getNodes().front(); - } - - if (arguments_projection_names.at(function_lambda_argument_index) == PROJECTION_NAME_PLACEHOLDER) - { - size_t lambda_projection_names_size =lambda_projection_names.size(); - if (lambda_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Lambda argument inside function expected to have 1 projection name. Actual {}", - lambda_projection_names_size); - - WriteBufferFromOwnString lambda_argument_projection_name_buffer; - lambda_argument_projection_name_buffer << "lambda("; - lambda_argument_projection_name_buffer << "tuple("; - - size_t lambda_argument_names_size = lambda_argument_names.size(); - - for (size_t i = 0; i < lambda_argument_names_size; ++i) - { - const auto & lambda_argument_name = lambda_argument_names[i]; - lambda_argument_projection_name_buffer << lambda_argument_name; - - if (i + 1 != lambda_argument_names_size) - lambda_argument_projection_name_buffer << ", "; - } - - lambda_argument_projection_name_buffer << "), "; - lambda_argument_projection_name_buffer << lambda_projection_names[0]; - lambda_argument_projection_name_buffer << ")"; - - lambda_projection_names.clear(); - - arguments_projection_names[function_lambda_argument_index] = lambda_argument_projection_name_buffer.str(); - } - - auto lambda_resolved_type = std::make_shared(function_data_type_argument_types, lambda_to_resolve_typed.getExpression()->getResultType()); - lambda_to_resolve_typed.resolve(lambda_resolved_type); - - argument_types[function_lambda_argument_index] = lambda_resolved_type; - argument_columns[function_lambda_argument_index].type = lambda_resolved_type; - function_arguments[function_lambda_argument_index] = std::move(lambda_to_resolve); - } - - /// Recalculate function projection name after lambda resolution - result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - } - - /** Create SET column for special function IN to allow constant folding - * if left and right arguments are constants. - * - * Example: SELECT * FROM test_table LIMIT 1 IN 1; - */ - if (is_special_function_in) - { - const auto * first_argument_constant_node = function_arguments[0]->as(); - const auto * second_argument_constant_node = function_arguments[1]->as(); - - if (first_argument_constant_node && second_argument_constant_node) - { - const auto & first_argument_constant_type = first_argument_constant_node->getResultType(); - const auto & second_argument_constant_literal = second_argument_constant_node->getValue(); - const auto & second_argument_constant_type = second_argument_constant_node->getResultType(); - - const auto & settings = scope.context->getSettingsRef(); - - auto result_block = getSetElementsForConstantValue(first_argument_constant_type, - second_argument_constant_literal, - second_argument_constant_type, - settings.transform_null_in); - - SizeLimits size_limits_for_set = {settings.max_rows_in_set, settings.max_bytes_in_set, settings.set_overflow_mode}; - - auto set = std::make_shared(size_limits_for_set, 0, settings.transform_null_in); - - set->setHeader(result_block.cloneEmpty().getColumnsWithTypeAndName()); - set->insertFromBlock(result_block.getColumnsWithTypeAndName()); - set->finishInsert(); - - auto future_set = std::make_shared(std::move(set)); - - /// Create constant set column for constant folding - - auto column_set = ColumnSet::create(1, std::move(future_set)); - argument_columns[1].column = ColumnConst::create(std::move(column_set), 1); - } - - argument_columns[1].type = std::make_shared(); - } - - std::shared_ptr constant_value; - - try - { - FunctionBasePtr function_base; - if (function_cache) - { - auto & cached_function = function_cache->function_base; - if (!cached_function) - cached_function = function->build(argument_columns); - - function_base = cached_function; - } - else - function_base = function->build(argument_columns); - - /// Do not constant fold get scalar functions - bool disable_constant_folding = function_name == "__getScalar" || function_name == "shardNum" || - function_name == "shardCount" || function_name == "hostName" || function_name == "tcpPort"; - - /** If function is suitable for constant folding try to convert it to constant. - * Example: SELECT plus(1, 1); - * Result: SELECT 2; - */ - if (function_base->isSuitableForConstantFolding() && !disable_constant_folding) - { - auto result_type = function_base->getResultType(); - auto executable_function = function_base->prepare(argument_columns); - - ColumnPtr column; - - if (all_arguments_constants) - { - size_t num_rows = function_arguments.empty() ? 0 : argument_columns.front().column->size(); - column = executable_function->execute(argument_columns, result_type, num_rows, true); - } - else - { - column = function_base->getConstantResultForNonConstArguments(argument_columns, result_type); - } - - if (column && column->getDataType() != result_type->getColumnType()) - throw Exception( - ErrorCodes::LOGICAL_ERROR, - "Unexpected return type from {}. Expected {}. Got {}", - function->getName(), - result_type->getColumnType(), - column->getDataType()); - - /** Do not perform constant folding if there are aggregate or arrayJoin functions inside function. - * Example: SELECT toTypeName(sum(number)) FROM numbers(10); - */ - if (column && isColumnConst(*column) && !typeid_cast(column.get())->getDataColumn().isDummy() && - !hasAggregateFunctionNodes(node) && !hasFunctionNode(node, "arrayJoin") && - /// Sanity check: do not convert large columns to constants - column->byteSize() < 1_MiB) - { - /// Replace function node with result constant node - Field column_constant_value; - column->get(0, column_constant_value); - constant_value = std::make_shared(std::move(column_constant_value), result_type); - } - } - - function_node.resolveAsFunction(std::move(function_base)); - } - catch (Exception & e) - { - e.addMessage("In scope {}", scope.scope_node->formatASTForErrorMessage()); - throw; - } - - if (constant_value) - node = std::make_shared(std::move(constant_value), node); - - return result_projection_names; -} - -/** Resolve expression node. - * Argument node can be replaced with different node, or even with list node in case of matcher resolution. - * Example: SELECT * FROM test_table; - * * - is matcher node, and it can be resolved into ListNode. - * - * Steps: - * 1. If node has alias, replace node with its value in scope alias map. Register alias in expression_aliases_in_resolve_process, to prevent resolving identifier - * which can bind to expression alias name. Check tryResolveIdentifierFromAliases documentation for additional explanation. - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * - * 2. Call specific resolve method depending on node type. - * - * If allow_table_expression = true and node is query node, then it is not evaluated as scalar subquery. - * Although if node is identifier that is resolved into query node that query is evaluated as scalar subquery. - * SELECT id, (SELECT 1) AS c FROM test_table WHERE a IN c; - * SELECT id, FROM test_table WHERE a IN (SELECT 1); - * - * 3. Special case identifier node. - * Try resolve it as expression identifier. - * Then if allow_lambda_expression = true try to resolve it as function. - * Then if allow_table_expression = true try to resolve it as table expression. - * - * 4. If node has alias, update its value in scope alias map. Deregister alias from expression_aliases_in_resolve_process. - */ -ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias) -{ - checkStackSize(); - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - /** There can be edge case, when subquery for IN function is resolved multiple times in different context. - * SELECT id IN (subquery AS value), value FROM test_table; - * When we start to resolve `value` identifier, subquery is already resolved but constant folding is not performed. - */ - auto node_type = node->getNodeType(); - if (!allow_table_expression && (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION)) - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - } - - return resolved_expression_it->second; - } - - String node_alias = node->getAlias(); - ProjectionNames result_projection_names; - - if (node_alias.empty()) - { - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - else - { - result_projection_names.push_back(node_alias); - } - - bool is_duplicated_alias = scope.aliases.nodes_with_duplicated_aliases.contains(node); - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.insert({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - /** Do not use alias table if node has alias same as some other node. - * Example: WITH x -> x + 1 AS lambda SELECT 1 AS lambda; - * During 1 AS lambda resolve if we use alias table we replace node with x -> x + 1 AS lambda. - * - * Do not use alias table if allow_table_expression = true and we resolve query node directly. - * Example: SELECT a FROM test_table WHERE id IN (SELECT 1) AS a; - * To support both (SELECT 1) AS expression in projection and (SELECT 1) as subquery in IN, do not use - * alias table because in alias table subquery could be evaluated as scalar. - */ - bool use_alias_table = !ignore_alias; - if (is_duplicated_alias || (allow_table_expression && isSubqueryNodeType(node->getNodeType()))) - use_alias_table = false; - - if (!node_alias.empty() && use_alias_table) - { - /** Node could be potentially resolved by resolving other nodes. - * SELECT b, a as b FROM test_table; - * - * To resolve b we need to resolve a. - */ - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - node = it->second; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - node = it->second; - } - } - - scope.pushExpressionNode(node); - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & identifier_node = node->as(); - auto unresolved_identifier = identifier_node.getIdentifier(); - auto resolve_identifier_expression_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier_node = resolve_identifier_expression_result.resolved_identifier; - - if (resolved_identifier_node && result_projection_names.empty() && - (resolve_identifier_expression_result.isResolvedFromJoinTree() || resolve_identifier_expression_result.isResolvedFromExpressionArguments())) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier_node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - - if (!resolved_identifier_node && allow_lambda_expression) - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::FUNCTION}, scope).resolved_identifier; - - if (!resolved_identifier_node && allow_table_expression) - { - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::TABLE_EXPRESSION}, scope).resolved_identifier; - - if (resolved_identifier_node) - { - /// If table identifier is resolved as CTE clone it and resolve - auto * subquery_node = resolved_identifier_node->as(); - auto * union_node = resolved_identifier_node->as(); - bool resolved_as_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - - if (resolved_as_cte) - { - resolved_identifier_node = resolved_identifier_node->clone(); - subquery_node = resolved_identifier_node->as(); - union_node = resolved_identifier_node->as(); - - std::string_view cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - if (subquery_node) - subquery_node->setIsCTE(false); - else - union_node->setIsCTE(false); - - IdentifierResolveScope subquery_scope(resolved_identifier_node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - /// CTE is being resolved, it's required to forbid to resolve to it again - /// because recursive CTEs are not supported, e.g.: - /// - /// WITH test1 AS (SELECT i + 1, j + 1 FROM test1) SELECT toInt64(4) i, toInt64(5) j FROM numbers(3) WHERE (i, j) IN test1; - /// - /// In this example argument of function `in` is being resolve here. If CTE `test1` is not forbidden, - /// `test1` is resolved to CTE (not to the table) in `initializeQueryJoinTreeNode` function. - ctes_in_resolve_process.insert(cte_name); - - if (subquery_node) - resolveQuery(resolved_identifier_node, subquery_scope); - else - resolveUnion(resolved_identifier_node, subquery_scope); - - ctes_in_resolve_process.erase(cte_name); - } - } - } - - if (!resolved_identifier_node) - { - std::string message_clarification; - if (allow_lambda_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::FUNCTION); - - if (allow_table_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::TABLE_EXPRESSION); - - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(unresolved_identifier, - scope, - true, - allow_lambda_expression, - allow_table_expression, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(unresolved_identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {}{} identifier '{}' in scope {}{}", - toStringLowercase(IdentifierLookupContext::EXPRESSION), - message_clarification, - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - node = std::move(resolved_identifier_node); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - { - result_projection_names.clear(); - resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - return resolved_expression_it->second; - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier '{}' resolve into list node and list node projection names are not initialized. In scope {}", - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_projection_names.empty()) - result_projection_names.push_back(unresolved_identifier.getFullName()); - - break; - } - case QueryTreeNodeType::MATCHER: - { - result_projection_names = resolveMatcher(node, scope); - break; - } - case QueryTreeNodeType::LIST: - { - /** Edge case if list expression has alias. - * Matchers cannot have aliases, but `untuple` function can. - * Example: SELECT a, untuple(CAST(('hello', 1) AS Tuple(name String, count UInt32))) AS a; - * During resolveFunction `untuple` function is replaced by list of 2 constants 'hello', 1. - */ - result_projection_names = resolveExpressionNodeList(node, scope, allow_lambda_expression, allow_lambda_expression); - break; - } - case QueryTreeNodeType::CONSTANT: - { - if (result_projection_names.empty()) - { - const auto & constant_node = node->as(); - result_projection_names.push_back(constant_node.getValueStringRepresentation()); - } - - /// Already resolved - break; - } - case QueryTreeNodeType::COLUMN: - { - auto & column_node = node->as(); - if (column_node.hasExpression()) - resolveExpressionNode(column_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (result_projection_names.empty()) - result_projection_names.push_back(column_node.getColumnName()); - - break; - } - case QueryTreeNodeType::FUNCTION: - { - auto function_projection_names = resolveFunction(node, scope); - - if (result_projection_names.empty() || node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(function_projection_names); - - break; - } - case QueryTreeNodeType::LAMBDA: - { - if (!allow_lambda_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (result_projection_names.empty()) - result_projection_names.push_back(PROJECTION_NAME_PLACEHOLDER); - - /// Lambda must be resolved by caller - break; - } - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - std::string projection_name = "_subquery_" + std::to_string(subquery_counter); - ++subquery_counter; - - if (node_type == QueryTreeNodeType::QUERY) - resolveQuery(node, subquery_scope); - else - resolveUnion(node, subquery_scope); - - if (!allow_table_expression) - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - - if (result_projection_names.empty()) - result_projection_names.push_back(std::move(projection_name)); - - break; - } - case QueryTreeNodeType::TABLE: - { - if (!allow_table_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Table {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node = node->as(); - result_projection_names.push_back(table_node.getStorageID().getFullNameNotQuoted()); - - break; - } - case QueryTreeNodeType::TRANSFORMER: - [[fallthrough]]; - case QueryTreeNodeType::SORT: - [[fallthrough]]; - case QueryTreeNodeType::INTERPOLATE: - [[fallthrough]]; - case QueryTreeNodeType::WINDOW: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::ARRAY_JOIN: - [[fallthrough]]; - case QueryTreeNodeType::JOIN: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "{} {} is not allowed in expression context. In scope {}", - node->getNodeType(), - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - validateTreeSize(node, scope.context->getSettingsRef().max_expanded_ast_elements, node_to_tree_size); - - /// Lambda can be inside the aggregate function, so we should check parent scopes. - /// Most likely only the root scope can have an arrgegate function, but let's check all just in case. - bool in_aggregate_function_scope = false; - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - in_aggregate_function_scope = in_aggregate_function_scope || scope_ptr->expressions_in_resolve_process_stack.hasAggregateFunction(); - - if (!in_aggregate_function_scope) - { - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - { - auto it = scope_ptr->nullable_group_by_keys.find(node); - if (it != scope_ptr->nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - break; - } - } - } - - /** Update aliases after expression node was resolved. - * Do not update node in alias table if we resolve it for duplicate alias. - */ - if (!node_alias.empty() && use_alias_table && !scope.group_by_use_nulls) - { - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - it->second = node; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - it->second = node; - } - } - - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.erase({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - if (!ignore_alias) - resolved_expressions.emplace(node, result_projection_names); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - return result_projection_names; -} - -/** Resolve expression node list. - * If expression is CTE subquery node it is skipped. - * If expression is resolved in list, it is flattened into initial node list. - * - * Such examples must work: - * Example: CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; SELECT plus(*) FROM test_table; - * Example: SELECT *** FROM system.one; - */ -ProjectionNames QueryAnalyzer::resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression) -{ - auto & node_list_typed = node_list->as(); - size_t node_list_size = node_list_typed.getNodes().size(); - - QueryTreeNodes result_nodes; - result_nodes.reserve(node_list_size); - - ProjectionNames result_projection_names; - - for (auto & node : node_list_typed.getNodes()) - { - auto node_to_resolve = node; - auto expression_node_projection_names = resolveExpressionNode(node_to_resolve, scope, allow_lambda_expression, allow_table_expression); - size_t expected_projection_names_size = 1; - if (auto * expression_list = node_to_resolve->as()) - { - expected_projection_names_size = expression_list->getNodes().size(); - for (auto & expression_list_node : expression_list->getNodes()) - result_nodes.push_back(expression_list_node); - } - else - { - result_nodes.push_back(std::move(node_to_resolve)); - } - - if (expression_node_projection_names.size() != expected_projection_names_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected {} projection names. Actual {}", - expected_projection_names_size, - expression_node_projection_names.size()); - - result_projection_names.insert(result_projection_names.end(), expression_node_projection_names.begin(), expression_node_projection_names.end()); - expression_node_projection_names.clear(); - } - - node_list_typed.getNodes() = std::move(result_nodes); - - return result_projection_names; -} - -/** Resolve sort columns nodes list. - */ -ProjectionNames QueryAnalyzer::resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames result_projection_names; - ProjectionNames sort_expression_projection_names; - ProjectionNames fill_from_expression_projection_names; - ProjectionNames fill_to_expression_projection_names; - ProjectionNames fill_step_expression_projection_names; - - auto & sort_node_list_typed = sort_node_list->as(); - for (auto & node : sort_node_list_typed.getNodes()) - { - auto & sort_node = node->as(); - sort_expression_projection_names = resolveExpressionNode(sort_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (auto * sort_column_list_node = sort_node.getExpression()->as()) - { - size_t sort_column_list_node_size = sort_column_list_node->getNodes().size(); - if (sort_column_list_node_size != 1) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Sort column node expression resolved into list with size {}. Expected 1. In scope {}", - sort_column_list_node_size, - scope.scope_node->formatASTForErrorMessage()); - } - - sort_node.getExpression() = sort_column_list_node->getNodes().front(); - } - - size_t sort_expression_projection_names_size = sort_expression_projection_names.size(); - if (sort_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort expression expected 1 projection name. Actual {}", - sort_expression_projection_names_size); - - if (sort_node.hasFillFrom()) - { - fill_from_expression_projection_names = resolveExpressionNode(sort_node.getFillFrom(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillFrom()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL FROM expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_from_expression_projection_names_size = fill_from_expression_projection_names.size(); - if (fill_from_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL FROM expression expected 1 projection name. Actual {}", - fill_from_expression_projection_names_size); - } - - if (sort_node.hasFillTo()) - { - fill_to_expression_projection_names = resolveExpressionNode(sort_node.getFillTo(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillTo()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL TO expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_to_expression_projection_names_size = fill_to_expression_projection_names.size(); - if (fill_to_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL TO expression expected 1 projection name. Actual {}", - fill_to_expression_projection_names_size); - } - - if (sort_node.hasFillStep()) - { - fill_step_expression_projection_names = resolveExpressionNode(sort_node.getFillStep(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillStep()->as(); - if (!constant_node) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - bool is_number = isColumnedAsNumber(constant_node->getResultType()); - bool is_interval = WhichDataType(constant_node->getResultType()).isInterval(); - if (!is_number && !is_interval) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_step_expression_projection_names_size = fill_step_expression_projection_names.size(); - if (fill_step_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort FILL STEP expression expected 1 projection name. Actual {}", - fill_step_expression_projection_names_size); - } - - auto sort_column_projection_name = calculateSortColumnProjectionName(node, - sort_expression_projection_names[0], - fill_from_expression_projection_names.empty() ? "" : fill_from_expression_projection_names.front(), - fill_to_expression_projection_names.empty() ? "" : fill_to_expression_projection_names.front(), - fill_step_expression_projection_names.empty() ? "" : fill_step_expression_projection_names.front()); - - result_projection_names.push_back(std::move(sort_column_projection_name)); - - sort_expression_projection_names.clear(); - fill_from_expression_projection_names.clear(); - fill_to_expression_projection_names.clear(); - fill_step_expression_projection_names.clear(); - } - - return result_projection_names; -} - -namespace -{ - -void expandTuplesInList(QueryTreeNodes & key_list) -{ - QueryTreeNodes expanded_keys; - expanded_keys.reserve(key_list.size()); - for (auto const & key : key_list) - { - if (auto * function = key->as(); function != nullptr && function->getFunctionName() == "tuple") - { - std::copy(function->getArguments().begin(), function->getArguments().end(), std::back_inserter(expanded_keys)); - } - else - expanded_keys.push_back(key); - } - key_list = std::move(expanded_keys); -} - -} - -/** Resolve GROUP BY clause. - */ -void QueryAnalyzer::resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope) -{ - if (query_node_typed.isGroupByWithGroupingSets()) - { - for (auto & grouping_sets_keys_list_node : query_node_typed.getGroupBy().getNodes()) - { - replaceNodesWithPositionalArguments(grouping_sets_keys_list_node, query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(grouping_sets_keys_list_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = grouping_sets_keys_list_node->as().getNodes(); - expandTuplesInList(group_by_list); - } - - if (scope.group_by_use_nulls) - { - for (const auto & grouping_set : query_node_typed.getGroupBy().getNodes()) - { - for (const auto & group_by_elem : grouping_set->as()->getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } - } - else - { - replaceNodesWithPositionalArguments(query_node_typed.getGroupByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getGroupByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = query_node_typed.getGroupBy().getNodes(); - expandTuplesInList(group_by_list); - - if (scope.group_by_use_nulls) - { - for (const auto & group_by_elem : query_node_typed.getGroupBy().getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } -} - -/** Resolve interpolate columns nodes list. - */ -void QueryAnalyzer::resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope) -{ - auto & interpolate_node_list_typed = interpolate_node_list->as(); - - for (auto & interpolate_node : interpolate_node_list_typed.getNodes()) - { - auto & interpolate_node_typed = interpolate_node->as(); - - auto * column_to_interpolate = interpolate_node_typed.getExpression()->as(); - if (!column_to_interpolate) - throw Exception(ErrorCodes::LOGICAL_ERROR, "INTERPOLATE can work only for indentifiers, but {} is found", - interpolate_node_typed.getExpression()->formatASTForErrorMessage()); - auto column_to_interpolate_name = column_to_interpolate->getIdentifier().getFullName(); - - resolveExpressionNode(interpolate_node_typed.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool is_column_constant = interpolate_node_typed.getExpression()->getNodeType() == QueryTreeNodeType::CONSTANT; - - auto & interpolation_to_resolve = interpolate_node_typed.getInterpolateExpression(); - IdentifierResolveScope interpolate_scope(interpolation_to_resolve, &scope /*parent_scope*/); - - auto fake_column_node = std::make_shared(NameAndTypePair(column_to_interpolate_name, interpolate_node_typed.getExpression()->getResultType()), interpolate_node_typed.getExpression()); - if (is_column_constant) - interpolate_scope.expression_argument_name_to_node.emplace(column_to_interpolate_name, fake_column_node); - - resolveExpressionNode(interpolation_to_resolve, interpolate_scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (is_column_constant) - interpolation_to_resolve = interpolation_to_resolve->cloneAndReplace(fake_column_node, interpolate_node_typed.getExpression()); - } -} - -/** Resolve window nodes list. - */ -void QueryAnalyzer::resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope) -{ - auto & window_node_list_typed = window_node_list->as(); - for (auto & node : window_node_list_typed.getNodes()) - resolveWindow(node, scope); -} - -NamesAndTypes QueryAnalyzer::resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames projection_names = resolveExpressionNodeList(projection_node_list, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto projection_nodes = projection_node_list->as().getNodes(); - size_t projection_nodes_size = projection_nodes.size(); - - NamesAndTypes projection_columns; - projection_columns.reserve(projection_nodes_size); - - for (size_t i = 0; i < projection_nodes_size; ++i) - { - auto projection_node = projection_nodes[i]; - - if (!isExpressionNodeType(projection_node->getNodeType())) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Projection node must be constant, function, column, query or union"); - - projection_columns.emplace_back(projection_names[i], projection_node->getResultType()); - } - - return projection_columns; -} - -/** Initialize query join tree node. - * - * 1. Resolve identifiers. - * 2. Register table, table function, query, union, join, array join nodes in scope table expressions in resolve process. - */ -void QueryAnalyzer::initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope) -{ - std::deque join_tree_node_ptrs_to_process_queue; - join_tree_node_ptrs_to_process_queue.push_back(&join_tree_node); - - while (!join_tree_node_ptrs_to_process_queue.empty()) - { - auto * current_join_tree_node_ptr = join_tree_node_ptrs_to_process_queue.front(); - join_tree_node_ptrs_to_process_queue.pop_front(); - - auto & current_join_tree_node = *current_join_tree_node_ptr; - auto current_join_tree_node_type = current_join_tree_node->getNodeType(); - - switch (current_join_tree_node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & from_table_identifier = current_join_tree_node->as(); - auto table_identifier_lookup = IdentifierLookup{from_table_identifier.getIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - - auto from_table_identifier_alias = from_table_identifier.getAlias(); - - IdentifierResolveSettings resolve_settings; - /// In join tree initialization ignore join tree as identifier lookup source - resolve_settings.allow_to_check_join_tree = false; - /** Disable resolve of subquery during identifier resolution. - * Example: SELECT * FROM (SELECT 1) AS t1, t1; - * During `t1` identifier resolution we resolve it into subquery SELECT 1, but we want to disable - * subquery resolution at this stage, because JOIN TREE of parent query is not resolved. - */ - resolve_settings.allow_to_resolve_subquery_during_identifier_resolution = false; - - scope.pushExpressionNode(current_join_tree_node); - - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, resolve_settings); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - auto resolved_identifier = table_identifier_resolve_result.resolved_identifier; - - if (!resolved_identifier) - throw Exception(ErrorCodes::UNKNOWN_TABLE, - "Unknown table expression identifier '{}' in scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - resolved_identifier = resolved_identifier->clone(); - - /// Update alias name to table expression map - auto table_expression_it = scope.aliases.alias_name_to_table_expression_node.find(from_table_identifier_alias); - if (table_expression_it != scope.aliases.alias_name_to_table_expression_node.end()) - table_expression_it->second = resolved_identifier; - - auto table_expression_modifiers = from_table_identifier.getTableExpressionModifiers(); - - auto * resolved_identifier_query_node = resolved_identifier->as(); - auto * resolved_identifier_union_node = resolved_identifier->as(); - - if (resolved_identifier_query_node || resolved_identifier_union_node) - { - if (table_expression_modifiers.has_value()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Table expression modifiers {} are not supported for subquery {}", - table_expression_modifiers->formatForErrorMessage(), - resolved_identifier->formatASTForErrorMessage()); - } - } - else if (auto * resolved_identifier_table_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else if (auto * resolved_identifier_table_function_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_function_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier in JOIN TREE '{}' resolved into unexpected table expression. In scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto current_join_tree_node_alias = current_join_tree_node->getAlias(); - resolved_identifier->setAlias(current_join_tree_node_alias); - current_join_tree_node = resolved_identifier; - - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::QUERY: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::UNION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - auto & array_join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&array_join.getTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::JOIN: - { - auto & join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&join.getLeftTableExpression()); - join_tree_node_ptrs_to_process_queue.push_back(&join.getRightTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - ++scope.joins_count; - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, UNION, ARRAY JOIN or JOIN. Actual {} {}. In scope {}", - current_join_tree_node->getNodeTypeName(), - current_join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - } -} - -/// Initialize table expression data for table expression node -void QueryAnalyzer::initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto table_expression_data_it = scope.table_expression_node_to_data.find(table_expression_node); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - return; - - TableExpressionData table_expression_data; - - if (table_node) - { - if (!table_node->getTemporaryTableName().empty()) - { - table_expression_data.table_name = table_node->getTemporaryTableName(); - table_expression_data.table_expression_name = table_node->getTemporaryTableName(); - } - else - { - const auto & table_storage_id = table_node->getStorageID(); - table_expression_data.database_name = table_storage_id.database_name; - table_expression_data.table_name = table_storage_id.table_name; - table_expression_data.table_expression_name = table_storage_id.getFullNameNotQuoted(); - } - - table_expression_data.table_expression_description = "table"; - } - else if (query_node || union_node) - { - table_expression_data.table_name = query_node ? query_node->getCTEName() : union_node->getCTEName(); - table_expression_data.table_expression_description = "subquery"; - } - else if (table_function_node) - { - table_expression_data.table_expression_description = "table_function"; - } - - if (table_expression_node->hasAlias()) - table_expression_data.table_expression_name = table_expression_node->getAlias(); - - if (table_node || table_function_node) - { - const auto & storage_snapshot = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - - auto get_column_options = GetColumnsOptions(GetColumnsOptions::All).withExtendedObjects().withVirtuals(); - if (storage_snapshot->storage.supportsSubcolumns()) - get_column_options.withSubcolumns(); - - auto column_names_and_types = storage_snapshot->getColumns(get_column_options); - table_expression_data.column_names_and_types = NamesAndTypes(column_names_and_types.begin(), column_names_and_types.end()); - - const auto & columns_description = storage_snapshot->metadata->getColumns(); - - std::vector> alias_columns_to_resolve; - ColumnNameToColumnNodeMap column_name_to_column_node; - column_name_to_column_node.reserve(column_names_and_types.size()); - - /** For ALIAS columns in table we must additionally analyze ALIAS expressions. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + 5); - * - * To do that we collect alias columns and build table column name to column node map. - * For each alias column we build identifier resolve scope, initialize it with table column name to node map - * and resolve alias column. - */ - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - for (const auto & subcolumn : columns_description.getSubcolumns(column_name_and_type.name)) - table_expression_data.subcolumn_names.insert(subcolumn.name); - const auto & column_default = columns_description.getDefault(column_name_and_type.name); - - if (column_default && column_default->kind == ColumnDefaultKind::Alias) - { - auto alias_expression = buildQueryTree(column_default->expression, scope.context); - auto column_node = std::make_shared(column_name_and_type, std::move(alias_expression), table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - alias_columns_to_resolve.emplace_back(column_name_and_type.name, column_node); - } - else - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - for (auto & [alias_column_to_resolve_name, alias_column_to_resolve] : alias_columns_to_resolve) - { - /** Alias column could be potentially resolved during resolve of other ALIAS column. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + alias_value_2, alias_value_2 ALIAS id + 5) ENGINE=TinyLog; - * - * During resolve of alias_value_1, alias_value_2 column will be resolved. - */ - alias_column_to_resolve = column_name_to_column_node[alias_column_to_resolve_name]; - - IdentifierResolveScope alias_column_resolve_scope(alias_column_to_resolve, nullptr /*parent_scope*/); - alias_column_resolve_scope.column_name_to_column_node = std::move(column_name_to_column_node); - alias_column_resolve_scope.context = scope.context; - - /// Initialize aliases in alias column scope - QueryExpressionsAliasVisitor visitor(alias_column_resolve_scope.aliases); - visitor.visit(alias_column_to_resolve->getExpression()); - - resolveExpressionNode(alias_column_resolve_scope.scope_node, - alias_column_resolve_scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - auto & resolved_expression = alias_column_to_resolve->getExpression(); - if (!resolved_expression->getResultType()->equals(*alias_column_to_resolve->getResultType())) - resolved_expression = buildCastFunction(resolved_expression, alias_column_to_resolve->getResultType(), scope.context, true); - column_name_to_column_node = std::move(alias_column_resolve_scope.column_name_to_column_node); - column_name_to_column_node[alias_column_to_resolve_name] = alias_column_to_resolve; - } - - table_expression_data.column_name_to_column_node = std::move(column_name_to_column_node); - } - else if (query_node || union_node) - { - table_expression_data.column_names_and_types = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - table_expression_data.column_name_to_column_node.reserve(table_expression_data.column_names_and_types.size()); - - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - table_expression_data.column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - table_expression_data.column_identifier_first_parts.reserve(table_expression_data.column_name_to_column_node.size()); - - for (auto & [column_name, _] : table_expression_data.column_name_to_column_node) - { - Identifier column_name_identifier(column_name); - table_expression_data.column_identifier_first_parts.insert(column_name_identifier.at(0)); - } - - if (auto * scope_query_node = scope.scope_node->as()) - { - auto left_table_expression = extractLeftTableExpression(scope_query_node->getJoinTree()); - if (table_expression_node.get() == left_table_expression.get() && - scope.joins_count == 1 && - scope.context->getSettingsRef().single_join_prefer_left_table) - table_expression_data.should_qualify_columns = false; - } - - scope.table_expression_node_to_data.emplace(table_expression_node, std::move(table_expression_data)); -} - -bool findIdentifier(const FunctionNode & function) -{ - for (const auto & argument : function.getArguments()) - { - if (argument->as()) - return true; - if (const auto * f = argument->as(); f && findIdentifier(*f)) - return true; - } - return false; -} - -/// Resolve table function node in scope -void QueryAnalyzer::resolveTableFunction(QueryTreeNodePtr & table_function_node, - IdentifierResolveScope & scope, - QueryExpressionsAliasVisitor & expressions_visitor, - bool nested_table_function) -{ - auto & table_function_node_typed = table_function_node->as(); - - if (!nested_table_function) - expressions_visitor.visit(table_function_node_typed.getArgumentsNode()); - - const auto & table_function_name = table_function_node_typed.getTableFunctionName(); - - auto & scope_context = scope.context; - - TableFunctionPtr table_function_ptr = TableFunctionFactory::instance().tryGet(table_function_name, scope_context); - if (!table_function_ptr) - { - String database_name = scope_context->getCurrentDatabase(); - String table_name; - - auto function_ast = table_function_node->toAST(); - Identifier table_identifier{table_function_name}; - if (table_identifier.getPartsSize() == 1) - { - table_name = table_identifier[0]; - } - else if (table_identifier.getPartsSize() == 2) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - - auto parametrized_view_storage = scope_context->getQueryContext()->buildParametrizedViewStorage(function_ast, database_name, table_name); - if (parametrized_view_storage) - { - auto fake_table_node = std::make_shared(parametrized_view_storage, scope_context); - fake_table_node->setAlias(table_function_node->getAlias()); - table_function_node = fake_table_node; - return; - } - - auto hints = TableFunctionFactory::instance().getHints(table_function_name); - if (!hints.empty()) - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}. Maybe you meant: {}", - table_function_name, - DB::toString(hints)); - else - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}", - table_function_name); - } - - QueryTreeNodes result_table_function_arguments; - - auto skip_analysis_arguments_indexes = table_function_ptr->skipAnalysisForArguments(table_function_node, scope_context); - - auto & table_function_arguments = table_function_node_typed.getArguments().getNodes(); - size_t table_function_arguments_size = table_function_arguments.size(); - - for (size_t table_function_argument_index = 0; table_function_argument_index < table_function_arguments_size; ++table_function_argument_index) - { - auto & table_function_argument = table_function_arguments[table_function_argument_index]; - - auto skip_argument_index_it = std::find(skip_analysis_arguments_indexes.begin(), - skip_analysis_arguments_indexes.end(), - table_function_argument_index); - if (skip_argument_index_it != skip_analysis_arguments_indexes.end()) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - if (auto * identifier_node = table_function_argument->as()) - { - const auto & unresolved_identifier = identifier_node->getIdentifier(); - auto identifier_resolve_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier = std::move(identifier_resolve_result.resolved_identifier); - - if (resolved_identifier && resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - result_table_function_arguments.push_back(std::move(resolved_identifier)); - else - result_table_function_arguments.push_back(table_function_argument); - - continue; - } - else if (auto * table_function_argument_function = table_function_argument->as()) - { - const auto & table_function_argument_function_name = table_function_argument_function->getFunctionName(); - if (TableFunctionFactory::instance().isTableFunctionName(table_function_argument_function_name)) - { - auto table_function_node_to_resolve_typed = std::make_shared(table_function_argument_function_name); - table_function_node_to_resolve_typed->getArgumentsNode() = table_function_argument_function->getArgumentsNode(); - - QueryTreeNodePtr table_function_node_to_resolve = std::move(table_function_node_to_resolve_typed); - resolveTableFunction(table_function_node_to_resolve, scope, expressions_visitor, true /*nested_table_function*/); - - result_table_function_arguments.push_back(std::move(table_function_node_to_resolve)); - continue; - } - } - - /** Table functions arguments can contain expressions with invalid identifiers. - * We cannot skip analysis for such arguments, because some table functions cannot provide - * information if analysis for argument should be skipped until other arguments will be resolved. - * - * Example: SELECT key from remote('127.0.0.{1,2}', view(select number AS key from numbers(2)), cityHash64(key)); - * Example: SELECT id from remote('127.0.0.{1,2}', 'default', 'test_table', cityHash64(id)); - */ - try - { - resolveExpressionNode(table_function_argument, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - catch (const Exception & exception) - { - if (exception.code() == ErrorCodes::UNKNOWN_IDENTIFIER) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - throw; - } - - if (auto * expression_list = table_function_argument->as()) - { - for (auto & expression_list_node : expression_list->getNodes()) - result_table_function_arguments.push_back(expression_list_node); - } - else - { - result_table_function_arguments.push_back(table_function_argument); - } - } - - table_function_node_typed.getArguments().getNodes() = std::move(result_table_function_arguments); - - auto table_function_ast = table_function_node_typed.toAST(); - table_function_ptr->parseArguments(table_function_ast, scope_context); - - - uint64_t use_structure_from_insertion_table_in_table_functions = scope_context->getSettingsRef().use_structure_from_insertion_table_in_table_functions; - if (!nested_table_function && - use_structure_from_insertion_table_in_table_functions && - scope_context->hasInsertionTable() && - table_function_ptr->needStructureHint()) - { - const auto & insertion_table = scope_context->getInsertionTable(); - if (!insertion_table.empty()) - { - const auto & insert_columns = DatabaseCatalog::instance() - .getTable(insertion_table, scope_context) - ->getInMemoryMetadataPtr() - ->getColumns(); - const auto & insert_column_names = scope_context->hasInsertionTableColumnNames() ? *scope_context->getInsertionTableColumnNames() : insert_columns.getOrdinary().getNames(); - DB::ColumnsDescription structure_hint; - - bool use_columns_from_insert_query = true; - - /// Insert table matches columns against SELECT expression by position, so we want to map - /// insert table columns to table function columns through names from SELECT expression. - - auto insert_column_name_it = insert_column_names.begin(); - auto insert_column_names_end = insert_column_names.end(); /// end iterator of the range covered by possible asterisk - auto virtual_column_names = table_function_ptr->getVirtualsToCheckBeforeUsingStructureHint(); - bool asterisk = false; - const auto & expression_list = scope.scope_node->as().getProjection(); - auto expression = expression_list.begin(); - - /// We want to go through SELECT expression list and correspond each expression to column in insert table - /// which type will be used as a hint for the file structure inference. - for (; expression != expression_list.end() && insert_column_name_it != insert_column_names_end; ++expression) - { - if (auto * identifier_node = (*expression)->as()) - { - - if (!virtual_column_names.contains(identifier_node->getIdentifier().getFullName())) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - ColumnDescription column = insert_columns.get(*insert_column_name_it); - column.name = identifier_node->getIdentifier().getFullName(); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else if (auto * matcher_node = (*expression)->as(); matcher_node && matcher_node->getMatcherType() == MatcherNodeType::ASTERISK) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Only one asterisk can be used in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - if (!structure_hint.empty()) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - asterisk = true; - } - else if (auto * function = (*expression)->as()) - { - if (use_structure_from_insertion_table_in_table_functions == 2 && findIdentifier(*function)) - { - use_columns_from_insert_query = false; - break; - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else - { - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - } - - if (use_structure_from_insertion_table_in_table_functions == 2 && !asterisk) - { - /// For input function we should check if input format supports reading subset of columns. - if (table_function_ptr->getName() == "input") - use_columns_from_insert_query = FormatFactory::instance().checkIfFormatSupportsSubsetOfColumns(scope.context->getInsertFormat(), scope.context); - else - use_columns_from_insert_query = table_function_ptr->supportsReadingSubsetOfColumns(scope.context); - } - - if (use_columns_from_insert_query) - { - if (expression == expression_list.end()) - { - /// Append tail of insert structure to the hint - if (asterisk) - { - for (; insert_column_name_it != insert_column_names_end; ++insert_column_name_it) - { - ColumnDescription column = insert_columns.get(*insert_column_name_it); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - } - - if (!structure_hint.empty()) - table_function_ptr->setStructureHint(structure_hint); - - } else if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::NUMBER_OF_COLUMNS_DOESNT_MATCH, "Number of columns in insert table less than required by SELECT expression."); - } - } - } - - auto table_function_storage = scope_context->getQueryContext()->executeTableFunction(table_function_ast, table_function_ptr); - table_function_node_typed.resolve(std::move(table_function_ptr), std::move(table_function_storage), scope_context, std::move(skip_analysis_arguments_indexes)); -} - -/// Resolve array join node in scope -void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & array_join_node_typed = array_join_node->as(); - resolveQueryJoinTreeNode(array_join_node_typed.getTableExpression(), scope, expressions_visitor); - - std::unordered_set array_join_column_names; - - /// Wrap array join expressions into column nodes, where array join expression is inner expression - - auto & array_join_nodes = array_join_node_typed.getJoinExpressions().getNodes(); - size_t array_join_nodes_size = array_join_nodes.size(); - - if (array_join_nodes_size == 0) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, - "ARRAY JOIN requires at least single expression"); - - std::vector array_join_column_expressions; - array_join_column_expressions.reserve(array_join_nodes_size); - - for (auto & array_join_expression : array_join_nodes) - { - auto array_join_expression_alias = array_join_expression->getAlias(); - - for (const auto & elem : array_join_nodes) - { - if (elem->hasAlias()) - scope.aliases.array_join_aliases.insert(elem->getAlias()); - - for (auto & child : elem->getChildren()) - { - if (child) - expressions_visitor.visit(child); - } - } - - std::string identifier_full_name; - - if (auto * identifier_node = array_join_expression->as()) - identifier_full_name = identifier_node->getIdentifier().getFullName(); - - resolveExpressionNode(array_join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/, true /*ignore_alias*/); - - auto process_array_join_expression = [&](QueryTreeNodePtr & expression) - { - auto result_type = expression->getResultType(); - bool is_array_type = isArray(result_type); - bool is_map_type = isMap(result_type); - - if (!is_array_type && !is_map_type) - throw Exception(ErrorCodes::TYPE_MISMATCH, - "ARRAY JOIN {} requires expression {} with Array or Map type. Actual {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - expression->formatASTForErrorMessage(), - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_map_type) - result_type = assert_cast(*result_type).getNestedType(); - - result_type = assert_cast(*result_type).getNestedType(); - - String array_join_column_name; - - if (!array_join_expression_alias.empty()) - { - array_join_column_name = array_join_expression_alias; - } - else if (auto * array_join_expression_inner_column = array_join_expression->as()) - { - array_join_column_name = array_join_expression_inner_column->getColumnName(); - } - else if (!identifier_full_name.empty()) - { - array_join_column_name = identifier_full_name; - } - else - { - array_join_column_name = "__array_join_expression_" + std::to_string(array_join_expressions_counter); - ++array_join_expressions_counter; - } - - if (array_join_column_names.contains(array_join_column_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "ARRAY JOIN {} multiple columns with name {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - array_join_column_name, - scope.scope_node->formatASTForErrorMessage()); - array_join_column_names.emplace(array_join_column_name); - - NameAndTypePair array_join_column(array_join_column_name, result_type); - auto array_join_column_node = std::make_shared(std::move(array_join_column), expression, array_join_node); - array_join_column_node->setAlias(array_join_expression_alias); - array_join_column_expressions.push_back(std::move(array_join_column_node)); - }; - - // Support ARRAY JOIN COLUMNS(...). COLUMNS transformer is resolved to list of columns. - if (auto * columns_list = array_join_expression->as()) - { - for (auto & array_join_subexpression : columns_list->getNodes()) - process_array_join_expression(array_join_subexpression); - } - else - { - process_array_join_expression(array_join_expression); - } - } - - array_join_nodes = std::move(array_join_column_expressions); -} - -void QueryAnalyzer::checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope) -{ - Names column_names; - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - if (join_node->as().getKind() != JoinKind::Paste) - return; - - auto * left_node = left_table_expr->as(); - auto * right_node = right_table_expr->as(); - - if (!left_node && !right_node) - return; - - if (left_node) - for (const auto & name_and_type : left_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - if (right_node) - for (const auto & name_and_type : right_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - - if (column_names.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of projection columns cannot be empty"); - - std::sort(column_names.begin(), column_names.end()); - for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is no any duplicates because it will lead to broken result - if (column_names[i] == column_names[i+1]) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add/change aliases to avoid duplication)" - "While processing '{}'", join_node->formatASTForErrorMessage()); -} - -/// Resolve join node in scope -void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & join_node_typed = join_node->as(); - - resolveQueryJoinTreeNode(join_node_typed.getLeftTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getLeftTableExpression(), scope); - - resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); - - if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) - checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope); - - if (join_node_typed.isOnJoinExpression()) - { - expressions_visitor.visit(join_node_typed.getJoinExpression()); - auto join_expression = join_node_typed.getJoinExpression(); - resolveExpressionNode(join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - join_node_typed.getJoinExpression() = std::move(join_expression); - } - else if (join_node_typed.isUsingJoinExpression()) - { - auto & join_using_list = join_node_typed.getJoinExpression()->as(); - std::unordered_set join_using_identifiers; - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto * identifier_node = join_using_node->as(); - if (!identifier_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} USING clause expected identifier. Actual {}", - join_node_typed.formatASTForErrorMessage(), - join_using_node->formatASTForErrorMessage()); - - const auto & identifier_full_name = identifier_node->getIdentifier().getFullName(); - - if (join_using_identifiers.contains(identifier_full_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} identifier '{}' appears more than once in USING clause", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name); - - join_using_identifiers.insert(identifier_full_name); - - const auto & settings = scope.context->getSettingsRef(); - - /** While resolving JOIN USING identifier, try to resolve identifier from parent subquery projection. - * Example: SELECT a + 1 AS b FROM (SELECT 1 AS a) t1 JOIN (SELECT 2 AS b) USING b - * In this case `b` is not in the left table expression, but it is in the parent subquery projection. - */ - auto try_resolve_identifier_from_query_projection = [this](const String & identifier_full_name_, - const QueryTreeNodePtr & left_table_expression, - const IdentifierResolveScope & scope_) -> QueryTreeNodePtr - { - const QueryNode * query_node = scope_.scope_node ? scope_.scope_node->as() : nullptr; - if (!query_node) - return nullptr; - - const auto & projection_list = query_node->getProjection(); - for (const auto & projection_node : projection_list.getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name_ == projection_node->getAlias()) - { - auto left_subquery = std::make_shared(query_node->getMutableContext()); - left_subquery->getProjection().getNodes().push_back(projection_node->clone()); - left_subquery->getJoinTree() = left_table_expression; - - IdentifierResolveScope left_subquery_scope(left_subquery, nullptr /*parent_scope*/); - resolveQuery(left_subquery, left_subquery_scope); - - const auto & resolved_nodes = left_subquery->getProjection().getNodes(); - if (resolved_nodes.size() == 1) - { - /// Create ColumnNode with expression from parent projection - return std::make_shared( - NameAndTypePair{identifier_full_name_, resolved_nodes.front()->getResultType()}, - resolved_nodes.front(), left_table_expression); - } - } - } - return nullptr; - }; - - QueryTreeNodePtr result_left_table_expression = nullptr; - /** With `analyzer_compatibility_join_using_top_level_identifier` alias in projection has higher priority than column from left table. - * But if aliased expression cannot be resolved from left table, we get UNKNOW_IDENTIFIER error, - * despite the fact that column from USING could be resolved from left table. - * It's compatibility with a default behavior for old analyzer. - */ - if (settings.analyzer_compatibility_join_using_top_level_identifier) - result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - IdentifierLookup identifier_lookup{identifier_node->getIdentifier(), IdentifierLookupContext::EXPRESSION}; - if (!result_left_table_expression) - result_left_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getLeftTableExpression(), scope); - - /** Here we may try to resolve identifier from projection in case it's not resolved from left table expression - * and analyzer_compatibility_join_using_top_level_identifier is disabled. - * For now we do not do this, because not all corner cases are clear. - * But let's at least mention it in error message - */ - /// if (!settings.analyzer_compatibility_join_using_top_level_identifier && !result_left_table_expression) - /// result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - if (!result_left_table_expression) - { - String extra_message; - const QueryNode * query_node = scope.scope_node ? scope.scope_node->as() : nullptr; - if (settings.analyzer_compatibility_join_using_top_level_identifier && query_node) - { - for (const auto & projection_node : query_node->getProjection().getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name == projection_node->getAlias()) - { - extra_message = fmt::format( - ", but alias '{}' is present in SELECT list." - " You may try to SET analyzer_compatibility_join_using_top_level_identifier = 1, to allow to use it in USING clause", - projection_node->formatASTForErrorMessage()); - break; - } - } - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from left table expression{}. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - extra_message, - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_left_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from left table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto result_right_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getRightTableExpression(), scope); - if (!result_right_table_expression) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - if (result_right_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto expression_types = DataTypes{result_left_table_expression->getResultType(), result_right_table_expression->getResultType()}; - DataTypePtr common_type = tryGetLeastSupertype(expression_types); - - if (!common_type) - throw Exception(ErrorCodes::NO_COMMON_TYPE, - "JOIN {} cannot infer common type for {} and {} in USING for identifier '{}'. In scope {}", - join_node_typed.formatASTForErrorMessage(), - result_left_table_expression->getResultType()->getName(), - result_right_table_expression->getResultType()->getName(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - NameAndTypePair join_using_column(identifier_full_name, common_type); - ListNodePtr join_using_expression = std::make_shared(QueryTreeNodes{result_left_table_expression, result_right_table_expression}); - auto join_using_column_node = std::make_shared(std::move(join_using_column), std::move(join_using_expression), join_node); - join_using_node = std::move(join_using_column_node); - } - } -} - -/** Resolve query join tree. - * - * Query join tree must be initialized before calling this function. - */ -void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto from_node_type = join_tree_node->getNodeType(); - - switch (from_node_type) - { - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - resolveExpressionNode(join_tree_node, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - resolveTableFunction(join_tree_node, scope, expressions_visitor, false /*nested_table_function*/); - break; - } - case QueryTreeNodeType::TABLE: - { - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - resolveArrayJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::JOIN: - { - resolveJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::IDENTIFIER: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifiers in FROM section must be already resolved. Node {}, scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, ARRAY JOIN or JOIN. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - auto join_tree_node_type = join_tree_node->getNodeType(); - if (isTableExpressionNodeType(join_tree_node_type)) - { - validateTableExpressionModifiers(join_tree_node, scope); - initializeTableExpressionData(join_tree_node, scope); - - auto & query_node = scope.scope_node->as(); - auto & mutable_context = query_node.getMutableContext(); - - if (!mutable_context->isDistributed()) - { - bool is_distributed = false; - - if (auto * table_node = join_tree_node->as()) - is_distributed = table_node->getStorage()->isRemote(); - else if (auto * table_function_node = join_tree_node->as()) - is_distributed = table_function_node->getStorage()->isRemote(); - - mutable_context->setDistributed(is_distributed); - } - } - - auto add_table_expression_alias_into_scope = [&](const QueryTreeNodePtr & table_expression_node) - { - const auto & alias_name = table_expression_node->getAlias(); - if (alias_name.empty()) - return; - - auto [it, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(alias_name, table_expression_node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Duplicate aliases {} for table expressions in FROM section are not allowed. Try to register {}. Already registered {}.", - alias_name, - table_expression_node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage()); - }; - - add_table_expression_alias_into_scope(join_tree_node); - scope.table_expressions_in_resolve_process.erase(join_tree_node.get()); -} - -/** Resolve query. - * This function modifies query node during resolve. It is caller responsibility to clone query node before resolve - * if it is needed for later use. - * - * query_node - query_tree_node that must have QueryNode type. - * scope - query scope. It is caller responsibility to create it. - * - * Resolve steps: - * 1. Validate subqueries depth, perform GROUP BY validation that does not depend on information about aggregate functions. - * 2. Initialize query scope with aliases. - * 3. Register CTE subqueries from WITH section in scope and remove them from WITH section. - * 4. Resolve JOIN TREE. - * 5. Resolve projection columns. - * 6. Resolve expressions in other query parts. - * 7. Validate nodes with duplicate aliases. - * 8. Validate aggregate functions, GROUPING function, window functions. - * 9. Remove WITH and WINDOW sections from query. - * 10. Remove aliases from expression and lambda nodes. - * 11. Resolve query tree node with projection columns. - */ -void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope) -{ - size_t max_subquery_depth = scope.context->getSettingsRef().max_subquery_depth; - if (max_subquery_depth && scope.subquery_depth > max_subquery_depth) - throw Exception(ErrorCodes::TOO_DEEP_SUBQUERIES, - "Too deep subqueries. Maximum: {}", - max_subquery_depth); - - auto & query_node_typed = query_node->as(); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.insert(query_node_typed.getCTEName()); - - bool is_rollup_or_cube = query_node_typed.isGroupByWithRollup() || query_node_typed.isGroupByWithCube(); - - if (query_node_typed.isGroupByWithGroupingSets() - && query_node_typed.isGroupByWithTotals() - && query_node_typed.getGroupBy().getNodes().size() != 1) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and GROUPING SETS are not supported together"); - - if (query_node_typed.isGroupByWithGroupingSets() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "GROUPING SETS are not supported together with ROLLUP and CUBE"); - - if (query_node_typed.isGroupByWithRollup() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithCube())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "ROLLUP is not supported together with GROUPING SETS and CUBE"); - - if (query_node_typed.isGroupByWithCube() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithRollup())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "CUBE is not supported together with GROUPING SETS and ROLLUP"); - - if (query_node_typed.hasHaving() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of HAVING"); - - if (query_node_typed.hasQualify() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of QUALIFY"); - - /// Initialize aliases in query node scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - - if (query_node_typed.hasWith()) - visitor.visit(query_node_typed.getWithNode()); - - if (!query_node_typed.getProjection().getNodes().empty()) - visitor.visit(query_node_typed.getProjectionNode()); - - if (query_node_typed.getPrewhere()) - visitor.visit(query_node_typed.getPrewhere()); - - if (query_node_typed.getWhere()) - visitor.visit(query_node_typed.getWhere()); - - if (query_node_typed.hasGroupBy()) - visitor.visit(query_node_typed.getGroupByNode()); - - if (query_node_typed.hasHaving()) - visitor.visit(query_node_typed.getHaving()); - - if (query_node_typed.hasWindow()) - visitor.visit(query_node_typed.getWindowNode()); - - if (query_node_typed.hasQualify()) - visitor.visit(query_node_typed.getQualify()); - - if (query_node_typed.hasOrderBy()) - visitor.visit(query_node_typed.getOrderByNode()); - - if (query_node_typed.hasInterpolate()) - visitor.visit(query_node_typed.getInterpolate()); - - if (query_node_typed.hasLimitByLimit()) - visitor.visit(query_node_typed.getLimitByLimit()); - - if (query_node_typed.hasLimitByOffset()) - visitor.visit(query_node_typed.getLimitByOffset()); - - if (query_node_typed.hasLimitBy()) - visitor.visit(query_node_typed.getLimitByNode()); - - if (query_node_typed.hasLimit()) - visitor.visit(query_node_typed.getLimit()); - - if (query_node_typed.hasOffset()) - visitor.visit(query_node_typed.getOffset()); - - /// Register CTE subqueries and remove them from WITH section - - auto & with_nodes = query_node_typed.getWith().getNodes(); - - for (auto & node : with_nodes) - { - auto * subquery_node = node->as(); - auto * union_node = node->as(); - - bool subquery_is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - if (!subquery_is_cte) - continue; - - const auto & cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - auto [_, inserted] = scope.cte_name_to_query_node.emplace(cte_name, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "CTE with name {} already exists. In scope {}", - cte_name, - scope.scope_node->formatASTForErrorMessage()); - } - - /** WITH section can be safely removed, because WITH section only can provide aliases to query expressions - * and CTE for other sections to use. - * - * Example: WITH 1 AS constant, (x -> x + 1) AS lambda, a AS (SELECT * FROM test_table); - */ - query_node_typed.getWith().getNodes().clear(); - - for (auto & window_node : query_node_typed.getWindow().getNodes()) - { - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - if (!parent_window_name.empty()) - { - auto window_node_it = scope.window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope.window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - scope.scope_node->formatASTForErrorMessage()); - - mergeWindowWithParentWindow(window_node, window_node_it->second, scope); - window_node_typed.setParentWindowName({}); - } - - auto [_, inserted] = scope.window_name_to_window_node.emplace(window_node_typed.getAlias(), window_node); - if (!inserted) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' is already defined. In scope {}", - window_node_typed.getAlias(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** Disable identifier cache during JOIN TREE resolve. - * Depending on JOIN expression section, identifier with same name - * can be resolved in different columns. - * - * Example: SELECT id FROM test_table AS t1 INNER JOIN test_table AS t2 ON t1.id = t2.id INNER JOIN test_table AS t3 ON t1.id = t3.id - * In first join expression ON t1.id = t2.id t1.id is resolved into test_table.id column. - * In second join expression ON t1.id = t3.id t1.id must be resolved into test_table.id column after first JOIN. - */ - scope.use_identifier_lookup_to_result_cache = false; - - if (query_node_typed.getJoinTree()) - { - TableExpressionsAliasVisitor table_expressions_visitor(scope); - table_expressions_visitor.visit(query_node_typed.getJoinTree()); - - initializeQueryJoinTreeNode(query_node_typed.getJoinTree(), scope); - scope.aliases.alias_name_to_table_expression_node.clear(); - - resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor); - } - - if (!scope.group_by_use_nulls) - scope.use_identifier_lookup_to_result_cache = true; - - /// Resolve query node sections. - - NamesAndTypes projection_columns; - - if (!scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - if (auto & prewhere_node = query_node_typed.getPrewhere()) - { - resolveExpressionNode(prewhere_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** Expressions in PREWHERE with JOIN should not change their type. - * Example: SELECT * FROM t1 JOIN t2 USING (a) PREWHERE a = 1 - * Column `a` in PREWHERE should be resolved from the left table - * and should not change its type to Nullable or to the supertype of `a` from t1 and t2. - * Here's a more complicated example where the column is somewhere inside an expression: - * SELECT a + 1 as b FROM t1 JOIN t2 USING (id) PREWHERE b = 1 - * The expression `a + 1 as b` in the projection and in PREWHERE should have different `a`. - */ - prewhere_node = prewhere_node->clone(); - ReplaceColumnsVisitor replace_visitor(scope.join_columns_with_changed_types, scope.context); - replace_visitor.visit(prewhere_node); - } - - if (query_node_typed.getWhere()) - resolveExpressionNode(query_node_typed.getWhere(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasGroupBy()) - resolveGroupByNode(query_node_typed, scope); - - if (scope.group_by_use_nulls) - { - resolved_expressions.clear(); - /// Clone is needed cause aliases share subtrees. - /// If not clone, the same (shared) subtree could be resolved again with different (Nullable) type - /// See 03023_group_by_use_nulls_analyzer_crashes - for (auto & [key, node] : scope.aliases.alias_name_to_expression_node_before_group_by) - scope.aliases.alias_name_to_expression_node_after_group_by[key] = node->clone(); - - scope.aliases.alias_name_to_expression_node = &scope.aliases.alias_name_to_expression_node_after_group_by; - } - - if (query_node_typed.hasHaving()) - resolveExpressionNode(query_node_typed.getHaving(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasWindow()) - resolveWindowNodeList(query_node_typed.getWindowNode(), scope); - - if (query_node_typed.hasQualify()) - resolveExpressionNode(query_node_typed.getQualify(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasOrderBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getOrderByNode(), query_node_typed.getProjection().getNodes(), scope); - - const auto & settings = scope.context->getSettingsRef(); - - expandOrderByAll(query_node_typed, settings); - resolveSortNodeList(query_node_typed.getOrderByNode(), scope); - } - - if (query_node_typed.hasInterpolate()) - resolveInterpolateColumnsNodeList(query_node_typed.getInterpolate(), scope); - - if (query_node_typed.hasLimitByLimit()) - { - resolveExpressionNode(query_node_typed.getLimitByLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByLimit(), "LIMIT BY LIMIT", scope); - } - - if (query_node_typed.hasLimitByOffset()) - { - resolveExpressionNode(query_node_typed.getLimitByOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByOffset(), "LIMIT BY OFFSET", scope); - } - - if (query_node_typed.hasLimitBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getLimitByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getLimitByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - - if (query_node_typed.hasLimit()) - { - resolveExpressionNode(query_node_typed.getLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimit(), "LIMIT", scope); - } - - if (query_node_typed.hasOffset()) - { - resolveExpressionNode(query_node_typed.getOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getOffset(), "OFFSET", scope); - } - - if (scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - /** Resolve nodes with duplicate aliases. - * Table expressions cannot have duplicate aliases. - * - * Such nodes during scope aliases collection are placed into duplicated array. - * After scope nodes are resolved, we can compare node with duplicate alias with - * node from scope alias table. - */ - for (const auto & node_with_duplicated_alias : scope.aliases.cloned_nodes_with_duplicated_aliases) - { - auto node = node_with_duplicated_alias; - auto node_alias = node->getAlias(); - - /// Add current alias to non cached set, because in case of cyclic alias identifier should not be substituted from cache. - /// See 02896_cyclic_aliases_crash. - resolveExpressionNode(node, scope, true /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool has_node_in_alias_table = false; - - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - if (!has_node_in_alias_table) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node {} with duplicate alias {} does not exist in alias table. In scope {}", - node->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - - node->removeAlias(); - } - - expandGroupByAll(query_node_typed); - - validateFilters(query_node); - validateAggregates(query_node, { .group_by_use_nulls = scope.group_by_use_nulls }); - - for (const auto & column : projection_columns) - { - if (isNotCreatable(column.type)) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Invalid projection column with type {}. In scope {}", - column.type->getName(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** WINDOW section can be safely removed, because WINDOW section can only provide window definition to window functions. - * - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - */ - query_node_typed.getWindow().getNodes().clear(); - - /// Remove aliases from expression and lambda nodes - - for (auto & [_, node] : *scope.aliases.alias_name_to_expression_node) - node->removeAlias(); - - for (auto & [_, node] : scope.aliases.alias_name_to_lambda_node) - node->removeAlias(); - - query_node_typed.resolveProjectionColumns(std::move(projection_columns)); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.erase(query_node_typed.getCTEName()); -} - -void QueryAnalyzer::resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope) -{ - auto & union_node_typed = union_node->as(); - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.insert(union_node_typed.getCTEName()); - - auto & queries_nodes = union_node_typed.getQueries().getNodes(); - - std::optional recursive_cte_table; - TableNodePtr recursive_cte_table_node; - - if (union_node_typed.isCTE() && union_node_typed.isRecursiveCTE()) - { - auto & non_recursive_query = queries_nodes[0]; - bool non_recursive_query_is_query_node = non_recursive_query->getNodeType() == QueryTreeNodeType::QUERY; - auto & non_recursive_query_mutable_context = non_recursive_query_is_query_node ? non_recursive_query->as().getMutableContext() - : non_recursive_query->as().getMutableContext(); - - IdentifierResolveScope non_recursive_subquery_scope(non_recursive_query, &scope /*parent_scope*/); - non_recursive_subquery_scope.subquery_depth = scope.subquery_depth + 1; - - if (non_recursive_query_is_query_node) - resolveQuery(non_recursive_query, non_recursive_subquery_scope); - else - resolveUnion(non_recursive_query, non_recursive_subquery_scope); - - auto temporary_table_columns = non_recursive_query_is_query_node - ? non_recursive_query->as().getProjectionColumns() - : non_recursive_query->as().computeProjectionColumns(); - - auto temporary_table_holder = std::make_shared( - non_recursive_query_mutable_context, - ColumnsDescription{NamesAndTypesList{temporary_table_columns.begin(), temporary_table_columns.end()}}, - ConstraintsDescription{}, - nullptr /*query*/, - true /*create_for_global_subquery*/); - auto temporary_table_storage = temporary_table_holder->getTable(); - - recursive_cte_table_node = std::make_shared(temporary_table_storage, non_recursive_query_mutable_context); - recursive_cte_table_node->setTemporaryTableName(union_node_typed.getCTEName()); - - recursive_cte_table.emplace(std::move(temporary_table_holder), std::move(temporary_table_storage), std::move(temporary_table_columns)); - } - - size_t queries_nodes_size = queries_nodes.size(); - for (size_t i = recursive_cte_table.has_value(); i < queries_nodes_size; ++i) - { - auto & query_node = queries_nodes[i]; - - IdentifierResolveScope subquery_scope(query_node, &scope /*parent_scope*/); - - if (recursive_cte_table_node) - subquery_scope.expression_argument_name_to_node[union_node_typed.getCTEName()] = recursive_cte_table_node; - - auto query_node_type = query_node->getNodeType(); - - if (query_node_type == QueryTreeNodeType::QUERY) - { - resolveQuery(query_node, subquery_scope); - } - else if (query_node_type == QueryTreeNodeType::UNION) - { - resolveUnion(query_node, subquery_scope); - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "UNION unsupported node {}. In scope {}", - query_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (recursive_cte_table && isStorageUsedInTree(recursive_cte_table->storage, union_node.get())) - { - if (union_node_typed.getUnionMode() != SelectUnionMode::UNION_ALL) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive CTE subquery {} with {} union mode is unsupported, only UNION ALL union mode is supported", - union_node_typed.formatASTForErrorMessage(), - toString(union_node_typed.getUnionMode())); - - union_node_typed.setRecursiveCTETable(std::move(*recursive_cte_table)); - } - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.erase(union_node_typed.getCTEName()); -} - -} - -QueryAnalysisPass::QueryAnalysisPass(QueryTreeNodePtr table_expression_, bool only_analyze_) - : table_expression(std::move(table_expression_)) - , only_analyze(only_analyze_) -{} - -QueryAnalysisPass::QueryAnalysisPass(bool only_analyze_) : only_analyze(only_analyze_) {} - -void QueryAnalysisPass::run(QueryTreeNodePtr & query_tree_node, ContextPtr context) -{ - QueryAnalyzer analyzer(only_analyze); - analyzer.resolve(query_tree_node, table_expression, context); - createUniqueTableAliases(query_tree_node, table_expression, context); -} - } diff --git a/src/Analyzer/QueryAnalysis/TableExpressionData.h b/src/Analyzer/QueryAnalysis/TableExpressionData.h index 3fca66e6eb8..18cbfa32366 100644 --- a/src/Analyzer/QueryAnalysis/TableExpressionData.h +++ b/src/Analyzer/QueryAnalysis/TableExpressionData.h @@ -1,403 +1,11 @@ -#include +#pragma once -#include - -#include -#include -#include - -#include -#include #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ProfileEvents -{ - extern const Event ScalarSubqueriesGlobalCacheHit; - extern const Event ScalarSubqueriesLocalCacheHit; - extern const Event ScalarSubqueriesCacheMiss; -} namespace DB { -namespace ErrorCodes -{ - extern const int UNSUPPORTED_METHOD; - extern const int UNKNOWN_IDENTIFIER; - extern const int UNKNOWN_FUNCTION; - extern const int LOGICAL_ERROR; - extern const int CYCLIC_ALIASES; - extern const int INCORRECT_RESULT_OF_SCALAR_SUBQUERY; - extern const int BAD_ARGUMENTS; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int MULTIPLE_EXPRESSIONS_FOR_ALIAS; - extern const int TYPE_MISMATCH; - extern const int AMBIGUOUS_IDENTIFIER; - extern const int INVALID_WITH_FILL_EXPRESSION; - extern const int INVALID_LIMIT_EXPRESSION; - extern const int EMPTY_LIST_OF_COLUMNS_QUERIED; - extern const int TOO_DEEP_SUBQUERIES; - extern const int UNKNOWN_AGGREGATE_FUNCTION; - extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION; - extern const int TOO_MANY_ARGUMENTS_FOR_FUNCTION; - extern const int ILLEGAL_FINAL; - extern const int SAMPLING_NOT_SUPPORTED; - extern const int NO_COMMON_TYPE; - extern const int NOT_IMPLEMENTED; - extern const int ALIAS_REQUIRED; - extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; - extern const int UNKNOWN_TABLE; - extern const int ILLEGAL_COLUMN; - extern const int NUMBER_OF_COLUMNS_DOESNT_MATCH; - extern const int FUNCTION_CANNOT_HAVE_PARAMETERS; - extern const int SYNTAX_ERROR; - extern const int UNEXPECTED_EXPRESSION; - extern const int INVALID_IDENTIFIER; -} - -/** Query analyzer implementation overview. Please check documentation in QueryAnalysisPass.h first. - * And additional documentation for each method, where special cases are described in detail. - * - * Each node in query must be resolved. For each query tree node resolved state is specific. - * - * For constant node no resolve process exists, it is resolved during construction. - * - * For table node no resolve process exists, it is resolved during construction. - * - * For function node to be resolved parameters and arguments must be resolved, function node must be initialized with concrete aggregate or - * non aggregate function and with result type. - * - * For lambda node there can be 2 different cases. - * 1. Standalone: WITH (x -> x + 1) AS lambda SELECT lambda(1); Such lambdas are inlined in query tree during query analysis pass. - * 2. Function arguments: WITH (x -> x + 1) AS lambda SELECT arrayMap(lambda, [1, 2, 3]); For such lambda resolution must - * set concrete lambda arguments (initially they are identifier nodes) and resolve lambda expression body. - * - * For query node resolve process must resolve all its inner nodes. - * - * For matcher node resolve process must replace it with matched nodes. - * - * For identifier node resolve process must replace it with concrete non identifier node. This part is most complex because - * for identifier resolution scopes and identifier lookup context play important part. - * - * ClickHouse SQL support lexical scoping for identifier resolution. Scope can be defined by query node or by expression node. - * Expression nodes that can define scope are lambdas and table ALIAS columns. - * - * Identifier lookup context can be expression, function, table. - * - * Examples: WITH (x -> x + 1) as func SELECT func() FROM func; During function `func` resolution identifier lookup is performed - * in function context. - * - * If there are no information of identifier context rules are following: - * 1. Try to resolve identifier in expression context. - * 2. Try to resolve identifier in function context, if it is allowed. Example: SELECT func(arguments); Here func identifier cannot be resolved in function context - * because query projection does not support that. - * 3. Try to resolve identifier in table context, if it is allowed. Example: SELECT table; Here table identifier cannot be resolved in function context - * because query projection does not support that. - * - * TODO: This does not supported properly before, because matchers could not be resolved from aliases. - * - * Identifiers are resolved with following rules: - * Resolution starts with current scope. - * 1. Try to resolve identifier from expression scope arguments. Lambda expression arguments are greatest priority. - * 2. Try to resolve identifier from aliases. - * 3. Try to resolve identifier from join tree if scope is query, or if there are registered table columns in scope. - * Steps 2 and 3 can be changed using prefer_column_name_to_alias setting. - * 4. If it is table lookup, try to resolve identifier from CTE. - * If identifier could not be resolved in current scope, resolution must be continued in parent scopes. - * 5. Try to resolve identifier from parent scopes. - * - * Additional rules about aliases and scopes. - * 1. Parent scope cannot refer alias from child scope. - * 2. Child scope can refer to alias in parent scope. - * - * Example: SELECT arrayMap(x -> x + 1 AS a, [1,2,3]), a; Identifier a is unknown in parent scope. - * Example: SELECT a FROM (SELECT 1 as a); Here we do not refer to alias a from child query scope. But we query it projection result, similar to tables. - * Example: WITH 1 as a SELECT (SELECT a) as b; Here in child scope identifier a is resolved using alias from parent scope. - * - * Additional rules about identifier binding. - * Bind for identifier to entity means that identifier first part match some node during analysis. - * If other parts of identifier cannot be resolved in that node, exception must be thrown. - * - * Example: - * CREATE TABLE test_table (id UInt64, compound_value Tuple(value UInt64)) ENGINE=TinyLog; - * SELECT compound_value.value, 1 AS compound_value FROM test_table; - * Identifier first part compound_value bound to entity with alias compound_value, but nested identifier part cannot be resolved from entity, - * lookup should not be continued, and exception must be thrown because if lookup continues that way identifier can be resolved from join tree. - * - * TODO: This was not supported properly before analyzer because nested identifier could not be resolved from alias. - * - * More complex example: - * CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; - * WITH cast(('Value'), 'Tuple (value UInt64') AS value SELECT (SELECT value FROM test_table); - * Identifier first part value bound to test_table column value, but nested identifier part cannot be resolved from it, - * lookup should not be continued, and exception must be thrown because if lookup continues identifier can be resolved from parent scope. - * - * TODO: Update exception messages - * TODO: Table identifiers with optional UUID. - * TODO: Lookup functions arrayReduce(sum, [1, 2, 3]); - * TODO: Support function identifier resolve from parent query scope, if lambda in parent scope does not capture any columns. - */ - -namespace -{ - -/// Identifier lookup context -enum class IdentifierLookupContext : uint8_t -{ - EXPRESSION = 0, - FUNCTION, - TABLE_EXPRESSION, -}; - -const char * toString(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "EXPRESSION"; - case IdentifierLookupContext::FUNCTION: return "FUNCTION"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "TABLE_EXPRESSION"; - } -} - -const char * toStringLowercase(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "expression"; - case IdentifierLookupContext::FUNCTION: return "function"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "table expression"; - } -} - -/** Structure that represent identifier lookup during query analysis. - * Lookup can be in query expression, function, table context. - */ -struct IdentifierLookup -{ - Identifier identifier; - IdentifierLookupContext lookup_context; - - bool isExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::EXPRESSION; - } - - bool isFunctionLookup() const - { - return lookup_context == IdentifierLookupContext::FUNCTION; - } - - bool isTableExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::TABLE_EXPRESSION; - } - - String dump() const - { - return identifier.getFullName() + ' ' + toString(lookup_context); - } -}; - -inline bool operator==(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return lhs.identifier.getFullName() == rhs.identifier.getFullName() && lhs.lookup_context == rhs.lookup_context; -} - -[[maybe_unused]] inline bool operator!=(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return !(lhs == rhs); -} - -struct IdentifierLookupHash -{ - size_t operator()(const IdentifierLookup & identifier_lookup) const - { - return std::hash()(identifier_lookup.identifier.getFullName()) ^ static_cast(identifier_lookup.lookup_context); - } -}; - -enum class IdentifierResolvePlace : UInt8 -{ - NONE = 0, - EXPRESSION_ARGUMENTS, - ALIASES, - JOIN_TREE, - /// Valid only for table lookup - CTE, - /// Valid only for table lookup - DATABASE_CATALOG -}; - -const char * toString(IdentifierResolvePlace resolved_identifier_place) -{ - switch (resolved_identifier_place) - { - case IdentifierResolvePlace::NONE: return "NONE"; - case IdentifierResolvePlace::EXPRESSION_ARGUMENTS: return "EXPRESSION_ARGUMENTS"; - case IdentifierResolvePlace::ALIASES: return "ALIASES"; - case IdentifierResolvePlace::JOIN_TREE: return "JOIN_TREE"; - case IdentifierResolvePlace::CTE: return "CTE"; - case IdentifierResolvePlace::DATABASE_CATALOG: return "DATABASE_CATALOG"; - } -} - -struct IdentifierResolveResult -{ - IdentifierResolveResult() = default; - - QueryTreeNodePtr resolved_identifier; - IdentifierResolvePlace resolve_place = IdentifierResolvePlace::NONE; - bool resolved_from_parent_scopes = false; - - [[maybe_unused]] bool isResolved() const - { - return resolve_place != IdentifierResolvePlace::NONE; - } - - [[maybe_unused]] bool isResolvedFromParentScopes() const - { - return resolved_from_parent_scopes; - } - - [[maybe_unused]] bool isResolvedFromExpressionArguments() const - { - return resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - } - - [[maybe_unused]] bool isResolvedFromAliases() const - { - return resolve_place == IdentifierResolvePlace::ALIASES; - } - - [[maybe_unused]] bool isResolvedFromJoinTree() const - { - return resolve_place == IdentifierResolvePlace::JOIN_TREE; - } - - [[maybe_unused]] bool isResolvedFromCTEs() const - { - return resolve_place == IdentifierResolvePlace::CTE; - } - - void dump(WriteBuffer & buffer) const - { - if (!resolved_identifier) - { - buffer << "unresolved"; - return; - } - - buffer << resolved_identifier->formatASTForErrorMessage() << " place " << toString(resolve_place) << " resolved from parent scopes " << resolved_from_parent_scopes; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -struct IdentifierResolveState -{ - IdentifierResolveResult resolve_result; - bool cyclic_identifier_resolve = false; -}; - -struct IdentifierResolveSettings -{ - /// Allow to check join tree during identifier resolution - bool allow_to_check_join_tree = true; - - /// Allow to check CTEs during table identifier resolution - bool allow_to_check_cte = true; - - /// Allow to check parent scopes during identifier resolution - bool allow_to_check_parent_scopes = true; - - /// Allow to check database catalog during table identifier resolution - bool allow_to_check_database_catalog = true; - - /// Allow to resolve subquery during identifier resolution - bool allow_to_resolve_subquery_during_identifier_resolution = true; -}; - struct StringTransparentHash { using is_transparent = void; @@ -421,7 +29,7 @@ struct StringTransparentHash using ColumnNameToColumnNodeMap = std::unordered_map>; -struct TableExpressionData +struct AnalysisTableExpressionData { std::string table_expression_name; std::string table_expression_description; @@ -472,8008 +80,4 @@ struct TableExpressionData } }; -class ExpressionsStack -{ -public: - void push(const QueryTreeNodePtr & node) - { - if (node->hasAlias()) - { - const auto & node_alias = node->getAlias(); - alias_name_to_expressions[node_alias].push_back(node); - } - - if (const auto * function = node->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - ++aggregate_functions_counter; - } - - expressions.emplace_back(node); - } - - void pop() - { - const auto & top_expression = expressions.back(); - const auto & top_expression_alias = top_expression->getAlias(); - - if (!top_expression_alias.empty()) - { - auto it = alias_name_to_expressions.find(top_expression_alias); - auto & alias_expressions = it->second; - alias_expressions.pop_back(); - - if (alias_expressions.empty()) - alias_name_to_expressions.erase(it); - } - - if (const auto * function = top_expression->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - --aggregate_functions_counter; - } - - expressions.pop_back(); - } - - [[maybe_unused]] const QueryTreeNodePtr & getRoot() const - { - return expressions.front(); - } - - const QueryTreeNodePtr & getTop() const - { - return expressions.back(); - } - - [[maybe_unused]] bool hasExpressionWithAlias(const std::string & alias) const - { - return alias_name_to_expressions.contains(alias); - } - - bool hasAggregateFunction() const - { - return aggregate_functions_counter > 0; - } - - QueryTreeNodePtr getExpressionWithAlias(const std::string & alias) const - { - auto expression_it = alias_name_to_expressions.find(alias); - if (expression_it == alias_name_to_expressions.end()) - return {}; - - return expression_it->second.front(); - } - - [[maybe_unused]] size_t size() const - { - return expressions.size(); - } - - bool empty() const - { - return expressions.empty(); - } - - void dump(WriteBuffer & buffer) const - { - buffer << expressions.size() << '\n'; - - for (const auto & expression : expressions) - { - buffer << "Expression "; - buffer << expression->formatASTForErrorMessage(); - - const auto & alias = expression->getAlias(); - if (!alias.empty()) - buffer << " alias " << alias; - - buffer << '\n'; - } - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } - -private: - QueryTreeNodes expressions; - size_t aggregate_functions_counter = 0; - std::unordered_map alias_name_to_expressions; -}; - -struct ScopeAliases -{ - /// Alias name to query expression node - std::unordered_map alias_name_to_expression_node_before_group_by; - std::unordered_map alias_name_to_expression_node_after_group_by; - - std::unordered_map * alias_name_to_expression_node = nullptr; - - /// Alias name to lambda node - std::unordered_map alias_name_to_lambda_node; - - /// Alias name to table expression node - std::unordered_map alias_name_to_table_expression_node; - - /// Expressions like `x as y` where we can't say whether it's a function, expression or table. - std::unordered_map transitive_aliases; - - /// Nodes with duplicated aliases - std::unordered_set nodes_with_duplicated_aliases; - std::vector cloned_nodes_with_duplicated_aliases; - - /// Names which are aliases from ARRAY JOIN. - /// This is needed to properly qualify columns from matchers and avoid name collision. - std::unordered_set array_join_aliases; - - std::unordered_map & getAliasMap(IdentifierLookupContext lookup_context) - { - switch (lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return *alias_name_to_expression_node; - case IdentifierLookupContext::FUNCTION: return alias_name_to_lambda_node; - case IdentifierLookupContext::TABLE_EXPRESSION: return alias_name_to_table_expression_node; - } - } - - enum class FindOption - { - FIRST_NAME, - FULL_NAME, - }; - - const std::string & getKey(const Identifier & identifier, FindOption find_option) - { - switch (find_option) - { - case FindOption::FIRST_NAME: return identifier.front(); - case FindOption::FULL_NAME: return identifier.getFullName(); - } - } - - QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) - { - auto & alias_map = getAliasMap(lookup.lookup_context); - const std::string * key = &getKey(lookup.identifier, find_option); - - auto it = alias_map.find(*key); - - if (it != alias_map.end()) - return &it->second; - - if (lookup.lookup_context == IdentifierLookupContext::TABLE_EXPRESSION) - return {}; - - while (it == alias_map.end()) - { - auto jt = transitive_aliases.find(*key); - if (jt == transitive_aliases.end()) - return {}; - - key = &(getKey(jt->second, find_option)); - it = alias_map.find(*key); - } - - return &it->second; - } - - const QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) const - { - return const_cast(this)->find(lookup, find_option); - } -}; - - -/** Projection names is name of query tree node that is used in projection part of query node. - * Example: SELECT id FROM test_table; - * `id` is projection name of column node - * - * Example: SELECT id AS id_alias FROM test_table; - * `id_alias` is projection name of column node - * - * Calculation of projection names is done during expression nodes resolution. This is done this way - * because after identifier node is resolved we lose information about identifier name. We could - * potentially save this information in query tree node itself, but that would require to clone it in some cases. - * Example: SELECT big_scalar_subquery AS a, a AS b, b AS c; - * All 3 nodes in projection are the same big_scalar_subquery, but they have different projection names. - * If we want to save it in query tree node, we have to clone subquery node that could lead to performance degradation. - * - * Possible solution is to separate query node metadata and query node content. So only node metadata could be cloned - * if we want to change projection name. This solution does not seem to be easy for client of query tree because projection - * name will be part of interface. If we potentially could hide projection names calculation in analyzer without introducing additional - * changes in query tree structure that would be preferable. - * - * Currently each resolve method returns projection names array. Resolve method must compute projection names of node. - * If node is resolved as list node this is case for `untuple` function or `matcher` result projection names array must contain projection names - * for result nodes. - * If node is not resolved as list node, projection names array contain single projection name for node. - * - * Rules for projection names: - * 1. If node has alias. It is node projection name. - * Except scenario where `untuple` function has alias. Example: SELECT untuple(expr) AS alias, alias. - * - * 2. For constant it is constant value string representation. - * - * 3. For identifier: - * If identifier is resolved from JOIN TREE, we want to remove additional identifier qualifications. - * Example: SELECT default.test_table.id FROM test_table. - * Result projection name is `id`. - * - * Example: SELECT t1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In example both test_table_1, test_table_2 have `id` column. - * In such case projection name is `t1.id` because if additional qualification is removed then column projection name `id` will be ambiguous. - * - * Example: SELECT default.test_table_1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In such case projection name is `test_table_1.id` because we remove unnecessary database qualification, but table name qualification cannot be removed - * because otherwise column projection name `id` will be ambiguous. - * - * If identifier is not resolved from JOIN TREE. Identifier name is projection name. - * Except scenario where `untuple` function resolved using identifier. Example: SELECT untuple(expr) AS alias, alias. - * Example: SELECT sum(1, 1) AS value, value. - * In such case both nodes have `value` projection names. - * - * Example: SELECT id AS value, value FROM test_table. - * In such case both nodes have have `value` projection names. - * - * Special case is `untuple` function. If `untuple` function specified with alias, then result nodes will have alias.tuple_column_name projection names. - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value) AS a; - * Result projection names are `value`, `a.id`. - * - * If `untuple` function does not have alias then result nodes will have `tupleElement(untuple_expression_projection_name, 'tuple_column_name') projection names. - * - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value); - * Result projection names are `value`, `tupleElement(value, 'id')`; - * - * 4. For function: - * Projection name consists from function_name(parameters_projection_names)(arguments_projection_names). - * Additionally if function is window function. Window node projection name is used with OVER clause. - * Example: function_name (parameters_names)(argument_projection_names) OVER window_name; - * Example: function_name (parameters_names)(argument_projection_names) OVER (PARTITION BY id ORDER BY id). - * Example: function_name (parameters_names)(argument_projection_names) OVER (window_name ORDER BY id). - * - * 5. For lambda: - * If it is standalone lambda that returns single expression, function projection name is used. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(1). - * Projection name is `lambda(1)`. - * - * If is it standalone lambda that returns list, projection names of list nodes are used. - * Example: WITH (x -> *) AS lambda SELECT lambda(1) FROM test_table; - * If test_table has two columns `id`, `value`. Then result projection names are `id`, `value`. - * - * If lambda is argument of function. - * Then projection name consists from lambda(tuple(lambda_arguments)(lambda_body_projection_name)); - * - * 6. For matcher: - * Matched nodes projection names are used as matcher projection names. - * - * Matched nodes must be qualified if needed. - * Example: SELECT * FROM test_table_1 AS t1, test_table_2 AS t2. - * In example table test_table_1 and test_table_2 both have `id`, `value` columns. - * Matched nodes after unqualified matcher resolve must be qualified to avoid ambiguous projection names. - * Result projection names must be `t1.id`, `t1.value`, `t2.id`, `t2.value`. - * - * There are special cases - * 1. For lambda inside APPLY matcher transformer: - * Example: SELECT * APPLY x -> toString(x) FROM test_table. - * In such case lambda argument projection name `x` will be replaced by matched node projection name. - * If table has two columns `id` and `value`. Then result projection names are `toString(id)`, `toString(value)`; - * - * 2. For unqualified matcher when JOIN tree contains JOIN with USING. - * Example: SELECT * FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING(id); - * Result projection names must be `id`, `t1.value`, `t2.value`. - * - * 7. For subquery: - * For subquery projection name consists of `_subquery_` prefix and implementation specific unique number suffix. - * Example: SELECT (SELECT 1), (SELECT 1 UNION DISTINCT SELECT 1); - * Result projection name can be `_subquery_1`, `subquery_2`; - * - * 8. For table: - * Table node can be used in expression context only as right argument of IN function. In that case identifier is used - * as table node projection name. - * Example: SELECT id IN test_table FROM test_table; - * Result projection name is `in(id, test_table)`. - */ -using ProjectionName = String; -using ProjectionNames = std::vector; -constexpr auto PROJECTION_NAME_PLACEHOLDER = "__projection_name_placeholder"; - -struct IdentifierResolveScope -{ - /// Construct identifier resolve scope using scope node, and parent scope - IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) - : scope_node(std::move(scope_node_)) - , parent_scope(parent_scope_) - { - if (parent_scope) - { - subquery_depth = parent_scope->subquery_depth; - context = parent_scope->context; - projection_mask_map = parent_scope->projection_mask_map; - } - else - projection_mask_map = std::make_shared>(); - - if (auto * union_node = scope_node->as()) - { - context = union_node->getContext(); - } - else if (auto * query_node = scope_node->as()) - { - context = query_node->getContext(); - group_by_use_nulls = context->getSettingsRef().group_by_use_nulls && - (query_node->isGroupByWithGroupingSets() || query_node->isGroupByWithRollup() || query_node->isGroupByWithCube()); - } - - if (context) - join_use_nulls = context->getSettingsRef().join_use_nulls; - else if (parent_scope) - join_use_nulls = parent_scope->join_use_nulls; - - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - QueryTreeNodePtr scope_node; - - IdentifierResolveScope * parent_scope = nullptr; - - ContextPtr context; - - /// Identifier lookup to result - std::unordered_map identifier_lookup_to_resolve_state; - - /// Argument can be expression like constant, column, function or table expression - std::unordered_map expression_argument_name_to_node; - - ScopeAliases aliases; - - /// Table column name to column node. Valid only during table ALIAS columns resolve. - ColumnNameToColumnNodeMap column_name_to_column_node; - - /// CTE name to query node - std::unordered_map cte_name_to_query_node; - - /// Window name to window node - std::unordered_map window_name_to_window_node; - - /// Current scope expression in resolve process stack - ExpressionsStack expressions_in_resolve_process_stack; - - /// Table expressions in resolve process - std::unordered_set table_expressions_in_resolve_process; - - /// Current scope expression - std::unordered_set non_cached_identifier_lookups_during_expression_resolve; - - /// Table expression node to data - std::unordered_map table_expression_node_to_data; - - QueryTreeNodePtrWithHashIgnoreTypesSet nullable_group_by_keys; - /// Here we count the number of nullable GROUP BY keys we met resolving expression. - /// E.g. for a query `SELECT tuple(tuple(number)) FROM numbers(10) GROUP BY (number, tuple(number)) with cube` - /// both `number` and `tuple(number)` would be in nullable_group_by_keys. - /// But when we resolve `tuple(tuple(number))` we should figure out that `tuple(number)` is already a key, - /// and we should not convert `number` to nullable. - size_t found_nullable_group_by_key_in_scope = 0; - - /** It's possible that after a JOIN, a column in the projection has a type different from the column in the source table. - * (For example, after join_use_nulls or USING column casted to supertype) - * However, the column in the projection still refers to the table as its source. - * This map is used to revert these columns back to their original columns in the source table. - */ - QueryTreeNodePtrWithHashMap join_columns_with_changed_types; - - /// Use identifier lookup to result cache - bool use_identifier_lookup_to_result_cache = true; - - /// Apply nullability to aggregation keys - bool group_by_use_nulls = false; - /// Join retutns NULLs instead of default values - bool join_use_nulls = false; - - /// JOINs count - size_t joins_count = 0; - - /// Subquery depth - size_t subquery_depth = 0; - - /** Scope join tree node for expression. - * Valid only during analysis construction for single expression. - */ - QueryTreeNodePtr expression_join_tree_node; - - /// Node hash to mask id map - std::shared_ptr> projection_mask_map; - - struct ResolvedFunctionsCache - { - FunctionOverloadResolverPtr resolver; - FunctionBasePtr function_base; - }; - - std::map functions_cache; - - [[maybe_unused]] const IdentifierResolveScope * getNearestQueryScope() const - { - const IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - IdentifierResolveScope * getNearestQueryScope() - { - IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - const TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - void pushExpressionNode(const QueryTreeNodePtr & node) - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.push(node); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - void popExpressionNode() - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.pop(); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_after_group_by; - } - - /// Dump identifier resolve scope - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Scope node " << scope_node->formatASTForErrorMessage() << '\n'; - buffer << "Identifier lookup to resolve state " << identifier_lookup_to_resolve_state.size() << '\n'; - for (const auto & [identifier, state] : identifier_lookup_to_resolve_state) - { - buffer << "Identifier " << identifier.dump() << " resolve result "; - state.resolve_result.dump(buffer); - buffer << '\n'; - } - - buffer << "Expression argument name to node " << expression_argument_name_to_node.size() << '\n'; - for (const auto & [alias_name, node] : expression_argument_name_to_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to expression node table size " << aliases.alias_name_to_expression_node->size() << '\n'; - for (const auto & [alias_name, node] : *aliases.alias_name_to_expression_node) - buffer << "Alias name " << alias_name << " expression node " << node->dumpTree() << '\n'; - - buffer << "Alias name to function node table size " << aliases.alias_name_to_lambda_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_lambda_node) - buffer << "Alias name " << alias_name << " lambda node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to table expression node table size " << aliases.alias_name_to_table_expression_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_table_expression_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "CTE name to query node table size " << cte_name_to_query_node.size() << '\n'; - for (const auto & [cte_name, node] : cte_name_to_query_node) - buffer << "CTE name " << cte_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "WINDOW name to window node table size " << window_name_to_window_node.size() << '\n'; - for (const auto & [window_name, node] : window_name_to_window_node) - buffer << "CTE name " << window_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Nodes with duplicated aliases size " << aliases.nodes_with_duplicated_aliases.size() << '\n'; - for (const auto & node : aliases.nodes_with_duplicated_aliases) - buffer << "Alias name " << node->getAlias() << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Expression resolve process stack " << '\n'; - expressions_in_resolve_process_stack.dump(buffer); - - buffer << "Table expressions in resolve process size " << table_expressions_in_resolve_process.size() << '\n'; - for (const auto & node : table_expressions_in_resolve_process) - buffer << "Table expression " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Non cached identifier lookups during expression resolve " << non_cached_identifier_lookups_during_expression_resolve.size() << '\n'; - for (const auto & identifier_lookup : non_cached_identifier_lookups_during_expression_resolve) - buffer << "Identifier lookup " << identifier_lookup.dump() << '\n'; - - buffer << "Table expression node to data " << table_expression_node_to_data.size() << '\n'; - for (const auto & [table_expression_node, table_expression_data] : table_expression_node_to_data) - buffer << "Table expression node " << table_expression_node->formatASTForErrorMessage() << " data " << table_expression_data.dump() << '\n'; - - buffer << "Use identifier lookup to result cache " << use_identifier_lookup_to_result_cache << '\n'; - buffer << "Subquery depth " << subquery_depth << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - - -/** Visitor that extracts expression and function aliases from node and initialize scope tables with it. - * Does not go into child lambdas and queries. - * - * Important: - * Identifier nodes with aliases are added both in alias to expression and alias to function map. - * - * These is necessary because identifier with alias can give alias name to any query tree node. - * - * Example: - * WITH (x -> x + 1) AS id, id AS value SELECT value(1); - * In this example id as value is identifier node that has alias, during scope initialization we cannot derive - * that id is actually lambda or expression. - * - * There are no easy solution here, without trying to make full featured expression resolution at this stage. - * Example: - * WITH (x -> x + 1) AS id, id AS id_1, id_1 AS id_2 SELECT id_2(1); - * Example: SELECT a, b AS a, b AS c, 1 AS c; - * - * It is client responsibility after resolving identifier node with alias, make following actions: - * 1. If identifier node was resolved in function scope, remove alias from scope expression map. - * 2. If identifier node was resolved in expression scope, remove alias from scope function map. - * - * That way we separate alias map initialization and expressions resolution. - */ -class QueryExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit QueryExpressionsAliasVisitor(ScopeAliases & aliases_) - : aliases(aliases_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node, false /*is_lambda_node*/); - } - - bool needChildVisit(const QueryTreeNodePtr &, const QueryTreeNodePtr & child) - { - if (auto * lambda_node = child->as()) - { - updateAliasesIfNeeded(child, true /*is_lambda_node*/); - return false; - } - else if (auto * query_tree_node = child->as()) - { - if (query_tree_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - else if (auto * union_node = child->as()) - { - if (union_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - - return true; - } -private: - void addDuplicatingAlias(const QueryTreeNodePtr & node) - { - aliases.nodes_with_duplicated_aliases.emplace(node); - auto cloned_node = node->clone(); - aliases.cloned_nodes_with_duplicated_aliases.emplace_back(cloned_node); - aliases.nodes_with_duplicated_aliases.emplace(cloned_node); - } - - void updateAliasesIfNeeded(const QueryTreeNodePtr & node, bool is_lambda_node) - { - if (!node->hasAlias()) - return; - - // We should not resolve expressions to WindowNode - if (node->getNodeType() == QueryTreeNodeType::WINDOW) - return; - - const auto & alias = node->getAlias(); - - if (is_lambda_node) - { - if (aliases.alias_name_to_expression_node->contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_lambda_node.insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - return; - } - - if (aliases.alias_name_to_lambda_node.contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_expression_node->insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - /// If node is identifier put it into transitive aliases map. - if (const auto * identifier = typeid_cast(node.get())) - aliases.transitive_aliases.insert(std::make_pair(alias, identifier->getIdentifier())); - } - - ScopeAliases & aliases; -}; - -class TableExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit TableExpressionsAliasVisitor(IdentifierResolveScope & scope_) - : scope(scope_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node); - } - - static bool needChildVisit(const QueryTreeNodePtr & node, const QueryTreeNodePtr & child) - { - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::ARRAY_JOIN: - { - const auto & array_join_node = node->as(); - return child.get() == array_join_node.getTableExpression().get(); - } - case QueryTreeNodeType::JOIN: - { - const auto & join_node = node->as(); - return child.get() == join_node.getLeftTableExpression().get() || child.get() == join_node.getRightTableExpression().get(); - } - default: - { - break; - } - } - - return false; - } - -private: - void updateAliasesIfNeeded(const QueryTreeNodePtr & node) - { - if (!node->hasAlias()) - return; - - const auto & node_alias = node->getAlias(); - auto [_, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(node_alias, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple table expressions with same alias {}. In scope {}", - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - IdentifierResolveScope & scope; -}; - -class QueryAnalyzer -{ -public: - explicit QueryAnalyzer(bool only_analyze_) : only_analyze(only_analyze_) {} - - void resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context) - { - IdentifierResolveScope scope(node, nullptr /*parent_scope*/); - - if (!scope.context) - scope.context = context; - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::QUERY: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For query analysis table expression must be empty"); - - resolveQuery(node, scope); - break; - } - case QueryTreeNodeType::UNION: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For union analysis table expression must be empty"); - - resolveUnion(node, scope); - break; - } - case QueryTreeNodeType::IDENTIFIER: - [[fallthrough]]; - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - [[fallthrough]]; - case QueryTreeNodeType::FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::LIST: - { - if (table_expression) - { - scope.expression_join_tree_node = table_expression; - validateTableExpressionModifiers(scope.expression_join_tree_node, scope); - initializeTableExpressionData(scope.expression_join_tree_node, scope); - } - - if (node_type == QueryTreeNodeType::LIST) - resolveExpressionNodeList(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - else - resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - QueryExpressionsAliasVisitor expressions_alias_visitor(scope.aliases); - resolveTableFunction(node, scope, expressions_alias_visitor, false /*nested_table_function*/); - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Node {} with type {} is not supported by query analyzer. " - "Supported nodes are query, union, identifier, constant, column, function, list.", - node->formatASTForErrorMessage(), - node->getNodeTypeName()); - } - } - } - -private: - /// Utility functions - - static bool isExpressionNodeType(QueryTreeNodeType node_type); - - static bool isFunctionExpressionNodeType(QueryTreeNodeType node_type); - - static bool isSubqueryNodeType(QueryTreeNodeType node_type); - - static bool isTableExpressionNodeType(QueryTreeNodeType node_type); - - static DataTypePtr getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node); - - static ProjectionName calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, - const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names); - - static ProjectionName calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name); - - static ProjectionName calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, - const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, - const ProjectionName & fill_to_expression_projection_name, - const ProjectionName & fill_step_expression_projection_name); - - static void collectCompoundExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result); - - static void collectTableExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result); - - static void collectScopeValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static void collectScopeWithParentScopesValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static std::vector collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers); - - static QueryTreeNodePtr wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path); - - QueryTreeNodePtr tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context); - - void evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & query_tree_node, IdentifierResolveScope & scope); - - static void mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope); - - void replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope); - - static void convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope); - - static void validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope); - - static std::pair recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into); - - static void expandGroupByAll(QueryNode & query_tree_node_typed); - - void expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings); - - static std::string - rewriteAggregateFunctionNameIfNeeded(const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context); - - static std::optional getColumnSideFromJoinTree(const QueryTreeNodePtr & resolved_identifier, const JoinNode & join_node) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - return {}; - - if (resolved_identifier->getNodeType() == QueryTreeNodeType::FUNCTION) - { - const auto & resolved_function = resolved_identifier->as(); - - const auto & argument_nodes = resolved_function.getArguments().getNodes(); - - std::optional result; - for (const auto & argument_node : argument_nodes) - { - auto table_side = getColumnSideFromJoinTree(argument_node, join_node); - if (table_side && result && *table_side != *result) - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Ambiguous identifier {}. In scope {}", - resolved_identifier->formatASTForErrorMessage(), - join_node.formatASTForErrorMessage()); - } - result = table_side; - } - return result; - } - - const auto * column_src = resolved_identifier->as().getColumnSource().get(); - - if (join_node.getLeftTableExpression().get() == column_src) - return JoinTableSide::Left; - if (join_node.getRightTableExpression().get() == column_src) - return JoinTableSide::Right; - return {}; - } - - static QueryTreeNodePtr convertJoinedColumnTypeToNullIfNeeded( - const QueryTreeNodePtr & resolved_identifier, - const JoinKind & join_kind, - std::optional resolved_side, - IdentifierResolveScope & scope) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && - JoinCommon::canBecomeNullable(resolved_identifier->getResultType()) && - (isFull(join_kind) || - (isLeft(join_kind) && resolved_side && *resolved_side == JoinTableSide::Right) || - (isRight(join_kind) && resolved_side && *resolved_side == JoinTableSide::Left))) - { - auto nullable_resolved_identifier = resolved_identifier->clone(); - auto & resolved_column = nullable_resolved_identifier->as(); - auto new_result_type = makeNullableOrLowCardinalityNullable(resolved_column.getColumnType()); - resolved_column.setColumnType(new_result_type); - if (resolved_column.hasExpression()) - { - auto & resolved_expression = resolved_column.getExpression(); - if (!resolved_expression->getResultType()->equals(*new_result_type)) - resolved_expression = buildCastFunction(resolved_expression, new_result_type, scope.context, true); - } - if (!nullable_resolved_identifier->isEqual(*resolved_identifier)) - scope.join_columns_with_changed_types[nullable_resolved_identifier] = resolved_identifier; - return nullable_resolved_identifier; - } - return nullptr; - } - - /// Resolve identifier functions - - static QueryTreeNodePtr tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context); - - QueryTreeNodePtr tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found = false); - - QueryTreeNodePtr tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings); - - QueryTreeNodePtr tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings = {}); - - QueryTreeNodePtr tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found = false); - - /// Resolve query tree nodes functions - - void qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static GetColumnsOptions buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context); - - using QueryTreeNodesWithNames = std::vector>; - - QueryTreeNodesWithNames getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope); - - void updateMatchedColumnsFromJoinUsing(QueryTreeNodesWithNames & result_matched_column_nodes_with_names, const QueryTreeNodePtr & source_table_expression, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionNames resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionName resolveWindow(QueryTreeNodePtr & window_node, IdentifierResolveScope & scope); - - ProjectionNames resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope); - - ProjectionNames resolveFunction(QueryTreeNodePtr & function_node, IdentifierResolveScope & scope); - - ProjectionNames resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias = false); - - ProjectionNames resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression); - - ProjectionNames resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope); - - void resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope); - - void resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope); - - void resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope); - - NamesAndTypes resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope); - - void initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope); - - void initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - void resolveTableFunction(QueryTreeNodePtr & table_function_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, bool nested_table_function); - - void resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope); - - void resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope); - - /// Lambdas that are currently in resolve process - std::unordered_set lambdas_in_resolve_process; - - /// CTEs that are currently in resolve process - std::unordered_set ctes_in_resolve_process; - - /// Function name to user defined lambda map - std::unordered_map function_name_to_user_defined_lambda; - - /// Array join expressions counter - size_t array_join_expressions_counter = 1; - - /// Subquery counter - size_t subquery_counter = 1; - - /// Global expression node to projection name map - std::unordered_map node_to_projection_name; - - /// Global resolve expression node to projection names map - std::unordered_map resolved_expressions; - - /// Global resolve expression node to tree size - std::unordered_map node_to_tree_size; - - /// Global scalar subquery to scalar value map - std::unordered_map scalar_subquery_to_scalar_value_local; - std::unordered_map scalar_subquery_to_scalar_value_global; - - const bool only_analyze; -}; - -/// Utility functions implementation - - -bool QueryAnalyzer::isExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::CONSTANT || node_type == QueryTreeNodeType::COLUMN || node_type == QueryTreeNodeType::FUNCTION - || node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isFunctionExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::LAMBDA; -} - -bool QueryAnalyzer::isSubqueryNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isTableExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::TABLE || node_type == QueryTreeNodeType::TABLE_FUNCTION || - isSubqueryNodeType(node_type); -} - -DataTypePtr QueryAnalyzer::getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node) -{ - auto node_type = query_tree_node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - { - return query_tree_node->getResultType(); - } - case QueryTreeNodeType::FUNCTION: - { - auto & function_node = query_tree_node->as(); - if (function_node.isResolved()) - return function_node.getResultType(); - break; - } - default: - { - break; - } - } - - return nullptr; -} - -ProjectionName QueryAnalyzer::calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names) -{ - const auto & function_node_typed = function_node->as(); - const auto & function_node_name = function_node_typed.getFunctionName(); - - bool is_array_function = function_node_name == "array"; - bool is_tuple_function = function_node_name == "tuple"; - - WriteBufferFromOwnString buffer; - - if (!is_array_function && !is_tuple_function) - buffer << function_node_name; - - if (!parameters_projection_names.empty()) - { - buffer << '('; - - size_t function_parameters_projection_names_size = parameters_projection_names.size(); - for (size_t i = 0; i < function_parameters_projection_names_size; ++i) - { - buffer << parameters_projection_names[i]; - - if (i + 1 != function_parameters_projection_names_size) - buffer << ", "; - } - - buffer << ')'; - } - - char open_bracket = '('; - char close_bracket = ')'; - - if (is_array_function) - { - open_bracket = '['; - close_bracket = ']'; - } - - buffer << open_bracket; - - size_t function_arguments_projection_names_size = arguments_projection_names.size(); - for (size_t i = 0; i < function_arguments_projection_names_size; ++i) - { - buffer << arguments_projection_names[i]; - - if (i + 1 != function_arguments_projection_names_size) - buffer << ", "; - } - - buffer << close_bracket; - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name) -{ - const auto & window_node_typed = window_node->as(); - const auto & window_frame = window_node_typed.getWindowFrame(); - - bool parent_window_node_has_partition_by = false; - bool parent_window_node_has_order_by = false; - - if (parent_window_node) - { - const auto & parent_window_node_typed = parent_window_node->as(); - parent_window_node_has_partition_by = parent_window_node_typed.hasPartitionBy(); - parent_window_node_has_order_by = parent_window_node_typed.hasOrderBy(); - } - - WriteBufferFromOwnString buffer; - - if (!parent_window_name.empty()) - buffer << parent_window_name; - - if (!partition_by_projection_names.empty() && !parent_window_node_has_partition_by) - { - if (!parent_window_name.empty()) - buffer << ' '; - - buffer << "PARTITION BY "; - - size_t partition_by_projection_names_size = partition_by_projection_names.size(); - for (size_t i = 0; i < partition_by_projection_names_size; ++i) - { - buffer << partition_by_projection_names[i]; - if (i + 1 != partition_by_projection_names_size) - buffer << ", "; - } - } - - if (!order_by_projection_names.empty() && !parent_window_node_has_order_by) - { - if (!partition_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << "ORDER BY "; - - size_t order_by_projection_names_size = order_by_projection_names.size(); - for (size_t i = 0; i < order_by_projection_names_size; ++i) - { - buffer << order_by_projection_names[i]; - if (i + 1 != order_by_projection_names_size) - buffer << ", "; - } - } - - if (!window_frame.is_default) - { - if (!partition_by_projection_names.empty() || !order_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << window_frame.type << " BETWEEN "; - if (window_frame.begin_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.begin_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_begin_offset_projection_name; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - - buffer << " AND "; - - if (window_frame.end_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.end_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_end_offset_projection_name; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - } - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, const ProjectionName & fill_to_expression_projection_name, const ProjectionName & fill_step_expression_projection_name) -{ - auto & sort_node_typed = sort_column_node->as(); - - WriteBufferFromOwnString sort_column_projection_name_buffer; - sort_column_projection_name_buffer << sort_expression_projection_name; - - auto sort_direction = sort_node_typed.getSortDirection(); - sort_column_projection_name_buffer << (sort_direction == SortDirection::ASCENDING ? " ASC" : " DESC"); - - auto nulls_sort_direction = sort_node_typed.getNullsSortDirection(); - - if (nulls_sort_direction) - sort_column_projection_name_buffer << " NULLS " << (nulls_sort_direction == sort_direction ? "LAST" : "FIRST"); - - if (auto collator = sort_node_typed.getCollator()) - sort_column_projection_name_buffer << " COLLATE " << collator->getLocale(); - - if (sort_node_typed.withFill()) - { - sort_column_projection_name_buffer << " WITH FILL"; - - if (sort_node_typed.hasFillFrom()) - sort_column_projection_name_buffer << " FROM " << fill_from_expression_projection_name; - - if (sort_node_typed.hasFillTo()) - sort_column_projection_name_buffer << " TO " << fill_to_expression_projection_name; - - if (sort_node_typed.hasFillStep()) - sort_column_projection_name_buffer << " STEP " << fill_step_expression_projection_name; - } - - return sort_column_projection_name_buffer.str(); -} - -/// Get valid identifiers for typo correction from compound expression -void QueryAnalyzer::collectCompoundExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result) -{ - IDataType::forEachSubcolumn([&](const auto &, const auto & name, const auto &) - { - Identifier subcolumn_indentifier(name); - size_t new_identifier_size = valid_identifier_prefix.getPartsSize() + subcolumn_indentifier.getPartsSize(); - - if (new_identifier_size == unresolved_identifier.getPartsSize()) - { - auto new_identifier = valid_identifier_prefix; - for (const auto & part : subcolumn_indentifier) - new_identifier.push_back(part); - - valid_identifiers_result.insert(std::move(new_identifier)); - } - }, ISerialization::SubstreamData(compound_expression_type->getDefaultSerialization())); -} - -/// Get valid identifiers for typo correction from table expression -void QueryAnalyzer::collectTableExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result) -{ - for (const auto & [column_name, column_node] : table_expression_data.column_name_to_column_node) - { - Identifier column_identifier(column_name); - if (unresolved_identifier.getPartsSize() == column_identifier.getPartsSize()) - valid_identifiers_result.insert(column_identifier); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier, - valid_identifiers_result); - - if (table_expression->hasAlias()) - { - Identifier column_identifier_with_alias({table_expression->getAlias()}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_alias.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_alias.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_alias); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_alias, - valid_identifiers_result); - } - - if (!table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name({table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name, - valid_identifiers_result); - } - - if (!table_expression_data.database_name.empty() && !table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name_and_database_name({table_expression_data.database_name, table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name_and_database_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name_and_database_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name_and_database_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name_and_database_name, - valid_identifiers_result); - } - } -} - -/// Get valid identifiers for typo correction from scope without looking at parent scopes -void QueryAnalyzer::collectScopeValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - bool identifier_is_short = unresolved_identifier.isShort(); - bool identifier_is_compound = unresolved_identifier.isCompound(); - - if (allow_expression_identifiers) - { - for (const auto & [name, expression] : *scope.aliases.alias_name_to_expression_node) - { - assert(expression); - auto expression_identifier = Identifier(name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - - for (const auto & [table_expression, table_expression_data] : scope.table_expression_node_to_data) - { - collectTableExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - table_expression, - table_expression_data, - valid_identifiers_result); - } - } - - if (identifier_is_short) - { - if (allow_function_identifiers) - { - for (const auto & [name, _] : *scope.aliases.alias_name_to_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - - if (allow_table_expression_identifiers) - { - for (const auto & [name, _] : scope.aliases.alias_name_to_table_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - } - - for (const auto & [argument_name, expression] : scope.expression_argument_name_to_node) - { - assert(expression); - auto expression_node_type = expression->getNodeType(); - - if (allow_expression_identifiers && isExpressionNodeType(expression_node_type)) - { - auto expression_identifier = Identifier(argument_name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - else if (identifier_is_short && allow_function_identifiers && isFunctionExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - else if (allow_table_expression_identifiers && isTableExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - } -} - -void QueryAnalyzer::collectScopeWithParentScopesValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - const IdentifierResolveScope * current_scope = &scope; - - while (current_scope) - { - collectScopeValidIdentifiersForTypoCorrection(unresolved_identifier, - *current_scope, - allow_expression_identifiers, - allow_function_identifiers, - allow_table_expression_identifiers, - valid_identifiers_result); - - current_scope = current_scope->parent_scope; - } -} - -std::vector QueryAnalyzer::collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers) -{ - std::vector prompting_strings; - prompting_strings.reserve(valid_identifiers.size()); - - for (const auto & valid_identifier : valid_identifiers) - prompting_strings.push_back(valid_identifier.getFullName()); - - return NamePrompter<1>::getHints(unresolved_identifier.getFullName(), prompting_strings); -} - -/** Wrap expression node in tuple element function calls for nested paths. - * Example: Expression node: compound_expression. Nested path: nested_path_1.nested_path_2. - * Result: tupleElement(tupleElement(compound_expression, 'nested_path_1'), 'nested_path_2'). - */ -QueryTreeNodePtr QueryAnalyzer::wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path) -{ - size_t nested_path_parts_size = nested_path.getPartsSize(); - for (size_t i = 0; i < nested_path_parts_size; ++i) - { - const auto & nested_path_part = nested_path[i]; - auto tuple_element_function = std::make_shared("tupleElement"); - - auto & tuple_element_function_arguments_nodes = tuple_element_function->getArguments().getNodes(); - tuple_element_function_arguments_nodes.reserve(2); - tuple_element_function_arguments_nodes.push_back(expression_node); - tuple_element_function_arguments_nodes.push_back(std::make_shared(nested_path_part)); - - expression_node = std::move(tuple_element_function); - } - - return expression_node; -} - -/** Try to get lambda node from sql user defined functions if sql user defined function with function name exists. - * Returns lambda node if function exists, nullptr otherwise. - */ -QueryTreeNodePtr QueryAnalyzer::tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context) -{ - auto user_defined_function = UserDefinedSQLFunctionFactory::instance().tryGet(function_name); - if (!user_defined_function) - return {}; - - auto it = function_name_to_user_defined_lambda.find(function_name); - if (it != function_name_to_user_defined_lambda.end()) - return it->second; - - const auto & create_function_query = user_defined_function->as(); - auto result_node = buildQueryTree(create_function_query->function_core, context); - if (result_node->getNodeType() != QueryTreeNodeType::LAMBDA) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "SQL user defined function {} must represent lambda expression. Actual {}", - function_name, - create_function_query->function_core->formatForErrorMessage()); - - function_name_to_user_defined_lambda.emplace(function_name, result_node); - - return result_node; -} - -bool subtreeHasViewSource(const IQueryTreeNode * node, const Context & context) -{ - if (!node) - return false; - - if (const auto * table_node = node->as()) - { - if (table_node->getStorageID().getFullNameNotQuoted() == context.getViewSource()->getStorageID().getFullNameNotQuoted()) - return true; - } - - for (const auto & child : node->getChildren()) - if (subtreeHasViewSource(child.get(), context)) - return true; - - return false; -} - -/// Evaluate scalar subquery and perform constant folding if scalar subquery does not have constant value -void QueryAnalyzer::evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - auto * query_node = node->as(); - auto * union_node = node->as(); - if (!query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node must have query or union type. Actual {} {}", - node->getNodeTypeName(), - node->formatASTForErrorMessage()); - - auto & context = scope.context; - - Block scalar_block; - - auto node_without_alias = node->clone(); - node_without_alias->removeAlias(); - - QueryTreeNodePtrWithHash node_with_hash(node_without_alias); - auto str_hash = DB::toString(node_with_hash.hash); - - bool can_use_global_scalars = !only_analyze && !(context->getViewSource() && subtreeHasViewSource(node_without_alias.get(), *context)); - - auto & scalars_cache = can_use_global_scalars ? scalar_subquery_to_scalar_value_global : scalar_subquery_to_scalar_value_local; - - if (scalars_cache.contains(node_with_hash)) - { - if (can_use_global_scalars) - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - else - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesLocalCacheHit); - - scalar_block = scalars_cache.at(node_with_hash); - } - else if (context->hasQueryContext() && can_use_global_scalars && context->getQueryContext()->hasScalar(str_hash)) - { - scalar_block = context->getQueryContext()->getScalar(str_hash); - scalar_subquery_to_scalar_value_global.emplace(node_with_hash, scalar_block); - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - } - else - { - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesCacheMiss); - auto subquery_context = Context::createCopy(context); - - Settings subquery_settings = context->getSettings(); - subquery_settings.max_result_rows = 1; - subquery_settings.extremes = false; - subquery_context->setSettings(subquery_settings); - /// When execute `INSERT INTO t WITH ... SELECT ...`, it may lead to `Unknown columns` - /// exception with this settings enabled(https://github.com/ClickHouse/ClickHouse/issues/52494). - subquery_context->setSetting("use_structure_from_insertion_table_in_table_functions", false); - - auto options = SelectQueryOptions(QueryProcessingStage::Complete, scope.subquery_depth, true /*is_subquery*/); - options.only_analyze = only_analyze; - auto interpreter = std::make_unique(node->toAST(), subquery_context, subquery_context->getViewSource(), options); - - if (only_analyze) - { - /// If query is only analyzed, then constants are not correct. - scalar_block = interpreter->getSampleBlock(); - for (auto & column : scalar_block) - { - if (column.column->empty()) - { - auto mut_col = column.column->cloneEmpty(); - mut_col->insertDefault(); - column.column = std::move(mut_col); - } - } - } - else - { - auto io = interpreter->execute(); - PullingAsyncPipelineExecutor executor(io.pipeline); - io.pipeline.setProgressCallback(context->getProgressCallback()); - io.pipeline.setProcessListElement(context->getProcessListElement()); - - Block block; - - while (block.rows() == 0 && executor.pull(block)) - { - } - - if (block.rows() == 0) - { - auto types = interpreter->getSampleBlock().getDataTypes(); - if (types.size() != 1) - types = {std::make_shared(types)}; - - auto & type = types[0]; - if (!type->isNullable()) - { - if (!type->canBeInsideNullable()) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, - "Scalar subquery returned empty result of type {} which cannot be Nullable", - type->getName()); - - type = makeNullable(type); - } - - auto scalar_column = type->createColumn(); - scalar_column->insert(Null()); - scalar_block.insert({std::move(scalar_column), type, "null"}); - } - else - { - if (block.rows() != 1) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - Block tmp_block; - while (tmp_block.rows() == 0 && executor.pull(tmp_block)) - { - } - - if (tmp_block.rows() != 0) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - block = materializeBlock(block); - size_t columns = block.columns(); - - if (columns == 1) - { - auto & column = block.getByPosition(0); - /// Here we wrap type to nullable if we can. - /// It is needed cause if subquery return no rows, it's result will be Null. - /// In case of many columns, do not check it cause tuple can't be nullable. - if (!column.type->isNullable() && column.type->canBeInsideNullable()) - { - column.type = makeNullable(column.type); - column.column = makeNullable(column.column); - } - - scalar_block = block; - } - else - { - /** Make unique column names for tuple. - * - * Example: SELECT (SELECT 2 AS x, x) - */ - makeUniqueColumnNamesInBlock(block); - - scalar_block.insert({ - ColumnTuple::create(block.getColumns()), - std::make_shared(block.getDataTypes(), block.getNames()), - "tuple"}); - } - } - } - - scalars_cache.emplace(node_with_hash, scalar_block); - if (can_use_global_scalars && context->hasQueryContext()) - context->getQueryContext()->addScalar(str_hash, scalar_block); - } - - const auto & scalar_column_with_type = scalar_block.safeGetByPosition(0); - const auto & scalar_type = scalar_column_with_type.type; - - Field scalar_value; - scalar_column_with_type.column->get(0, scalar_value); - - const auto * scalar_type_name = scalar_block.safeGetByPosition(0).type->getFamilyName(); - static const std::set useless_literal_types = {"Array", "Tuple", "AggregateFunction", "Function", "Set", "LowCardinality"}; - auto * nearest_query_scope = scope.getNearestQueryScope(); - - /// Always convert to literals when there is no query context - if (!context->getSettingsRef().enable_scalar_subquery_optimization || - !useless_literal_types.contains(scalar_type_name) || - !context->hasQueryContext() || - !nearest_query_scope) - { - auto constant_value = std::make_shared(std::move(scalar_value), scalar_type); - auto constant_node = std::make_shared(constant_value, node); - - if (constant_node->getValue().isNull()) - { - node = buildCastFunction(constant_node, constant_node->getResultType(), context); - node = std::make_shared(std::move(constant_value), node); - } - else - node = std::move(constant_node); - - return; - } - - auto & nearest_query_scope_query_node = nearest_query_scope->scope_node->as(); - auto & mutable_context = nearest_query_scope_query_node.getMutableContext(); - - auto scalar_query_hash_string = DB::toString(node_with_hash.hash) + (only_analyze ? "_analyze" : ""); - - if (mutable_context->hasQueryContext()) - mutable_context->getQueryContext()->addScalar(scalar_query_hash_string, scalar_block); - - mutable_context->addScalar(scalar_query_hash_string, scalar_block); - - std::string get_scalar_function_name = "__getScalar"; - - auto scalar_query_hash_constant_value = std::make_shared(std::move(scalar_query_hash_string), std::make_shared()); - auto scalar_query_hash_constant_node = std::make_shared(std::move(scalar_query_hash_constant_value)); - - auto get_scalar_function_node = std::make_shared(get_scalar_function_name); - get_scalar_function_node->getArguments().getNodes().push_back(std::move(scalar_query_hash_constant_node)); - - auto get_scalar_function = FunctionFactory::instance().get(get_scalar_function_name, mutable_context); - get_scalar_function_node->resolveAsFunction(get_scalar_function->build(get_scalar_function_node->getArgumentColumns())); - - node = std::move(get_scalar_function_node); -} - -void QueryAnalyzer::mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope) -{ - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - - auto & parent_window_node_typed = parent_window_node->as(); - - /** If an existing_window_name is specified it must refer to an earlier - * entry in the WINDOW list; the new window copies its partitioning clause - * from that entry, as well as its ordering clause if any. In this case - * the new window cannot specify its own PARTITION BY clause, and it can - * specify ORDER BY only if the copied window does not have one. The new - * window always uses its own frame clause; the copied window must not - * specify a frame clause. - * https://www.postgresql.org/docs/current/sql-select.html - */ - if (window_node_typed.hasPartitionBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override PARTITION BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (window_node_typed.hasOrderBy() && parent_window_node_typed.hasOrderBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override a non-empty ORDER BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (!parent_window_node_typed.getWindowFrame().is_default) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parent window '{}' is not allowed to define a frame: while processing derived window definition '{}'. In scope {}", - parent_window_name, - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - window_node_typed.getPartitionByNode() = parent_window_node_typed.getPartitionBy().clone(); - - if (parent_window_node_typed.hasOrderBy()) - window_node_typed.getOrderByNode() = parent_window_node_typed.getOrderBy().clone(); -} - -/** Replace nodes in node list with positional arguments. - * - * Example: SELECT id, value FROM test_table GROUP BY 1, 2; - * Example: SELECT id, value FROM test_table ORDER BY 1, 2; - * Example: SELECT id, value FROM test_table LIMIT 5 BY 1, 2; - */ -void QueryAnalyzer::replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope) -{ - const auto & settings = scope.context->getSettingsRef(); - if (!settings.enable_positional_arguments || scope.context->getClientInfo().query_kind != ClientInfo::QueryKind::INITIAL_QUERY) - return; - - auto & node_list_typed = node_list->as(); - - for (auto & node : node_list_typed.getNodes()) - { - auto * node_to_replace = &node; - - if (auto * sort_node = node->as()) - node_to_replace = &sort_node->getExpression(); - - auto * constant_node = (*node_to_replace)->as(); - - if (!constant_node - || (constant_node->getValue().getType() != Field::Types::UInt64 - && constant_node->getValue().getType() != Field::Types::Int64)) - continue; - - UInt64 pos; - if (constant_node->getValue().getType() == Field::Types::UInt64) - { - pos = constant_node->getValue().get(); - } - else // Int64 - { - auto value = constant_node->getValue().get(); - if (value > 0) - pos = value; - else - { - if (value < -static_cast(projection_nodes.size())) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Negative positional argument number {} is out of bounds. Expected in range [-{}, -1]. In scope {}", - value, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - pos = projection_nodes.size() + value + 1; - } - } - - if (!pos || pos > projection_nodes.size()) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Positional argument number {} is out of bounds. Expected in range [1, {}]. In scope {}", - pos, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - - --pos; - *node_to_replace = projection_nodes[pos]->clone(); - if (auto it = resolved_expressions.find(projection_nodes[pos]); it != resolved_expressions.end()) - { - resolved_expressions[*node_to_replace] = it->second; - } - } -} - -void QueryAnalyzer::convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope) -{ - const auto * limit_offset_constant_node = expression_node->as(); - if (!limit_offset_constant_node || !isNativeNumber(removeNullable(limit_offset_constant_node->getResultType()))) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} expression must be constant with numeric type. Actual {}. In scope {}", - expression_description, - expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - Field converted_value = convertFieldToType(limit_offset_constant_node->getValue(), DataTypeUInt64()); - if (converted_value.isNull()) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} numeric constant expression is not representable as UInt64", - expression_description); - - auto constant_value = std::make_shared(std::move(converted_value), std::make_shared()); - auto result_constant_node = std::make_shared(std::move(constant_value)); - result_constant_node->getSourceExpression() = limit_offset_constant_node->getSourceExpression(); - - expression_node = std::move(result_constant_node); -} - -void QueryAnalyzer::validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unexpected table expression. Expected table, table function, query or union node. Table node: {}, scope node: {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (table_node || table_function_node) - { - auto table_expression_modifiers = table_node ? table_node->getTableExpressionModifiers() : table_function_node->getTableExpressionModifiers(); - - if (table_expression_modifiers.has_value()) - { - const auto & storage = table_node ? table_node->getStorage() : table_function_node->getStorage(); - if (table_expression_modifiers->hasFinal() && !storage->supportsFinal()) - throw Exception(ErrorCodes::ILLEGAL_FINAL, - "Storage {} doesn't support FINAL", - storage->getName()); - - if (table_expression_modifiers->hasSampleSizeRatio() && !storage->supportsSampling()) - throw Exception(ErrorCodes::SAMPLING_NOT_SUPPORTED, - "Storage {} doesn't support sampling", - storage->getStorageID().getFullNameNotQuoted()); - } - } -} - -void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - bool table_expression_has_alias = table_expression_node->hasAlias(); - if (table_expression_has_alias) - return; - - if (join_node->as().getKind() == JoinKind::Paste) - return; - - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - if ((query_node && !query_node->getCTEName().empty()) || (union_node && !union_node->getCTEName().empty())) - return; - - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || - table_expression_node_type == QueryTreeNodeType::QUERY || - table_expression_node_type == QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::ALIAS_REQUIRED, - "JOIN {} no alias for subquery or table function {}. " - "In scope {} (set joined_subquery_requires_alias = 0 to disable restriction)", - join_node->formatASTForErrorMessage(), - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); -} - -std::pair QueryAnalyzer::recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into) -{ - checkStackSize(); - - if (node->as()) - { - into.push_back(node); - return {false, 1}; - } - - auto * function = node->as(); - - if (!function) - return {false, 0}; - - if (function->isAggregateFunction()) - return {true, 0}; - - UInt64 pushed_children = 0; - bool has_aggregate = false; - - for (auto & child : function->getArguments().getNodes()) - { - auto [child_has_aggregate, child_pushed_children] = recursivelyCollectMaxOrdinaryExpressions(child, into); - has_aggregate |= child_has_aggregate; - pushed_children += child_pushed_children; - } - - /// The current function is not aggregate function and there is no aggregate function in its arguments, - /// so use the current function to replace its arguments - if (!has_aggregate) - { - for (UInt64 i = 0; i < pushed_children; i++) - into.pop_back(); - - into.push_back(node); - pushed_children = 1; - } - - return {has_aggregate, pushed_children}; -} - -/** Expand GROUP BY ALL by extracting all the SELECT-ed expressions that are not aggregate functions. - * - * For a special case that if there is a function having both aggregate functions and other fields as its arguments, - * the `GROUP BY` keys will contain the maximum non-aggregate fields we can extract from it. - * - * Example: - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY ALL - * will expand as - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY substring(a, 4, 2), substring(a, 1, 2) - */ -void QueryAnalyzer::expandGroupByAll(QueryNode & query_tree_node_typed) -{ - if (!query_tree_node_typed.isGroupByAll()) - return; - - auto & group_by_nodes = query_tree_node_typed.getGroupBy().getNodes(); - auto & projection_list = query_tree_node_typed.getProjection(); - - for (auto & node : projection_list.getNodes()) - recursivelyCollectMaxOrdinaryExpressions(node, group_by_nodes); - query_tree_node_typed.setIsGroupByAll(false); -} - -void QueryAnalyzer::expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings) -{ - if (!settings.enable_order_by_all || !query_tree_node_typed.isOrderByAll()) - return; - - auto * all_node = query_tree_node_typed.getOrderBy().getNodes()[0]->as(); - if (!all_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Select analyze for not sort node."); - - auto & projection_nodes = query_tree_node_typed.getProjection().getNodes(); - auto list_node = std::make_shared(); - list_node->getNodes().reserve(projection_nodes.size()); - - for (auto & node : projection_nodes) - { - /// Detect and reject ambiguous statements: - /// E.g. for a table with columns "all", "a", "b": - /// - SELECT all, a, b ORDER BY all; -- should we sort by all columns in SELECT or by column "all"? - /// - SELECT a, b AS all ORDER BY all; -- like before but "all" as alias - /// - SELECT func(...) AS all ORDER BY all; -- like before but "all" as function - /// - SELECT a, b ORDER BY all; -- tricky in other way: does the user want to sort by columns in SELECT clause or by not SELECTed column "all"? - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - auto projection_names = resolved_expression_it->second; - if (projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected 1 projection names. Actual {}", - projection_names.size()); - if (boost::iequals(projection_names[0], "all")) - throw Exception(ErrorCodes::UNEXPECTED_EXPRESSION, - "Cannot use ORDER BY ALL to sort a column with name 'all', please disable setting `enable_order_by_all` and try again"); - } - - auto sort_node = std::make_shared(node, all_node->getSortDirection(), all_node->getNullsSortDirection()); - list_node->getNodes().push_back(sort_node); - } - - query_tree_node_typed.getOrderByNode() = list_node; - query_tree_node_typed.setIsOrderByAll(false); -} - -std::string QueryAnalyzer::rewriteAggregateFunctionNameIfNeeded( - const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context) -{ - std::string result_aggregate_function_name = aggregate_function_name; - auto aggregate_function_name_lowercase = Poco::toLower(aggregate_function_name); - - const auto & settings = context->getSettingsRef(); - - if (aggregate_function_name_lowercase == "countdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - } - else if (aggregate_function_name_lowercase == "countdistinctif" || aggregate_function_name_lowercase == "countifdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - result_aggregate_function_name += "If"; - } - - /// Replace aggregateFunctionIfDistinct into aggregateFunctionDistinctIf to make execution more optimal - if (result_aggregate_function_name.ends_with("ifdistinct")) - { - size_t prefix_length = result_aggregate_function_name.size() - strlen("ifdistinct"); - result_aggregate_function_name = result_aggregate_function_name.substr(0, prefix_length) + "DistinctIf"; - } - - bool need_add_or_null = settings.aggregate_functions_null_for_empty && !result_aggregate_function_name.ends_with("OrNull"); - if (need_add_or_null) - { - auto properties = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (!properties->returns_default_when_only_null) - result_aggregate_function_name += "OrNull"; - } - - /** Move -OrNull suffix ahead, this should execute after add -OrNull suffix. - * Used to rewrite aggregate functions with -OrNull suffix in some cases. - * Example: sumIfOrNull. - * Result: sumOrNullIf. - */ - if (result_aggregate_function_name.ends_with("OrNull")) - { - auto function_properies = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (function_properies && !function_properies->returns_default_when_only_null) - { - size_t function_name_size = result_aggregate_function_name.size(); - - static constexpr std::array suffixes_to_replace = {"MergeState", "Merge", "State", "If"}; - for (const auto & suffix : suffixes_to_replace) - { - auto suffix_string_value = String(suffix); - auto suffix_to_check = suffix_string_value + "OrNull"; - - if (!result_aggregate_function_name.ends_with(suffix_to_check)) - continue; - - result_aggregate_function_name = result_aggregate_function_name.substr(0, function_name_size - suffix_to_check.size()); - result_aggregate_function_name += "OrNull"; - result_aggregate_function_name += suffix_string_value; - - break; - } - } - } - - return result_aggregate_function_name; -} - -/// Resolve identifier functions implementation - -/// Try resolve table identifier from database catalog -QueryTreeNodePtr QueryAnalyzer::tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context) -{ - size_t parts_size = table_identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected table identifier to contain 1 or 2 parts. Actual '{}'", - table_identifier.getFullName()); - - std::string database_name; - std::string table_name; - - if (table_identifier.isCompound()) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - else - { - table_name = table_identifier[0]; - } - - StorageID storage_id(database_name, table_name); - storage_id = context->resolveStorageID(storage_id); - bool is_temporary_table = storage_id.getDatabaseName() == DatabaseCatalog::TEMPORARY_DATABASE; - - StoragePtr storage; - - if (is_temporary_table) - storage = DatabaseCatalog::instance().getTable(storage_id, context); - else - storage = DatabaseCatalog::instance().tryGetTable(storage_id, context); - - if (!storage) - return {}; - - auto storage_lock = storage->lockForShare(context->getInitialQueryId(), context->getSettingsRef().lock_acquire_timeout); - auto storage_snapshot = storage->getStorageSnapshot(storage->getInMemoryMetadataPtr(), context); - auto result = std::make_shared(std::move(storage), std::move(storage_lock), std::move(storage_snapshot)); - if (is_temporary_table) - result->setTemporaryTableName(table_name); - - return result; -} - -/// Resolve identifier from compound expression -/// If identifier cannot be resolved throw exception or return nullptr if can_be_not_found is true -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found) -{ - Identifier compound_expression_identifier; - for (size_t i = 0; i < identifier_bind_size; ++i) - compound_expression_identifier.push_back(expression_identifier[i]); - - IdentifierView nested_path(expression_identifier); - nested_path.popFirst(identifier_bind_size); - - auto expression_type = compound_expression->getResultType(); - - if (!expression_type->hasSubcolumn(nested_path.getFullName())) - { - if (auto * column = compound_expression->as()) - { - const DataTypePtr & column_type = column->getColumn().getTypeInStorage(); - if (column_type->getTypeId() == TypeIndex::Object) - { - const auto * object_type = checkAndGetDataType(column_type.get()); - if (object_type->getSchemaFormat() == "json" && object_type->hasNullableSubcolumns()) - { - QueryTreeNodePtr constant_node_null = std::make_shared(Field()); - return constant_node_null; - } - } - } - - if (can_be_not_found) - return {}; - - std::unordered_set valid_identifiers; - collectCompoundExpressionValidIdentifiersForTypoCorrection(expression_identifier, - expression_type, - compound_expression_identifier, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(expression_identifier, valid_identifiers); - - String compound_expression_from_error_message; - if (!compound_expression_source.empty()) - { - compound_expression_from_error_message += " from "; - compound_expression_from_error_message += compound_expression_source; - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier {} nested path {} cannot be resolved from type {}{}. In scope {}{}", - expression_identifier, - nested_path, - expression_type->getName(), - compound_expression_from_error_message, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - QueryTreeNodePtr get_subcolumn_function = std::make_shared("getSubcolumn"); - auto & get_subcolumn_function_arguments_nodes = get_subcolumn_function->as()->getArguments().getNodes(); - - get_subcolumn_function_arguments_nodes.reserve(2); - get_subcolumn_function_arguments_nodes.push_back(compound_expression); - get_subcolumn_function_arguments_nodes.push_back(std::make_shared(nested_path.getFullName())); - - resolveFunction(get_subcolumn_function, scope); - return get_subcolumn_function; -} - -/** Resolve identifier from expression arguments. - * - * Expression arguments can be initialized during lambda analysis or they could be provided externally. - * Expression arguments must be already resolved nodes. This is client responsibility to resolve them. - * - * Example: SELECT arrayMap(x -> x + 1, [1,2,3]); - * For lambda x -> x + 1, `x` is lambda expression argument. - * - * Resolve strategy: - * 1. Try to bind identifier to scope argument name to node map. - * 2. If identifier is binded but expression context and node type are incompatible return nullptr. - * - * It is important to support edge cases, where we lookup for table or function node, but argument has same name. - * Example: WITH (x -> x + 1) AS func, (func -> func(1) + func) AS lambda SELECT lambda(1); - * - * 3. If identifier is compound and identifier lookup is in expression context use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - auto it = scope.expression_argument_name_to_node.find(identifier_lookup.identifier.getFullName()); - bool resolve_full_identifier = it != scope.expression_argument_name_to_node.end(); - - if (!resolve_full_identifier) - { - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - it = scope.expression_argument_name_to_node.find(identifier_bind_part); - if (it == scope.expression_argument_name_to_node.end()) - return {}; - } - - auto node_type = it->second->getNodeType(); - if (identifier_lookup.isExpressionLookup() && !isExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isTableExpressionLookup() && !isTableExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isFunctionLookup() && !isFunctionExpressionNodeType(node_type)) - return {}; - - if (!resolve_full_identifier && identifier_lookup.identifier.isCompound() && identifier_lookup.isExpressionLookup()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return it->second; -} - -bool QueryAnalyzer::tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope) -{ - return scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME) != nullptr || scope.aliases.array_join_aliases.contains(identifier_lookup.identifier.front()); -} - -/** Resolve identifier from scope aliases. - * - * Resolve strategy: - * 1. If alias is registered in current expressions that are in resolve process and if top expression is not part of bottom expression with the same alias subtree - * throw cyclic aliases exception. - * Otherwise prevent cache usage for identifier lookup and return nullptr. - * - * This is special scenario where identifier has name the same as alias name in one of its parent expressions including itself. - * In such case we cannot resolve identifier from aliases because of recursion. It is client responsibility to register and deregister alias - * names during expressions resolve. - * - * We must prevent cache usage for lookup because lookup outside of expression is supposed to return other value. - * Example: SELECT (id + 1) AS id, id + 2. Lookup for id inside (id + 1) as id should return id from table, but lookup (id + 2) should return - * (id + 1) AS id. - * - * Below cases should work: - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * SELECT (id + 1) AS id FROM test_table; - * SELECT (1 + (1 + id)) AS id FROM test_table; - * - * Below cases should throw cyclic aliases exception: - * SELECT (id + b) AS id, id as b FROM test_table; - * SELECT (1 + b + 1 + id) AS id, b as c, id as b FROM test_table; - * - * 2. Depending on IdentifierLookupContext get alias name to node map from IdentifierResolveScope. - * 3. Try to bind identifier to alias name in map. If there are no such binding return nullptr. - * 4. If node in map is not resolved, resolve it. It is important in case of compound expressions. - * Example: SELECT value.a, cast('(1)', 'Tuple(a UInt64)') AS value; - * - * Special case if node is identifier node. - * Example: SELECT value, id AS value FROM test_table; - * - * Add node in current scope expressions in resolve process stack. - * Try to resolve identifier. - * If identifier is resolved, depending on lookup context, erase entry from expression or lambda map. Check QueryExpressionsAliasVisitor documentation. - * Pop node from current scope expressions in resolve process stack. - * - * 5. If identifier is compound and identifier lookup is in expression context, use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - auto * it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME); - if (it == nullptr) - return {}; - - QueryTreeNodePtr & alias_node = *it; - - if (!alias_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node with alias {} is not valid. In scope {}", - identifier_bind_part, - scope.scope_node->formatASTForErrorMessage()); - - if (auto root_expression_with_alias = scope.expressions_in_resolve_process_stack.getExpressionWithAlias(identifier_bind_part)) - { - const auto top_expression = scope.expressions_in_resolve_process_stack.getTop(); - - if (!isNodePartOfTree(top_expression.get(), root_expression_with_alias.get())) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - scope.non_cached_identifier_lookups_during_expression_resolve.insert(identifier_lookup); - return {}; - } - - auto node_type = alias_node->getNodeType(); - - /// Resolve expression if necessary - if (node_type == QueryTreeNodeType::IDENTIFIER) - { - scope.pushExpressionNode(alias_node); - - auto & alias_identifier_node = alias_node->as(); - auto identifier = alias_identifier_node.getIdentifier(); - auto lookup_result = tryResolveIdentifier(IdentifierLookup{identifier, identifier_lookup.lookup_context}, scope, identifier_resolve_settings); - if (!lookup_result.resolved_identifier) - { - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(identifier, scope, true, false, false, valid_identifiers); - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {} identifier '{}'. In scope {}{}", - toStringLowercase(identifier_lookup.lookup_context), - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - alias_node = lookup_result.resolved_identifier; - scope.popExpressionNode(); - } - else if (node_type == QueryTreeNodeType::FUNCTION) - { - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - else if (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION) - { - if (identifier_resolve_settings.allow_to_resolve_subquery_during_identifier_resolution) - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, identifier_lookup.isTableExpressionLookup() /*allow_table_expression*/); - } - - if (identifier_lookup.identifier.isCompound() && alias_node) - { - if (identifier_lookup.isExpressionLookup()) - { - return tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - 1 /*identifier_bind_size*/, - alias_node, - {} /* compound_expression_source */, - scope, - identifier_resolve_settings.allow_to_check_join_tree /* can_be_not_found */); - } - else if (identifier_lookup.isFunctionLookup() || identifier_lookup.isTableExpressionLookup()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Compound identifier '{}' cannot be resolved as {}. In scope {}", - identifier_lookup.identifier.getFullName(), - identifier_lookup.isFunctionLookup() ? "function" : "table expression", - scope.scope_node->formatASTForErrorMessage()); - } - } - - return alias_node; -} - -/** Resolve identifier from table columns. - * - * 1. If table column nodes are empty or identifier is not expression lookup return nullptr. - * 2. If identifier full name match table column use column. Save information that we resolve identifier using full name. - * 3. Else if identifier binds to table column, use column. - * 4. Try to resolve column ALIAS expression if it exists. - * 5. If identifier was compound and was not resolved using full name during step 1 use `tryResolveIdentifierFromCompoundExpression`. - * This can be the case with compound ALIAS columns. - * - * Example: - * CREATE TABLE test_table (id UInt64, value Tuple(id UInt64, value String), alias_value ALIAS value.id) ENGINE=TinyLog; - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - if (scope.column_name_to_column_node.empty() || !identifier_lookup.isExpressionLookup()) - return {}; - - const auto & identifier = identifier_lookup.identifier; - auto it = scope.column_name_to_column_node.find(identifier.getFullName()); - bool full_column_name_match = it != scope.column_name_to_column_node.end(); - - if (!full_column_name_match) - { - it = scope.column_name_to_column_node.find(identifier_lookup.identifier[0]); - if (it == scope.column_name_to_column_node.end()) - return {}; - } - - if (it->second->hasExpression()) - resolveExpressionNode(it->second->getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - QueryTreeNodePtr result = it->second; - - if (!full_column_name_match && identifier.isCompound()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return result; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - if (parts_size == 1 && path_start == table_name) - return true; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return true; - else - return false; - } - - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier)) || table_expression_data.canBindIdentifier(IdentifierView(identifier))) - return true; - - if (identifier.getPartsSize() == 1) - return false; - - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return true; - - if (identifier.getPartsSize() == 2) - return false; - - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return true; - - return false; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node_to_ignore, - const IdentifierResolveScope & scope) -{ - bool can_bind_identifier_to_table_expression = false; - - for (const auto & [table_expression_node, _] : scope.table_expression_node_to_data) - { - if (table_expression_node.get() == table_expression_node_to_ignore.get()) - continue; - - can_bind_identifier_to_table_expression = tryBindIdentifierToTableExpression(identifier_lookup, table_expression_node, scope); - if (can_bind_identifier_to_table_expression) - break; - } - - return can_bind_identifier_to_table_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found) -{ - auto identifier_without_column_qualifier = identifier; - identifier_without_column_qualifier.popFirst(identifier_column_qualifier_parts); - - /** Compound identifier cannot be resolved directly from storage if storage is not table. - * - * Example: SELECT test_table.id.value1.value2 FROM test_table; - * In table storage column test_table.id.value1.value2 will exists. - * - * Example: SELECT test_subquery.compound_expression.value FROM (SELECT compound_expression AS value) AS test_subquery; - * Here there is no column with name test_subquery.compound_expression.value, and additional wrap in tuple element is required. - */ - - QueryTreeNodePtr result_expression; - bool match_full_identifier = false; - - const auto & identifier_full_name = identifier_without_column_qualifier.getFullName(); - auto it = table_expression_data.column_name_to_column_node.find(identifier_full_name); - bool can_resolve_directly_from_storage = it != table_expression_data.column_name_to_column_node.end(); - if (can_resolve_directly_from_storage && table_expression_data.subcolumn_names.contains(identifier_full_name)) - { - /** In the case when we have an ARRAY JOIN, we should not resolve subcolumns directly from storage. - * For example, consider the following SQL query: - * SELECT ProfileEvents.Values FROM system.query_log ARRAY JOIN ProfileEvents - * In this case, ProfileEvents.Values should also be array joined, not directly resolved from storage. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - if (nearest_query_scope_query_node && nearest_query_scope_query_node->getJoinTree()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - can_resolve_directly_from_storage = false; - } - - if (can_resolve_directly_from_storage) - { - match_full_identifier = true; - result_expression = it->second; - } - else - { - it = table_expression_data.column_name_to_column_node.find(identifier_without_column_qualifier.at(0)); - if (it != table_expression_data.column_name_to_column_node.end()) - result_expression = it->second; - } - - bool clone_is_needed = true; - - String table_expression_source = table_expression_data.table_expression_description; - if (!table_expression_data.table_expression_name.empty()) - table_expression_source += " with name " + table_expression_data.table_expression_name; - - if (result_expression && !match_full_identifier && identifier_without_column_qualifier.isCompound()) - { - size_t identifier_bind_size = identifier_column_qualifier_parts + 1; - result_expression = tryResolveIdentifierFromCompoundExpression(identifier, - identifier_bind_size, - result_expression, - table_expression_source, - scope, - can_be_not_found); - if (can_be_not_found && !result_expression) - return {}; - clone_is_needed = false; - } - - if (!result_expression) - { - QueryTreeNodes nested_column_nodes; - DataTypes nested_types; - Array nested_names_array; - - for (const auto & [column_name, _] : table_expression_data.column_names_and_types) - { - Identifier column_name_identifier_without_last_part(column_name); - auto column_name_identifier_last_part = column_name_identifier_without_last_part.getParts().back(); - column_name_identifier_without_last_part.popLast(); - - if (identifier_without_column_qualifier.getFullName() != column_name_identifier_without_last_part.getFullName()) - continue; - - auto column_node_it = table_expression_data.column_name_to_column_node.find(column_name); - if (column_node_it == table_expression_data.column_name_to_column_node.end()) - continue; - - const auto & column_node = column_node_it->second; - const auto & column_type = column_node->getColumnType(); - const auto * column_type_array = typeid_cast(column_type.get()); - if (!column_type_array) - continue; - - nested_column_nodes.push_back(column_node); - nested_types.push_back(column_type_array->getNestedType()); - nested_names_array.push_back(Field(std::move(column_name_identifier_last_part))); - } - - if (!nested_types.empty()) - { - auto nested_function_node = std::make_shared("nested"); - auto & nested_function_node_arguments = nested_function_node->getArguments().getNodes(); - - auto nested_function_names_array_type = std::make_shared(std::make_shared()); - auto nested_function_names_constant_node = std::make_shared(std::move(nested_names_array), - std::move(nested_function_names_array_type)); - nested_function_node_arguments.push_back(std::move(nested_function_names_constant_node)); - nested_function_node_arguments.insert(nested_function_node_arguments.end(), - nested_column_nodes.begin(), - nested_column_nodes.end()); - - auto nested_function = FunctionFactory::instance().get(nested_function_node->getFunctionName(), scope.context); - nested_function_node->resolveAsFunction(nested_function->build(nested_function_node->getArgumentColumns())); - - clone_is_needed = false; - result_expression = std::move(nested_function_node); - } - } - - if (!result_expression) - { - if (can_be_not_found) - return {}; - std::unordered_set valid_identifiers; - collectTableExpressionValidIdentifiersForTypoCorrection(identifier, - table_expression_node, - table_expression_data, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Identifier '{}' cannot be resolved from {}. In scope {}{}", - identifier.getFullName(), - table_expression_source, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (clone_is_needed) - result_expression = result_expression->clone(); - - auto qualified_identifier = identifier; - - for (size_t i = 0; i < identifier_column_qualifier_parts; ++i) - { - auto qualified_identifier_with_removed_part = qualified_identifier; - qualified_identifier_with_removed_part.popFirst(); - - if (qualified_identifier_with_removed_part.empty()) - break; - - IdentifierLookup column_identifier_lookup = {qualified_identifier_with_removed_part, IdentifierLookupContext::EXPRESSION}; - if (tryBindIdentifierToAliases(column_identifier_lookup, scope)) - break; - - if (table_expression_data.should_qualify_columns && - tryBindIdentifierToTableExpressions(column_identifier_lookup, table_expression_node, scope)) - break; - - qualified_identifier = std::move(qualified_identifier_with_removed_part); - } - - auto qualified_identifier_full_name = qualified_identifier.getFullName(); - node_to_projection_name.emplace(result_expression, std::move(qualified_identifier_full_name)); - - return result_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (parts_size == 1 && path_start == table_name) - return table_expression_node; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return table_expression_node; - else - return {}; - } - - /** If identifier first part binds to some column start or table has full identifier name. Then we can try to find whole identifier in table. - * 1. Try to bind identifier first part to column in table, if true get full identifier from table or throw exception. - * 2. Try to bind identifier first part to table name or storage alias, if true remove first part and try to get full identifier from table or throw exception. - * Storage alias works for subquery, table function as well. - * 3. Try to bind identifier first parts to database name and table name, if true remove first two parts and try to get full identifier from table or throw exception. - */ - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier))) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/); - - if (table_expression_data.canBindIdentifier(IdentifierView(identifier))) - { - /** This check is insufficient to determine whether and identifier can be resolved from table expression. - * A further check will be performed in `tryResolveIdentifierFromStorage` to see if we have such a subcolumn. - * In cases where the subcolumn cannot be found we want to have `nullptr` instead of exception. - * So, we set `can_be_not_found = true` to have an attempt to resolve the identifier from another table expression. - * Example: `SELECT t.t from (SELECT 1 as t) AS a FULL JOIN (SELECT 1 as t) as t ON a.t = t.t;` - * Initially, we will try to resolve t.t from `a` because `t.` is bound to `1 as t`. However, as it is not a nested column, we will need to resolve it from the second table expression. - */ - auto resolved_identifier = tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/, true /*can_be_not_found*/); - if (resolved_identifier) - return resolved_identifier; - } - - if (identifier.getPartsSize() == 1) - return {}; - - const auto & table_name = table_expression_data.table_name; - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 1 /*identifier_column_qualifier_parts*/); - - if (identifier.getPartsSize() == 2) - return {}; - - const auto & database_name = table_expression_data.database_name; - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 2 /*identifier_column_qualifier_parts*/); - - return {}; -} - -QueryTreeNodePtr checkIsMissedObjectJSONSubcolumn(const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier) -{ - if (left_resolved_identifier && right_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT - && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL" && right_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (left_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (right_resolved_identifier && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & right_resolved_column = right_resolved_identifier->as(); - if (right_resolved_column.getValueStringRepresentation() == "NULL") - return right_resolved_identifier; - } - return {}; -} - -/// Used to replace columns that changed type because of JOIN to their original type -class ReplaceColumnsVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit ReplaceColumnsVisitor(const QueryTreeNodePtrWithHashMap & replacement_map_, const ContextPtr & context_) - : replacement_map(replacement_map_) - , context(context_) - {} - - /// Apply replacement transitively, because column may change it's type twice, one to have a supertype and then because of `joun_use_nulls` - static QueryTreeNodePtr findTransitiveReplacement(QueryTreeNodePtr node, const QueryTreeNodePtrWithHashMap & replacement_map_) - { - auto it = replacement_map_.find(node); - QueryTreeNodePtr result_node = nullptr; - for (; it != replacement_map_.end(); it = replacement_map_.find(result_node)) - { - if (result_node && result_node->isEqual(*it->second)) - { - Strings map_dump; - for (const auto & [k, v]: replacement_map_) - map_dump.push_back(fmt::format("{} -> {} (is_equals: {}, is_same: {})", - k.node->dumpTree(), v->dumpTree(), k.node->isEqual(*v), k.node == v)); - throw Exception(ErrorCodes::LOGICAL_ERROR, "Infinite loop in query tree replacement map: {}", fmt::join(map_dump, "; ")); - } - chassert(it->second); - - result_node = it->second; - } - return result_node; - } - - void visitImpl(QueryTreeNodePtr & node) - { - if (auto replacement_node = findTransitiveReplacement(node, replacement_map)) - node = replacement_node; - - if (auto * function_node = node->as(); function_node && function_node->isResolved()) - rerunFunctionResolve(function_node, context); - } - - /// We want to re-run resolve for function _after_ its arguments are replaced - bool shouldTraverseTopToBottom() const { return false; } - - bool needChildVisit(QueryTreeNodePtr & /* parent */, QueryTreeNodePtr & child) - { - /// Visit only expressions, but not subqueries - return child->getNodeType() == QueryTreeNodeType::IDENTIFIER - || child->getNodeType() == QueryTreeNodeType::LIST - || child->getNodeType() == QueryTreeNodeType::FUNCTION - || child->getNodeType() == QueryTreeNodeType::COLUMN; - } - -private: - const QueryTreeNodePtrWithHashMap & replacement_map; - const ContextPtr & context; -}; - -/// Compare resolved identifiers considering columns that become nullable after JOIN -bool resolvedIdenfiersFromJoinAreEquals( - const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier, - const IdentifierResolveScope & scope) -{ - auto left_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(left_resolved_identifier, scope.join_columns_with_changed_types); - const auto & left_resolved_to_compare = left_original_node ? left_original_node : left_resolved_identifier; - - auto right_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(right_resolved_identifier, scope.join_columns_with_changed_types); - const auto & right_resolved_to_compare = right_original_node ? right_original_node : right_resolved_identifier; - - return left_resolved_to_compare->isEqual(*right_resolved_to_compare, IQueryTreeNode::CompareOptions{.compare_aliases = false}); -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_join_node = table_expression_node->as(); - auto left_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getLeftTableExpression(), scope); - auto right_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getRightTableExpression(), scope); - - if (!identifier_lookup.isExpressionLookup()) - { - if (left_resolved_identifier && right_resolved_identifier) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.dump(), - scope.scope_node->formatASTForErrorMessage()); - - return left_resolved_identifier ? left_resolved_identifier : right_resolved_identifier; - } - - bool join_node_in_resolve_process = scope.table_expressions_in_resolve_process.contains(table_expression_node.get()); - - std::unordered_map join_using_column_name_to_column_node; - - if (!join_node_in_resolve_process && from_join_node.isUsingJoinExpression()) - { - auto & join_using_list = from_join_node.getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & column_node = join_using_node->as(); - join_using_column_name_to_column_node.emplace(column_node.getColumnName(), std::static_pointer_cast(join_using_node)); - } - } - - auto check_nested_column_not_in_using = [&join_using_column_name_to_column_node, &identifier_lookup](const QueryTreeNodePtr & node) - { - /** tldr: When an identifier is resolved into the function `nested` or `getSubcolumn`, and - * some column in its argument is in the USING list and its type has to be updated, we throw an error to avoid overcomplication. - * - * Identifiers can be resolved into functions in case of nested or subcolumns. - * For example `t.t.t` can be resolved into `getSubcolumn(t, 't.t')` function in case of `t` is `Tuple`. - * So, `t` in USING list is resolved from JOIN itself and has supertype of columns from left and right table. - * But `t` in `getSubcolumn` argument is still resolved from table and we need to update its type. - * - * Example: - * - * SELECT t.t FROM ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t UInt32, s1 String), s1 String) as t - * ) AS a FULL JOIN ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t Int32, s2 String), s2 String) as t - * ) AS b USING t; - * - * Result type of `t` is `Tuple(Tuple(Int64, String), String)` (different type and no names for subcolumns), - * so it may be tricky to have a correct type for `t.t` that is resolved into getSubcolumn(t, 't'). - * - * It can be more complicated in case of Nested subcolumns, in that case in query: - * SELECT t FROM ... JOIN ... USING (t.t) - * Here, `t` is resolved into function `nested(['t', 's'], t.t, t.s) so, `t.t` should be from JOIN and `t.s` should be from table. - * - * Updating type accordingly is pretty complicated, so just forbid such cases. - * - * While it still may work for storages that support selecting subcolumns directly without `getSubcolumn` function: - * SELECT t, t.t, toTypeName(t), toTypeName(t.t) FROM t1 AS a FULL JOIN t2 AS b USING t.t; - * We just support it as a best-effort: `t` will have original type from table, but `t.t` will have super-type from JOIN. - * Probably it's good to prohibit such cases as well, but it's not clear how to check it in general case. - */ - if (node->getNodeType() != QueryTreeNodeType::FUNCTION) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {}, expected function node", node->getNodeType()); - - const auto & function_argument_nodes = node->as().getArguments().getNodes(); - for (const auto & argument_node : function_argument_nodes) - { - if (argument_node->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_name = argument_node->as().getColumnName(); - if (join_using_column_name_to_column_node.contains(column_name)) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Cannot select subcolumn for identifier '{}' while joining using column '{}'", - identifier_lookup.identifier, column_name); - } - else if (argument_node->getNodeType() == QueryTreeNodeType::CONSTANT) - { - continue; - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {} for argument node in {}", - argument_node->getNodeType(), node->formatASTForErrorMessage()); - } - } - }; - - std::optional resolved_side; - QueryTreeNodePtr resolved_identifier; - - JoinKind join_kind = from_join_node.getKind(); - - /// If columns from left or right table were missed Object(Nullable('json')) subcolumns, they will be replaced - /// to ConstantNode(NULL), which can't be cast to ColumnNode, so we resolve it here. - if (auto missed_subcolumn_identifier = checkIsMissedObjectJSONSubcolumn(left_resolved_identifier, right_resolved_identifier)) - return missed_subcolumn_identifier; - - if (left_resolved_identifier && right_resolved_identifier) - { - auto using_column_node_it = join_using_column_name_to_column_node.end(); - if (left_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && right_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getColumnName() == right_resolved_column.getColumnName()) - using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - } - else - { - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(left_resolved_identifier); - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(right_resolved_identifier); - } - - if (using_column_node_it != join_using_column_name_to_column_node.end()) - { - JoinTableSide using_column_inner_column_table_side = isRight(join_kind) ? JoinTableSide::Right : JoinTableSide::Left; - auto & using_column_node = using_column_node_it->second->as(); - auto & using_expression_list = using_column_node.getExpression()->as(); - - size_t inner_column_node_index = using_column_inner_column_table_side == JoinTableSide::Left ? 0 : 1; - const auto & inner_column_node = using_expression_list.getNodes().at(inner_column_node_index); - - auto result_column_node = inner_column_node->clone(); - auto & result_column = result_column_node->as(); - result_column.setColumnType(using_column_node.getColumnType()); - - const auto & join_using_left_column = using_expression_list.getNodes().at(0); - if (!result_column_node->isEqual(*join_using_left_column)) - scope.join_columns_with_changed_types[result_column_node] = join_using_left_column; - - resolved_identifier = std::move(result_column_node); - } - else if (resolvedIdenfiersFromJoinAreEquals(left_resolved_identifier, right_resolved_identifier, scope)) - { - const auto & identifier_path_part = identifier_lookup.identifier.front(); - auto * left_resolved_identifier_column = left_resolved_identifier->as(); - auto * right_resolved_identifier_column = right_resolved_identifier->as(); - - if (left_resolved_identifier_column && right_resolved_identifier_column) - { - const auto & left_column_source_alias = left_resolved_identifier_column->getColumnSource()->getAlias(); - const auto & right_column_source_alias = right_resolved_identifier_column->getColumnSource()->getAlias(); - - /** If column from right table was resolved using alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one JOIN system.one AS A ON A.dummy = system.one.dummy; - * - * If alias is specified for left table, and alias is not specified for right table and identifier was resolved - * without using left table alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one AS A JOIN system.one ON A.dummy = system.one.dummy; - * - * Otherwise we prefer column from left table. - */ - bool column_resolved_using_right_alias = identifier_path_part == right_column_source_alias; - bool column_resolved_without_using_left_alias = !left_column_source_alias.empty() - && right_column_source_alias.empty() - && identifier_path_part != left_column_source_alias; - if (column_resolved_using_right_alias || column_resolved_without_using_left_alias) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else if (scope.joins_count == 1 && scope.context->getSettingsRef().single_join_prefer_left_table) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - else - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier '{}'. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - else if (left_resolved_identifier) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(left_resolved_identifier); - } - else - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*left_resolved_column.getColumnType())) - { - auto left_resolved_column_clone = std::static_pointer_cast(left_resolved_column.clone()); - left_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(left_resolved_column_clone); - - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - else if (right_resolved_identifier) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(right_resolved_identifier); - } - else - { - auto & right_resolved_column = right_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(right_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*right_resolved_column.getColumnType())) - { - auto right_resolved_column_clone = std::static_pointer_cast(right_resolved_column.clone()); - right_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(right_resolved_column_clone); - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - - if (join_node_in_resolve_process || !resolved_identifier) - return resolved_identifier; - - if (scope.join_use_nulls) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier); - auto nullable_resolved_identifier = convertJoinedColumnTypeToNullIfNeeded(resolved_identifier, join_kind, resolved_side, scope); - if (nullable_resolved_identifier) - { - resolved_identifier = nullable_resolved_identifier; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(resolved_identifier, projection_name_it->second); - } - } - } - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope) -{ - const auto * resolved_function = resolved_expression->as(); - if (!resolved_function || resolved_function->getFunctionName() != "getSubcolumn") - return {}; - - const auto * array_join_parent_column = array_join_column_inner_expression.get(); - - /** If both resolved and array-joined expressions are subcolumns, try to match them: - * For example, in `SELECT t.map.values FROM (SELECT * FROM tbl) ARRAY JOIN t.map` - * Identifier `t.map.values` is resolved into `getSubcolumn(t, 'map.values')` and t.map is resolved into `getSubcolumn(t, 'map')` - * Since we need to perform array join on `getSubcolumn(t, 'map')`, `t.map.values` should become `getSubcolumn(getSubcolumn(t, 'map'), 'values')` - * - * Note: It doesn't work when subcolumn in ARRAY JOIN is transformed by another expression, for example - * SELECT c.map, c.map.values FROM (SELECT * FROM tbl) ARRAY JOIN mapApply(x -> x, t.map); - */ - String array_join_subcolumn_prefix; - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "getSubcolumn") - { - const auto & argument_nodes = array_join_column_inner_expression_function->getArguments().getNodes(); - if (argument_nodes.size() == 2 && argument_nodes.at(1)->getNodeType() == QueryTreeNodeType::CONSTANT) - { - const auto & constant_node = argument_nodes.at(1)->as(); - const auto & constant_node_value = constant_node.getValue(); - if (constant_node_value.getType() == Field::Types::String) - { - array_join_subcolumn_prefix = constant_node_value.get() + "."; - array_join_parent_column = argument_nodes.at(0).get(); - } - } - } - - const auto & argument_nodes = resolved_function->getArguments().getNodes(); - if (argument_nodes.size() != 2 && !array_join_parent_column->isEqual(*argument_nodes.at(0))) - return {}; - - const auto * second_argument = argument_nodes.at(1)->as(); - if (!second_argument || second_argument->getValue().getType() != Field::Types::String) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected constant string as second argument of getSubcolumn function {}", resolved_function->dumpTree()); - - const auto & resolved_subcolumn_path = second_argument->getValue().get(); - if (!startsWith(resolved_subcolumn_path, array_join_subcolumn_prefix)) - return {}; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(array_join_column_expression_typed.getColumn(), array_join_column_expression_typed.getColumnSource())); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(resolved_subcolumn_path.substr(array_join_subcolumn_prefix.size()))); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - return function_query_node; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & array_join_node = table_expression_node->as(); - const auto & array_join_column_expressions_list = array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions_list.getNodes(); - - QueryTreeNodePtr array_join_resolved_expression; - - /** Special case when qualified or unqualified identifier point to array join expression without alias. - * - * CREATE TABLE test_table (id UInt64, value String, value_array Array(UInt8)) ENGINE=TinyLog; - * SELECT id, value, value_array, test_table.value_array, default.test_table.value_array FROM test_table ARRAY JOIN value_array; - * - * value_array, test_table.value_array, default.test_table.value_array must be resolved into array join expression. - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - if (array_join_column_expression_typed.hasAlias()) - continue; - - auto & array_join_column_inner_expression = array_join_column_expression_typed.getExpressionOrThrow(); - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "nested" && - array_join_column_inner_expression_function->getArguments().getNodes().size() > 1 && - isTuple(array_join_column_expression_typed.getResultType())) - { - const auto & nested_function_arguments = array_join_column_inner_expression_function->getArguments().getNodes(); - size_t nested_function_arguments_size = nested_function_arguments.size(); - - const auto & nested_keys_names_constant_node = nested_function_arguments[0]->as(); - const auto & nested_keys_names = nested_keys_names_constant_node.getValue().get(); - size_t nested_keys_names_size = nested_keys_names.size(); - - if (nested_keys_names_size == nested_function_arguments_size - 1) - { - for (size_t i = 1; i < nested_function_arguments_size; ++i) - { - if (!nested_function_arguments[i]->isEqual(*resolved_expression)) - continue; - - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - - const auto & nested_key_name = nested_keys_names[i - 1].get(); - Identifier nested_identifier = Identifier(nested_key_name); - auto tuple_element_function = wrapExpressionNodeInTupleElement(array_join_column, nested_identifier); - resolveFunction(tuple_element_function, scope); - - array_join_resolved_expression = std::move(tuple_element_function); - break; - } - } - } - - if (array_join_resolved_expression) - break; - - if (array_join_column_inner_expression->isEqual(*resolved_expression)) - { - array_join_resolved_expression = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - break; - } - - /// When we select subcolumn of array joined column it also should be array joined - array_join_resolved_expression = matchArrayJoinSubcolumns(array_join_column_inner_expression, array_join_column_expression_typed, resolved_expression, scope); - if (array_join_resolved_expression) - break; - } - return array_join_resolved_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_array_join_node = table_expression_node->as(); - auto resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_array_join_node.getTableExpression(), scope); - - if (scope.table_expressions_in_resolve_process.contains(table_expression_node.get()) || !identifier_lookup.isExpressionLookup()) - return resolved_identifier; - - const auto & array_join_column_expressions = from_array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions.getNodes(); - - /** Allow JOIN with USING with ARRAY JOIN. - * - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN [1,2,3] AS id INNER JOIN test_table_2 AS t2 USING (id); - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN t1.id AS id INNER JOIN test_table_2 AS t2 USING (id); - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - - IdentifierView identifier_view(identifier_lookup.identifier); - - if (identifier_view.isCompound() && from_array_join_node.hasAlias() && identifier_view.front() == from_array_join_node.getAlias()) - identifier_view.popFirst(); - - const auto & alias_or_name = array_join_column_expression_typed.hasAlias() - ? array_join_column_expression_typed.getAlias() - : array_join_column_expression_typed.getColumnName(); - - if (identifier_view.front() == alias_or_name) - identifier_view.popFirst(); - else if (identifier_view.getFullName() == alias_or_name) - identifier_view.popFirst(identifier_view.getPartsSize()); /// Clear - else - continue; - - if (identifier_view.empty()) - { - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - return array_join_column; - } - - auto compound_expr = tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - identifier_lookup.identifier.getPartsSize() - identifier_view.getPartsSize() /*identifier_bind_size*/, - array_join_column_expression, - {} /* compound_expression_source */, - scope, - true /* can_be_not_found */); - - if (compound_expr) - return compound_expr; - } - - if (!resolved_identifier) - return nullptr; - - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(resolved_identifier, table_expression_node, scope); - if (array_join_resolved_expression) - resolved_identifier = std::move(array_join_resolved_expression); - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope) -{ - auto join_tree_node_type = join_tree_node->getNodeType(); - - switch (join_tree_node_type) - { - case QueryTreeNodeType::JOIN: - return tryResolveIdentifierFromJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::ARRAY_JOIN: - return tryResolveIdentifierFromArrayJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - [[fallthrough]]; - case QueryTreeNodeType::TABLE: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - { - /** Edge case scenario when subquery in FROM node try to resolve identifier from parent scopes, when FROM is not resolved. - * SELECT subquery.b AS value FROM (SELECT value, 1 AS b) AS subquery; - * TODO: This can be supported - */ - if (scope.table_expressions_in_resolve_process.contains(join_tree_node.get())) - return {}; - - return tryResolveIdentifierFromTableExpression(identifier_lookup, join_tree_node, scope); - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Scope FROM section expected table, table function, query, union, join or array join. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } -} - -/** Resolve identifier from scope join tree. - * - * 1. If identifier is in function lookup context return nullptr. - * 2. Try to resolve identifier from table columns. - * 3. If there is no FROM section return nullptr. - * 4. If identifier is in table lookup context, check if it has 1 or 2 parts, otherwise throw exception. - * If identifier has 2 parts try to match it with database_name and table_name. - * If identifier has 1 part try to match it with table_name, then try to match it with table alias. - * 5. If identifier is in expression lookup context, we first need to bind identifier to some table column using identifier first part. - * Start with identifier first part, if it match some column name in table try to get column with full identifier name. - * TODO: Need to check if it is okay to throw exception if compound identifier first part bind to column but column is not valid. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope) -{ - if (identifier_lookup.isFunctionLookup()) - return {}; - - /// Try to resolve identifier from table columns - if (auto resolved_identifier = tryResolveIdentifierFromTableColumns(identifier_lookup, scope)) - return resolved_identifier; - - if (scope.expression_join_tree_node) - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, scope.expression_join_tree_node, scope); - - auto * query_scope_node = scope.scope_node->as(); - if (!query_scope_node || !query_scope_node->getJoinTree()) - return {}; - - const auto & join_tree_node = query_scope_node->getJoinTree(); - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_tree_node, scope); -} - -/** Try resolve identifier in current scope parent scopes. - * - * TODO: If column is matched, throw exception that nested subqueries are not supported. - * - * If initial scope is expression. Then try to resolve identifier in parent scopes until query scope is hit. - * For query scope resolve strategy is same as if initial scope if query. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - bool initial_scope_is_query = scope.scope_node->getNodeType() == QueryTreeNodeType::QUERY; - bool initial_scope_is_expression = !initial_scope_is_query; - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_parent_scopes = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - IdentifierResolveScope * scope_to_check = scope.parent_scope; - - if (initial_scope_is_expression) - { - while (scope_to_check != nullptr) - { - auto resolve_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - if (resolve_result.resolved_identifier) - return resolve_result; - - bool scope_was_query = scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY; - scope_to_check = scope_to_check->parent_scope; - - if (scope_was_query) - break; - } - } - - if (!scope.context->getSettingsRef().enable_global_with_statement) - return {}; - - /** Nested subqueries cannot access outer subqueries table expressions from JOIN tree because - * that can prevent resolution of table expression from CTE. - * - * Example: WITH a AS (SELECT number FROM numbers(1)), b AS (SELECT number FROM a) SELECT * FROM a as l, b as r; - */ - if (identifier_lookup.isTableExpressionLookup()) - identifier_resolve_settings.allow_to_check_join_tree = false; - - while (scope_to_check != nullptr) - { - auto lookup_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - const auto & resolved_identifier = lookup_result.resolved_identifier; - - scope_to_check = scope_to_check->parent_scope; - - if (resolved_identifier) - { - auto * subquery_node = resolved_identifier->as(); - auto * union_node = resolved_identifier->as(); - - bool is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - bool is_table_from_expression_arguments = lookup_result.resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS && - resolved_identifier->getNodeType() == QueryTreeNodeType::TABLE; - bool is_valid_table_expression = is_cte || is_table_from_expression_arguments; - - /** From parent scopes we can resolve table identifiers only as CTE. - * Example: SELECT (SELECT 1 FROM a) FROM test_table AS a; - * - * During child scope table identifier resolve a, table node test_table with alias a from parent scope - * is invalid. - */ - if (identifier_lookup.isTableExpressionLookup() && !is_valid_table_expression) - continue; - - if (is_valid_table_expression || resolved_identifier->as()) - { - return lookup_result; - } - else if (auto * resolved_function = resolved_identifier->as()) - { - /// Special case: scalar subquery was executed and replaced by __getScalar function. - /// Handle it as a constant. - if (resolved_function->getFunctionName() == "__getScalar") - return lookup_result; - } - - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Resolve identifier '{}' from parent scope only supported for constants and CTE. Actual {} node type {}. In scope {}", - identifier_lookup.identifier.getFullName(), - resolved_identifier->formatASTForErrorMessage(), - resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - return {}; -} - -/** Resolve identifier in scope. - * - * If identifier was resolved resolve identified lookup status will be updated. - * - * Steps: - * 1. Register identifier lookup in scope identifier lookup to resolve status table. - * If entry is already registered and is not resolved, that means that we have cyclic aliases for identifier. - * Example: SELECT a AS b, b AS a; - * Try resolve identifier in current scope: - * 3. Try resolve identifier from expression arguments. - * - * If prefer_column_name_to_alias = true. - * 4. Try to resolve identifier from join tree. - * 5. Try to resolve identifier from aliases. - * Otherwise. - * 4. Try to resolve identifier from aliases. - * 5. Try to resolve identifier from join tree. - * - * 6. If it is table identifier lookup try to lookup identifier in current scope CTEs. - * - * 7. If identifier is not resolved in current scope, try to resolve it in parent scopes. - * 8. If identifier is not resolved from parent scopes and it is table identifier lookup try to lookup identifier - * in database catalog. - * - * Same is not done for functions because function resolution is more complex, and in case of aggregate functions requires not only name - * but also argument types, it is responsibility of resolve function method to handle resolution of function name. - * - * 9. If identifier was not resolved, or identifier caching was disabled remove it from identifier lookup to resolve status table. - * - * It is okay for identifier to be not resolved, in case we want first try to lookup identifier in one context, - * then if there is no identifier in this context, try to lookup in another context. - * Example: Try to lookup identifier as expression, if it is not found, lookup as function. - * Example: Try to lookup identifier as expression, if it is not found, lookup as table. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - auto it = scope.identifier_lookup_to_resolve_state.find(identifier_lookup); - if (it != scope.identifier_lookup_to_resolve_state.end()) - { - if (it->second.cyclic_identifier_resolve) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (!it->second.resolve_result.isResolved()) - it->second.cyclic_identifier_resolve = true; - - if (it->second.resolve_result.isResolved() && - scope.use_identifier_lookup_to_result_cache && - !scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) && - (!it->second.resolve_result.isResolvedFromCTEs() || !ctes_in_resolve_process.contains(identifier_lookup.identifier.getFullName()))) - return it->second.resolve_result; - } - else - { - auto [insert_it, _] = scope.identifier_lookup_to_resolve_state.insert({identifier_lookup, IdentifierResolveState()}); - it = insert_it; - } - - /// Resolve identifier from current scope - - IdentifierResolveResult resolve_result; - resolve_result.resolved_identifier = tryResolveIdentifierFromExpressionArguments(identifier_lookup, scope); - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - - if (!resolve_result.resolved_identifier) - { - bool prefer_column_name_to_alias = scope.context->getSettingsRef().prefer_column_name_to_alias; - - if (identifier_lookup.isExpressionLookup()) - { - /* For aliases from ARRAY JOIN we prefer column from join tree: - * SELECT id FROM ( SELECT ... ) AS subquery ARRAY JOIN [0] AS id INNER JOIN second_table USING (id) - * In the example, identifier `id` should be resolved into one from USING (id) column. - */ - - auto * alias_it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FULL_NAME); - if (alias_it && (*alias_it)->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_node = (*alias_it)->as(); - if (column_node.getColumnSource()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - prefer_column_name_to_alias = true; - } - } - - if (unlikely(prefer_column_name_to_alias)) - { - if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - - if (!resolve_result.resolved_identifier) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - } - else - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - { - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - else if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - } - } - - if (!resolve_result.resolved_identifier && identifier_lookup.isTableExpressionLookup()) - { - auto full_name = identifier_lookup.identifier.getFullName(); - auto cte_query_node_it = scope.cte_name_to_query_node.find(full_name); - - /// CTE may reference table expressions with the same name, e.g.: - /// - /// WITH test1 AS (SELECT * FROM test1) SELECT * FROM test1; - /// - /// Since we don't support recursive CTEs, `test1` identifier inside of CTE - /// references to table .test1. - /// This means that the example above is equivalent to the following query: - /// - /// SELECT * FROM test1; - /// - /// To accomplish this behaviour it's not allowed to resolve identifiers to - /// CTE that is being resolved. - if (cte_query_node_it != scope.cte_name_to_query_node.end() - && !ctes_in_resolve_process.contains(full_name)) - { - resolve_result.resolved_identifier = cte_query_node_it->second; - resolve_result.resolve_place = IdentifierResolvePlace::CTE; - } - } - - /// Try to resolve identifier from parent scopes - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_parent_scopes) - { - resolve_result = tryResolveIdentifierInParentScopes(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolved_from_parent_scopes = true; - } - - /// Try to resolve table identifier from database catalog - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_database_catalog && identifier_lookup.isTableExpressionLookup()) - { - resolve_result.resolved_identifier = tryResolveTableIdentifierFromDatabaseCatalog(identifier_lookup.identifier, scope.context); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::DATABASE_CATALOG; - } - - bool was_cyclic_identifier_resolve = it->second.cyclic_identifier_resolve; - if (!was_cyclic_identifier_resolve) - it->second.resolve_result = resolve_result; - it->second.cyclic_identifier_resolve = false; - - /** If identifier was not resolved, or during expression resolution identifier was explicitly added into non cached set, - * or identifier caching was disabled in resolve scope we remove identifier lookup result from identifier lookup to result table. - */ - if (!was_cyclic_identifier_resolve && (!resolve_result.resolved_identifier || - scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) || - !scope.use_identifier_lookup_to_result_cache)) - scope.identifier_lookup_to_resolve_state.erase(it); - - return resolve_result; -} - -/// Resolve query tree nodes functions implementation - -/** Qualify column nodes with projection names. - * - * Example: SELECT * FROM test_table AS t1, test_table AS t2; - */ -void QueryAnalyzer::qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - /// Build additional column qualification parts array - std::vector additional_column_qualification_parts; - - if (table_expression_node->hasAlias()) - additional_column_qualification_parts = {table_expression_node->getAlias()}; - else if (auto * table_node = table_expression_node->as()) - additional_column_qualification_parts = {table_node->getStorageID().getDatabaseName(), table_node->getStorageID().getTableName()}; - - size_t additional_column_qualification_parts_size = additional_column_qualification_parts.size(); - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - /** For each matched column node iterate over additional column qualifications and apply them if column needs to be qualified. - * To check if column needs to be qualified we check if column name can bind to any other table expression in scope or to scope aliases. - */ - std::vector column_qualified_identifier_parts; - - for (const auto & column_node : column_nodes) - { - const auto & column_name = column_node->as().getColumnName(); - column_qualified_identifier_parts = Identifier(column_name).getParts(); - - /// Iterate over additional column qualifications and apply them if needed - for (size_t i = 0; i < additional_column_qualification_parts_size; ++i) - { - auto identifier_to_check = Identifier(column_qualified_identifier_parts); - IdentifierLookup identifier_lookup{identifier_to_check, IdentifierLookupContext::EXPRESSION}; - bool need_to_qualify = table_expression_data.should_qualify_columns; - if (need_to_qualify) - need_to_qualify = tryBindIdentifierToTableExpressions(identifier_lookup, table_expression_node, scope); - - if (tryBindIdentifierToAliases(identifier_lookup, scope)) - need_to_qualify = true; - - if (need_to_qualify) - { - /** Add last qualification part that was not used into column qualified identifier. - * If additional column qualification parts consists from [database_name, table_name]. - * On first iteration if column is needed to be qualified to qualify it with table_name. - * On second iteration if column is needed to be qualified to qualify it with database_name. - */ - size_t part_index_to_use_for_qualification = additional_column_qualification_parts_size - i - 1; - const auto & part_to_use = additional_column_qualification_parts[part_index_to_use_for_qualification]; - column_qualified_identifier_parts.insert(column_qualified_identifier_parts.begin(), part_to_use); - } - else - { - break; - } - } - - auto qualified_node_name = Identifier(column_qualified_identifier_parts).getFullName(); - node_to_projection_name.emplace(column_node, qualified_node_name); - } -} - -/// Build get columns options for matcher -GetColumnsOptions QueryAnalyzer::buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context) -{ - auto & matcher_node_typed = matcher_node->as(); - UInt8 get_columns_options_kind = GetColumnsOptions::AllPhysicalAndAliases; - - if (matcher_node_typed.isAsteriskMatcher()) - { - get_columns_options_kind = GetColumnsOptions::Ordinary; - - const auto & settings = context->getSettingsRef(); - - if (settings.asterisk_include_alias_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Aliases; - - if (settings.asterisk_include_materialized_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Materialized; - } - - return GetColumnsOptions(static_cast(get_columns_options_kind)); -} - -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - /** Use resolved columns from table expression data in nearest query scope if available. - * It is important for ALIAS columns to use column nodes with resolved ALIAS expression. - */ - const TableExpressionData * table_expression_data = nullptr; - const auto * nearest_query_scope = scope.getNearestQueryScope(); - if (nearest_query_scope) - table_expression_data = &nearest_query_scope->getTableExpressionDataOrThrow(table_expression_node); - - QueryTreeNodes matched_column_nodes; - - for (const auto & column : matched_columns) - { - const auto & column_name = column.name; - if (!matcher_node_typed.isMatchingColumn(column_name)) - continue; - - if (table_expression_data) - { - auto column_node_it = table_expression_data->column_name_to_column_node.find(column_name); - if (column_node_it != table_expression_data->column_name_to_column_node.end()) - { - matched_column_nodes.emplace_back(column_node_it->second); - continue; - } - } - - matched_column_nodes.emplace_back(std::make_shared(column, table_expression_node)); - } - - const auto & qualify_matched_column_nodes_scope = nearest_query_scope ? *nearest_query_scope : scope; - qualifyColumnNodesWithProjectionNames(matched_column_nodes, table_expression_node, qualify_matched_column_nodes_scope); - - QueryAnalyzer::QueryTreeNodesWithNames matched_column_nodes_with_names; - matched_column_nodes_with_names.reserve(matched_column_nodes.size()); - - for (auto && matched_column_node : matched_column_nodes) - { - auto column_name = matched_column_node->as().getColumnName(); - matched_column_nodes_with_names.emplace_back(std::move(matched_column_node), std::move(column_name)); - } - - return matched_column_nodes_with_names; -} - -bool hasTableExpressionInJoinTree(const QueryTreeNodePtr & join_tree_node, const QueryTreeNodePtr & table_expression) -{ - QueryTreeNodes nodes_to_process; - nodes_to_process.push_back(join_tree_node); - - while (!nodes_to_process.empty()) - { - auto node_to_process = std::move(nodes_to_process.back()); - nodes_to_process.pop_back(); - if (node_to_process == table_expression) - return true; - - if (node_to_process->getNodeType() == QueryTreeNodeType::JOIN) - { - const auto & join_node = node_to_process->as(); - nodes_to_process.push_back(join_node.getLeftTableExpression()); - nodes_to_process.push_back(join_node.getRightTableExpression()); - } - } - return false; -} - -/// Columns that resolved from matcher can also match columns from JOIN USING. -/// In that case we update type to type of column in USING section. -/// TODO: It's not completely correct for qualified matchers, so t1.* should be resolved to left table column type. -/// But in planner we do not distinguish such cases. -void QueryAnalyzer::updateMatchedColumnsFromJoinUsing( - QueryTreeNodesWithNames & result_matched_column_nodes_with_names, - const QueryTreeNodePtr & source_table_expression, - IdentifierResolveScope & scope) -{ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "There are no table sources. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - const auto & join_tree = nearest_query_scope_query_node->getJoinTree(); - - const auto * join_node = join_tree->as(); - if (join_node && join_node->isUsingJoinExpression()) - { - const auto & join_using_list = join_node->getJoinExpression()->as(); - const auto & join_using_nodes = join_using_list.getNodes(); - - for (auto & [matched_column_node, _] : result_matched_column_nodes_with_names) - { - auto & matched_column_node_typed = matched_column_node->as(); - const auto & matched_column_name = matched_column_node_typed.getColumnName(); - - for (const auto & join_using_node : join_using_nodes) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (matched_column_name != join_using_column_name) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - auto it = node_to_projection_name.find(matched_column_node); - - if (hasTableExpressionInJoinTree(join_node->getLeftTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(0); - else if (hasTableExpressionInJoinTree(join_node->getRightTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(1); - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Cannot find column {} in JOIN USING section {}", - matched_column_node->dumpTree(), join_node->dumpTree()); - - matched_column_node = matched_column_node->clone(); - if (it != node_to_projection_name.end()) - node_to_projection_name.emplace(matched_column_node, it->second); - - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - } - } - } -} - -/** Resolve qualified tree matcher. - * - * First try to match qualified identifier to expression. If qualified identifier matched expression node then - * if expression is compound match it column names using matcher `isMatchingColumn` method, if expression is not compound, throw exception. - * If qualified identifier did not match expression in query tree, try to lookup qualified identifier in table context. - */ -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isQualified()); - - auto expression_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::EXPRESSION}; - auto expression_identifier_resolve_result = tryResolveIdentifier(expression_identifier_lookup, scope); - auto expression_query_tree_node = expression_identifier_resolve_result.resolved_identifier; - - /// Try to resolve unqualified matcher for query expression - - if (expression_query_tree_node) - { - auto result_type = expression_query_tree_node->getResultType(); - - while (true) - { - if (const auto * array_type = typeid_cast(result_type.get())) - result_type = array_type->getNestedType(); - else if (const auto * map_type = typeid_cast(result_type.get())) - result_type = map_type->getNestedType(); - else - break; - } - - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Qualified matcher {} find non compound expression {} with type {}. Expected tuple or array of tuples. In scope {}", - matcher_node->formatASTForErrorMessage(), - expression_query_tree_node->formatASTForErrorMessage(), - expression_query_tree_node->getResultType()->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - auto qualified_matcher_element_identifier = matcher_node_typed.getQualifiedIdentifier(); - for (const auto & element_name : element_names) - { - if (!matcher_node_typed.isMatchingColumn(element_name)) - continue; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back(expression_query_tree_node); - get_subcolumn_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - qualified_matcher_element_identifier.push_back(element_name); - node_to_projection_name.emplace(function_query_node, qualified_matcher_element_identifier.getFullName()); - qualified_matcher_element_identifier.pop_back(); - - matched_expression_nodes_with_column_names.emplace_back(std::move(function_query_node), element_name); - } - - return matched_expression_nodes_with_column_names; - } - - /// Try to resolve qualified matcher for table expression - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_cte = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - auto table_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, identifier_resolve_settings); - auto table_expression_node = table_identifier_resolve_result.resolved_identifier; - - if (!table_expression_node) - { - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Qualified matcher {} does not find table. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - NamesAndTypes matched_columns; - - auto * table_expression_query_node = table_expression_node->as(); - auto * table_expression_union_node = table_expression_node->as(); - auto * table_expression_table_node = table_expression_node->as(); - auto * table_expression_table_function_node = table_expression_node->as(); - - if (table_expression_query_node || table_expression_union_node) - { - matched_columns = table_expression_query_node ? table_expression_query_node->getProjectionColumns() - : table_expression_union_node->computeProjectionColumns(); - } - else if (table_expression_table_node || table_expression_table_function_node) - { - const auto & storage_snapshot = table_expression_table_node ? table_expression_table_node->getStorageSnapshot() - : table_expression_table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - matched_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Invalid table expression node {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto result_matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression_node, - matched_columns, - scope); - - updateMatchedColumnsFromJoinUsing(result_matched_column_nodes_with_names, table_expression_node, scope); - - return result_matched_column_nodes_with_names; -} - -/// Resolve non qualified matcher, using scope join tree node. -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isUnqualified()); - - /** There can be edge case if matcher is inside lambda expression. - * Try to find parent query expression using parent scopes. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unqualified matcher {} cannot be resolved. There are no table sources. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** For unqualifited matcher resolve we build table expressions stack from JOIN tree and then process it. - * For table, table function, query, union table expressions add matched columns into table expressions columns stack. - * For array join continue processing. - * For join node combine last left and right table expressions columns on stack together. It is important that if JOIN has USING - * we must add USING columns before combining left and right table expressions columns. Columns from left and right table - * expressions that have same names as columns in USING clause must be skipped. - */ - - auto table_expressions_stack = buildTableExpressionsStack(nearest_query_scope_query_node->getJoinTree()); - std::vector table_expressions_column_nodes_with_names_stack; - - std::unordered_set table_expression_column_names_to_skip; - - QueryTreeNodesWithNames result; - - if (matcher_node_typed.getMatcherType() == MatcherNodeType::COLUMNS_LIST) - { - auto identifiers = matcher_node_typed.getColumnsIdentifiers(); - result.reserve(identifiers.size()); - - for (const auto & identifier : identifiers) - { - auto resolve_result = tryResolveIdentifier(IdentifierLookup{identifier, IdentifierLookupContext::EXPRESSION}, scope); - if (!resolve_result.isResolved()) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Unknown identifier '{}' inside COLUMNS matcher. In scope {}", - identifier.getFullName(), scope.dump()); - - // TODO: Introduce IdentifierLookupContext::COLUMN and get rid of this check - auto * resolved_column = resolve_result.resolved_identifier->as(); - if (!resolved_column) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier '{}' inside COLUMNS matcher must resolve into a column, but got {}. In scope {}", - identifier.getFullName(), - resolve_result.resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - result.emplace_back(resolve_result.resolved_identifier, resolved_column->getColumnName()); - } - return result; - } - - result.resize(matcher_node_typed.getColumnsIdentifiers().size()); - - for (auto & table_expression : table_expressions_stack) - { - bool table_expression_in_resolve_process = nearest_query_scope->table_expressions_in_resolve_process.contains(table_expression.get()); - - if (auto * array_join_node = table_expression->as()) - { - if (table_expressions_column_nodes_with_names_stack.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 1 table expressions on stack before ARRAY JOIN processing"); - - if (table_expression_in_resolve_process) - continue; - - auto & table_expression_column_nodes_with_names = table_expressions_column_nodes_with_names_stack.back(); - - for (auto & [table_expression_column_node, _] : table_expression_column_nodes_with_names) - { - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(table_expression_column_node, - table_expression, - scope); - if (array_join_resolved_expression) - table_expression_column_node = std::move(array_join_resolved_expression); - } - - continue; - } - - auto * join_node = table_expression->as(); - - if (join_node) - { - size_t table_expressions_column_nodes_with_names_stack_size = table_expressions_column_nodes_with_names_stack.size(); - if (table_expressions_column_nodes_with_names_stack_size < 2) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 2 table expressions on stack before JOIN processing. Actual {}", - table_expressions_column_nodes_with_names_stack_size); - - auto right_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - auto left_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - table_expression_column_names_to_skip.clear(); - - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - /** If there is JOIN with USING we need to match only single USING column and do not use left table expression - * and right table expression column with same name. - * - * Example: SELECT id FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING (id); - */ - if (!table_expression_in_resolve_process && join_node->isUsingJoinExpression()) - { - auto & join_using_list = join_node->getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (!matcher_node_typed.isMatchingColumn(join_using_column_name)) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - /** If column doesn't exists in the table, then do not match column from USING clause. - * Example: SELECT a + 1 AS id, * FROM (SELECT 1 AS a) AS t1 JOIN (SELECT 2 AS id) AS t2 USING (id); - * In this case `id` is not present in the left table expression, - * so asterisk should return `id` from the right table expression. - */ - auto is_column_from_parent_scope = [&scope](const QueryTreeNodePtr & using_node_from_table) - { - const auto & using_column_from_table = using_node_from_table->as(); - auto table_expression_data_it = scope.table_expression_node_to_data.find(using_column_from_table.getColumnSource()); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - { - const auto & table_expression_data = table_expression_data_it->second; - const auto & column_name = using_column_from_table.getColumnName(); - return !table_expression_data.column_name_to_column_node.contains(column_name); - } - return false; - }; - - if (is_column_from_parent_scope(join_using_column_nodes.at(0)) || - is_column_from_parent_scope(join_using_column_nodes.at(1))) - continue; - - QueryTreeNodePtr matched_column_node; - - if (isRight(join_node->getKind())) - matched_column_node = join_using_column_nodes.at(1); - else - matched_column_node = join_using_column_nodes.at(0); - - matched_column_node = matched_column_node->clone(); - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - - table_expression_column_names_to_skip.insert(join_using_column_name); - matched_expression_nodes_with_column_names.emplace_back(std::move(matched_column_node), join_using_column_name); - } - } - - for (auto && left_table_column_with_name : left_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(left_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(left_table_column_with_name)); - } - - for (auto && right_table_column_with_name : right_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(right_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(right_table_column_with_name)); - } - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_expression_nodes_with_column_names)); - continue; - } - - if (table_expression_in_resolve_process) - { - table_expressions_column_nodes_with_names_stack.emplace_back(); - continue; - } - - auto * table_node = table_expression->as(); - auto * table_function_node = table_expression->as(); - auto * query_node = table_expression->as(); - auto * union_node = table_expression->as(); - - NamesAndTypes table_expression_columns; - - if (query_node || union_node) - { - table_expression_columns = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - } - else if (table_node || table_function_node) - { - const auto & storage_snapshot - = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - table_expression_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unqualified matcher {} resolve unexpected table expression. In scope {}", - matcher_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression, - table_expression_columns, - scope); - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_column_nodes_with_names)); - } - - for (auto & table_expression_column_nodes_with_names : table_expressions_column_nodes_with_names_stack) - { - for (auto && table_expression_column_node_with_name : table_expression_column_nodes_with_names) - result.push_back(std::move(table_expression_column_node_with_name)); - } - - return result; -} - - -/** Resolve query tree matcher. Check MatcherNode.h for detailed matcher description. Check ColumnTransformers.h for detailed transformers description. - * - * 1. Populate matched expression nodes resolving qualified or unqualified matcher. - * 2. Apply column transformers to matched expression nodes. For strict column transformers save used column names. - * 3. Validate strict column transformers. - */ -ProjectionNames QueryAnalyzer::resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - QueryTreeNodesWithNames matched_expression_nodes_with_names; - - if (matcher_node_typed.isQualified()) - matched_expression_nodes_with_names = resolveQualifiedMatcher(matcher_node, scope); - else - matched_expression_nodes_with_names = resolveUnqualifiedMatcher(matcher_node, scope); - - if (scope.join_use_nulls) - { - /** If we are resolving matcher came from the result of JOIN and `join_use_nulls` is set, - * we need to convert joined column type to Nullable. - * We are taking the nearest JoinNode to check to which table column belongs, - * because for LEFT/RIGHT join, we convert only the corresponding side. - */ - const auto * nearest_query_scope = scope.getNearestQueryScope(); - const QueryNode * nearest_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - const QueryTreeNodePtr & nearest_scope_join_tree = nearest_scope_query_node ? nearest_scope_query_node->getJoinTree() : nullptr; - const JoinNode * nearest_scope_join_node = nearest_scope_join_tree ? nearest_scope_join_tree->as() : nullptr; - if (nearest_scope_join_node) - { - for (auto & [node, node_name] : matched_expression_nodes_with_names) - { - auto join_identifier_side = getColumnSideFromJoinTree(node, *nearest_scope_join_node); - auto projection_name_it = node_to_projection_name.find(node); - auto nullable_node = convertJoinedColumnTypeToNullIfNeeded(node, nearest_scope_join_node->getKind(), join_identifier_side, scope); - if (nullable_node) - { - node = nullable_node; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(node, projection_name_it->second); - } - } - } - } - } - - if (!scope.expressions_in_resolve_process_stack.hasAggregateFunction()) - { - for (auto & [node, _] : matched_expression_nodes_with_names) - { - auto it = scope.nullable_group_by_keys.find(node); - if (it != scope.nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - } - } - } - - std::unordered_map> strict_transformer_to_used_column_names; - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - auto * except_transformer = transformer->as(); - auto * replace_transformer = transformer->as(); - - if (except_transformer && except_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(except_transformer, std::unordered_set()); - else if (replace_transformer && replace_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(replace_transformer, std::unordered_set()); - } - - ListNodePtr list = std::make_shared(); - ProjectionNames result_projection_names; - ProjectionNames node_projection_names; - - for (auto & [node, column_name] : matched_expression_nodes_with_names) - { - bool apply_transformer_was_used = false; - bool replace_transformer_was_used = false; - bool execute_apply_transformer = false; - bool execute_replace_transformer = false; - - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - else - result_projection_names.push_back(column_name); - - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - if (auto * apply_transformer = transformer->as()) - { - const auto & expression_node = apply_transformer->getExpressionNode(); - apply_transformer_was_used = true; - - if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::LAMBDA) - { - auto lambda_expression_to_resolve = expression_node->clone(); - IdentifierResolveScope lambda_scope(expression_node, &scope /*parent_scope*/); - node_projection_names = resolveLambda(expression_node, lambda_expression_to_resolve, {node}, lambda_scope); - auto & lambda_expression_to_resolve_typed = lambda_expression_to_resolve->as(); - node = lambda_expression_to_resolve_typed.getExpression(); - } - else if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::FUNCTION) - { - auto function_to_resolve_untyped = expression_node->clone(); - auto & function_to_resolve_typed = function_to_resolve_untyped->as(); - function_to_resolve_typed.getArguments().getNodes().push_back(node); - node_projection_names = resolveFunction(function_to_resolve_untyped, scope); - node = function_to_resolve_untyped; - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unsupported apply matcher expression type. Expected lambda or function apply transformer. Actual {}. In scope {}", - transformer->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - execute_apply_transformer = true; - } - else if (auto * except_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - if (except_transformer->isColumnMatching(column_name)) - { - if (except_transformer->isStrict()) - strict_transformer_to_used_column_names[except_transformer].insert(column_name); - - node = {}; - break; - } - } - else if (auto * replace_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - auto replace_expression = replace_transformer->findReplacementExpression(column_name); - if (!replace_expression) - continue; - - replace_transformer_was_used = true; - - if (replace_transformer->isStrict()) - strict_transformer_to_used_column_names[replace_transformer].insert(column_name); - - node = replace_expression->clone(); - node_projection_names = resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** If replace expression resolved as single node, we want to use replace column name as result projection name, instead - * of using replace expression projection name. - * - * Example: SELECT * REPLACE id + 5 AS id FROM test_table; - */ - if (node_projection_names.size() == 1) - node_projection_names[0] = column_name; - - execute_replace_transformer = true; - } - - if (execute_apply_transformer || execute_replace_transformer) - { - if (auto * node_list = node->as()) - { - auto & node_list_nodes = node_list->getNodes(); - size_t node_list_nodes_size = node_list_nodes.size(); - - if (node_list_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "{} transformer {} resolved as list node with size {}. Expected 1. In scope {}", - execute_apply_transformer ? "APPLY" : "REPLACE", - transformer->formatASTForErrorMessage(), - node_list_nodes_size, - scope.scope_node->formatASTForErrorMessage()); - - node = node_list_nodes[0]; - } - - if (node_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Matcher node expected 1 projection name. Actual {}", node_projection_names.size()); - - result_projection_names.back() = std::move(node_projection_names[0]); - node_to_projection_name.emplace(node, result_projection_names.back()); - node_projection_names.clear(); - } - } - - if (node) - list->getNodes().push_back(node); - else - result_projection_names.pop_back(); - } - - for (auto & [strict_transformer, used_column_names] : strict_transformer_to_used_column_names) - { - auto strict_transformer_type = strict_transformer->getTransformerType(); - const Names * strict_transformer_column_names = nullptr; - - switch (strict_transformer_type) - { - case ColumnTransfomerType::EXCEPT: - { - const auto * except_transformer = static_cast(strict_transformer); - const auto & except_names = except_transformer->getExceptColumnNames(); - - if (except_names.size() != used_column_names.size()) - strict_transformer_column_names = &except_transformer->getExceptColumnNames(); - - break; - } - case ColumnTransfomerType::REPLACE: - { - const auto * replace_transformer = static_cast(strict_transformer); - const auto & replacement_names = replace_transformer->getReplacementsNames(); - - if (replacement_names.size() != used_column_names.size()) - strict_transformer_column_names = &replace_transformer->getReplacementsNames(); - - break; - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected strict EXCEPT or REPLACE column transformer. Actual type {}. In scope {}", - toString(strict_transformer_type), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (!strict_transformer_column_names) - continue; - - Names non_matched_column_names; - size_t strict_transformer_column_names_size = strict_transformer_column_names->size(); - for (size_t i = 0; i < strict_transformer_column_names_size; ++i) - { - const auto & column_name = (*strict_transformer_column_names)[i]; - if (used_column_names.find(column_name) == used_column_names.end()) - non_matched_column_names.push_back(column_name); - } - - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Strict {} column transformer {} expects following column(s) : {}. In scope {}", - toString(strict_transformer_type), - strict_transformer->formatASTForErrorMessage(), - fmt::join(non_matched_column_names, ", "), - scope.scope_node->formatASTForErrorMessage()); - } - - auto original_ast = matcher_node->getOriginalAST(); - matcher_node = std::move(list); - if (original_ast) - matcher_node->setOriginalAST(original_ast); - - return result_projection_names; -} - -/** Resolve window function window node. - * - * Node can be identifier or window node. - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - * Example: SELECT count(*) OVER (PARTITION BY id); - * - * If node has parent window name specified, then parent window definition is searched in nearest query scope WINDOW section. - * If node is identifier, than node is replaced with window definition. - * If node is window, that window node is merged with parent window node. - * - * Window node PARTITION BY and ORDER BY parts are resolved. - * If window node has frame begin OFFSET or frame end OFFSET specified, they are resolved, and window node frame constants are updated. - * Window node frame is validated. - */ -ProjectionName QueryAnalyzer::resolveWindow(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - std::string parent_window_name; - auto * identifier_node = node->as(); - - ProjectionName result_projection_name; - QueryTreeNodePtr parent_window_node; - - if (identifier_node) - parent_window_name = identifier_node->getIdentifier().getFullName(); - else if (auto * window_node = node->as()) - parent_window_name = window_node->getParentWindowName(); - - if (!parent_window_name.empty()) - { - auto * nearest_query_scope = scope.getNearestQueryScope(); - - if (!nearest_query_scope) - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Window '{}' does not exist.", parent_window_name); - - auto & scope_window_name_to_window_node = nearest_query_scope->window_name_to_window_node; - - auto window_node_it = scope_window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope_window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - nearest_query_scope->scope_node->formatASTForErrorMessage()); - - parent_window_node = window_node_it->second; - - if (identifier_node) - { - node = parent_window_node->clone(); - result_projection_name = parent_window_name; - } - else - { - mergeWindowWithParentWindow(node, parent_window_node, scope); - } - } - - auto & window_node = node->as(); - window_node.setParentWindowName({}); - - ProjectionNames partition_by_projection_names = resolveExpressionNodeList(window_node.getPartitionByNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - ProjectionNames order_by_projection_names = resolveSortNodeList(window_node.getOrderByNode(), scope); - - ProjectionNames frame_begin_offset_projection_names; - ProjectionNames frame_end_offset_projection_names; - - if (window_node.hasFrameBeginOffset()) - { - frame_begin_offset_projection_names = resolveExpressionNode(window_node.getFrameBeginOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_begin_constant_node = window_node.getFrameBeginOffsetNode()->as(); - if (!window_frame_begin_constant_node || !isNativeNumber(removeNullable(window_frame_begin_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameBeginOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().begin_offset = window_frame_begin_constant_node->getValue(); - if (frame_begin_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_begin_offset_projection_names.size()); - } - - if (window_node.hasFrameEndOffset()) - { - frame_end_offset_projection_names = resolveExpressionNode(window_node.getFrameEndOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_end_constant_node = window_node.getFrameEndOffsetNode()->as(); - if (!window_frame_end_constant_node || !isNativeNumber(removeNullable(window_frame_end_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameEndOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().end_offset = window_frame_end_constant_node->getValue(); - if (frame_end_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_end_offset_projection_names.size()); - } - - window_node.getWindowFrame().checkValid(); - - if (result_projection_name.empty()) - { - result_projection_name = calculateWindowProjectionName(node, - parent_window_node, - parent_window_name, - partition_by_projection_names, - order_by_projection_names, - frame_begin_offset_projection_names.empty() ? "" : frame_begin_offset_projection_names.front(), - frame_end_offset_projection_names.empty() ? "" : frame_end_offset_projection_names.front()); - } - - return result_projection_name; -} - -/** Resolve lambda function. - * This function modified lambda_node during resolve. It is caller responsibility to clone lambda before resolve - * if it is needed for later use. - * - * Lambda body expression result projection names is used as lambda projection names. - * - * Lambda expression can be resolved into list node. It is caller responsibility to handle it properly. - * - * lambda_node - node that must have LambdaNode type. - * lambda_node_to_resolve - lambda node to resolve that must have LambdaNode type. - * arguments - lambda arguments. - * scope - lambda scope. It is client responsibility to create it. - * - * Resolve steps: - * 1. Validate arguments. - * 2. Register lambda node in lambdas in resolve process. This is necessary to prevent recursive lambda resolving. - * 3. Initialize scope with lambda aliases. - * 4. Validate lambda argument names, and scope expressions. - * 5. Resolve lambda body expression. - * 6. Deregister lambda node from lambdas in resolve process. - */ -ProjectionNames QueryAnalyzer::resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope) -{ - auto & lambda_to_resolve = lambda_node_to_resolve->as(); - auto & lambda_arguments_nodes = lambda_to_resolve.getArguments().getNodes(); - size_t lambda_arguments_nodes_size = lambda_arguments_nodes.size(); - - /** Register lambda as being resolved, to prevent recursive lambdas resolution. - * Example: WITH (x -> x + lambda_2(x)) AS lambda_1, (x -> x + lambda_1(x)) AS lambda_2 SELECT 1; - */ - auto it = lambdas_in_resolve_process.find(lambda_node.get()); - if (it != lambdas_in_resolve_process.end()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive lambda {}. In scope {}", - lambda_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - lambdas_in_resolve_process.emplace(lambda_node.get()); - - size_t arguments_size = lambda_arguments.size(); - if (lambda_arguments_nodes_size != arguments_size) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} expect {} arguments. Actual {}. In scope {}", - lambda_to_resolve.formatASTForErrorMessage(), - lambda_arguments_nodes_size, - arguments_size, - scope.scope_node->formatASTForErrorMessage()); - - /// Initialize aliases in lambda scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - visitor.visit(lambda_to_resolve.getExpression()); - - /** Replace lambda arguments with new arguments. - * Additionally validate that there are no aliases with same name as lambda arguments. - * Arguments are registered in current scope expression_argument_name_to_node map. - */ - QueryTreeNodes lambda_new_arguments_nodes; - lambda_new_arguments_nodes.reserve(lambda_arguments_nodes_size); - - for (size_t i = 0; i < lambda_arguments_nodes_size; ++i) - { - auto & lambda_argument_node = lambda_arguments_nodes[i]; - const auto * lambda_argument_identifier = lambda_argument_node->as(); - const auto * lambda_argument_column = lambda_argument_node->as(); - if (!lambda_argument_identifier && !lambda_argument_column) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected IDENTIFIER or COLUMN as lambda argument, got {}", lambda_node->dumpTree()); - const auto & lambda_argument_name = lambda_argument_identifier ? lambda_argument_identifier->getIdentifier().getFullName() - : lambda_argument_column->getColumnName(); - - bool has_expression_node = scope.aliases.alias_name_to_expression_node->contains(lambda_argument_name); - bool has_alias_node = scope.aliases.alias_name_to_lambda_node.contains(lambda_argument_name); - - if (has_expression_node || has_alias_node) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Alias name '{}' inside lambda {} cannot have same name as lambda argument. In scope {}", - lambda_argument_name, - lambda_argument_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - scope.expression_argument_name_to_node.emplace(lambda_argument_name, lambda_arguments[i]); - lambda_new_arguments_nodes.push_back(lambda_arguments[i]); - } - - lambda_to_resolve.getArguments().getNodes() = std::move(lambda_new_arguments_nodes); - - /// Lambda body expression is resolved as standard query expression node. - auto result_projection_names = resolveExpressionNode(lambda_to_resolve.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - lambdas_in_resolve_process.erase(lambda_node.get()); - - return result_projection_names; -} - -namespace -{ -void checkFunctionNodeHasEmptyNullsAction(FunctionNode const & node) -{ - if (node.getNullsAction() != NullsAction::EMPTY) - throw Exception( - ErrorCodes::SYNTAX_ERROR, - "Function with name '{}' cannot use {} NULLS", - node.getFunctionName(), - node.getNullsAction() == NullsAction::IGNORE_NULLS ? "IGNORE" : "RESPECT"); -} -} - -/** Resolve function node in scope. - * During function node resolve, function node can be replaced with another expression (if it match lambda or sql user defined function), - * with constant (if it allow constant folding), or with expression list. It is caller responsibility to handle such cases appropriately. - * - * Steps: - * 1. Resolve function parameters. Validate that each function parameter must be constant node. - * 2. Try to lookup function as lambda in current scope. If it is lambda we can skip `in` and `count` special handling. - * 3. If function is count function, that take unqualified ASTERISK matcher, remove it from its arguments. Example: SELECT count(*) FROM test_table; - * 4. If function is `IN` function, then right part of `IN` function is replaced as subquery. - * 5. Resolve function arguments list, lambda expressions are allowed as function arguments. - * For `IN` function table expressions are allowed as function arguments. - * 6. Initialize argument_columns, argument_types, function_lambda_arguments_indexes arrays from function arguments. - * 7. If function name identifier was not resolved as function in current scope, try to lookup lambda from sql user defined functions factory. - * 8. If function was resolve as lambda from step 2 or 7, then resolve lambda using function arguments and replace function node with lambda result. - * After than function node is resolved. - * 9. If function was not resolved during step 6 as lambda, then try to resolve function as window function or executable user defined function - * or ordinary function or aggregate function. - * - * If function is resolved as window function or executable user defined function or aggregate function, function node is resolved - * no additional special handling is required. - * - * 8. If function was resolved as non aggregate function. Then if some of function arguments are lambda expressions, their result types need to be initialized and - * they must be resolved. - * 9. If function is suitable for constant folding, try to perform constant folding for function node. - */ -ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - FunctionNodePtr function_node_ptr = std::static_pointer_cast(node); - auto function_name = function_node_ptr->getFunctionName(); - - /// Resolve function parameters - - auto parameters_projection_names = resolveExpressionNodeList(function_node_ptr->getParametersNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - /// Convert function parameters into constant parameters array - - Array parameters; - - auto & parameters_nodes = function_node_ptr->getParameters().getNodes(); - parameters.reserve(parameters_nodes.size()); - - for (auto & parameter_node : parameters_nodes) - { - const auto * constant_node = parameter_node->as(); - if (!constant_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parameter for function '{}' expected to have constant value. Actual {}. In scope {}", - function_name, - parameter_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - parameters.push_back(constant_node->getValue()); - } - - //// If function node is not window function try to lookup function node name as lambda identifier. - QueryTreeNodePtr lambda_expression_untyped; - if (!function_node_ptr->isWindowFunction()) - { - auto function_lookup_result = tryResolveIdentifier({Identifier{function_name}, IdentifierLookupContext::FUNCTION}, scope); - lambda_expression_untyped = function_lookup_result.resolved_identifier; - } - - bool is_special_function_in = false; - bool is_special_function_dict_get = false; - bool is_special_function_join_get = false; - bool is_special_function_exists = false; - bool is_special_function_if = false; - - if (!lambda_expression_untyped) - { - is_special_function_in = isNameOfInFunction(function_name); - is_special_function_dict_get = functionIsDictGet(function_name); - is_special_function_join_get = functionIsJoinGet(function_name); - is_special_function_exists = function_name == "exists"; - is_special_function_if = function_name == "if"; - - auto function_name_lowercase = Poco::toLower(function_name); - - /** Special handling for count and countState functions. - * - * Example: SELECT count(*) FROM test_table - * Example: SELECT countState(*) FROM test_table; - */ - if (function_node_ptr->getArguments().getNodes().size() == 1 && - (function_name_lowercase == "count" || function_name_lowercase == "countstate")) - { - auto * matcher_node = function_node_ptr->getArguments().getNodes().front()->as(); - if (matcher_node && matcher_node->isUnqualified()) - function_node_ptr->getArguments().getNodes().clear(); - } - } - - /** Special functions dictGet and its variations and joinGet can be executed when first argument is identifier. - * Example: SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Try to resolve identifier as expression identifier and if it is resolved use it. - * Example: WITH 'dict_name' AS identifier SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Otherwise replace identifier with identifier full name constant. - * Validation that dictionary exists or table exists will be performed during function `getReturnType` method call. - */ - if ((is_special_function_dict_get || is_special_function_join_get) && - !function_node_ptr->getArguments().getNodes().empty() && - function_node_ptr->getArguments().getNodes()[0]->getNodeType() == QueryTreeNodeType::IDENTIFIER) - { - auto & first_argument = function_node_ptr->getArguments().getNodes()[0]; - auto & first_argument_identifier = first_argument->as(); - auto identifier = first_argument_identifier.getIdentifier(); - - IdentifierLookup identifier_lookup{identifier, IdentifierLookupContext::EXPRESSION}; - auto resolve_result = tryResolveIdentifier(identifier_lookup, scope); - - if (resolve_result.isResolved()) - { - first_argument = std::move(resolve_result.resolved_identifier); - } - else - { - size_t parts_size = identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected {} function first argument identifier to contain 1 or 2 parts. Actual '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_special_function_dict_get) - { - scope.context->getExternalDictionariesLoader().assertDictionaryStructureExists(identifier.getFullName(), scope.context); - } - else - { - auto table_node = tryResolveTableIdentifierFromDatabaseCatalog(identifier, scope.context); - if (!table_node) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} first argument expected table identifier '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node_typed = table_node->as(); - if (!std::dynamic_pointer_cast(table_node_typed.getStorage())) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} table '{}' should have engine StorageJoin. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - first_argument = std::make_shared(identifier.getFullName()); - } - } - - if (is_special_function_exists) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /// Rewrite EXISTS (subquery) into 1 IN (SELECT 1 FROM (subquery) LIMIT 1). - auto & exists_subquery_argument = function_node_ptr->getArguments().getNodes().at(0); - - auto constant_data_type = std::make_shared(); - - auto in_subquery = std::make_shared(Context::createCopy(scope.context)); - in_subquery->setIsSubquery(true); - in_subquery->getProjection().getNodes().push_back(std::make_shared(1UL, constant_data_type)); - in_subquery->getJoinTree() = exists_subquery_argument; - in_subquery->getLimit() = std::make_shared(1UL, constant_data_type); - - function_node_ptr = std::make_shared("in"); - function_node_ptr->getArguments().getNodes() = {std::make_shared(1UL, constant_data_type), in_subquery}; - node = function_node_ptr; - function_name = "in"; - is_special_function_in = true; - } - - if (is_special_function_if && !function_node_ptr->getArguments().getNodes().empty()) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /** Handle special case with constant If function, even if some of the arguments are invalid. - * - * SELECT if(hasColumnInTable('system', 'numbers', 'not_existing_column'), not_existing_column, 5) FROM system.numbers; - */ - auto & if_function_arguments = function_node_ptr->getArguments().getNodes(); - auto if_function_condition = if_function_arguments[0]; - resolveExpressionNode(if_function_condition, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto constant_condition = tryExtractConstantFromConditionNode(if_function_condition); - - if (constant_condition.has_value() && if_function_arguments.size() == 3) - { - QueryTreeNodePtr constant_if_result_node; - QueryTreeNodePtr possibly_invalid_argument_node; - - if (*constant_condition) - { - possibly_invalid_argument_node = if_function_arguments[2]; - constant_if_result_node = if_function_arguments[1]; - } - else - { - possibly_invalid_argument_node = if_function_arguments[1]; - constant_if_result_node = if_function_arguments[2]; - } - - bool apply_constant_if_optimization = false; - - try - { - resolveExpressionNode(possibly_invalid_argument_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - } - catch (...) - { - apply_constant_if_optimization = true; - } - - if (apply_constant_if_optimization) - { - auto result_projection_names = resolveExpressionNode(constant_if_result_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - node = std::move(constant_if_result_node); - return result_projection_names; - } - } - } - - /// Resolve function arguments - bool allow_table_expressions = is_special_function_in; - auto arguments_projection_names = resolveExpressionNodeList(function_node_ptr->getArgumentsNode(), - scope, - true /*allow_lambda_expression*/, - allow_table_expressions /*allow_table_expression*/); - - /// Mask arguments if needed - if (!scope.context->getSettingsRef().format_display_secrets_in_show_and_select) - { - if (FunctionSecretArgumentsFinder::Result secret_arguments = FunctionSecretArgumentsFinderTreeNode(*function_node_ptr).getResult(); secret_arguments.count) - { - auto & argument_nodes = function_node_ptr->getArgumentsNode()->as().getNodes(); - - for (size_t n = secret_arguments.start; n < secret_arguments.start + secret_arguments.count; ++n) - { - if (auto * constant = argument_nodes[n]->as()) - { - auto mask = scope.projection_mask_map->insert({constant->getTreeHash(), scope.projection_mask_map->size() + 1}).first->second; - constant->setMaskId(mask); - arguments_projection_names[n] = "[HIDDEN id: " + std::to_string(mask) + "]"; - } - } - } - } - - auto & function_node = *function_node_ptr; - - /// Replace right IN function argument if it is table or table function with subquery that read ordinary columns - if (is_special_function_in) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - if (scope.context->getSettingsRef().transform_null_in) - { - static constexpr std::array, 4> in_function_to_replace_null_in_function_map = - {{ - {"in", "nullIn"}, - {"notIn", "notNullIn"}, - {"globalIn", "globalNullIn"}, - {"globalNotIn", "globalNotNullIn"}, - }}; - - for (const auto & [in_function_name, in_function_name_to_replace] : in_function_to_replace_null_in_function_map) - { - if (function_name == in_function_name) - { - function_name = in_function_name_to_replace; - break; - } - } - } - - auto & function_in_arguments_nodes = function_node.getArguments().getNodes(); - if (function_in_arguments_nodes.size() != 2) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function '{}' expects 2 arguments", function_name); - - auto & in_second_argument = function_in_arguments_nodes[1]; - auto * table_node = in_second_argument->as(); - auto * table_function_node = in_second_argument->as(); - - if (table_node) - { - /// If table is already prepared set, we do not replace it with subquery. - /// If table is not a StorageSet, we'll create plan to build set in the Planner. - } - else if (table_function_node) - { - const auto & storage_snapshot = table_function_node->getStorageSnapshot(); - auto columns_to_select = storage_snapshot->getColumns(GetColumnsOptions(GetColumnsOptions::Ordinary)); - - size_t columns_to_select_size = columns_to_select.size(); - - auto column_nodes_to_select = std::make_shared(); - column_nodes_to_select->getNodes().reserve(columns_to_select_size); - - NamesAndTypes projection_columns; - projection_columns.reserve(columns_to_select_size); - - for (auto & column : columns_to_select) - { - column_nodes_to_select->getNodes().emplace_back(std::make_shared(column, in_second_argument)); - projection_columns.emplace_back(column.name, column.type); - } - - auto in_second_argument_query_node = std::make_shared(Context::createCopy(scope.context)); - in_second_argument_query_node->setIsSubquery(true); - in_second_argument_query_node->getProjectionNode() = std::move(column_nodes_to_select); - in_second_argument_query_node->getJoinTree() = std::move(in_second_argument); - in_second_argument_query_node->resolveProjectionColumns(std::move(projection_columns)); - - in_second_argument = std::move(in_second_argument_query_node); - } - else - { - /// Replace storage with values storage of insertion block - if (StoragePtr storage = scope.context->getViewSource()) - { - QueryTreeNodePtr table_expression; - /// Process possibly nested sub-selects - for (auto * query_node = in_second_argument->as(); query_node; query_node = table_expression->as()) - table_expression = extractLeftTableExpression(query_node->getJoinTree()); - - if (table_expression) - { - if (auto * query_table_node = table_expression->as()) - { - if (query_table_node->getStorageID().getFullNameNotQuoted() == storage->getStorageID().getFullNameNotQuoted()) - { - auto replacement_table_expression = std::make_shared(storage, scope.context); - if (std::optional table_expression_modifiers = query_table_node->getTableExpressionModifiers()) - replacement_table_expression->setTableExpressionModifiers(*table_expression_modifiers); - in_second_argument = in_second_argument->cloneAndReplace(table_expression, std::move(replacement_table_expression)); - } - } - } - } - - resolveExpressionNode(in_second_argument, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - } - } - - /// Initialize function argument columns - - ColumnsWithTypeAndName argument_columns; - DataTypes argument_types; - bool all_arguments_constants = true; - std::vector function_lambda_arguments_indexes; - - auto & function_arguments = function_node.getArguments().getNodes(); - size_t function_arguments_size = function_arguments.size(); - - for (size_t function_argument_index = 0; function_argument_index < function_arguments_size; ++function_argument_index) - { - auto & function_argument = function_arguments[function_argument_index]; - - ColumnWithTypeAndName argument_column; - argument_column.name = arguments_projection_names[function_argument_index]; - - /** If function argument is lambda, save lambda argument index and initialize argument type as DataTypeFunction - * where function argument types are initialized with empty array of lambda arguments size. - */ - if (const auto * lambda_node = function_argument->as()) - { - size_t lambda_arguments_size = lambda_node->getArguments().getNodes().size(); - argument_column.type = std::make_shared(DataTypes(lambda_arguments_size, nullptr), nullptr); - function_lambda_arguments_indexes.push_back(function_argument_index); - } - else if (is_special_function_in && function_argument_index == 1) - { - argument_column.type = std::make_shared(); - } - else - { - argument_column.type = function_argument->getResultType(); - } - - if (!argument_column.type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' argument is not resolved. In scope {}", - function_name, - scope.scope_node->formatASTForErrorMessage()); - - bool argument_is_constant = false; - const auto * constant_node = function_argument->as(); - if (constant_node) - { - argument_column.column = constant_node->getResultType()->createColumnConst(1, constant_node->getValue()); - argument_column.type = constant_node->getResultType(); - argument_is_constant = true; - } - else if (const auto * get_scalar_function_node = function_argument->as(); - get_scalar_function_node && get_scalar_function_node->getFunctionName() == "__getScalar") - { - /// Allow constant folding through getScalar - const auto * get_scalar_const_arg = get_scalar_function_node->getArguments().getNodes().at(0)->as(); - if (get_scalar_const_arg && scope.context->hasQueryContext()) - { - auto query_context = scope.context->getQueryContext(); - auto scalar_string = toString(get_scalar_const_arg->getValue()); - if (query_context->hasScalar(scalar_string)) - { - auto scalar = query_context->getScalar(scalar_string); - argument_column.column = ColumnConst::create(scalar.getByPosition(0).column, 1); - argument_column.type = get_scalar_function_node->getResultType(); - argument_is_constant = true; - } - } - } - - all_arguments_constants &= argument_is_constant; - - argument_types.push_back(argument_column.type); - argument_columns.emplace_back(std::move(argument_column)); - } - - /// Calculate function projection name - ProjectionNames result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - - /** Try to resolve function as - * 1. Lambda function in current scope. Example: WITH (x -> x + 1) AS lambda SELECT lambda(1); - * 2. Lambda function from sql user defined functions. - * 3. Special `untuple` function. - * 4. Special `grouping` function. - * 5. Window function. - * 6. Executable user defined function. - * 7. Ordinary function. - * 8. Aggregate function. - * - * TODO: Provide better error hints. - */ - if (!function_node.isWindowFunction()) - { - if (!lambda_expression_untyped) - lambda_expression_untyped = tryGetLambdaFromSQLUserDefinedFunctions(function_node.getFunctionName(), scope.context); - - /** If function is resolved as lambda. - * Clone lambda before resolve. - * Initialize lambda arguments as function arguments. - * Resolve lambda and then replace function node with resolved lambda expression body. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(value) FROM test_table; - * Result: SELECT value + 1 FROM test_table; - */ - if (lambda_expression_untyped) - { - auto * lambda_expression = lambda_expression_untyped->as(); - if (!lambda_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function identifier '{}' must be resolved as lambda. Actual {}. In scope {}", - function_node.getFunctionName(), - lambda_expression_untyped->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - if (!parameters.empty()) - { - throw Exception( - ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_node.formatASTForErrorMessage()); - } - - auto lambda_expression_clone = lambda_expression_untyped->clone(); - - IdentifierResolveScope lambda_scope(lambda_expression_clone, &scope /*parent_scope*/); - ProjectionNames lambda_projection_names = resolveLambda(lambda_expression_untyped, lambda_expression_clone, function_arguments, lambda_scope); - - auto & resolved_lambda = lambda_expression_clone->as(); - node = resolved_lambda.getExpression(); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(lambda_projection_names); - - return result_projection_names; - } - - if (function_name == "untuple") - { - /// Special handling of `untuple` function - - if (function_arguments.size() != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' must have 1 argument. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - const auto & untuple_argument = function_arguments[0]; - /// Handle this special case first as `getResultType()` might return nullptr - if (untuple_argument->as()) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Function untuple can't have lambda-expressions as arguments"); - - auto result_type = untuple_argument->getResultType(); - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' argument must have compound type. Actual type {}. In scope {}", - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - - auto result_list = std::make_shared(); - result_list->getNodes().reserve(element_names.size()); - - for (const auto & element_name : element_names) - { - auto tuple_element_function = std::make_shared("tupleElement"); - tuple_element_function->getArguments().getNodes().push_back(untuple_argument); - tuple_element_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = tuple_element_function; - resolveFunction(function_query_node, scope); - - result_list->getNodes().push_back(std::move(function_query_node)); - } - - auto untuple_argument_projection_name = arguments_projection_names.at(0); - result_projection_names.clear(); - - for (const auto & element_name : element_names) - { - if (node->hasAlias()) - result_projection_names.push_back(node->getAlias() + '.' + element_name); - else - result_projection_names.push_back(fmt::format("tupleElement({}, '{}')", untuple_argument_projection_name, element_name)); - } - - node = std::move(result_list); - return result_projection_names; - } - else if (function_name == "grouping") - { - /// It is responsibility of planner to perform additional handling of grouping function - if (function_arguments_size == 0) - throw Exception(ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING expects at least one argument"); - else if (function_arguments_size > 64) - throw Exception(ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING can have up to 64 arguments, but {} provided", - function_arguments_size); - checkFunctionNodeHasEmptyNullsAction(function_node); - - bool force_grouping_standard_compatibility = scope.context->getSettingsRef().force_grouping_standard_compatibility; - auto grouping_function = std::make_shared(force_grouping_standard_compatibility); - auto grouping_function_adaptor = std::make_shared(std::move(grouping_function)); - function_node.resolveAsFunction(grouping_function_adaptor->build(argument_columns)); - - return result_projection_names; - } - } - - if (function_node.isWindowFunction()) - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - throw Exception(ErrorCodes::UNKNOWN_AGGREGATE_FUNCTION, "Aggregate function with name '{}' does not exist. In scope {}{}", - function_name, scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(AggregateFunctionFactory::instance().getHints(function_name))); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Window function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsWindowFunction(std::move(aggregate_function)); - - bool window_node_is_identifier = function_node.getWindowNode()->getNodeType() == QueryTreeNodeType::IDENTIFIER; - ProjectionName window_projection_name = resolveWindow(function_node.getWindowNode(), scope); - - if (window_node_is_identifier) - result_projection_names[0] += " OVER " + window_projection_name; - else - result_projection_names[0] += " OVER (" + window_projection_name + ')'; - - return result_projection_names; - } - - FunctionOverloadResolverPtr function = UserDefinedExecutableFunctionFactory::instance().tryGet(function_name, scope.context, parameters); /// NOLINT(readability-static-accessed-through-instance) - bool is_executable_udf = true; - - IdentifierResolveScope::ResolvedFunctionsCache * function_cache = nullptr; - - if (!function) - { - /// This is a hack to allow a query like `select randConstant(), randConstant(), randConstant()`. - /// Function randConstant() would return the same value for the same arguments (in scope). - - auto hash = function_node_ptr->getTreeHash(); - function_cache = &scope.functions_cache[hash]; - if (!function_cache->resolver) - function_cache->resolver = FunctionFactory::instance().tryGet(function_name, scope.context); - - function = function_cache->resolver; - - is_executable_udf = false; - } - - if (function) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - } - else - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - std::vector possible_function_names; - - auto function_names = UserDefinedExecutableFunctionFactory::instance().getRegisteredNames(scope.context); /// NOLINT(readability-static-accessed-through-instance) - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = UserDefinedSQLFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = FunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = AggregateFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - for (auto & [name, lambda_node] : scope.aliases.alias_name_to_lambda_node) - { - if (lambda_node->getNodeType() == QueryTreeNodeType::LAMBDA) - possible_function_names.push_back(name); - } - - auto hints = NamePrompter<2>::getHints(function_name, possible_function_names); - - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Function with name '{}' does not exist. In scope {}{}", - function_name, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Aggregate function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsAggregateFunction(std::move(aggregate_function)); - - return result_projection_names; - } - - /// Executable UDFs may have parameters. They are checked in UserDefinedExecutableFunctionFactory. - if (!parameters.empty() && !is_executable_udf) - { - throw Exception(ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_name); - } - - /** For lambda arguments we need to initialize lambda argument types DataTypeFunction using `getLambdaArgumentTypes` function. - * Then each lambda arguments are initialized with columns, where column source is lambda. - * This information is important for later steps of query processing. - * Example: SELECT arrayMap(x -> x + 1, [1, 2, 3]). - * lambda node x -> x + 1 identifier x is resolved as column where source is lambda node. - */ - bool has_lambda_arguments = !function_lambda_arguments_indexes.empty(); - if (has_lambda_arguments) - { - function->getLambdaArgumentTypes(argument_types); - - ProjectionNames lambda_projection_names; - for (auto & function_lambda_argument_index : function_lambda_arguments_indexes) - { - auto & lambda_argument = function_arguments[function_lambda_argument_index]; - auto lambda_to_resolve = lambda_argument->clone(); - auto & lambda_to_resolve_typed = lambda_to_resolve->as(); - - const auto & lambda_argument_names = lambda_to_resolve_typed.getArgumentNames(); - size_t lambda_arguments_size = lambda_to_resolve_typed.getArguments().getNodes().size(); - - const auto * function_data_type = typeid_cast(argument_types[function_lambda_argument_index].get()); - if (!function_data_type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' expected function data type for lambda argument with index {}. Actual {}. In scope {}", - function_name, - function_lambda_argument_index, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & function_data_type_argument_types = function_data_type->getArgumentTypes(); - size_t function_data_type_arguments_size = function_data_type_argument_types.size(); - if (function_data_type_arguments_size != lambda_arguments_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}" - "' function data type for lambda argument with index {} arguments size mismatch. " - "Actual {}. Expected {}. In scope {}", - function_name, - function_data_type_arguments_size, - lambda_arguments_size, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - QueryTreeNodes lambda_arguments; - lambda_arguments.reserve(lambda_arguments_size); - - for (size_t i = 0; i < lambda_arguments_size; ++i) - { - const auto & argument_type = function_data_type_argument_types[i]; - auto column_name_and_type = NameAndTypePair{lambda_argument_names[i], argument_type}; - lambda_arguments.push_back(std::make_shared(std::move(column_name_and_type), lambda_to_resolve)); - } - - IdentifierResolveScope lambda_scope(lambda_to_resolve, &scope /*parent_scope*/); - lambda_projection_names = resolveLambda(lambda_argument, lambda_to_resolve, lambda_arguments, lambda_scope); - - if (auto * lambda_list_node_result = lambda_to_resolve_typed.getExpression()->as()) - { - size_t lambda_list_node_result_nodes_size = lambda_list_node_result->getNodes().size(); - - if (lambda_list_node_result_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Lambda as function argument resolved as list node with size {}. Expected 1. In scope {}", - lambda_list_node_result_nodes_size, - lambda_to_resolve->formatASTForErrorMessage()); - - lambda_to_resolve_typed.getExpression() = lambda_list_node_result->getNodes().front(); - } - - if (arguments_projection_names.at(function_lambda_argument_index) == PROJECTION_NAME_PLACEHOLDER) - { - size_t lambda_projection_names_size =lambda_projection_names.size(); - if (lambda_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Lambda argument inside function expected to have 1 projection name. Actual {}", - lambda_projection_names_size); - - WriteBufferFromOwnString lambda_argument_projection_name_buffer; - lambda_argument_projection_name_buffer << "lambda("; - lambda_argument_projection_name_buffer << "tuple("; - - size_t lambda_argument_names_size = lambda_argument_names.size(); - - for (size_t i = 0; i < lambda_argument_names_size; ++i) - { - const auto & lambda_argument_name = lambda_argument_names[i]; - lambda_argument_projection_name_buffer << lambda_argument_name; - - if (i + 1 != lambda_argument_names_size) - lambda_argument_projection_name_buffer << ", "; - } - - lambda_argument_projection_name_buffer << "), "; - lambda_argument_projection_name_buffer << lambda_projection_names[0]; - lambda_argument_projection_name_buffer << ")"; - - lambda_projection_names.clear(); - - arguments_projection_names[function_lambda_argument_index] = lambda_argument_projection_name_buffer.str(); - } - - auto lambda_resolved_type = std::make_shared(function_data_type_argument_types, lambda_to_resolve_typed.getExpression()->getResultType()); - lambda_to_resolve_typed.resolve(lambda_resolved_type); - - argument_types[function_lambda_argument_index] = lambda_resolved_type; - argument_columns[function_lambda_argument_index].type = lambda_resolved_type; - function_arguments[function_lambda_argument_index] = std::move(lambda_to_resolve); - } - - /// Recalculate function projection name after lambda resolution - result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - } - - /** Create SET column for special function IN to allow constant folding - * if left and right arguments are constants. - * - * Example: SELECT * FROM test_table LIMIT 1 IN 1; - */ - if (is_special_function_in) - { - const auto * first_argument_constant_node = function_arguments[0]->as(); - const auto * second_argument_constant_node = function_arguments[1]->as(); - - if (first_argument_constant_node && second_argument_constant_node) - { - const auto & first_argument_constant_type = first_argument_constant_node->getResultType(); - const auto & second_argument_constant_literal = second_argument_constant_node->getValue(); - const auto & second_argument_constant_type = second_argument_constant_node->getResultType(); - - const auto & settings = scope.context->getSettingsRef(); - - auto result_block = getSetElementsForConstantValue(first_argument_constant_type, - second_argument_constant_literal, - second_argument_constant_type, - settings.transform_null_in); - - SizeLimits size_limits_for_set = {settings.max_rows_in_set, settings.max_bytes_in_set, settings.set_overflow_mode}; - - auto set = std::make_shared(size_limits_for_set, 0, settings.transform_null_in); - - set->setHeader(result_block.cloneEmpty().getColumnsWithTypeAndName()); - set->insertFromBlock(result_block.getColumnsWithTypeAndName()); - set->finishInsert(); - - auto future_set = std::make_shared(std::move(set)); - - /// Create constant set column for constant folding - - auto column_set = ColumnSet::create(1, std::move(future_set)); - argument_columns[1].column = ColumnConst::create(std::move(column_set), 1); - } - - argument_columns[1].type = std::make_shared(); - } - - std::shared_ptr constant_value; - - try - { - FunctionBasePtr function_base; - if (function_cache) - { - auto & cached_function = function_cache->function_base; - if (!cached_function) - cached_function = function->build(argument_columns); - - function_base = cached_function; - } - else - function_base = function->build(argument_columns); - - /// Do not constant fold get scalar functions - bool disable_constant_folding = function_name == "__getScalar" || function_name == "shardNum" || - function_name == "shardCount" || function_name == "hostName" || function_name == "tcpPort"; - - /** If function is suitable for constant folding try to convert it to constant. - * Example: SELECT plus(1, 1); - * Result: SELECT 2; - */ - if (function_base->isSuitableForConstantFolding() && !disable_constant_folding) - { - auto result_type = function_base->getResultType(); - auto executable_function = function_base->prepare(argument_columns); - - ColumnPtr column; - - if (all_arguments_constants) - { - size_t num_rows = function_arguments.empty() ? 0 : argument_columns.front().column->size(); - column = executable_function->execute(argument_columns, result_type, num_rows, true); - } - else - { - column = function_base->getConstantResultForNonConstArguments(argument_columns, result_type); - } - - if (column && column->getDataType() != result_type->getColumnType()) - throw Exception( - ErrorCodes::LOGICAL_ERROR, - "Unexpected return type from {}. Expected {}. Got {}", - function->getName(), - result_type->getColumnType(), - column->getDataType()); - - /** Do not perform constant folding if there are aggregate or arrayJoin functions inside function. - * Example: SELECT toTypeName(sum(number)) FROM numbers(10); - */ - if (column && isColumnConst(*column) && !typeid_cast(column.get())->getDataColumn().isDummy() && - !hasAggregateFunctionNodes(node) && !hasFunctionNode(node, "arrayJoin") && - /// Sanity check: do not convert large columns to constants - column->byteSize() < 1_MiB) - { - /// Replace function node with result constant node - Field column_constant_value; - column->get(0, column_constant_value); - constant_value = std::make_shared(std::move(column_constant_value), result_type); - } - } - - function_node.resolveAsFunction(std::move(function_base)); - } - catch (Exception & e) - { - e.addMessage("In scope {}", scope.scope_node->formatASTForErrorMessage()); - throw; - } - - if (constant_value) - node = std::make_shared(std::move(constant_value), node); - - return result_projection_names; -} - -/** Resolve expression node. - * Argument node can be replaced with different node, or even with list node in case of matcher resolution. - * Example: SELECT * FROM test_table; - * * - is matcher node, and it can be resolved into ListNode. - * - * Steps: - * 1. If node has alias, replace node with its value in scope alias map. Register alias in expression_aliases_in_resolve_process, to prevent resolving identifier - * which can bind to expression alias name. Check tryResolveIdentifierFromAliases documentation for additional explanation. - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * - * 2. Call specific resolve method depending on node type. - * - * If allow_table_expression = true and node is query node, then it is not evaluated as scalar subquery. - * Although if node is identifier that is resolved into query node that query is evaluated as scalar subquery. - * SELECT id, (SELECT 1) AS c FROM test_table WHERE a IN c; - * SELECT id, FROM test_table WHERE a IN (SELECT 1); - * - * 3. Special case identifier node. - * Try resolve it as expression identifier. - * Then if allow_lambda_expression = true try to resolve it as function. - * Then if allow_table_expression = true try to resolve it as table expression. - * - * 4. If node has alias, update its value in scope alias map. Deregister alias from expression_aliases_in_resolve_process. - */ -ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias) -{ - checkStackSize(); - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - /** There can be edge case, when subquery for IN function is resolved multiple times in different context. - * SELECT id IN (subquery AS value), value FROM test_table; - * When we start to resolve `value` identifier, subquery is already resolved but constant folding is not performed. - */ - auto node_type = node->getNodeType(); - if (!allow_table_expression && (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION)) - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - } - - return resolved_expression_it->second; - } - - String node_alias = node->getAlias(); - ProjectionNames result_projection_names; - - if (node_alias.empty()) - { - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - else - { - result_projection_names.push_back(node_alias); - } - - bool is_duplicated_alias = scope.aliases.nodes_with_duplicated_aliases.contains(node); - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.insert({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - /** Do not use alias table if node has alias same as some other node. - * Example: WITH x -> x + 1 AS lambda SELECT 1 AS lambda; - * During 1 AS lambda resolve if we use alias table we replace node with x -> x + 1 AS lambda. - * - * Do not use alias table if allow_table_expression = true and we resolve query node directly. - * Example: SELECT a FROM test_table WHERE id IN (SELECT 1) AS a; - * To support both (SELECT 1) AS expression in projection and (SELECT 1) as subquery in IN, do not use - * alias table because in alias table subquery could be evaluated as scalar. - */ - bool use_alias_table = !ignore_alias; - if (is_duplicated_alias || (allow_table_expression && isSubqueryNodeType(node->getNodeType()))) - use_alias_table = false; - - if (!node_alias.empty() && use_alias_table) - { - /** Node could be potentially resolved by resolving other nodes. - * SELECT b, a as b FROM test_table; - * - * To resolve b we need to resolve a. - */ - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - node = it->second; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - node = it->second; - } - } - - scope.pushExpressionNode(node); - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & identifier_node = node->as(); - auto unresolved_identifier = identifier_node.getIdentifier(); - auto resolve_identifier_expression_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier_node = resolve_identifier_expression_result.resolved_identifier; - - if (resolved_identifier_node && result_projection_names.empty() && - (resolve_identifier_expression_result.isResolvedFromJoinTree() || resolve_identifier_expression_result.isResolvedFromExpressionArguments())) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier_node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - - if (!resolved_identifier_node && allow_lambda_expression) - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::FUNCTION}, scope).resolved_identifier; - - if (!resolved_identifier_node && allow_table_expression) - { - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::TABLE_EXPRESSION}, scope).resolved_identifier; - - if (resolved_identifier_node) - { - /// If table identifier is resolved as CTE clone it and resolve - auto * subquery_node = resolved_identifier_node->as(); - auto * union_node = resolved_identifier_node->as(); - bool resolved_as_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - - if (resolved_as_cte) - { - resolved_identifier_node = resolved_identifier_node->clone(); - subquery_node = resolved_identifier_node->as(); - union_node = resolved_identifier_node->as(); - - std::string_view cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - if (subquery_node) - subquery_node->setIsCTE(false); - else - union_node->setIsCTE(false); - - IdentifierResolveScope subquery_scope(resolved_identifier_node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - /// CTE is being resolved, it's required to forbid to resolve to it again - /// because recursive CTEs are not supported, e.g.: - /// - /// WITH test1 AS (SELECT i + 1, j + 1 FROM test1) SELECT toInt64(4) i, toInt64(5) j FROM numbers(3) WHERE (i, j) IN test1; - /// - /// In this example argument of function `in` is being resolve here. If CTE `test1` is not forbidden, - /// `test1` is resolved to CTE (not to the table) in `initializeQueryJoinTreeNode` function. - ctes_in_resolve_process.insert(cte_name); - - if (subquery_node) - resolveQuery(resolved_identifier_node, subquery_scope); - else - resolveUnion(resolved_identifier_node, subquery_scope); - - ctes_in_resolve_process.erase(cte_name); - } - } - } - - if (!resolved_identifier_node) - { - std::string message_clarification; - if (allow_lambda_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::FUNCTION); - - if (allow_table_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::TABLE_EXPRESSION); - - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(unresolved_identifier, - scope, - true, - allow_lambda_expression, - allow_table_expression, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(unresolved_identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {}{} identifier '{}' in scope {}{}", - toStringLowercase(IdentifierLookupContext::EXPRESSION), - message_clarification, - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - node = std::move(resolved_identifier_node); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - { - result_projection_names.clear(); - resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - return resolved_expression_it->second; - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier '{}' resolve into list node and list node projection names are not initialized. In scope {}", - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_projection_names.empty()) - result_projection_names.push_back(unresolved_identifier.getFullName()); - - break; - } - case QueryTreeNodeType::MATCHER: - { - result_projection_names = resolveMatcher(node, scope); - break; - } - case QueryTreeNodeType::LIST: - { - /** Edge case if list expression has alias. - * Matchers cannot have aliases, but `untuple` function can. - * Example: SELECT a, untuple(CAST(('hello', 1) AS Tuple(name String, count UInt32))) AS a; - * During resolveFunction `untuple` function is replaced by list of 2 constants 'hello', 1. - */ - result_projection_names = resolveExpressionNodeList(node, scope, allow_lambda_expression, allow_lambda_expression); - break; - } - case QueryTreeNodeType::CONSTANT: - { - if (result_projection_names.empty()) - { - const auto & constant_node = node->as(); - result_projection_names.push_back(constant_node.getValueStringRepresentation()); - } - - /// Already resolved - break; - } - case QueryTreeNodeType::COLUMN: - { - auto & column_node = node->as(); - if (column_node.hasExpression()) - resolveExpressionNode(column_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (result_projection_names.empty()) - result_projection_names.push_back(column_node.getColumnName()); - - break; - } - case QueryTreeNodeType::FUNCTION: - { - auto function_projection_names = resolveFunction(node, scope); - - if (result_projection_names.empty() || node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(function_projection_names); - - break; - } - case QueryTreeNodeType::LAMBDA: - { - if (!allow_lambda_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (result_projection_names.empty()) - result_projection_names.push_back(PROJECTION_NAME_PLACEHOLDER); - - /// Lambda must be resolved by caller - break; - } - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - std::string projection_name = "_subquery_" + std::to_string(subquery_counter); - ++subquery_counter; - - if (node_type == QueryTreeNodeType::QUERY) - resolveQuery(node, subquery_scope); - else - resolveUnion(node, subquery_scope); - - if (!allow_table_expression) - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - - if (result_projection_names.empty()) - result_projection_names.push_back(std::move(projection_name)); - - break; - } - case QueryTreeNodeType::TABLE: - { - if (!allow_table_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Table {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node = node->as(); - result_projection_names.push_back(table_node.getStorageID().getFullNameNotQuoted()); - - break; - } - case QueryTreeNodeType::TRANSFORMER: - [[fallthrough]]; - case QueryTreeNodeType::SORT: - [[fallthrough]]; - case QueryTreeNodeType::INTERPOLATE: - [[fallthrough]]; - case QueryTreeNodeType::WINDOW: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::ARRAY_JOIN: - [[fallthrough]]; - case QueryTreeNodeType::JOIN: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "{} {} is not allowed in expression context. In scope {}", - node->getNodeType(), - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - validateTreeSize(node, scope.context->getSettingsRef().max_expanded_ast_elements, node_to_tree_size); - - /// Lambda can be inside the aggregate function, so we should check parent scopes. - /// Most likely only the root scope can have an arrgegate function, but let's check all just in case. - bool in_aggregate_function_scope = false; - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - in_aggregate_function_scope = in_aggregate_function_scope || scope_ptr->expressions_in_resolve_process_stack.hasAggregateFunction(); - - if (!in_aggregate_function_scope) - { - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - { - auto it = scope_ptr->nullable_group_by_keys.find(node); - if (it != scope_ptr->nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - break; - } - } - } - - /** Update aliases after expression node was resolved. - * Do not update node in alias table if we resolve it for duplicate alias. - */ - if (!node_alias.empty() && use_alias_table && !scope.group_by_use_nulls) - { - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - it->second = node; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - it->second = node; - } - } - - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.erase({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - if (!ignore_alias) - resolved_expressions.emplace(node, result_projection_names); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - return result_projection_names; -} - -/** Resolve expression node list. - * If expression is CTE subquery node it is skipped. - * If expression is resolved in list, it is flattened into initial node list. - * - * Such examples must work: - * Example: CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; SELECT plus(*) FROM test_table; - * Example: SELECT *** FROM system.one; - */ -ProjectionNames QueryAnalyzer::resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression) -{ - auto & node_list_typed = node_list->as(); - size_t node_list_size = node_list_typed.getNodes().size(); - - QueryTreeNodes result_nodes; - result_nodes.reserve(node_list_size); - - ProjectionNames result_projection_names; - - for (auto & node : node_list_typed.getNodes()) - { - auto node_to_resolve = node; - auto expression_node_projection_names = resolveExpressionNode(node_to_resolve, scope, allow_lambda_expression, allow_table_expression); - size_t expected_projection_names_size = 1; - if (auto * expression_list = node_to_resolve->as()) - { - expected_projection_names_size = expression_list->getNodes().size(); - for (auto & expression_list_node : expression_list->getNodes()) - result_nodes.push_back(expression_list_node); - } - else - { - result_nodes.push_back(std::move(node_to_resolve)); - } - - if (expression_node_projection_names.size() != expected_projection_names_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected {} projection names. Actual {}", - expected_projection_names_size, - expression_node_projection_names.size()); - - result_projection_names.insert(result_projection_names.end(), expression_node_projection_names.begin(), expression_node_projection_names.end()); - expression_node_projection_names.clear(); - } - - node_list_typed.getNodes() = std::move(result_nodes); - - return result_projection_names; -} - -/** Resolve sort columns nodes list. - */ -ProjectionNames QueryAnalyzer::resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames result_projection_names; - ProjectionNames sort_expression_projection_names; - ProjectionNames fill_from_expression_projection_names; - ProjectionNames fill_to_expression_projection_names; - ProjectionNames fill_step_expression_projection_names; - - auto & sort_node_list_typed = sort_node_list->as(); - for (auto & node : sort_node_list_typed.getNodes()) - { - auto & sort_node = node->as(); - sort_expression_projection_names = resolveExpressionNode(sort_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (auto * sort_column_list_node = sort_node.getExpression()->as()) - { - size_t sort_column_list_node_size = sort_column_list_node->getNodes().size(); - if (sort_column_list_node_size != 1) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Sort column node expression resolved into list with size {}. Expected 1. In scope {}", - sort_column_list_node_size, - scope.scope_node->formatASTForErrorMessage()); - } - - sort_node.getExpression() = sort_column_list_node->getNodes().front(); - } - - size_t sort_expression_projection_names_size = sort_expression_projection_names.size(); - if (sort_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort expression expected 1 projection name. Actual {}", - sort_expression_projection_names_size); - - if (sort_node.hasFillFrom()) - { - fill_from_expression_projection_names = resolveExpressionNode(sort_node.getFillFrom(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillFrom()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL FROM expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_from_expression_projection_names_size = fill_from_expression_projection_names.size(); - if (fill_from_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL FROM expression expected 1 projection name. Actual {}", - fill_from_expression_projection_names_size); - } - - if (sort_node.hasFillTo()) - { - fill_to_expression_projection_names = resolveExpressionNode(sort_node.getFillTo(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillTo()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL TO expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_to_expression_projection_names_size = fill_to_expression_projection_names.size(); - if (fill_to_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL TO expression expected 1 projection name. Actual {}", - fill_to_expression_projection_names_size); - } - - if (sort_node.hasFillStep()) - { - fill_step_expression_projection_names = resolveExpressionNode(sort_node.getFillStep(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillStep()->as(); - if (!constant_node) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - bool is_number = isColumnedAsNumber(constant_node->getResultType()); - bool is_interval = WhichDataType(constant_node->getResultType()).isInterval(); - if (!is_number && !is_interval) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_step_expression_projection_names_size = fill_step_expression_projection_names.size(); - if (fill_step_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort FILL STEP expression expected 1 projection name. Actual {}", - fill_step_expression_projection_names_size); - } - - auto sort_column_projection_name = calculateSortColumnProjectionName(node, - sort_expression_projection_names[0], - fill_from_expression_projection_names.empty() ? "" : fill_from_expression_projection_names.front(), - fill_to_expression_projection_names.empty() ? "" : fill_to_expression_projection_names.front(), - fill_step_expression_projection_names.empty() ? "" : fill_step_expression_projection_names.front()); - - result_projection_names.push_back(std::move(sort_column_projection_name)); - - sort_expression_projection_names.clear(); - fill_from_expression_projection_names.clear(); - fill_to_expression_projection_names.clear(); - fill_step_expression_projection_names.clear(); - } - - return result_projection_names; -} - -namespace -{ - -void expandTuplesInList(QueryTreeNodes & key_list) -{ - QueryTreeNodes expanded_keys; - expanded_keys.reserve(key_list.size()); - for (auto const & key : key_list) - { - if (auto * function = key->as(); function != nullptr && function->getFunctionName() == "tuple") - { - std::copy(function->getArguments().begin(), function->getArguments().end(), std::back_inserter(expanded_keys)); - } - else - expanded_keys.push_back(key); - } - key_list = std::move(expanded_keys); -} - -} - -/** Resolve GROUP BY clause. - */ -void QueryAnalyzer::resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope) -{ - if (query_node_typed.isGroupByWithGroupingSets()) - { - for (auto & grouping_sets_keys_list_node : query_node_typed.getGroupBy().getNodes()) - { - replaceNodesWithPositionalArguments(grouping_sets_keys_list_node, query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(grouping_sets_keys_list_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = grouping_sets_keys_list_node->as().getNodes(); - expandTuplesInList(group_by_list); - } - - if (scope.group_by_use_nulls) - { - for (const auto & grouping_set : query_node_typed.getGroupBy().getNodes()) - { - for (const auto & group_by_elem : grouping_set->as()->getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } - } - else - { - replaceNodesWithPositionalArguments(query_node_typed.getGroupByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getGroupByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = query_node_typed.getGroupBy().getNodes(); - expandTuplesInList(group_by_list); - - if (scope.group_by_use_nulls) - { - for (const auto & group_by_elem : query_node_typed.getGroupBy().getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } -} - -/** Resolve interpolate columns nodes list. - */ -void QueryAnalyzer::resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope) -{ - auto & interpolate_node_list_typed = interpolate_node_list->as(); - - for (auto & interpolate_node : interpolate_node_list_typed.getNodes()) - { - auto & interpolate_node_typed = interpolate_node->as(); - - auto * column_to_interpolate = interpolate_node_typed.getExpression()->as(); - if (!column_to_interpolate) - throw Exception(ErrorCodes::LOGICAL_ERROR, "INTERPOLATE can work only for indentifiers, but {} is found", - interpolate_node_typed.getExpression()->formatASTForErrorMessage()); - auto column_to_interpolate_name = column_to_interpolate->getIdentifier().getFullName(); - - resolveExpressionNode(interpolate_node_typed.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool is_column_constant = interpolate_node_typed.getExpression()->getNodeType() == QueryTreeNodeType::CONSTANT; - - auto & interpolation_to_resolve = interpolate_node_typed.getInterpolateExpression(); - IdentifierResolveScope interpolate_scope(interpolation_to_resolve, &scope /*parent_scope*/); - - auto fake_column_node = std::make_shared(NameAndTypePair(column_to_interpolate_name, interpolate_node_typed.getExpression()->getResultType()), interpolate_node_typed.getExpression()); - if (is_column_constant) - interpolate_scope.expression_argument_name_to_node.emplace(column_to_interpolate_name, fake_column_node); - - resolveExpressionNode(interpolation_to_resolve, interpolate_scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (is_column_constant) - interpolation_to_resolve = interpolation_to_resolve->cloneAndReplace(fake_column_node, interpolate_node_typed.getExpression()); - } -} - -/** Resolve window nodes list. - */ -void QueryAnalyzer::resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope) -{ - auto & window_node_list_typed = window_node_list->as(); - for (auto & node : window_node_list_typed.getNodes()) - resolveWindow(node, scope); -} - -NamesAndTypes QueryAnalyzer::resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames projection_names = resolveExpressionNodeList(projection_node_list, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto projection_nodes = projection_node_list->as().getNodes(); - size_t projection_nodes_size = projection_nodes.size(); - - NamesAndTypes projection_columns; - projection_columns.reserve(projection_nodes_size); - - for (size_t i = 0; i < projection_nodes_size; ++i) - { - auto projection_node = projection_nodes[i]; - - if (!isExpressionNodeType(projection_node->getNodeType())) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Projection node must be constant, function, column, query or union"); - - projection_columns.emplace_back(projection_names[i], projection_node->getResultType()); - } - - return projection_columns; -} - -/** Initialize query join tree node. - * - * 1. Resolve identifiers. - * 2. Register table, table function, query, union, join, array join nodes in scope table expressions in resolve process. - */ -void QueryAnalyzer::initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope) -{ - std::deque join_tree_node_ptrs_to_process_queue; - join_tree_node_ptrs_to_process_queue.push_back(&join_tree_node); - - while (!join_tree_node_ptrs_to_process_queue.empty()) - { - auto * current_join_tree_node_ptr = join_tree_node_ptrs_to_process_queue.front(); - join_tree_node_ptrs_to_process_queue.pop_front(); - - auto & current_join_tree_node = *current_join_tree_node_ptr; - auto current_join_tree_node_type = current_join_tree_node->getNodeType(); - - switch (current_join_tree_node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & from_table_identifier = current_join_tree_node->as(); - auto table_identifier_lookup = IdentifierLookup{from_table_identifier.getIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - - auto from_table_identifier_alias = from_table_identifier.getAlias(); - - IdentifierResolveSettings resolve_settings; - /// In join tree initialization ignore join tree as identifier lookup source - resolve_settings.allow_to_check_join_tree = false; - /** Disable resolve of subquery during identifier resolution. - * Example: SELECT * FROM (SELECT 1) AS t1, t1; - * During `t1` identifier resolution we resolve it into subquery SELECT 1, but we want to disable - * subquery resolution at this stage, because JOIN TREE of parent query is not resolved. - */ - resolve_settings.allow_to_resolve_subquery_during_identifier_resolution = false; - - scope.pushExpressionNode(current_join_tree_node); - - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, resolve_settings); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - auto resolved_identifier = table_identifier_resolve_result.resolved_identifier; - - if (!resolved_identifier) - throw Exception(ErrorCodes::UNKNOWN_TABLE, - "Unknown table expression identifier '{}' in scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - resolved_identifier = resolved_identifier->clone(); - - /// Update alias name to table expression map - auto table_expression_it = scope.aliases.alias_name_to_table_expression_node.find(from_table_identifier_alias); - if (table_expression_it != scope.aliases.alias_name_to_table_expression_node.end()) - table_expression_it->second = resolved_identifier; - - auto table_expression_modifiers = from_table_identifier.getTableExpressionModifiers(); - - auto * resolved_identifier_query_node = resolved_identifier->as(); - auto * resolved_identifier_union_node = resolved_identifier->as(); - - if (resolved_identifier_query_node || resolved_identifier_union_node) - { - if (table_expression_modifiers.has_value()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Table expression modifiers {} are not supported for subquery {}", - table_expression_modifiers->formatForErrorMessage(), - resolved_identifier->formatASTForErrorMessage()); - } - } - else if (auto * resolved_identifier_table_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else if (auto * resolved_identifier_table_function_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_function_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier in JOIN TREE '{}' resolved into unexpected table expression. In scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto current_join_tree_node_alias = current_join_tree_node->getAlias(); - resolved_identifier->setAlias(current_join_tree_node_alias); - current_join_tree_node = resolved_identifier; - - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::QUERY: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::UNION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - auto & array_join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&array_join.getTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::JOIN: - { - auto & join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&join.getLeftTableExpression()); - join_tree_node_ptrs_to_process_queue.push_back(&join.getRightTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - ++scope.joins_count; - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, UNION, ARRAY JOIN or JOIN. Actual {} {}. In scope {}", - current_join_tree_node->getNodeTypeName(), - current_join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - } -} - -/// Initialize table expression data for table expression node -void QueryAnalyzer::initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto table_expression_data_it = scope.table_expression_node_to_data.find(table_expression_node); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - return; - - TableExpressionData table_expression_data; - - if (table_node) - { - if (!table_node->getTemporaryTableName().empty()) - { - table_expression_data.table_name = table_node->getTemporaryTableName(); - table_expression_data.table_expression_name = table_node->getTemporaryTableName(); - } - else - { - const auto & table_storage_id = table_node->getStorageID(); - table_expression_data.database_name = table_storage_id.database_name; - table_expression_data.table_name = table_storage_id.table_name; - table_expression_data.table_expression_name = table_storage_id.getFullNameNotQuoted(); - } - - table_expression_data.table_expression_description = "table"; - } - else if (query_node || union_node) - { - table_expression_data.table_name = query_node ? query_node->getCTEName() : union_node->getCTEName(); - table_expression_data.table_expression_description = "subquery"; - } - else if (table_function_node) - { - table_expression_data.table_expression_description = "table_function"; - } - - if (table_expression_node->hasAlias()) - table_expression_data.table_expression_name = table_expression_node->getAlias(); - - if (table_node || table_function_node) - { - const auto & storage_snapshot = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - - auto get_column_options = GetColumnsOptions(GetColumnsOptions::All).withExtendedObjects().withVirtuals(); - if (storage_snapshot->storage.supportsSubcolumns()) - get_column_options.withSubcolumns(); - - auto column_names_and_types = storage_snapshot->getColumns(get_column_options); - table_expression_data.column_names_and_types = NamesAndTypes(column_names_and_types.begin(), column_names_and_types.end()); - - const auto & columns_description = storage_snapshot->metadata->getColumns(); - - std::vector> alias_columns_to_resolve; - ColumnNameToColumnNodeMap column_name_to_column_node; - column_name_to_column_node.reserve(column_names_and_types.size()); - - /** For ALIAS columns in table we must additionally analyze ALIAS expressions. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + 5); - * - * To do that we collect alias columns and build table column name to column node map. - * For each alias column we build identifier resolve scope, initialize it with table column name to node map - * and resolve alias column. - */ - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - for (const auto & subcolumn : columns_description.getSubcolumns(column_name_and_type.name)) - table_expression_data.subcolumn_names.insert(subcolumn.name); - const auto & column_default = columns_description.getDefault(column_name_and_type.name); - - if (column_default && column_default->kind == ColumnDefaultKind::Alias) - { - auto alias_expression = buildQueryTree(column_default->expression, scope.context); - auto column_node = std::make_shared(column_name_and_type, std::move(alias_expression), table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - alias_columns_to_resolve.emplace_back(column_name_and_type.name, column_node); - } - else - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - for (auto & [alias_column_to_resolve_name, alias_column_to_resolve] : alias_columns_to_resolve) - { - /** Alias column could be potentially resolved during resolve of other ALIAS column. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + alias_value_2, alias_value_2 ALIAS id + 5) ENGINE=TinyLog; - * - * During resolve of alias_value_1, alias_value_2 column will be resolved. - */ - alias_column_to_resolve = column_name_to_column_node[alias_column_to_resolve_name]; - - IdentifierResolveScope alias_column_resolve_scope(alias_column_to_resolve, nullptr /*parent_scope*/); - alias_column_resolve_scope.column_name_to_column_node = std::move(column_name_to_column_node); - alias_column_resolve_scope.context = scope.context; - - /// Initialize aliases in alias column scope - QueryExpressionsAliasVisitor visitor(alias_column_resolve_scope.aliases); - visitor.visit(alias_column_to_resolve->getExpression()); - - resolveExpressionNode(alias_column_resolve_scope.scope_node, - alias_column_resolve_scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - auto & resolved_expression = alias_column_to_resolve->getExpression(); - if (!resolved_expression->getResultType()->equals(*alias_column_to_resolve->getResultType())) - resolved_expression = buildCastFunction(resolved_expression, alias_column_to_resolve->getResultType(), scope.context, true); - column_name_to_column_node = std::move(alias_column_resolve_scope.column_name_to_column_node); - column_name_to_column_node[alias_column_to_resolve_name] = alias_column_to_resolve; - } - - table_expression_data.column_name_to_column_node = std::move(column_name_to_column_node); - } - else if (query_node || union_node) - { - table_expression_data.column_names_and_types = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - table_expression_data.column_name_to_column_node.reserve(table_expression_data.column_names_and_types.size()); - - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - table_expression_data.column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - table_expression_data.column_identifier_first_parts.reserve(table_expression_data.column_name_to_column_node.size()); - - for (auto & [column_name, _] : table_expression_data.column_name_to_column_node) - { - Identifier column_name_identifier(column_name); - table_expression_data.column_identifier_first_parts.insert(column_name_identifier.at(0)); - } - - if (auto * scope_query_node = scope.scope_node->as()) - { - auto left_table_expression = extractLeftTableExpression(scope_query_node->getJoinTree()); - if (table_expression_node.get() == left_table_expression.get() && - scope.joins_count == 1 && - scope.context->getSettingsRef().single_join_prefer_left_table) - table_expression_data.should_qualify_columns = false; - } - - scope.table_expression_node_to_data.emplace(table_expression_node, std::move(table_expression_data)); -} - -bool findIdentifier(const FunctionNode & function) -{ - for (const auto & argument : function.getArguments()) - { - if (argument->as()) - return true; - if (const auto * f = argument->as(); f && findIdentifier(*f)) - return true; - } - return false; -} - -/// Resolve table function node in scope -void QueryAnalyzer::resolveTableFunction(QueryTreeNodePtr & table_function_node, - IdentifierResolveScope & scope, - QueryExpressionsAliasVisitor & expressions_visitor, - bool nested_table_function) -{ - auto & table_function_node_typed = table_function_node->as(); - - if (!nested_table_function) - expressions_visitor.visit(table_function_node_typed.getArgumentsNode()); - - const auto & table_function_name = table_function_node_typed.getTableFunctionName(); - - auto & scope_context = scope.context; - - TableFunctionPtr table_function_ptr = TableFunctionFactory::instance().tryGet(table_function_name, scope_context); - if (!table_function_ptr) - { - String database_name = scope_context->getCurrentDatabase(); - String table_name; - - auto function_ast = table_function_node->toAST(); - Identifier table_identifier{table_function_name}; - if (table_identifier.getPartsSize() == 1) - { - table_name = table_identifier[0]; - } - else if (table_identifier.getPartsSize() == 2) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - - auto parametrized_view_storage = scope_context->getQueryContext()->buildParametrizedViewStorage(function_ast, database_name, table_name); - if (parametrized_view_storage) - { - auto fake_table_node = std::make_shared(parametrized_view_storage, scope_context); - fake_table_node->setAlias(table_function_node->getAlias()); - table_function_node = fake_table_node; - return; - } - - auto hints = TableFunctionFactory::instance().getHints(table_function_name); - if (!hints.empty()) - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}. Maybe you meant: {}", - table_function_name, - DB::toString(hints)); - else - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}", - table_function_name); - } - - QueryTreeNodes result_table_function_arguments; - - auto skip_analysis_arguments_indexes = table_function_ptr->skipAnalysisForArguments(table_function_node, scope_context); - - auto & table_function_arguments = table_function_node_typed.getArguments().getNodes(); - size_t table_function_arguments_size = table_function_arguments.size(); - - for (size_t table_function_argument_index = 0; table_function_argument_index < table_function_arguments_size; ++table_function_argument_index) - { - auto & table_function_argument = table_function_arguments[table_function_argument_index]; - - auto skip_argument_index_it = std::find(skip_analysis_arguments_indexes.begin(), - skip_analysis_arguments_indexes.end(), - table_function_argument_index); - if (skip_argument_index_it != skip_analysis_arguments_indexes.end()) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - if (auto * identifier_node = table_function_argument->as()) - { - const auto & unresolved_identifier = identifier_node->getIdentifier(); - auto identifier_resolve_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier = std::move(identifier_resolve_result.resolved_identifier); - - if (resolved_identifier && resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - result_table_function_arguments.push_back(std::move(resolved_identifier)); - else - result_table_function_arguments.push_back(table_function_argument); - - continue; - } - else if (auto * table_function_argument_function = table_function_argument->as()) - { - const auto & table_function_argument_function_name = table_function_argument_function->getFunctionName(); - if (TableFunctionFactory::instance().isTableFunctionName(table_function_argument_function_name)) - { - auto table_function_node_to_resolve_typed = std::make_shared(table_function_argument_function_name); - table_function_node_to_resolve_typed->getArgumentsNode() = table_function_argument_function->getArgumentsNode(); - - QueryTreeNodePtr table_function_node_to_resolve = std::move(table_function_node_to_resolve_typed); - resolveTableFunction(table_function_node_to_resolve, scope, expressions_visitor, true /*nested_table_function*/); - - result_table_function_arguments.push_back(std::move(table_function_node_to_resolve)); - continue; - } - } - - /** Table functions arguments can contain expressions with invalid identifiers. - * We cannot skip analysis for such arguments, because some table functions cannot provide - * information if analysis for argument should be skipped until other arguments will be resolved. - * - * Example: SELECT key from remote('127.0.0.{1,2}', view(select number AS key from numbers(2)), cityHash64(key)); - * Example: SELECT id from remote('127.0.0.{1,2}', 'default', 'test_table', cityHash64(id)); - */ - try - { - resolveExpressionNode(table_function_argument, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - catch (const Exception & exception) - { - if (exception.code() == ErrorCodes::UNKNOWN_IDENTIFIER) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - throw; - } - - if (auto * expression_list = table_function_argument->as()) - { - for (auto & expression_list_node : expression_list->getNodes()) - result_table_function_arguments.push_back(expression_list_node); - } - else - { - result_table_function_arguments.push_back(table_function_argument); - } - } - - table_function_node_typed.getArguments().getNodes() = std::move(result_table_function_arguments); - - auto table_function_ast = table_function_node_typed.toAST(); - table_function_ptr->parseArguments(table_function_ast, scope_context); - - - uint64_t use_structure_from_insertion_table_in_table_functions = scope_context->getSettingsRef().use_structure_from_insertion_table_in_table_functions; - if (!nested_table_function && - use_structure_from_insertion_table_in_table_functions && - scope_context->hasInsertionTable() && - table_function_ptr->needStructureHint()) - { - const auto & insertion_table = scope_context->getInsertionTable(); - if (!insertion_table.empty()) - { - const auto & insert_columns = DatabaseCatalog::instance() - .getTable(insertion_table, scope_context) - ->getInMemoryMetadataPtr() - ->getColumns(); - const auto & insert_column_names = scope_context->hasInsertionTableColumnNames() ? *scope_context->getInsertionTableColumnNames() : insert_columns.getOrdinary().getNames(); - DB::ColumnsDescription structure_hint; - - bool use_columns_from_insert_query = true; - - /// Insert table matches columns against SELECT expression by position, so we want to map - /// insert table columns to table function columns through names from SELECT expression. - - auto insert_column_name_it = insert_column_names.begin(); - auto insert_column_names_end = insert_column_names.end(); /// end iterator of the range covered by possible asterisk - auto virtual_column_names = table_function_ptr->getVirtualsToCheckBeforeUsingStructureHint(); - bool asterisk = false; - const auto & expression_list = scope.scope_node->as().getProjection(); - auto expression = expression_list.begin(); - - /// We want to go through SELECT expression list and correspond each expression to column in insert table - /// which type will be used as a hint for the file structure inference. - for (; expression != expression_list.end() && insert_column_name_it != insert_column_names_end; ++expression) - { - if (auto * identifier_node = (*expression)->as()) - { - - if (!virtual_column_names.contains(identifier_node->getIdentifier().getFullName())) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - ColumnDescription column = insert_columns.get(*insert_column_name_it); - column.name = identifier_node->getIdentifier().getFullName(); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else if (auto * matcher_node = (*expression)->as(); matcher_node && matcher_node->getMatcherType() == MatcherNodeType::ASTERISK) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Only one asterisk can be used in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - if (!structure_hint.empty()) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - asterisk = true; - } - else if (auto * function = (*expression)->as()) - { - if (use_structure_from_insertion_table_in_table_functions == 2 && findIdentifier(*function)) - { - use_columns_from_insert_query = false; - break; - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else - { - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - } - - if (use_structure_from_insertion_table_in_table_functions == 2 && !asterisk) - { - /// For input function we should check if input format supports reading subset of columns. - if (table_function_ptr->getName() == "input") - use_columns_from_insert_query = FormatFactory::instance().checkIfFormatSupportsSubsetOfColumns(scope.context->getInsertFormat(), scope.context); - else - use_columns_from_insert_query = table_function_ptr->supportsReadingSubsetOfColumns(scope.context); - } - - if (use_columns_from_insert_query) - { - if (expression == expression_list.end()) - { - /// Append tail of insert structure to the hint - if (asterisk) - { - for (; insert_column_name_it != insert_column_names_end; ++insert_column_name_it) - { - ColumnDescription column = insert_columns.get(*insert_column_name_it); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - } - - if (!structure_hint.empty()) - table_function_ptr->setStructureHint(structure_hint); - - } else if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::NUMBER_OF_COLUMNS_DOESNT_MATCH, "Number of columns in insert table less than required by SELECT expression."); - } - } - } - - auto table_function_storage = scope_context->getQueryContext()->executeTableFunction(table_function_ast, table_function_ptr); - table_function_node_typed.resolve(std::move(table_function_ptr), std::move(table_function_storage), scope_context, std::move(skip_analysis_arguments_indexes)); -} - -/// Resolve array join node in scope -void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & array_join_node_typed = array_join_node->as(); - resolveQueryJoinTreeNode(array_join_node_typed.getTableExpression(), scope, expressions_visitor); - - std::unordered_set array_join_column_names; - - /// Wrap array join expressions into column nodes, where array join expression is inner expression - - auto & array_join_nodes = array_join_node_typed.getJoinExpressions().getNodes(); - size_t array_join_nodes_size = array_join_nodes.size(); - - if (array_join_nodes_size == 0) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, - "ARRAY JOIN requires at least single expression"); - - std::vector array_join_column_expressions; - array_join_column_expressions.reserve(array_join_nodes_size); - - for (auto & array_join_expression : array_join_nodes) - { - auto array_join_expression_alias = array_join_expression->getAlias(); - - for (const auto & elem : array_join_nodes) - { - if (elem->hasAlias()) - scope.aliases.array_join_aliases.insert(elem->getAlias()); - - for (auto & child : elem->getChildren()) - { - if (child) - expressions_visitor.visit(child); - } - } - - std::string identifier_full_name; - - if (auto * identifier_node = array_join_expression->as()) - identifier_full_name = identifier_node->getIdentifier().getFullName(); - - resolveExpressionNode(array_join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/, true /*ignore_alias*/); - - auto process_array_join_expression = [&](QueryTreeNodePtr & expression) - { - auto result_type = expression->getResultType(); - bool is_array_type = isArray(result_type); - bool is_map_type = isMap(result_type); - - if (!is_array_type && !is_map_type) - throw Exception(ErrorCodes::TYPE_MISMATCH, - "ARRAY JOIN {} requires expression {} with Array or Map type. Actual {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - expression->formatASTForErrorMessage(), - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_map_type) - result_type = assert_cast(*result_type).getNestedType(); - - result_type = assert_cast(*result_type).getNestedType(); - - String array_join_column_name; - - if (!array_join_expression_alias.empty()) - { - array_join_column_name = array_join_expression_alias; - } - else if (auto * array_join_expression_inner_column = array_join_expression->as()) - { - array_join_column_name = array_join_expression_inner_column->getColumnName(); - } - else if (!identifier_full_name.empty()) - { - array_join_column_name = identifier_full_name; - } - else - { - array_join_column_name = "__array_join_expression_" + std::to_string(array_join_expressions_counter); - ++array_join_expressions_counter; - } - - if (array_join_column_names.contains(array_join_column_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "ARRAY JOIN {} multiple columns with name {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - array_join_column_name, - scope.scope_node->formatASTForErrorMessage()); - array_join_column_names.emplace(array_join_column_name); - - NameAndTypePair array_join_column(array_join_column_name, result_type); - auto array_join_column_node = std::make_shared(std::move(array_join_column), expression, array_join_node); - array_join_column_node->setAlias(array_join_expression_alias); - array_join_column_expressions.push_back(std::move(array_join_column_node)); - }; - - // Support ARRAY JOIN COLUMNS(...). COLUMNS transformer is resolved to list of columns. - if (auto * columns_list = array_join_expression->as()) - { - for (auto & array_join_subexpression : columns_list->getNodes()) - process_array_join_expression(array_join_subexpression); - } - else - { - process_array_join_expression(array_join_expression); - } - } - - array_join_nodes = std::move(array_join_column_expressions); -} - -void QueryAnalyzer::checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope) -{ - Names column_names; - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - if (join_node->as().getKind() != JoinKind::Paste) - return; - - auto * left_node = left_table_expr->as(); - auto * right_node = right_table_expr->as(); - - if (!left_node && !right_node) - return; - - if (left_node) - for (const auto & name_and_type : left_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - if (right_node) - for (const auto & name_and_type : right_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - - if (column_names.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of projection columns cannot be empty"); - - std::sort(column_names.begin(), column_names.end()); - for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is no any duplicates because it will lead to broken result - if (column_names[i] == column_names[i+1]) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add/change aliases to avoid duplication)" - "While processing '{}'", join_node->formatASTForErrorMessage()); -} - -/// Resolve join node in scope -void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & join_node_typed = join_node->as(); - - resolveQueryJoinTreeNode(join_node_typed.getLeftTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getLeftTableExpression(), scope); - - resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); - - if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) - checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope); - - if (join_node_typed.isOnJoinExpression()) - { - expressions_visitor.visit(join_node_typed.getJoinExpression()); - auto join_expression = join_node_typed.getJoinExpression(); - resolveExpressionNode(join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - join_node_typed.getJoinExpression() = std::move(join_expression); - } - else if (join_node_typed.isUsingJoinExpression()) - { - auto & join_using_list = join_node_typed.getJoinExpression()->as(); - std::unordered_set join_using_identifiers; - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto * identifier_node = join_using_node->as(); - if (!identifier_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} USING clause expected identifier. Actual {}", - join_node_typed.formatASTForErrorMessage(), - join_using_node->formatASTForErrorMessage()); - - const auto & identifier_full_name = identifier_node->getIdentifier().getFullName(); - - if (join_using_identifiers.contains(identifier_full_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} identifier '{}' appears more than once in USING clause", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name); - - join_using_identifiers.insert(identifier_full_name); - - const auto & settings = scope.context->getSettingsRef(); - - /** While resolving JOIN USING identifier, try to resolve identifier from parent subquery projection. - * Example: SELECT a + 1 AS b FROM (SELECT 1 AS a) t1 JOIN (SELECT 2 AS b) USING b - * In this case `b` is not in the left table expression, but it is in the parent subquery projection. - */ - auto try_resolve_identifier_from_query_projection = [this](const String & identifier_full_name_, - const QueryTreeNodePtr & left_table_expression, - const IdentifierResolveScope & scope_) -> QueryTreeNodePtr - { - const QueryNode * query_node = scope_.scope_node ? scope_.scope_node->as() : nullptr; - if (!query_node) - return nullptr; - - const auto & projection_list = query_node->getProjection(); - for (const auto & projection_node : projection_list.getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name_ == projection_node->getAlias()) - { - auto left_subquery = std::make_shared(query_node->getMutableContext()); - left_subquery->getProjection().getNodes().push_back(projection_node->clone()); - left_subquery->getJoinTree() = left_table_expression; - - IdentifierResolveScope left_subquery_scope(left_subquery, nullptr /*parent_scope*/); - resolveQuery(left_subquery, left_subquery_scope); - - const auto & resolved_nodes = left_subquery->getProjection().getNodes(); - if (resolved_nodes.size() == 1) - { - /// Create ColumnNode with expression from parent projection - return std::make_shared( - NameAndTypePair{identifier_full_name_, resolved_nodes.front()->getResultType()}, - resolved_nodes.front(), left_table_expression); - } - } - } - return nullptr; - }; - - QueryTreeNodePtr result_left_table_expression = nullptr; - /** With `analyzer_compatibility_join_using_top_level_identifier` alias in projection has higher priority than column from left table. - * But if aliased expression cannot be resolved from left table, we get UNKNOW_IDENTIFIER error, - * despite the fact that column from USING could be resolved from left table. - * It's compatibility with a default behavior for old analyzer. - */ - if (settings.analyzer_compatibility_join_using_top_level_identifier) - result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - IdentifierLookup identifier_lookup{identifier_node->getIdentifier(), IdentifierLookupContext::EXPRESSION}; - if (!result_left_table_expression) - result_left_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getLeftTableExpression(), scope); - - /** Here we may try to resolve identifier from projection in case it's not resolved from left table expression - * and analyzer_compatibility_join_using_top_level_identifier is disabled. - * For now we do not do this, because not all corner cases are clear. - * But let's at least mention it in error message - */ - /// if (!settings.analyzer_compatibility_join_using_top_level_identifier && !result_left_table_expression) - /// result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - if (!result_left_table_expression) - { - String extra_message; - const QueryNode * query_node = scope.scope_node ? scope.scope_node->as() : nullptr; - if (settings.analyzer_compatibility_join_using_top_level_identifier && query_node) - { - for (const auto & projection_node : query_node->getProjection().getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name == projection_node->getAlias()) - { - extra_message = fmt::format( - ", but alias '{}' is present in SELECT list." - " You may try to SET analyzer_compatibility_join_using_top_level_identifier = 1, to allow to use it in USING clause", - projection_node->formatASTForErrorMessage()); - break; - } - } - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from left table expression{}. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - extra_message, - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_left_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from left table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto result_right_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getRightTableExpression(), scope); - if (!result_right_table_expression) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - if (result_right_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto expression_types = DataTypes{result_left_table_expression->getResultType(), result_right_table_expression->getResultType()}; - DataTypePtr common_type = tryGetLeastSupertype(expression_types); - - if (!common_type) - throw Exception(ErrorCodes::NO_COMMON_TYPE, - "JOIN {} cannot infer common type for {} and {} in USING for identifier '{}'. In scope {}", - join_node_typed.formatASTForErrorMessage(), - result_left_table_expression->getResultType()->getName(), - result_right_table_expression->getResultType()->getName(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - NameAndTypePair join_using_column(identifier_full_name, common_type); - ListNodePtr join_using_expression = std::make_shared(QueryTreeNodes{result_left_table_expression, result_right_table_expression}); - auto join_using_column_node = std::make_shared(std::move(join_using_column), std::move(join_using_expression), join_node); - join_using_node = std::move(join_using_column_node); - } - } -} - -/** Resolve query join tree. - * - * Query join tree must be initialized before calling this function. - */ -void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto from_node_type = join_tree_node->getNodeType(); - - switch (from_node_type) - { - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - resolveExpressionNode(join_tree_node, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - resolveTableFunction(join_tree_node, scope, expressions_visitor, false /*nested_table_function*/); - break; - } - case QueryTreeNodeType::TABLE: - { - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - resolveArrayJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::JOIN: - { - resolveJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::IDENTIFIER: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifiers in FROM section must be already resolved. Node {}, scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, ARRAY JOIN or JOIN. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - auto join_tree_node_type = join_tree_node->getNodeType(); - if (isTableExpressionNodeType(join_tree_node_type)) - { - validateTableExpressionModifiers(join_tree_node, scope); - initializeTableExpressionData(join_tree_node, scope); - - auto & query_node = scope.scope_node->as(); - auto & mutable_context = query_node.getMutableContext(); - - if (!mutable_context->isDistributed()) - { - bool is_distributed = false; - - if (auto * table_node = join_tree_node->as()) - is_distributed = table_node->getStorage()->isRemote(); - else if (auto * table_function_node = join_tree_node->as()) - is_distributed = table_function_node->getStorage()->isRemote(); - - mutable_context->setDistributed(is_distributed); - } - } - - auto add_table_expression_alias_into_scope = [&](const QueryTreeNodePtr & table_expression_node) - { - const auto & alias_name = table_expression_node->getAlias(); - if (alias_name.empty()) - return; - - auto [it, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(alias_name, table_expression_node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Duplicate aliases {} for table expressions in FROM section are not allowed. Try to register {}. Already registered {}.", - alias_name, - table_expression_node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage()); - }; - - add_table_expression_alias_into_scope(join_tree_node); - scope.table_expressions_in_resolve_process.erase(join_tree_node.get()); -} - -/** Resolve query. - * This function modifies query node during resolve. It is caller responsibility to clone query node before resolve - * if it is needed for later use. - * - * query_node - query_tree_node that must have QueryNode type. - * scope - query scope. It is caller responsibility to create it. - * - * Resolve steps: - * 1. Validate subqueries depth, perform GROUP BY validation that does not depend on information about aggregate functions. - * 2. Initialize query scope with aliases. - * 3. Register CTE subqueries from WITH section in scope and remove them from WITH section. - * 4. Resolve JOIN TREE. - * 5. Resolve projection columns. - * 6. Resolve expressions in other query parts. - * 7. Validate nodes with duplicate aliases. - * 8. Validate aggregate functions, GROUPING function, window functions. - * 9. Remove WITH and WINDOW sections from query. - * 10. Remove aliases from expression and lambda nodes. - * 11. Resolve query tree node with projection columns. - */ -void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope) -{ - size_t max_subquery_depth = scope.context->getSettingsRef().max_subquery_depth; - if (max_subquery_depth && scope.subquery_depth > max_subquery_depth) - throw Exception(ErrorCodes::TOO_DEEP_SUBQUERIES, - "Too deep subqueries. Maximum: {}", - max_subquery_depth); - - auto & query_node_typed = query_node->as(); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.insert(query_node_typed.getCTEName()); - - bool is_rollup_or_cube = query_node_typed.isGroupByWithRollup() || query_node_typed.isGroupByWithCube(); - - if (query_node_typed.isGroupByWithGroupingSets() - && query_node_typed.isGroupByWithTotals() - && query_node_typed.getGroupBy().getNodes().size() != 1) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and GROUPING SETS are not supported together"); - - if (query_node_typed.isGroupByWithGroupingSets() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "GROUPING SETS are not supported together with ROLLUP and CUBE"); - - if (query_node_typed.isGroupByWithRollup() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithCube())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "ROLLUP is not supported together with GROUPING SETS and CUBE"); - - if (query_node_typed.isGroupByWithCube() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithRollup())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "CUBE is not supported together with GROUPING SETS and ROLLUP"); - - if (query_node_typed.hasHaving() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of HAVING"); - - if (query_node_typed.hasQualify() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of QUALIFY"); - - /// Initialize aliases in query node scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - - if (query_node_typed.hasWith()) - visitor.visit(query_node_typed.getWithNode()); - - if (!query_node_typed.getProjection().getNodes().empty()) - visitor.visit(query_node_typed.getProjectionNode()); - - if (query_node_typed.getPrewhere()) - visitor.visit(query_node_typed.getPrewhere()); - - if (query_node_typed.getWhere()) - visitor.visit(query_node_typed.getWhere()); - - if (query_node_typed.hasGroupBy()) - visitor.visit(query_node_typed.getGroupByNode()); - - if (query_node_typed.hasHaving()) - visitor.visit(query_node_typed.getHaving()); - - if (query_node_typed.hasWindow()) - visitor.visit(query_node_typed.getWindowNode()); - - if (query_node_typed.hasQualify()) - visitor.visit(query_node_typed.getQualify()); - - if (query_node_typed.hasOrderBy()) - visitor.visit(query_node_typed.getOrderByNode()); - - if (query_node_typed.hasInterpolate()) - visitor.visit(query_node_typed.getInterpolate()); - - if (query_node_typed.hasLimitByLimit()) - visitor.visit(query_node_typed.getLimitByLimit()); - - if (query_node_typed.hasLimitByOffset()) - visitor.visit(query_node_typed.getLimitByOffset()); - - if (query_node_typed.hasLimitBy()) - visitor.visit(query_node_typed.getLimitByNode()); - - if (query_node_typed.hasLimit()) - visitor.visit(query_node_typed.getLimit()); - - if (query_node_typed.hasOffset()) - visitor.visit(query_node_typed.getOffset()); - - /// Register CTE subqueries and remove them from WITH section - - auto & with_nodes = query_node_typed.getWith().getNodes(); - - for (auto & node : with_nodes) - { - auto * subquery_node = node->as(); - auto * union_node = node->as(); - - bool subquery_is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - if (!subquery_is_cte) - continue; - - const auto & cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - auto [_, inserted] = scope.cte_name_to_query_node.emplace(cte_name, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "CTE with name {} already exists. In scope {}", - cte_name, - scope.scope_node->formatASTForErrorMessage()); - } - - /** WITH section can be safely removed, because WITH section only can provide aliases to query expressions - * and CTE for other sections to use. - * - * Example: WITH 1 AS constant, (x -> x + 1) AS lambda, a AS (SELECT * FROM test_table); - */ - query_node_typed.getWith().getNodes().clear(); - - for (auto & window_node : query_node_typed.getWindow().getNodes()) - { - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - if (!parent_window_name.empty()) - { - auto window_node_it = scope.window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope.window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - scope.scope_node->formatASTForErrorMessage()); - - mergeWindowWithParentWindow(window_node, window_node_it->second, scope); - window_node_typed.setParentWindowName({}); - } - - auto [_, inserted] = scope.window_name_to_window_node.emplace(window_node_typed.getAlias(), window_node); - if (!inserted) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' is already defined. In scope {}", - window_node_typed.getAlias(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** Disable identifier cache during JOIN TREE resolve. - * Depending on JOIN expression section, identifier with same name - * can be resolved in different columns. - * - * Example: SELECT id FROM test_table AS t1 INNER JOIN test_table AS t2 ON t1.id = t2.id INNER JOIN test_table AS t3 ON t1.id = t3.id - * In first join expression ON t1.id = t2.id t1.id is resolved into test_table.id column. - * In second join expression ON t1.id = t3.id t1.id must be resolved into test_table.id column after first JOIN. - */ - scope.use_identifier_lookup_to_result_cache = false; - - if (query_node_typed.getJoinTree()) - { - TableExpressionsAliasVisitor table_expressions_visitor(scope); - table_expressions_visitor.visit(query_node_typed.getJoinTree()); - - initializeQueryJoinTreeNode(query_node_typed.getJoinTree(), scope); - scope.aliases.alias_name_to_table_expression_node.clear(); - - resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor); - } - - if (!scope.group_by_use_nulls) - scope.use_identifier_lookup_to_result_cache = true; - - /// Resolve query node sections. - - NamesAndTypes projection_columns; - - if (!scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - if (auto & prewhere_node = query_node_typed.getPrewhere()) - { - resolveExpressionNode(prewhere_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** Expressions in PREWHERE with JOIN should not change their type. - * Example: SELECT * FROM t1 JOIN t2 USING (a) PREWHERE a = 1 - * Column `a` in PREWHERE should be resolved from the left table - * and should not change its type to Nullable or to the supertype of `a` from t1 and t2. - * Here's a more complicated example where the column is somewhere inside an expression: - * SELECT a + 1 as b FROM t1 JOIN t2 USING (id) PREWHERE b = 1 - * The expression `a + 1 as b` in the projection and in PREWHERE should have different `a`. - */ - prewhere_node = prewhere_node->clone(); - ReplaceColumnsVisitor replace_visitor(scope.join_columns_with_changed_types, scope.context); - replace_visitor.visit(prewhere_node); - } - - if (query_node_typed.getWhere()) - resolveExpressionNode(query_node_typed.getWhere(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasGroupBy()) - resolveGroupByNode(query_node_typed, scope); - - if (scope.group_by_use_nulls) - { - resolved_expressions.clear(); - /// Clone is needed cause aliases share subtrees. - /// If not clone, the same (shared) subtree could be resolved again with different (Nullable) type - /// See 03023_group_by_use_nulls_analyzer_crashes - for (auto & [key, node] : scope.aliases.alias_name_to_expression_node_before_group_by) - scope.aliases.alias_name_to_expression_node_after_group_by[key] = node->clone(); - - scope.aliases.alias_name_to_expression_node = &scope.aliases.alias_name_to_expression_node_after_group_by; - } - - if (query_node_typed.hasHaving()) - resolveExpressionNode(query_node_typed.getHaving(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasWindow()) - resolveWindowNodeList(query_node_typed.getWindowNode(), scope); - - if (query_node_typed.hasQualify()) - resolveExpressionNode(query_node_typed.getQualify(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasOrderBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getOrderByNode(), query_node_typed.getProjection().getNodes(), scope); - - const auto & settings = scope.context->getSettingsRef(); - - expandOrderByAll(query_node_typed, settings); - resolveSortNodeList(query_node_typed.getOrderByNode(), scope); - } - - if (query_node_typed.hasInterpolate()) - resolveInterpolateColumnsNodeList(query_node_typed.getInterpolate(), scope); - - if (query_node_typed.hasLimitByLimit()) - { - resolveExpressionNode(query_node_typed.getLimitByLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByLimit(), "LIMIT BY LIMIT", scope); - } - - if (query_node_typed.hasLimitByOffset()) - { - resolveExpressionNode(query_node_typed.getLimitByOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByOffset(), "LIMIT BY OFFSET", scope); - } - - if (query_node_typed.hasLimitBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getLimitByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getLimitByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - - if (query_node_typed.hasLimit()) - { - resolveExpressionNode(query_node_typed.getLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimit(), "LIMIT", scope); - } - - if (query_node_typed.hasOffset()) - { - resolveExpressionNode(query_node_typed.getOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getOffset(), "OFFSET", scope); - } - - if (scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - /** Resolve nodes with duplicate aliases. - * Table expressions cannot have duplicate aliases. - * - * Such nodes during scope aliases collection are placed into duplicated array. - * After scope nodes are resolved, we can compare node with duplicate alias with - * node from scope alias table. - */ - for (const auto & node_with_duplicated_alias : scope.aliases.cloned_nodes_with_duplicated_aliases) - { - auto node = node_with_duplicated_alias; - auto node_alias = node->getAlias(); - - /// Add current alias to non cached set, because in case of cyclic alias identifier should not be substituted from cache. - /// See 02896_cyclic_aliases_crash. - resolveExpressionNode(node, scope, true /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool has_node_in_alias_table = false; - - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - if (!has_node_in_alias_table) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node {} with duplicate alias {} does not exist in alias table. In scope {}", - node->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - - node->removeAlias(); - } - - expandGroupByAll(query_node_typed); - - validateFilters(query_node); - validateAggregates(query_node, { .group_by_use_nulls = scope.group_by_use_nulls }); - - for (const auto & column : projection_columns) - { - if (isNotCreatable(column.type)) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Invalid projection column with type {}. In scope {}", - column.type->getName(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** WINDOW section can be safely removed, because WINDOW section can only provide window definition to window functions. - * - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - */ - query_node_typed.getWindow().getNodes().clear(); - - /// Remove aliases from expression and lambda nodes - - for (auto & [_, node] : *scope.aliases.alias_name_to_expression_node) - node->removeAlias(); - - for (auto & [_, node] : scope.aliases.alias_name_to_lambda_node) - node->removeAlias(); - - query_node_typed.resolveProjectionColumns(std::move(projection_columns)); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.erase(query_node_typed.getCTEName()); -} - -void QueryAnalyzer::resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope) -{ - auto & union_node_typed = union_node->as(); - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.insert(union_node_typed.getCTEName()); - - auto & queries_nodes = union_node_typed.getQueries().getNodes(); - - std::optional recursive_cte_table; - TableNodePtr recursive_cte_table_node; - - if (union_node_typed.isCTE() && union_node_typed.isRecursiveCTE()) - { - auto & non_recursive_query = queries_nodes[0]; - bool non_recursive_query_is_query_node = non_recursive_query->getNodeType() == QueryTreeNodeType::QUERY; - auto & non_recursive_query_mutable_context = non_recursive_query_is_query_node ? non_recursive_query->as().getMutableContext() - : non_recursive_query->as().getMutableContext(); - - IdentifierResolveScope non_recursive_subquery_scope(non_recursive_query, &scope /*parent_scope*/); - non_recursive_subquery_scope.subquery_depth = scope.subquery_depth + 1; - - if (non_recursive_query_is_query_node) - resolveQuery(non_recursive_query, non_recursive_subquery_scope); - else - resolveUnion(non_recursive_query, non_recursive_subquery_scope); - - auto temporary_table_columns = non_recursive_query_is_query_node - ? non_recursive_query->as().getProjectionColumns() - : non_recursive_query->as().computeProjectionColumns(); - - auto temporary_table_holder = std::make_shared( - non_recursive_query_mutable_context, - ColumnsDescription{NamesAndTypesList{temporary_table_columns.begin(), temporary_table_columns.end()}}, - ConstraintsDescription{}, - nullptr /*query*/, - true /*create_for_global_subquery*/); - auto temporary_table_storage = temporary_table_holder->getTable(); - - recursive_cte_table_node = std::make_shared(temporary_table_storage, non_recursive_query_mutable_context); - recursive_cte_table_node->setTemporaryTableName(union_node_typed.getCTEName()); - - recursive_cte_table.emplace(std::move(temporary_table_holder), std::move(temporary_table_storage), std::move(temporary_table_columns)); - } - - size_t queries_nodes_size = queries_nodes.size(); - for (size_t i = recursive_cte_table.has_value(); i < queries_nodes_size; ++i) - { - auto & query_node = queries_nodes[i]; - - IdentifierResolveScope subquery_scope(query_node, &scope /*parent_scope*/); - - if (recursive_cte_table_node) - subquery_scope.expression_argument_name_to_node[union_node_typed.getCTEName()] = recursive_cte_table_node; - - auto query_node_type = query_node->getNodeType(); - - if (query_node_type == QueryTreeNodeType::QUERY) - { - resolveQuery(query_node, subquery_scope); - } - else if (query_node_type == QueryTreeNodeType::UNION) - { - resolveUnion(query_node, subquery_scope); - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "UNION unsupported node {}. In scope {}", - query_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (recursive_cte_table && isStorageUsedInTree(recursive_cte_table->storage, union_node.get())) - { - if (union_node_typed.getUnionMode() != SelectUnionMode::UNION_ALL) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive CTE subquery {} with {} union mode is unsupported, only UNION ALL union mode is supported", - union_node_typed.formatASTForErrorMessage(), - toString(union_node_typed.getUnionMode())); - - union_node_typed.setRecursiveCTETable(std::move(*recursive_cte_table)); - } - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.erase(union_node_typed.getCTEName()); -} - -} - -QueryAnalysisPass::QueryAnalysisPass(QueryTreeNodePtr table_expression_, bool only_analyze_) - : table_expression(std::move(table_expression_)) - , only_analyze(only_analyze_) -{} - -QueryAnalysisPass::QueryAnalysisPass(bool only_analyze_) : only_analyze(only_analyze_) {} - -void QueryAnalysisPass::run(QueryTreeNodePtr & query_tree_node, ContextPtr context) -{ - QueryAnalyzer analyzer(only_analyze); - analyzer.resolve(query_tree_node, table_expression, context); - createUniqueTableAliases(query_tree_node, table_expression, context); -} - } diff --git a/src/Analyzer/QueryAnalysis/TableExpressionsAliasVisitor.h b/src/Analyzer/QueryAnalysis/TableExpressionsAliasVisitor.h index 3fca66e6eb8..3191a0a97ac 100644 --- a/src/Analyzer/QueryAnalysis/TableExpressionsAliasVisitor.h +++ b/src/Analyzer/QueryAnalysis/TableExpressionsAliasVisitor.h @@ -1,1152 +1,18 @@ -#include +#pragma once -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include - -namespace ProfileEvents -{ - extern const Event ScalarSubqueriesGlobalCacheHit; - extern const Event ScalarSubqueriesLocalCacheHit; - extern const Event ScalarSubqueriesCacheMiss; -} namespace DB { namespace ErrorCodes { - extern const int UNSUPPORTED_METHOD; - extern const int UNKNOWN_IDENTIFIER; - extern const int UNKNOWN_FUNCTION; - extern const int LOGICAL_ERROR; - extern const int CYCLIC_ALIASES; - extern const int INCORRECT_RESULT_OF_SCALAR_SUBQUERY; - extern const int BAD_ARGUMENTS; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; extern const int MULTIPLE_EXPRESSIONS_FOR_ALIAS; - extern const int TYPE_MISMATCH; - extern const int AMBIGUOUS_IDENTIFIER; - extern const int INVALID_WITH_FILL_EXPRESSION; - extern const int INVALID_LIMIT_EXPRESSION; - extern const int EMPTY_LIST_OF_COLUMNS_QUERIED; - extern const int TOO_DEEP_SUBQUERIES; - extern const int UNKNOWN_AGGREGATE_FUNCTION; - extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION; - extern const int TOO_MANY_ARGUMENTS_FOR_FUNCTION; - extern const int ILLEGAL_FINAL; - extern const int SAMPLING_NOT_SUPPORTED; - extern const int NO_COMMON_TYPE; - extern const int NOT_IMPLEMENTED; - extern const int ALIAS_REQUIRED; - extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; - extern const int UNKNOWN_TABLE; - extern const int ILLEGAL_COLUMN; - extern const int NUMBER_OF_COLUMNS_DOESNT_MATCH; - extern const int FUNCTION_CANNOT_HAVE_PARAMETERS; - extern const int SYNTAX_ERROR; - extern const int UNEXPECTED_EXPRESSION; - extern const int INVALID_IDENTIFIER; } -/** Query analyzer implementation overview. Please check documentation in QueryAnalysisPass.h first. - * And additional documentation for each method, where special cases are described in detail. - * - * Each node in query must be resolved. For each query tree node resolved state is specific. - * - * For constant node no resolve process exists, it is resolved during construction. - * - * For table node no resolve process exists, it is resolved during construction. - * - * For function node to be resolved parameters and arguments must be resolved, function node must be initialized with concrete aggregate or - * non aggregate function and with result type. - * - * For lambda node there can be 2 different cases. - * 1. Standalone: WITH (x -> x + 1) AS lambda SELECT lambda(1); Such lambdas are inlined in query tree during query analysis pass. - * 2. Function arguments: WITH (x -> x + 1) AS lambda SELECT arrayMap(lambda, [1, 2, 3]); For such lambda resolution must - * set concrete lambda arguments (initially they are identifier nodes) and resolve lambda expression body. - * - * For query node resolve process must resolve all its inner nodes. - * - * For matcher node resolve process must replace it with matched nodes. - * - * For identifier node resolve process must replace it with concrete non identifier node. This part is most complex because - * for identifier resolution scopes and identifier lookup context play important part. - * - * ClickHouse SQL support lexical scoping for identifier resolution. Scope can be defined by query node or by expression node. - * Expression nodes that can define scope are lambdas and table ALIAS columns. - * - * Identifier lookup context can be expression, function, table. - * - * Examples: WITH (x -> x + 1) as func SELECT func() FROM func; During function `func` resolution identifier lookup is performed - * in function context. - * - * If there are no information of identifier context rules are following: - * 1. Try to resolve identifier in expression context. - * 2. Try to resolve identifier in function context, if it is allowed. Example: SELECT func(arguments); Here func identifier cannot be resolved in function context - * because query projection does not support that. - * 3. Try to resolve identifier in table context, if it is allowed. Example: SELECT table; Here table identifier cannot be resolved in function context - * because query projection does not support that. - * - * TODO: This does not supported properly before, because matchers could not be resolved from aliases. - * - * Identifiers are resolved with following rules: - * Resolution starts with current scope. - * 1. Try to resolve identifier from expression scope arguments. Lambda expression arguments are greatest priority. - * 2. Try to resolve identifier from aliases. - * 3. Try to resolve identifier from join tree if scope is query, or if there are registered table columns in scope. - * Steps 2 and 3 can be changed using prefer_column_name_to_alias setting. - * 4. If it is table lookup, try to resolve identifier from CTE. - * If identifier could not be resolved in current scope, resolution must be continued in parent scopes. - * 5. Try to resolve identifier from parent scopes. - * - * Additional rules about aliases and scopes. - * 1. Parent scope cannot refer alias from child scope. - * 2. Child scope can refer to alias in parent scope. - * - * Example: SELECT arrayMap(x -> x + 1 AS a, [1,2,3]), a; Identifier a is unknown in parent scope. - * Example: SELECT a FROM (SELECT 1 as a); Here we do not refer to alias a from child query scope. But we query it projection result, similar to tables. - * Example: WITH 1 as a SELECT (SELECT a) as b; Here in child scope identifier a is resolved using alias from parent scope. - * - * Additional rules about identifier binding. - * Bind for identifier to entity means that identifier first part match some node during analysis. - * If other parts of identifier cannot be resolved in that node, exception must be thrown. - * - * Example: - * CREATE TABLE test_table (id UInt64, compound_value Tuple(value UInt64)) ENGINE=TinyLog; - * SELECT compound_value.value, 1 AS compound_value FROM test_table; - * Identifier first part compound_value bound to entity with alias compound_value, but nested identifier part cannot be resolved from entity, - * lookup should not be continued, and exception must be thrown because if lookup continues that way identifier can be resolved from join tree. - * - * TODO: This was not supported properly before analyzer because nested identifier could not be resolved from alias. - * - * More complex example: - * CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; - * WITH cast(('Value'), 'Tuple (value UInt64') AS value SELECT (SELECT value FROM test_table); - * Identifier first part value bound to test_table column value, but nested identifier part cannot be resolved from it, - * lookup should not be continued, and exception must be thrown because if lookup continues identifier can be resolved from parent scope. - * - * TODO: Update exception messages - * TODO: Table identifiers with optional UUID. - * TODO: Lookup functions arrayReduce(sum, [1, 2, 3]); - * TODO: Support function identifier resolve from parent query scope, if lambda in parent scope does not capture any columns. - */ - -namespace -{ - -/// Identifier lookup context -enum class IdentifierLookupContext : uint8_t -{ - EXPRESSION = 0, - FUNCTION, - TABLE_EXPRESSION, -}; - -const char * toString(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "EXPRESSION"; - case IdentifierLookupContext::FUNCTION: return "FUNCTION"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "TABLE_EXPRESSION"; - } -} - -const char * toStringLowercase(IdentifierLookupContext identifier_lookup_context) -{ - switch (identifier_lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return "expression"; - case IdentifierLookupContext::FUNCTION: return "function"; - case IdentifierLookupContext::TABLE_EXPRESSION: return "table expression"; - } -} - -/** Structure that represent identifier lookup during query analysis. - * Lookup can be in query expression, function, table context. - */ -struct IdentifierLookup -{ - Identifier identifier; - IdentifierLookupContext lookup_context; - - bool isExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::EXPRESSION; - } - - bool isFunctionLookup() const - { - return lookup_context == IdentifierLookupContext::FUNCTION; - } - - bool isTableExpressionLookup() const - { - return lookup_context == IdentifierLookupContext::TABLE_EXPRESSION; - } - - String dump() const - { - return identifier.getFullName() + ' ' + toString(lookup_context); - } -}; - -inline bool operator==(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return lhs.identifier.getFullName() == rhs.identifier.getFullName() && lhs.lookup_context == rhs.lookup_context; -} - -[[maybe_unused]] inline bool operator!=(const IdentifierLookup & lhs, const IdentifierLookup & rhs) -{ - return !(lhs == rhs); -} - -struct IdentifierLookupHash -{ - size_t operator()(const IdentifierLookup & identifier_lookup) const - { - return std::hash()(identifier_lookup.identifier.getFullName()) ^ static_cast(identifier_lookup.lookup_context); - } -}; - -enum class IdentifierResolvePlace : UInt8 -{ - NONE = 0, - EXPRESSION_ARGUMENTS, - ALIASES, - JOIN_TREE, - /// Valid only for table lookup - CTE, - /// Valid only for table lookup - DATABASE_CATALOG -}; - -const char * toString(IdentifierResolvePlace resolved_identifier_place) -{ - switch (resolved_identifier_place) - { - case IdentifierResolvePlace::NONE: return "NONE"; - case IdentifierResolvePlace::EXPRESSION_ARGUMENTS: return "EXPRESSION_ARGUMENTS"; - case IdentifierResolvePlace::ALIASES: return "ALIASES"; - case IdentifierResolvePlace::JOIN_TREE: return "JOIN_TREE"; - case IdentifierResolvePlace::CTE: return "CTE"; - case IdentifierResolvePlace::DATABASE_CATALOG: return "DATABASE_CATALOG"; - } -} - -struct IdentifierResolveResult -{ - IdentifierResolveResult() = default; - - QueryTreeNodePtr resolved_identifier; - IdentifierResolvePlace resolve_place = IdentifierResolvePlace::NONE; - bool resolved_from_parent_scopes = false; - - [[maybe_unused]] bool isResolved() const - { - return resolve_place != IdentifierResolvePlace::NONE; - } - - [[maybe_unused]] bool isResolvedFromParentScopes() const - { - return resolved_from_parent_scopes; - } - - [[maybe_unused]] bool isResolvedFromExpressionArguments() const - { - return resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - } - - [[maybe_unused]] bool isResolvedFromAliases() const - { - return resolve_place == IdentifierResolvePlace::ALIASES; - } - - [[maybe_unused]] bool isResolvedFromJoinTree() const - { - return resolve_place == IdentifierResolvePlace::JOIN_TREE; - } - - [[maybe_unused]] bool isResolvedFromCTEs() const - { - return resolve_place == IdentifierResolvePlace::CTE; - } - - void dump(WriteBuffer & buffer) const - { - if (!resolved_identifier) - { - buffer << "unresolved"; - return; - } - - buffer << resolved_identifier->formatASTForErrorMessage() << " place " << toString(resolve_place) << " resolved from parent scopes " << resolved_from_parent_scopes; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -struct IdentifierResolveState -{ - IdentifierResolveResult resolve_result; - bool cyclic_identifier_resolve = false; -}; - -struct IdentifierResolveSettings -{ - /// Allow to check join tree during identifier resolution - bool allow_to_check_join_tree = true; - - /// Allow to check CTEs during table identifier resolution - bool allow_to_check_cte = true; - - /// Allow to check parent scopes during identifier resolution - bool allow_to_check_parent_scopes = true; - - /// Allow to check database catalog during table identifier resolution - bool allow_to_check_database_catalog = true; - - /// Allow to resolve subquery during identifier resolution - bool allow_to_resolve_subquery_during_identifier_resolution = true; -}; - -struct StringTransparentHash -{ - using is_transparent = void; - using hash = std::hash; - - [[maybe_unused]] size_t operator()(const char * data) const - { - return hash()(data); - } - - size_t operator()(std::string_view data) const - { - return hash()(data); - } - - size_t operator()(const std::string & data) const - { - return hash()(data); - } -}; - -using ColumnNameToColumnNodeMap = std::unordered_map>; - -struct TableExpressionData -{ - std::string table_expression_name; - std::string table_expression_description; - std::string database_name; - std::string table_name; - bool should_qualify_columns = true; - NamesAndTypes column_names_and_types; - ColumnNameToColumnNodeMap column_name_to_column_node; - std::unordered_set subcolumn_names; /// Subset columns that are subcolumns of other columns - std::unordered_set> column_identifier_first_parts; - - bool hasFullIdentifierName(IdentifierView identifier_view) const - { - return column_name_to_column_node.contains(identifier_view.getFullName()); - } - - bool canBindIdentifier(IdentifierView identifier_view) const - { - return column_identifier_first_parts.contains(identifier_view.at(0)); - } - - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Table expression name " << table_expression_name; - - if (!table_expression_description.empty()) - buffer << " table expression description " << table_expression_description; - - if (!database_name.empty()) - buffer << " database name " << database_name; - - if (!table_name.empty()) - buffer << " table name " << table_name; - - buffer << " should qualify columns " << should_qualify_columns; - buffer << " columns size " << column_name_to_column_node.size() << '\n'; - - for (const auto & [column_name, column_node] : column_name_to_column_node) - buffer << "Column name " << column_name << " column node " << column_node->dumpTree() << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - -class ExpressionsStack -{ -public: - void push(const QueryTreeNodePtr & node) - { - if (node->hasAlias()) - { - const auto & node_alias = node->getAlias(); - alias_name_to_expressions[node_alias].push_back(node); - } - - if (const auto * function = node->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - ++aggregate_functions_counter; - } - - expressions.emplace_back(node); - } - - void pop() - { - const auto & top_expression = expressions.back(); - const auto & top_expression_alias = top_expression->getAlias(); - - if (!top_expression_alias.empty()) - { - auto it = alias_name_to_expressions.find(top_expression_alias); - auto & alias_expressions = it->second; - alias_expressions.pop_back(); - - if (alias_expressions.empty()) - alias_name_to_expressions.erase(it); - } - - if (const auto * function = top_expression->as()) - { - if (AggregateFunctionFactory::instance().isAggregateFunctionName(function->getFunctionName())) - --aggregate_functions_counter; - } - - expressions.pop_back(); - } - - [[maybe_unused]] const QueryTreeNodePtr & getRoot() const - { - return expressions.front(); - } - - const QueryTreeNodePtr & getTop() const - { - return expressions.back(); - } - - [[maybe_unused]] bool hasExpressionWithAlias(const std::string & alias) const - { - return alias_name_to_expressions.contains(alias); - } - - bool hasAggregateFunction() const - { - return aggregate_functions_counter > 0; - } - - QueryTreeNodePtr getExpressionWithAlias(const std::string & alias) const - { - auto expression_it = alias_name_to_expressions.find(alias); - if (expression_it == alias_name_to_expressions.end()) - return {}; - - return expression_it->second.front(); - } - - [[maybe_unused]] size_t size() const - { - return expressions.size(); - } - - bool empty() const - { - return expressions.empty(); - } - - void dump(WriteBuffer & buffer) const - { - buffer << expressions.size() << '\n'; - - for (const auto & expression : expressions) - { - buffer << "Expression "; - buffer << expression->formatASTForErrorMessage(); - - const auto & alias = expression->getAlias(); - if (!alias.empty()) - buffer << " alias " << alias; - - buffer << '\n'; - } - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } - -private: - QueryTreeNodes expressions; - size_t aggregate_functions_counter = 0; - std::unordered_map alias_name_to_expressions; -}; - -struct ScopeAliases -{ - /// Alias name to query expression node - std::unordered_map alias_name_to_expression_node_before_group_by; - std::unordered_map alias_name_to_expression_node_after_group_by; - - std::unordered_map * alias_name_to_expression_node = nullptr; - - /// Alias name to lambda node - std::unordered_map alias_name_to_lambda_node; - - /// Alias name to table expression node - std::unordered_map alias_name_to_table_expression_node; - - /// Expressions like `x as y` where we can't say whether it's a function, expression or table. - std::unordered_map transitive_aliases; - - /// Nodes with duplicated aliases - std::unordered_set nodes_with_duplicated_aliases; - std::vector cloned_nodes_with_duplicated_aliases; - - /// Names which are aliases from ARRAY JOIN. - /// This is needed to properly qualify columns from matchers and avoid name collision. - std::unordered_set array_join_aliases; - - std::unordered_map & getAliasMap(IdentifierLookupContext lookup_context) - { - switch (lookup_context) - { - case IdentifierLookupContext::EXPRESSION: return *alias_name_to_expression_node; - case IdentifierLookupContext::FUNCTION: return alias_name_to_lambda_node; - case IdentifierLookupContext::TABLE_EXPRESSION: return alias_name_to_table_expression_node; - } - } - - enum class FindOption - { - FIRST_NAME, - FULL_NAME, - }; - - const std::string & getKey(const Identifier & identifier, FindOption find_option) - { - switch (find_option) - { - case FindOption::FIRST_NAME: return identifier.front(); - case FindOption::FULL_NAME: return identifier.getFullName(); - } - } - - QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) - { - auto & alias_map = getAliasMap(lookup.lookup_context); - const std::string * key = &getKey(lookup.identifier, find_option); - - auto it = alias_map.find(*key); - - if (it != alias_map.end()) - return &it->second; - - if (lookup.lookup_context == IdentifierLookupContext::TABLE_EXPRESSION) - return {}; - - while (it == alias_map.end()) - { - auto jt = transitive_aliases.find(*key); - if (jt == transitive_aliases.end()) - return {}; - - key = &(getKey(jt->second, find_option)); - it = alias_map.find(*key); - } - - return &it->second; - } - - const QueryTreeNodePtr * find(IdentifierLookup lookup, FindOption find_option) const - { - return const_cast(this)->find(lookup, find_option); - } -}; - - -/** Projection names is name of query tree node that is used in projection part of query node. - * Example: SELECT id FROM test_table; - * `id` is projection name of column node - * - * Example: SELECT id AS id_alias FROM test_table; - * `id_alias` is projection name of column node - * - * Calculation of projection names is done during expression nodes resolution. This is done this way - * because after identifier node is resolved we lose information about identifier name. We could - * potentially save this information in query tree node itself, but that would require to clone it in some cases. - * Example: SELECT big_scalar_subquery AS a, a AS b, b AS c; - * All 3 nodes in projection are the same big_scalar_subquery, but they have different projection names. - * If we want to save it in query tree node, we have to clone subquery node that could lead to performance degradation. - * - * Possible solution is to separate query node metadata and query node content. So only node metadata could be cloned - * if we want to change projection name. This solution does not seem to be easy for client of query tree because projection - * name will be part of interface. If we potentially could hide projection names calculation in analyzer without introducing additional - * changes in query tree structure that would be preferable. - * - * Currently each resolve method returns projection names array. Resolve method must compute projection names of node. - * If node is resolved as list node this is case for `untuple` function or `matcher` result projection names array must contain projection names - * for result nodes. - * If node is not resolved as list node, projection names array contain single projection name for node. - * - * Rules for projection names: - * 1. If node has alias. It is node projection name. - * Except scenario where `untuple` function has alias. Example: SELECT untuple(expr) AS alias, alias. - * - * 2. For constant it is constant value string representation. - * - * 3. For identifier: - * If identifier is resolved from JOIN TREE, we want to remove additional identifier qualifications. - * Example: SELECT default.test_table.id FROM test_table. - * Result projection name is `id`. - * - * Example: SELECT t1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In example both test_table_1, test_table_2 have `id` column. - * In such case projection name is `t1.id` because if additional qualification is removed then column projection name `id` will be ambiguous. - * - * Example: SELECT default.test_table_1.id FROM test_table_1 AS t1, test_table_2 AS t2 - * In such case projection name is `test_table_1.id` because we remove unnecessary database qualification, but table name qualification cannot be removed - * because otherwise column projection name `id` will be ambiguous. - * - * If identifier is not resolved from JOIN TREE. Identifier name is projection name. - * Except scenario where `untuple` function resolved using identifier. Example: SELECT untuple(expr) AS alias, alias. - * Example: SELECT sum(1, 1) AS value, value. - * In such case both nodes have `value` projection names. - * - * Example: SELECT id AS value, value FROM test_table. - * In such case both nodes have have `value` projection names. - * - * Special case is `untuple` function. If `untuple` function specified with alias, then result nodes will have alias.tuple_column_name projection names. - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value) AS a; - * Result projection names are `value`, `a.id`. - * - * If `untuple` function does not have alias then result nodes will have `tupleElement(untuple_expression_projection_name, 'tuple_column_name') projection names. - * - * Example: SELECT cast(tuple(1), 'Tuple(id UInt64)') AS value, untuple(value); - * Result projection names are `value`, `tupleElement(value, 'id')`; - * - * 4. For function: - * Projection name consists from function_name(parameters_projection_names)(arguments_projection_names). - * Additionally if function is window function. Window node projection name is used with OVER clause. - * Example: function_name (parameters_names)(argument_projection_names) OVER window_name; - * Example: function_name (parameters_names)(argument_projection_names) OVER (PARTITION BY id ORDER BY id). - * Example: function_name (parameters_names)(argument_projection_names) OVER (window_name ORDER BY id). - * - * 5. For lambda: - * If it is standalone lambda that returns single expression, function projection name is used. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(1). - * Projection name is `lambda(1)`. - * - * If is it standalone lambda that returns list, projection names of list nodes are used. - * Example: WITH (x -> *) AS lambda SELECT lambda(1) FROM test_table; - * If test_table has two columns `id`, `value`. Then result projection names are `id`, `value`. - * - * If lambda is argument of function. - * Then projection name consists from lambda(tuple(lambda_arguments)(lambda_body_projection_name)); - * - * 6. For matcher: - * Matched nodes projection names are used as matcher projection names. - * - * Matched nodes must be qualified if needed. - * Example: SELECT * FROM test_table_1 AS t1, test_table_2 AS t2. - * In example table test_table_1 and test_table_2 both have `id`, `value` columns. - * Matched nodes after unqualified matcher resolve must be qualified to avoid ambiguous projection names. - * Result projection names must be `t1.id`, `t1.value`, `t2.id`, `t2.value`. - * - * There are special cases - * 1. For lambda inside APPLY matcher transformer: - * Example: SELECT * APPLY x -> toString(x) FROM test_table. - * In such case lambda argument projection name `x` will be replaced by matched node projection name. - * If table has two columns `id` and `value`. Then result projection names are `toString(id)`, `toString(value)`; - * - * 2. For unqualified matcher when JOIN tree contains JOIN with USING. - * Example: SELECT * FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING(id); - * Result projection names must be `id`, `t1.value`, `t2.value`. - * - * 7. For subquery: - * For subquery projection name consists of `_subquery_` prefix and implementation specific unique number suffix. - * Example: SELECT (SELECT 1), (SELECT 1 UNION DISTINCT SELECT 1); - * Result projection name can be `_subquery_1`, `subquery_2`; - * - * 8. For table: - * Table node can be used in expression context only as right argument of IN function. In that case identifier is used - * as table node projection name. - * Example: SELECT id IN test_table FROM test_table; - * Result projection name is `in(id, test_table)`. - */ -using ProjectionName = String; -using ProjectionNames = std::vector; -constexpr auto PROJECTION_NAME_PLACEHOLDER = "__projection_name_placeholder"; - -struct IdentifierResolveScope -{ - /// Construct identifier resolve scope using scope node, and parent scope - IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) - : scope_node(std::move(scope_node_)) - , parent_scope(parent_scope_) - { - if (parent_scope) - { - subquery_depth = parent_scope->subquery_depth; - context = parent_scope->context; - projection_mask_map = parent_scope->projection_mask_map; - } - else - projection_mask_map = std::make_shared>(); - - if (auto * union_node = scope_node->as()) - { - context = union_node->getContext(); - } - else if (auto * query_node = scope_node->as()) - { - context = query_node->getContext(); - group_by_use_nulls = context->getSettingsRef().group_by_use_nulls && - (query_node->isGroupByWithGroupingSets() || query_node->isGroupByWithRollup() || query_node->isGroupByWithCube()); - } - - if (context) - join_use_nulls = context->getSettingsRef().join_use_nulls; - else if (parent_scope) - join_use_nulls = parent_scope->join_use_nulls; - - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - QueryTreeNodePtr scope_node; - - IdentifierResolveScope * parent_scope = nullptr; - - ContextPtr context; - - /// Identifier lookup to result - std::unordered_map identifier_lookup_to_resolve_state; - - /// Argument can be expression like constant, column, function or table expression - std::unordered_map expression_argument_name_to_node; - - ScopeAliases aliases; - - /// Table column name to column node. Valid only during table ALIAS columns resolve. - ColumnNameToColumnNodeMap column_name_to_column_node; - - /// CTE name to query node - std::unordered_map cte_name_to_query_node; - - /// Window name to window node - std::unordered_map window_name_to_window_node; - - /// Current scope expression in resolve process stack - ExpressionsStack expressions_in_resolve_process_stack; - - /// Table expressions in resolve process - std::unordered_set table_expressions_in_resolve_process; - - /// Current scope expression - std::unordered_set non_cached_identifier_lookups_during_expression_resolve; - - /// Table expression node to data - std::unordered_map table_expression_node_to_data; - - QueryTreeNodePtrWithHashIgnoreTypesSet nullable_group_by_keys; - /// Here we count the number of nullable GROUP BY keys we met resolving expression. - /// E.g. for a query `SELECT tuple(tuple(number)) FROM numbers(10) GROUP BY (number, tuple(number)) with cube` - /// both `number` and `tuple(number)` would be in nullable_group_by_keys. - /// But when we resolve `tuple(tuple(number))` we should figure out that `tuple(number)` is already a key, - /// and we should not convert `number` to nullable. - size_t found_nullable_group_by_key_in_scope = 0; - - /** It's possible that after a JOIN, a column in the projection has a type different from the column in the source table. - * (For example, after join_use_nulls or USING column casted to supertype) - * However, the column in the projection still refers to the table as its source. - * This map is used to revert these columns back to their original columns in the source table. - */ - QueryTreeNodePtrWithHashMap join_columns_with_changed_types; - - /// Use identifier lookup to result cache - bool use_identifier_lookup_to_result_cache = true; - - /// Apply nullability to aggregation keys - bool group_by_use_nulls = false; - /// Join retutns NULLs instead of default values - bool join_use_nulls = false; - - /// JOINs count - size_t joins_count = 0; - - /// Subquery depth - size_t subquery_depth = 0; - - /** Scope join tree node for expression. - * Valid only during analysis construction for single expression. - */ - QueryTreeNodePtr expression_join_tree_node; - - /// Node hash to mask id map - std::shared_ptr> projection_mask_map; - - struct ResolvedFunctionsCache - { - FunctionOverloadResolverPtr resolver; - FunctionBasePtr function_base; - }; - - std::map functions_cache; - - [[maybe_unused]] const IdentifierResolveScope * getNearestQueryScope() const - { - const IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - IdentifierResolveScope * getNearestQueryScope() - { - IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - const TableExpressionData & getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - void pushExpressionNode(const QueryTreeNodePtr & node) - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.push(node); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - void popExpressionNode() - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.pop(); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_after_group_by; - } - - /// Dump identifier resolve scope - [[maybe_unused]] void dump(WriteBuffer & buffer) const - { - buffer << "Scope node " << scope_node->formatASTForErrorMessage() << '\n'; - buffer << "Identifier lookup to resolve state " << identifier_lookup_to_resolve_state.size() << '\n'; - for (const auto & [identifier, state] : identifier_lookup_to_resolve_state) - { - buffer << "Identifier " << identifier.dump() << " resolve result "; - state.resolve_result.dump(buffer); - buffer << '\n'; - } - - buffer << "Expression argument name to node " << expression_argument_name_to_node.size() << '\n'; - for (const auto & [alias_name, node] : expression_argument_name_to_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to expression node table size " << aliases.alias_name_to_expression_node->size() << '\n'; - for (const auto & [alias_name, node] : *aliases.alias_name_to_expression_node) - buffer << "Alias name " << alias_name << " expression node " << node->dumpTree() << '\n'; - - buffer << "Alias name to function node table size " << aliases.alias_name_to_lambda_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_lambda_node) - buffer << "Alias name " << alias_name << " lambda node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to table expression node table size " << aliases.alias_name_to_table_expression_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_table_expression_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "CTE name to query node table size " << cte_name_to_query_node.size() << '\n'; - for (const auto & [cte_name, node] : cte_name_to_query_node) - buffer << "CTE name " << cte_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "WINDOW name to window node table size " << window_name_to_window_node.size() << '\n'; - for (const auto & [window_name, node] : window_name_to_window_node) - buffer << "CTE name " << window_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Nodes with duplicated aliases size " << aliases.nodes_with_duplicated_aliases.size() << '\n'; - for (const auto & node : aliases.nodes_with_duplicated_aliases) - buffer << "Alias name " << node->getAlias() << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Expression resolve process stack " << '\n'; - expressions_in_resolve_process_stack.dump(buffer); - - buffer << "Table expressions in resolve process size " << table_expressions_in_resolve_process.size() << '\n'; - for (const auto & node : table_expressions_in_resolve_process) - buffer << "Table expression " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Non cached identifier lookups during expression resolve " << non_cached_identifier_lookups_during_expression_resolve.size() << '\n'; - for (const auto & identifier_lookup : non_cached_identifier_lookups_during_expression_resolve) - buffer << "Identifier lookup " << identifier_lookup.dump() << '\n'; - - buffer << "Table expression node to data " << table_expression_node_to_data.size() << '\n'; - for (const auto & [table_expression_node, table_expression_data] : table_expression_node_to_data) - buffer << "Table expression node " << table_expression_node->formatASTForErrorMessage() << " data " << table_expression_data.dump() << '\n'; - - buffer << "Use identifier lookup to result cache " << use_identifier_lookup_to_result_cache << '\n'; - buffer << "Subquery depth " << subquery_depth << '\n'; - } - - [[maybe_unused]] String dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } -}; - - -/** Visitor that extracts expression and function aliases from node and initialize scope tables with it. - * Does not go into child lambdas and queries. - * - * Important: - * Identifier nodes with aliases are added both in alias to expression and alias to function map. - * - * These is necessary because identifier with alias can give alias name to any query tree node. - * - * Example: - * WITH (x -> x + 1) AS id, id AS value SELECT value(1); - * In this example id as value is identifier node that has alias, during scope initialization we cannot derive - * that id is actually lambda or expression. - * - * There are no easy solution here, without trying to make full featured expression resolution at this stage. - * Example: - * WITH (x -> x + 1) AS id, id AS id_1, id_1 AS id_2 SELECT id_2(1); - * Example: SELECT a, b AS a, b AS c, 1 AS c; - * - * It is client responsibility after resolving identifier node with alias, make following actions: - * 1. If identifier node was resolved in function scope, remove alias from scope expression map. - * 2. If identifier node was resolved in expression scope, remove alias from scope function map. - * - * That way we separate alias map initialization and expressions resolution. - */ -class QueryExpressionsAliasVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit QueryExpressionsAliasVisitor(ScopeAliases & aliases_) - : aliases(aliases_) - {} - - void visitImpl(QueryTreeNodePtr & node) - { - updateAliasesIfNeeded(node, false /*is_lambda_node*/); - } - - bool needChildVisit(const QueryTreeNodePtr &, const QueryTreeNodePtr & child) - { - if (auto * lambda_node = child->as()) - { - updateAliasesIfNeeded(child, true /*is_lambda_node*/); - return false; - } - else if (auto * query_tree_node = child->as()) - { - if (query_tree_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - else if (auto * union_node = child->as()) - { - if (union_node->isCTE()) - return false; - - updateAliasesIfNeeded(child, false /*is_lambda_node*/); - return false; - } - - return true; - } -private: - void addDuplicatingAlias(const QueryTreeNodePtr & node) - { - aliases.nodes_with_duplicated_aliases.emplace(node); - auto cloned_node = node->clone(); - aliases.cloned_nodes_with_duplicated_aliases.emplace_back(cloned_node); - aliases.nodes_with_duplicated_aliases.emplace(cloned_node); - } - - void updateAliasesIfNeeded(const QueryTreeNodePtr & node, bool is_lambda_node) - { - if (!node->hasAlias()) - return; - - // We should not resolve expressions to WindowNode - if (node->getNodeType() == QueryTreeNodeType::WINDOW) - return; - - const auto & alias = node->getAlias(); - - if (is_lambda_node) - { - if (aliases.alias_name_to_expression_node->contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_lambda_node.insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - return; - } - - if (aliases.alias_name_to_lambda_node.contains(alias)) - addDuplicatingAlias(node); - - auto [_, inserted] = aliases.alias_name_to_expression_node->insert(std::make_pair(alias, node)); - if (!inserted) - addDuplicatingAlias(node); - - /// If node is identifier put it into transitive aliases map. - if (const auto * identifier = typeid_cast(node.get())) - aliases.transitive_aliases.insert(std::make_pair(alias, identifier->getIdentifier())); - } - - ScopeAliases & aliases; -}; - class TableExpressionsAliasVisitor : public InDepthQueryTreeVisitor { public: @@ -1202,7278 +68,4 @@ private: IdentifierResolveScope & scope; }; -class QueryAnalyzer -{ -public: - explicit QueryAnalyzer(bool only_analyze_) : only_analyze(only_analyze_) {} - - void resolve(QueryTreeNodePtr & node, const QueryTreeNodePtr & table_expression, ContextPtr context) - { - IdentifierResolveScope scope(node, nullptr /*parent_scope*/); - - if (!scope.context) - scope.context = context; - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::QUERY: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For query analysis table expression must be empty"); - - resolveQuery(node, scope); - break; - } - case QueryTreeNodeType::UNION: - { - if (table_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "For union analysis table expression must be empty"); - - resolveUnion(node, scope); - break; - } - case QueryTreeNodeType::IDENTIFIER: - [[fallthrough]]; - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - [[fallthrough]]; - case QueryTreeNodeType::FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::LIST: - { - if (table_expression) - { - scope.expression_join_tree_node = table_expression; - validateTableExpressionModifiers(scope.expression_join_tree_node, scope); - initializeTableExpressionData(scope.expression_join_tree_node, scope); - } - - if (node_type == QueryTreeNodeType::LIST) - resolveExpressionNodeList(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - else - resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - QueryExpressionsAliasVisitor expressions_alias_visitor(scope.aliases); - resolveTableFunction(node, scope, expressions_alias_visitor, false /*nested_table_function*/); - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Node {} with type {} is not supported by query analyzer. " - "Supported nodes are query, union, identifier, constant, column, function, list.", - node->formatASTForErrorMessage(), - node->getNodeTypeName()); - } - } - } - -private: - /// Utility functions - - static bool isExpressionNodeType(QueryTreeNodeType node_type); - - static bool isFunctionExpressionNodeType(QueryTreeNodeType node_type); - - static bool isSubqueryNodeType(QueryTreeNodeType node_type); - - static bool isTableExpressionNodeType(QueryTreeNodeType node_type); - - static DataTypePtr getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node); - - static ProjectionName calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, - const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names); - - static ProjectionName calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name); - - static ProjectionName calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, - const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, - const ProjectionName & fill_to_expression_projection_name, - const ProjectionName & fill_step_expression_projection_name); - - static void collectCompoundExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result); - - static void collectTableExpressionValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result); - - static void collectScopeValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static void collectScopeWithParentScopesValidIdentifiersForTypoCorrection(const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result); - - static std::vector collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers); - - static QueryTreeNodePtr wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path); - - QueryTreeNodePtr tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context); - - void evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & query_tree_node, IdentifierResolveScope & scope); - - static void mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope); - - void replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope); - - static void convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope); - - static void validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - static void checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope); - - static std::pair recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into); - - static void expandGroupByAll(QueryNode & query_tree_node_typed); - - void expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings); - - static std::string - rewriteAggregateFunctionNameIfNeeded(const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context); - - static std::optional getColumnSideFromJoinTree(const QueryTreeNodePtr & resolved_identifier, const JoinNode & join_node) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - return {}; - - if (resolved_identifier->getNodeType() == QueryTreeNodeType::FUNCTION) - { - const auto & resolved_function = resolved_identifier->as(); - - const auto & argument_nodes = resolved_function.getArguments().getNodes(); - - std::optional result; - for (const auto & argument_node : argument_nodes) - { - auto table_side = getColumnSideFromJoinTree(argument_node, join_node); - if (table_side && result && *table_side != *result) - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Ambiguous identifier {}. In scope {}", - resolved_identifier->formatASTForErrorMessage(), - join_node.formatASTForErrorMessage()); - } - result = table_side; - } - return result; - } - - const auto * column_src = resolved_identifier->as().getColumnSource().get(); - - if (join_node.getLeftTableExpression().get() == column_src) - return JoinTableSide::Left; - if (join_node.getRightTableExpression().get() == column_src) - return JoinTableSide::Right; - return {}; - } - - static QueryTreeNodePtr convertJoinedColumnTypeToNullIfNeeded( - const QueryTreeNodePtr & resolved_identifier, - const JoinKind & join_kind, - std::optional resolved_side, - IdentifierResolveScope & scope) - { - if (resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && - JoinCommon::canBecomeNullable(resolved_identifier->getResultType()) && - (isFull(join_kind) || - (isLeft(join_kind) && resolved_side && *resolved_side == JoinTableSide::Right) || - (isRight(join_kind) && resolved_side && *resolved_side == JoinTableSide::Left))) - { - auto nullable_resolved_identifier = resolved_identifier->clone(); - auto & resolved_column = nullable_resolved_identifier->as(); - auto new_result_type = makeNullableOrLowCardinalityNullable(resolved_column.getColumnType()); - resolved_column.setColumnType(new_result_type); - if (resolved_column.hasExpression()) - { - auto & resolved_expression = resolved_column.getExpression(); - if (!resolved_expression->getResultType()->equals(*new_result_type)) - resolved_expression = buildCastFunction(resolved_expression, new_result_type, scope.context, true); - } - if (!nullable_resolved_identifier->isEqual(*resolved_identifier)) - scope.join_columns_with_changed_types[nullable_resolved_identifier] = resolved_identifier; - return nullable_resolved_identifier; - } - return nullptr; - } - - /// Resolve identifier functions - - static QueryTreeNodePtr tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context); - - QueryTreeNodePtr tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found = false); - - QueryTreeNodePtr tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings); - - QueryTreeNodePtr tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static bool tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope); - - QueryTreeNodePtr tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope); - - IdentifierResolveResult tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings = {}); - - QueryTreeNodePtr tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found = false); - - /// Resolve query tree nodes functions - - void qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope); - - static GetColumnsOptions buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context); - - using QueryTreeNodesWithNames = std::vector>; - - QueryTreeNodesWithNames getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope); - - void updateMatchedColumnsFromJoinUsing(QueryTreeNodesWithNames & result_matched_column_nodes_with_names, const QueryTreeNodePtr & source_table_expression, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - QueryTreeNodesWithNames resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionNames resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope); - - ProjectionName resolveWindow(QueryTreeNodePtr & window_node, IdentifierResolveScope & scope); - - ProjectionNames resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope); - - ProjectionNames resolveFunction(QueryTreeNodePtr & function_node, IdentifierResolveScope & scope); - - ProjectionNames resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias = false); - - ProjectionNames resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression); - - ProjectionNames resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope); - - void resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope); - - void resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope); - - void resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope); - - NamesAndTypes resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope); - - void initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope); - - void initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope); - - void resolveTableFunction(QueryTreeNodePtr & table_function_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor, bool nested_table_function); - - void resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor); - - void resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope); - - void resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope); - - /// Lambdas that are currently in resolve process - std::unordered_set lambdas_in_resolve_process; - - /// CTEs that are currently in resolve process - std::unordered_set ctes_in_resolve_process; - - /// Function name to user defined lambda map - std::unordered_map function_name_to_user_defined_lambda; - - /// Array join expressions counter - size_t array_join_expressions_counter = 1; - - /// Subquery counter - size_t subquery_counter = 1; - - /// Global expression node to projection name map - std::unordered_map node_to_projection_name; - - /// Global resolve expression node to projection names map - std::unordered_map resolved_expressions; - - /// Global resolve expression node to tree size - std::unordered_map node_to_tree_size; - - /// Global scalar subquery to scalar value map - std::unordered_map scalar_subquery_to_scalar_value_local; - std::unordered_map scalar_subquery_to_scalar_value_global; - - const bool only_analyze; -}; - -/// Utility functions implementation - - -bool QueryAnalyzer::isExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::CONSTANT || node_type == QueryTreeNodeType::COLUMN || node_type == QueryTreeNodeType::FUNCTION - || node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isFunctionExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::LAMBDA; -} - -bool QueryAnalyzer::isSubqueryNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION; -} - -bool QueryAnalyzer::isTableExpressionNodeType(QueryTreeNodeType node_type) -{ - return node_type == QueryTreeNodeType::TABLE || node_type == QueryTreeNodeType::TABLE_FUNCTION || - isSubqueryNodeType(node_type); -} - -DataTypePtr QueryAnalyzer::getExpressionNodeResultTypeOrNull(const QueryTreeNodePtr & query_tree_node) -{ - auto node_type = query_tree_node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::CONSTANT: - [[fallthrough]]; - case QueryTreeNodeType::COLUMN: - { - return query_tree_node->getResultType(); - } - case QueryTreeNodeType::FUNCTION: - { - auto & function_node = query_tree_node->as(); - if (function_node.isResolved()) - return function_node.getResultType(); - break; - } - default: - { - break; - } - } - - return nullptr; -} - -ProjectionName QueryAnalyzer::calculateFunctionProjectionName(const QueryTreeNodePtr & function_node, const ProjectionNames & parameters_projection_names, - const ProjectionNames & arguments_projection_names) -{ - const auto & function_node_typed = function_node->as(); - const auto & function_node_name = function_node_typed.getFunctionName(); - - bool is_array_function = function_node_name == "array"; - bool is_tuple_function = function_node_name == "tuple"; - - WriteBufferFromOwnString buffer; - - if (!is_array_function && !is_tuple_function) - buffer << function_node_name; - - if (!parameters_projection_names.empty()) - { - buffer << '('; - - size_t function_parameters_projection_names_size = parameters_projection_names.size(); - for (size_t i = 0; i < function_parameters_projection_names_size; ++i) - { - buffer << parameters_projection_names[i]; - - if (i + 1 != function_parameters_projection_names_size) - buffer << ", "; - } - - buffer << ')'; - } - - char open_bracket = '('; - char close_bracket = ')'; - - if (is_array_function) - { - open_bracket = '['; - close_bracket = ']'; - } - - buffer << open_bracket; - - size_t function_arguments_projection_names_size = arguments_projection_names.size(); - for (size_t i = 0; i < function_arguments_projection_names_size; ++i) - { - buffer << arguments_projection_names[i]; - - if (i + 1 != function_arguments_projection_names_size) - buffer << ", "; - } - - buffer << close_bracket; - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateWindowProjectionName(const QueryTreeNodePtr & window_node, - const QueryTreeNodePtr & parent_window_node, - const String & parent_window_name, - const ProjectionNames & partition_by_projection_names, - const ProjectionNames & order_by_projection_names, - const ProjectionName & frame_begin_offset_projection_name, - const ProjectionName & frame_end_offset_projection_name) -{ - const auto & window_node_typed = window_node->as(); - const auto & window_frame = window_node_typed.getWindowFrame(); - - bool parent_window_node_has_partition_by = false; - bool parent_window_node_has_order_by = false; - - if (parent_window_node) - { - const auto & parent_window_node_typed = parent_window_node->as(); - parent_window_node_has_partition_by = parent_window_node_typed.hasPartitionBy(); - parent_window_node_has_order_by = parent_window_node_typed.hasOrderBy(); - } - - WriteBufferFromOwnString buffer; - - if (!parent_window_name.empty()) - buffer << parent_window_name; - - if (!partition_by_projection_names.empty() && !parent_window_node_has_partition_by) - { - if (!parent_window_name.empty()) - buffer << ' '; - - buffer << "PARTITION BY "; - - size_t partition_by_projection_names_size = partition_by_projection_names.size(); - for (size_t i = 0; i < partition_by_projection_names_size; ++i) - { - buffer << partition_by_projection_names[i]; - if (i + 1 != partition_by_projection_names_size) - buffer << ", "; - } - } - - if (!order_by_projection_names.empty() && !parent_window_node_has_order_by) - { - if (!partition_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << "ORDER BY "; - - size_t order_by_projection_names_size = order_by_projection_names.size(); - for (size_t i = 0; i < order_by_projection_names_size; ++i) - { - buffer << order_by_projection_names[i]; - if (i + 1 != order_by_projection_names_size) - buffer << ", "; - } - } - - if (!window_frame.is_default) - { - if (!partition_by_projection_names.empty() || !order_by_projection_names.empty() || !parent_window_name.empty()) - buffer << ' '; - - buffer << window_frame.type << " BETWEEN "; - if (window_frame.begin_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.begin_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_begin_offset_projection_name; - buffer << " " << (window_frame.begin_preceding ? "PRECEDING" : "FOLLOWING"); - } - - buffer << " AND "; - - if (window_frame.end_type == WindowFrame::BoundaryType::Current) - { - buffer << "CURRENT ROW"; - } - else if (window_frame.end_type == WindowFrame::BoundaryType::Unbounded) - { - buffer << "UNBOUNDED"; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - else - { - buffer << frame_end_offset_projection_name; - buffer << " " << (window_frame.end_preceding ? "PRECEDING" : "FOLLOWING"); - } - } - - return buffer.str(); -} - -ProjectionName QueryAnalyzer::calculateSortColumnProjectionName(const QueryTreeNodePtr & sort_column_node, const ProjectionName & sort_expression_projection_name, - const ProjectionName & fill_from_expression_projection_name, const ProjectionName & fill_to_expression_projection_name, const ProjectionName & fill_step_expression_projection_name) -{ - auto & sort_node_typed = sort_column_node->as(); - - WriteBufferFromOwnString sort_column_projection_name_buffer; - sort_column_projection_name_buffer << sort_expression_projection_name; - - auto sort_direction = sort_node_typed.getSortDirection(); - sort_column_projection_name_buffer << (sort_direction == SortDirection::ASCENDING ? " ASC" : " DESC"); - - auto nulls_sort_direction = sort_node_typed.getNullsSortDirection(); - - if (nulls_sort_direction) - sort_column_projection_name_buffer << " NULLS " << (nulls_sort_direction == sort_direction ? "LAST" : "FIRST"); - - if (auto collator = sort_node_typed.getCollator()) - sort_column_projection_name_buffer << " COLLATE " << collator->getLocale(); - - if (sort_node_typed.withFill()) - { - sort_column_projection_name_buffer << " WITH FILL"; - - if (sort_node_typed.hasFillFrom()) - sort_column_projection_name_buffer << " FROM " << fill_from_expression_projection_name; - - if (sort_node_typed.hasFillTo()) - sort_column_projection_name_buffer << " TO " << fill_to_expression_projection_name; - - if (sort_node_typed.hasFillStep()) - sort_column_projection_name_buffer << " STEP " << fill_step_expression_projection_name; - } - - return sort_column_projection_name_buffer.str(); -} - -/// Get valid identifiers for typo correction from compound expression -void QueryAnalyzer::collectCompoundExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const DataTypePtr & compound_expression_type, - const Identifier & valid_identifier_prefix, - std::unordered_set & valid_identifiers_result) -{ - IDataType::forEachSubcolumn([&](const auto &, const auto & name, const auto &) - { - Identifier subcolumn_indentifier(name); - size_t new_identifier_size = valid_identifier_prefix.getPartsSize() + subcolumn_indentifier.getPartsSize(); - - if (new_identifier_size == unresolved_identifier.getPartsSize()) - { - auto new_identifier = valid_identifier_prefix; - for (const auto & part : subcolumn_indentifier) - new_identifier.push_back(part); - - valid_identifiers_result.insert(std::move(new_identifier)); - } - }, ISerialization::SubstreamData(compound_expression_type->getDefaultSerialization())); -} - -/// Get valid identifiers for typo correction from table expression -void QueryAnalyzer::collectTableExpressionValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const QueryTreeNodePtr & table_expression, - const TableExpressionData & table_expression_data, - std::unordered_set & valid_identifiers_result) -{ - for (const auto & [column_name, column_node] : table_expression_data.column_name_to_column_node) - { - Identifier column_identifier(column_name); - if (unresolved_identifier.getPartsSize() == column_identifier.getPartsSize()) - valid_identifiers_result.insert(column_identifier); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier, - valid_identifiers_result); - - if (table_expression->hasAlias()) - { - Identifier column_identifier_with_alias({table_expression->getAlias()}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_alias.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_alias.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_alias); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_alias, - valid_identifiers_result); - } - - if (!table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name({table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name, - valid_identifiers_result); - } - - if (!table_expression_data.database_name.empty() && !table_expression_data.table_name.empty()) - { - Identifier column_identifier_with_table_name_and_database_name({table_expression_data.database_name, table_expression_data.table_name}); - for (const auto & column_identifier_part : column_identifier) - column_identifier_with_table_name_and_database_name.push_back(column_identifier_part); - - if (unresolved_identifier.getPartsSize() == column_identifier_with_table_name_and_database_name.getPartsSize()) - valid_identifiers_result.insert(column_identifier_with_table_name_and_database_name); - - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - column_node->getColumnType(), - column_identifier_with_table_name_and_database_name, - valid_identifiers_result); - } - } -} - -/// Get valid identifiers for typo correction from scope without looking at parent scopes -void QueryAnalyzer::collectScopeValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - bool identifier_is_short = unresolved_identifier.isShort(); - bool identifier_is_compound = unresolved_identifier.isCompound(); - - if (allow_expression_identifiers) - { - for (const auto & [name, expression] : *scope.aliases.alias_name_to_expression_node) - { - assert(expression); - auto expression_identifier = Identifier(name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - - for (const auto & [table_expression, table_expression_data] : scope.table_expression_node_to_data) - { - collectTableExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - table_expression, - table_expression_data, - valid_identifiers_result); - } - } - - if (identifier_is_short) - { - if (allow_function_identifiers) - { - for (const auto & [name, _] : *scope.aliases.alias_name_to_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - - if (allow_table_expression_identifiers) - { - for (const auto & [name, _] : scope.aliases.alias_name_to_table_expression_node) - valid_identifiers_result.insert(Identifier(name)); - } - } - - for (const auto & [argument_name, expression] : scope.expression_argument_name_to_node) - { - assert(expression); - auto expression_node_type = expression->getNodeType(); - - if (allow_expression_identifiers && isExpressionNodeType(expression_node_type)) - { - auto expression_identifier = Identifier(argument_name); - valid_identifiers_result.insert(expression_identifier); - - auto result_type = getExpressionNodeResultTypeOrNull(expression); - - if (identifier_is_compound && result_type) - { - collectCompoundExpressionValidIdentifiersForTypoCorrection(unresolved_identifier, - result_type, - expression_identifier, - valid_identifiers_result); - } - } - else if (identifier_is_short && allow_function_identifiers && isFunctionExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - else if (allow_table_expression_identifiers && isTableExpressionNodeType(expression_node_type)) - { - valid_identifiers_result.insert(Identifier(argument_name)); - } - } -} - -void QueryAnalyzer::collectScopeWithParentScopesValidIdentifiersForTypoCorrection( - const Identifier & unresolved_identifier, - const IdentifierResolveScope & scope, - bool allow_expression_identifiers, - bool allow_function_identifiers, - bool allow_table_expression_identifiers, - std::unordered_set & valid_identifiers_result) -{ - const IdentifierResolveScope * current_scope = &scope; - - while (current_scope) - { - collectScopeValidIdentifiersForTypoCorrection(unresolved_identifier, - *current_scope, - allow_expression_identifiers, - allow_function_identifiers, - allow_table_expression_identifiers, - valid_identifiers_result); - - current_scope = current_scope->parent_scope; - } -} - -std::vector QueryAnalyzer::collectIdentifierTypoHints(const Identifier & unresolved_identifier, const std::unordered_set & valid_identifiers) -{ - std::vector prompting_strings; - prompting_strings.reserve(valid_identifiers.size()); - - for (const auto & valid_identifier : valid_identifiers) - prompting_strings.push_back(valid_identifier.getFullName()); - - return NamePrompter<1>::getHints(unresolved_identifier.getFullName(), prompting_strings); -} - -/** Wrap expression node in tuple element function calls for nested paths. - * Example: Expression node: compound_expression. Nested path: nested_path_1.nested_path_2. - * Result: tupleElement(tupleElement(compound_expression, 'nested_path_1'), 'nested_path_2'). - */ -QueryTreeNodePtr QueryAnalyzer::wrapExpressionNodeInTupleElement(QueryTreeNodePtr expression_node, IdentifierView nested_path) -{ - size_t nested_path_parts_size = nested_path.getPartsSize(); - for (size_t i = 0; i < nested_path_parts_size; ++i) - { - const auto & nested_path_part = nested_path[i]; - auto tuple_element_function = std::make_shared("tupleElement"); - - auto & tuple_element_function_arguments_nodes = tuple_element_function->getArguments().getNodes(); - tuple_element_function_arguments_nodes.reserve(2); - tuple_element_function_arguments_nodes.push_back(expression_node); - tuple_element_function_arguments_nodes.push_back(std::make_shared(nested_path_part)); - - expression_node = std::move(tuple_element_function); - } - - return expression_node; -} - -/** Try to get lambda node from sql user defined functions if sql user defined function with function name exists. - * Returns lambda node if function exists, nullptr otherwise. - */ -QueryTreeNodePtr QueryAnalyzer::tryGetLambdaFromSQLUserDefinedFunctions(const std::string & function_name, ContextPtr context) -{ - auto user_defined_function = UserDefinedSQLFunctionFactory::instance().tryGet(function_name); - if (!user_defined_function) - return {}; - - auto it = function_name_to_user_defined_lambda.find(function_name); - if (it != function_name_to_user_defined_lambda.end()) - return it->second; - - const auto & create_function_query = user_defined_function->as(); - auto result_node = buildQueryTree(create_function_query->function_core, context); - if (result_node->getNodeType() != QueryTreeNodeType::LAMBDA) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "SQL user defined function {} must represent lambda expression. Actual {}", - function_name, - create_function_query->function_core->formatForErrorMessage()); - - function_name_to_user_defined_lambda.emplace(function_name, result_node); - - return result_node; -} - -bool subtreeHasViewSource(const IQueryTreeNode * node, const Context & context) -{ - if (!node) - return false; - - if (const auto * table_node = node->as()) - { - if (table_node->getStorageID().getFullNameNotQuoted() == context.getViewSource()->getStorageID().getFullNameNotQuoted()) - return true; - } - - for (const auto & child : node->getChildren()) - if (subtreeHasViewSource(child.get(), context)) - return true; - - return false; -} - -/// Evaluate scalar subquery and perform constant folding if scalar subquery does not have constant value -void QueryAnalyzer::evaluateScalarSubqueryIfNeeded(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - auto * query_node = node->as(); - auto * union_node = node->as(); - if (!query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node must have query or union type. Actual {} {}", - node->getNodeTypeName(), - node->formatASTForErrorMessage()); - - auto & context = scope.context; - - Block scalar_block; - - auto node_without_alias = node->clone(); - node_without_alias->removeAlias(); - - QueryTreeNodePtrWithHash node_with_hash(node_without_alias); - auto str_hash = DB::toString(node_with_hash.hash); - - bool can_use_global_scalars = !only_analyze && !(context->getViewSource() && subtreeHasViewSource(node_without_alias.get(), *context)); - - auto & scalars_cache = can_use_global_scalars ? scalar_subquery_to_scalar_value_global : scalar_subquery_to_scalar_value_local; - - if (scalars_cache.contains(node_with_hash)) - { - if (can_use_global_scalars) - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - else - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesLocalCacheHit); - - scalar_block = scalars_cache.at(node_with_hash); - } - else if (context->hasQueryContext() && can_use_global_scalars && context->getQueryContext()->hasScalar(str_hash)) - { - scalar_block = context->getQueryContext()->getScalar(str_hash); - scalar_subquery_to_scalar_value_global.emplace(node_with_hash, scalar_block); - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesGlobalCacheHit); - } - else - { - ProfileEvents::increment(ProfileEvents::ScalarSubqueriesCacheMiss); - auto subquery_context = Context::createCopy(context); - - Settings subquery_settings = context->getSettings(); - subquery_settings.max_result_rows = 1; - subquery_settings.extremes = false; - subquery_context->setSettings(subquery_settings); - /// When execute `INSERT INTO t WITH ... SELECT ...`, it may lead to `Unknown columns` - /// exception with this settings enabled(https://github.com/ClickHouse/ClickHouse/issues/52494). - subquery_context->setSetting("use_structure_from_insertion_table_in_table_functions", false); - - auto options = SelectQueryOptions(QueryProcessingStage::Complete, scope.subquery_depth, true /*is_subquery*/); - options.only_analyze = only_analyze; - auto interpreter = std::make_unique(node->toAST(), subquery_context, subquery_context->getViewSource(), options); - - if (only_analyze) - { - /// If query is only analyzed, then constants are not correct. - scalar_block = interpreter->getSampleBlock(); - for (auto & column : scalar_block) - { - if (column.column->empty()) - { - auto mut_col = column.column->cloneEmpty(); - mut_col->insertDefault(); - column.column = std::move(mut_col); - } - } - } - else - { - auto io = interpreter->execute(); - PullingAsyncPipelineExecutor executor(io.pipeline); - io.pipeline.setProgressCallback(context->getProgressCallback()); - io.pipeline.setProcessListElement(context->getProcessListElement()); - - Block block; - - while (block.rows() == 0 && executor.pull(block)) - { - } - - if (block.rows() == 0) - { - auto types = interpreter->getSampleBlock().getDataTypes(); - if (types.size() != 1) - types = {std::make_shared(types)}; - - auto & type = types[0]; - if (!type->isNullable()) - { - if (!type->canBeInsideNullable()) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, - "Scalar subquery returned empty result of type {} which cannot be Nullable", - type->getName()); - - type = makeNullable(type); - } - - auto scalar_column = type->createColumn(); - scalar_column->insert(Null()); - scalar_block.insert({std::move(scalar_column), type, "null"}); - } - else - { - if (block.rows() != 1) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - Block tmp_block; - while (tmp_block.rows() == 0 && executor.pull(tmp_block)) - { - } - - if (tmp_block.rows() != 0) - throw Exception(ErrorCodes::INCORRECT_RESULT_OF_SCALAR_SUBQUERY, "Scalar subquery returned more than one row"); - - block = materializeBlock(block); - size_t columns = block.columns(); - - if (columns == 1) - { - auto & column = block.getByPosition(0); - /// Here we wrap type to nullable if we can. - /// It is needed cause if subquery return no rows, it's result will be Null. - /// In case of many columns, do not check it cause tuple can't be nullable. - if (!column.type->isNullable() && column.type->canBeInsideNullable()) - { - column.type = makeNullable(column.type); - column.column = makeNullable(column.column); - } - - scalar_block = block; - } - else - { - /** Make unique column names for tuple. - * - * Example: SELECT (SELECT 2 AS x, x) - */ - makeUniqueColumnNamesInBlock(block); - - scalar_block.insert({ - ColumnTuple::create(block.getColumns()), - std::make_shared(block.getDataTypes(), block.getNames()), - "tuple"}); - } - } - } - - scalars_cache.emplace(node_with_hash, scalar_block); - if (can_use_global_scalars && context->hasQueryContext()) - context->getQueryContext()->addScalar(str_hash, scalar_block); - } - - const auto & scalar_column_with_type = scalar_block.safeGetByPosition(0); - const auto & scalar_type = scalar_column_with_type.type; - - Field scalar_value; - scalar_column_with_type.column->get(0, scalar_value); - - const auto * scalar_type_name = scalar_block.safeGetByPosition(0).type->getFamilyName(); - static const std::set useless_literal_types = {"Array", "Tuple", "AggregateFunction", "Function", "Set", "LowCardinality"}; - auto * nearest_query_scope = scope.getNearestQueryScope(); - - /// Always convert to literals when there is no query context - if (!context->getSettingsRef().enable_scalar_subquery_optimization || - !useless_literal_types.contains(scalar_type_name) || - !context->hasQueryContext() || - !nearest_query_scope) - { - auto constant_value = std::make_shared(std::move(scalar_value), scalar_type); - auto constant_node = std::make_shared(constant_value, node); - - if (constant_node->getValue().isNull()) - { - node = buildCastFunction(constant_node, constant_node->getResultType(), context); - node = std::make_shared(std::move(constant_value), node); - } - else - node = std::move(constant_node); - - return; - } - - auto & nearest_query_scope_query_node = nearest_query_scope->scope_node->as(); - auto & mutable_context = nearest_query_scope_query_node.getMutableContext(); - - auto scalar_query_hash_string = DB::toString(node_with_hash.hash) + (only_analyze ? "_analyze" : ""); - - if (mutable_context->hasQueryContext()) - mutable_context->getQueryContext()->addScalar(scalar_query_hash_string, scalar_block); - - mutable_context->addScalar(scalar_query_hash_string, scalar_block); - - std::string get_scalar_function_name = "__getScalar"; - - auto scalar_query_hash_constant_value = std::make_shared(std::move(scalar_query_hash_string), std::make_shared()); - auto scalar_query_hash_constant_node = std::make_shared(std::move(scalar_query_hash_constant_value)); - - auto get_scalar_function_node = std::make_shared(get_scalar_function_name); - get_scalar_function_node->getArguments().getNodes().push_back(std::move(scalar_query_hash_constant_node)); - - auto get_scalar_function = FunctionFactory::instance().get(get_scalar_function_name, mutable_context); - get_scalar_function_node->resolveAsFunction(get_scalar_function->build(get_scalar_function_node->getArgumentColumns())); - - node = std::move(get_scalar_function_node); -} - -void QueryAnalyzer::mergeWindowWithParentWindow(const QueryTreeNodePtr & window_node, const QueryTreeNodePtr & parent_window_node, IdentifierResolveScope & scope) -{ - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - - auto & parent_window_node_typed = parent_window_node->as(); - - /** If an existing_window_name is specified it must refer to an earlier - * entry in the WINDOW list; the new window copies its partitioning clause - * from that entry, as well as its ordering clause if any. In this case - * the new window cannot specify its own PARTITION BY clause, and it can - * specify ORDER BY only if the copied window does not have one. The new - * window always uses its own frame clause; the copied window must not - * specify a frame clause. - * https://www.postgresql.org/docs/current/sql-select.html - */ - if (window_node_typed.hasPartitionBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override PARTITION BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (window_node_typed.hasOrderBy() && parent_window_node_typed.hasOrderBy()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Derived window definition '{}' is not allowed to override a non-empty ORDER BY. In scope {}", - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (!parent_window_node_typed.getWindowFrame().is_default) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parent window '{}' is not allowed to define a frame: while processing derived window definition '{}'. In scope {}", - parent_window_name, - window_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - window_node_typed.getPartitionByNode() = parent_window_node_typed.getPartitionBy().clone(); - - if (parent_window_node_typed.hasOrderBy()) - window_node_typed.getOrderByNode() = parent_window_node_typed.getOrderBy().clone(); -} - -/** Replace nodes in node list with positional arguments. - * - * Example: SELECT id, value FROM test_table GROUP BY 1, 2; - * Example: SELECT id, value FROM test_table ORDER BY 1, 2; - * Example: SELECT id, value FROM test_table LIMIT 5 BY 1, 2; - */ -void QueryAnalyzer::replaceNodesWithPositionalArguments(QueryTreeNodePtr & node_list, const QueryTreeNodes & projection_nodes, IdentifierResolveScope & scope) -{ - const auto & settings = scope.context->getSettingsRef(); - if (!settings.enable_positional_arguments || scope.context->getClientInfo().query_kind != ClientInfo::QueryKind::INITIAL_QUERY) - return; - - auto & node_list_typed = node_list->as(); - - for (auto & node : node_list_typed.getNodes()) - { - auto * node_to_replace = &node; - - if (auto * sort_node = node->as()) - node_to_replace = &sort_node->getExpression(); - - auto * constant_node = (*node_to_replace)->as(); - - if (!constant_node - || (constant_node->getValue().getType() != Field::Types::UInt64 - && constant_node->getValue().getType() != Field::Types::Int64)) - continue; - - UInt64 pos; - if (constant_node->getValue().getType() == Field::Types::UInt64) - { - pos = constant_node->getValue().get(); - } - else // Int64 - { - auto value = constant_node->getValue().get(); - if (value > 0) - pos = value; - else - { - if (value < -static_cast(projection_nodes.size())) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Negative positional argument number {} is out of bounds. Expected in range [-{}, -1]. In scope {}", - value, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - pos = projection_nodes.size() + value + 1; - } - } - - if (!pos || pos > projection_nodes.size()) - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Positional argument number {} is out of bounds. Expected in range [1, {}]. In scope {}", - pos, - projection_nodes.size(), - scope.scope_node->formatASTForErrorMessage()); - - --pos; - *node_to_replace = projection_nodes[pos]->clone(); - if (auto it = resolved_expressions.find(projection_nodes[pos]); it != resolved_expressions.end()) - { - resolved_expressions[*node_to_replace] = it->second; - } - } -} - -void QueryAnalyzer::convertLimitOffsetExpression(QueryTreeNodePtr & expression_node, const String & expression_description, IdentifierResolveScope & scope) -{ - const auto * limit_offset_constant_node = expression_node->as(); - if (!limit_offset_constant_node || !isNativeNumber(removeNullable(limit_offset_constant_node->getResultType()))) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} expression must be constant with numeric type. Actual {}. In scope {}", - expression_description, - expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - Field converted_value = convertFieldToType(limit_offset_constant_node->getValue(), DataTypeUInt64()); - if (converted_value.isNull()) - throw Exception(ErrorCodes::INVALID_LIMIT_EXPRESSION, - "{} numeric constant expression is not representable as UInt64", - expression_description); - - auto constant_value = std::make_shared(std::move(converted_value), std::make_shared()); - auto result_constant_node = std::make_shared(std::move(constant_value)); - result_constant_node->getSourceExpression() = limit_offset_constant_node->getSourceExpression(); - - expression_node = std::move(result_constant_node); -} - -void QueryAnalyzer::validateTableExpressionModifiers(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unexpected table expression. Expected table, table function, query or union node. Table node: {}, scope node: {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (table_node || table_function_node) - { - auto table_expression_modifiers = table_node ? table_node->getTableExpressionModifiers() : table_function_node->getTableExpressionModifiers(); - - if (table_expression_modifiers.has_value()) - { - const auto & storage = table_node ? table_node->getStorage() : table_function_node->getStorage(); - if (table_expression_modifiers->hasFinal() && !storage->supportsFinal()) - throw Exception(ErrorCodes::ILLEGAL_FINAL, - "Storage {} doesn't support FINAL", - storage->getName()); - - if (table_expression_modifiers->hasSampleSizeRatio() && !storage->supportsSampling()) - throw Exception(ErrorCodes::SAMPLING_NOT_SUPPORTED, - "Storage {} doesn't support sampling", - storage->getStorageID().getFullNameNotQuoted()); - } - } -} - -void QueryAnalyzer::validateJoinTableExpressionWithoutAlias(const QueryTreeNodePtr & join_node, const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - bool table_expression_has_alias = table_expression_node->hasAlias(); - if (table_expression_has_alias) - return; - - if (join_node->as().getKind() == JoinKind::Paste) - return; - - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - if ((query_node && !query_node->getCTEName().empty()) || (union_node && !union_node->getCTEName().empty())) - return; - - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type == QueryTreeNodeType::TABLE_FUNCTION || - table_expression_node_type == QueryTreeNodeType::QUERY || - table_expression_node_type == QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::ALIAS_REQUIRED, - "JOIN {} no alias for subquery or table function {}. " - "In scope {} (set joined_subquery_requires_alias = 0 to disable restriction)", - join_node->formatASTForErrorMessage(), - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); -} - -std::pair QueryAnalyzer::recursivelyCollectMaxOrdinaryExpressions(QueryTreeNodePtr & node, QueryTreeNodes & into) -{ - checkStackSize(); - - if (node->as()) - { - into.push_back(node); - return {false, 1}; - } - - auto * function = node->as(); - - if (!function) - return {false, 0}; - - if (function->isAggregateFunction()) - return {true, 0}; - - UInt64 pushed_children = 0; - bool has_aggregate = false; - - for (auto & child : function->getArguments().getNodes()) - { - auto [child_has_aggregate, child_pushed_children] = recursivelyCollectMaxOrdinaryExpressions(child, into); - has_aggregate |= child_has_aggregate; - pushed_children += child_pushed_children; - } - - /// The current function is not aggregate function and there is no aggregate function in its arguments, - /// so use the current function to replace its arguments - if (!has_aggregate) - { - for (UInt64 i = 0; i < pushed_children; i++) - into.pop_back(); - - into.push_back(node); - pushed_children = 1; - } - - return {has_aggregate, pushed_children}; -} - -/** Expand GROUP BY ALL by extracting all the SELECT-ed expressions that are not aggregate functions. - * - * For a special case that if there is a function having both aggregate functions and other fields as its arguments, - * the `GROUP BY` keys will contain the maximum non-aggregate fields we can extract from it. - * - * Example: - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY ALL - * will expand as - * SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t GROUP BY substring(a, 4, 2), substring(a, 1, 2) - */ -void QueryAnalyzer::expandGroupByAll(QueryNode & query_tree_node_typed) -{ - if (!query_tree_node_typed.isGroupByAll()) - return; - - auto & group_by_nodes = query_tree_node_typed.getGroupBy().getNodes(); - auto & projection_list = query_tree_node_typed.getProjection(); - - for (auto & node : projection_list.getNodes()) - recursivelyCollectMaxOrdinaryExpressions(node, group_by_nodes); - query_tree_node_typed.setIsGroupByAll(false); -} - -void QueryAnalyzer::expandOrderByAll(QueryNode & query_tree_node_typed, const Settings & settings) -{ - if (!settings.enable_order_by_all || !query_tree_node_typed.isOrderByAll()) - return; - - auto * all_node = query_tree_node_typed.getOrderBy().getNodes()[0]->as(); - if (!all_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Select analyze for not sort node."); - - auto & projection_nodes = query_tree_node_typed.getProjection().getNodes(); - auto list_node = std::make_shared(); - list_node->getNodes().reserve(projection_nodes.size()); - - for (auto & node : projection_nodes) - { - /// Detect and reject ambiguous statements: - /// E.g. for a table with columns "all", "a", "b": - /// - SELECT all, a, b ORDER BY all; -- should we sort by all columns in SELECT or by column "all"? - /// - SELECT a, b AS all ORDER BY all; -- like before but "all" as alias - /// - SELECT func(...) AS all ORDER BY all; -- like before but "all" as function - /// - SELECT a, b ORDER BY all; -- tricky in other way: does the user want to sort by columns in SELECT clause or by not SELECTed column "all"? - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - auto projection_names = resolved_expression_it->second; - if (projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected 1 projection names. Actual {}", - projection_names.size()); - if (boost::iequals(projection_names[0], "all")) - throw Exception(ErrorCodes::UNEXPECTED_EXPRESSION, - "Cannot use ORDER BY ALL to sort a column with name 'all', please disable setting `enable_order_by_all` and try again"); - } - - auto sort_node = std::make_shared(node, all_node->getSortDirection(), all_node->getNullsSortDirection()); - list_node->getNodes().push_back(sort_node); - } - - query_tree_node_typed.getOrderByNode() = list_node; - query_tree_node_typed.setIsOrderByAll(false); -} - -std::string QueryAnalyzer::rewriteAggregateFunctionNameIfNeeded( - const std::string & aggregate_function_name, NullsAction action, const ContextPtr & context) -{ - std::string result_aggregate_function_name = aggregate_function_name; - auto aggregate_function_name_lowercase = Poco::toLower(aggregate_function_name); - - const auto & settings = context->getSettingsRef(); - - if (aggregate_function_name_lowercase == "countdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - } - else if (aggregate_function_name_lowercase == "countdistinctif" || aggregate_function_name_lowercase == "countifdistinct") - { - result_aggregate_function_name = settings.count_distinct_implementation; - result_aggregate_function_name += "If"; - } - - /// Replace aggregateFunctionIfDistinct into aggregateFunctionDistinctIf to make execution more optimal - if (result_aggregate_function_name.ends_with("ifdistinct")) - { - size_t prefix_length = result_aggregate_function_name.size() - strlen("ifdistinct"); - result_aggregate_function_name = result_aggregate_function_name.substr(0, prefix_length) + "DistinctIf"; - } - - bool need_add_or_null = settings.aggregate_functions_null_for_empty && !result_aggregate_function_name.ends_with("OrNull"); - if (need_add_or_null) - { - auto properties = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (!properties->returns_default_when_only_null) - result_aggregate_function_name += "OrNull"; - } - - /** Move -OrNull suffix ahead, this should execute after add -OrNull suffix. - * Used to rewrite aggregate functions with -OrNull suffix in some cases. - * Example: sumIfOrNull. - * Result: sumOrNullIf. - */ - if (result_aggregate_function_name.ends_with("OrNull")) - { - auto function_properies = AggregateFunctionFactory::instance().tryGetProperties(result_aggregate_function_name, action); - if (function_properies && !function_properies->returns_default_when_only_null) - { - size_t function_name_size = result_aggregate_function_name.size(); - - static constexpr std::array suffixes_to_replace = {"MergeState", "Merge", "State", "If"}; - for (const auto & suffix : suffixes_to_replace) - { - auto suffix_string_value = String(suffix); - auto suffix_to_check = suffix_string_value + "OrNull"; - - if (!result_aggregate_function_name.ends_with(suffix_to_check)) - continue; - - result_aggregate_function_name = result_aggregate_function_name.substr(0, function_name_size - suffix_to_check.size()); - result_aggregate_function_name += "OrNull"; - result_aggregate_function_name += suffix_string_value; - - break; - } - } - } - - return result_aggregate_function_name; -} - -/// Resolve identifier functions implementation - -/// Try resolve table identifier from database catalog -QueryTreeNodePtr QueryAnalyzer::tryResolveTableIdentifierFromDatabaseCatalog(const Identifier & table_identifier, ContextPtr context) -{ - size_t parts_size = table_identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected table identifier to contain 1 or 2 parts. Actual '{}'", - table_identifier.getFullName()); - - std::string database_name; - std::string table_name; - - if (table_identifier.isCompound()) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - else - { - table_name = table_identifier[0]; - } - - StorageID storage_id(database_name, table_name); - storage_id = context->resolveStorageID(storage_id); - bool is_temporary_table = storage_id.getDatabaseName() == DatabaseCatalog::TEMPORARY_DATABASE; - - StoragePtr storage; - - if (is_temporary_table) - storage = DatabaseCatalog::instance().getTable(storage_id, context); - else - storage = DatabaseCatalog::instance().tryGetTable(storage_id, context); - - if (!storage) - return {}; - - auto storage_lock = storage->lockForShare(context->getInitialQueryId(), context->getSettingsRef().lock_acquire_timeout); - auto storage_snapshot = storage->getStorageSnapshot(storage->getInMemoryMetadataPtr(), context); - auto result = std::make_shared(std::move(storage), std::move(storage_lock), std::move(storage_snapshot)); - if (is_temporary_table) - result->setTemporaryTableName(table_name); - - return result; -} - -/// Resolve identifier from compound expression -/// If identifier cannot be resolved throw exception or return nullptr if can_be_not_found is true -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromCompoundExpression(const Identifier & expression_identifier, - size_t identifier_bind_size, - const QueryTreeNodePtr & compound_expression, - String compound_expression_source, - IdentifierResolveScope & scope, - bool can_be_not_found) -{ - Identifier compound_expression_identifier; - for (size_t i = 0; i < identifier_bind_size; ++i) - compound_expression_identifier.push_back(expression_identifier[i]); - - IdentifierView nested_path(expression_identifier); - nested_path.popFirst(identifier_bind_size); - - auto expression_type = compound_expression->getResultType(); - - if (!expression_type->hasSubcolumn(nested_path.getFullName())) - { - if (auto * column = compound_expression->as()) - { - const DataTypePtr & column_type = column->getColumn().getTypeInStorage(); - if (column_type->getTypeId() == TypeIndex::Object) - { - const auto * object_type = checkAndGetDataType(column_type.get()); - if (object_type->getSchemaFormat() == "json" && object_type->hasNullableSubcolumns()) - { - QueryTreeNodePtr constant_node_null = std::make_shared(Field()); - return constant_node_null; - } - } - } - - if (can_be_not_found) - return {}; - - std::unordered_set valid_identifiers; - collectCompoundExpressionValidIdentifiersForTypoCorrection(expression_identifier, - expression_type, - compound_expression_identifier, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(expression_identifier, valid_identifiers); - - String compound_expression_from_error_message; - if (!compound_expression_source.empty()) - { - compound_expression_from_error_message += " from "; - compound_expression_from_error_message += compound_expression_source; - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier {} nested path {} cannot be resolved from type {}{}. In scope {}{}", - expression_identifier, - nested_path, - expression_type->getName(), - compound_expression_from_error_message, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - QueryTreeNodePtr get_subcolumn_function = std::make_shared("getSubcolumn"); - auto & get_subcolumn_function_arguments_nodes = get_subcolumn_function->as()->getArguments().getNodes(); - - get_subcolumn_function_arguments_nodes.reserve(2); - get_subcolumn_function_arguments_nodes.push_back(compound_expression); - get_subcolumn_function_arguments_nodes.push_back(std::make_shared(nested_path.getFullName())); - - resolveFunction(get_subcolumn_function, scope); - return get_subcolumn_function; -} - -/** Resolve identifier from expression arguments. - * - * Expression arguments can be initialized during lambda analysis or they could be provided externally. - * Expression arguments must be already resolved nodes. This is client responsibility to resolve them. - * - * Example: SELECT arrayMap(x -> x + 1, [1,2,3]); - * For lambda x -> x + 1, `x` is lambda expression argument. - * - * Resolve strategy: - * 1. Try to bind identifier to scope argument name to node map. - * 2. If identifier is binded but expression context and node type are incompatible return nullptr. - * - * It is important to support edge cases, where we lookup for table or function node, but argument has same name. - * Example: WITH (x -> x + 1) AS func, (func -> func(1) + func) AS lambda SELECT lambda(1); - * - * 3. If identifier is compound and identifier lookup is in expression context use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromExpressionArguments(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - auto it = scope.expression_argument_name_to_node.find(identifier_lookup.identifier.getFullName()); - bool resolve_full_identifier = it != scope.expression_argument_name_to_node.end(); - - if (!resolve_full_identifier) - { - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - it = scope.expression_argument_name_to_node.find(identifier_bind_part); - if (it == scope.expression_argument_name_to_node.end()) - return {}; - } - - auto node_type = it->second->getNodeType(); - if (identifier_lookup.isExpressionLookup() && !isExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isTableExpressionLookup() && !isTableExpressionNodeType(node_type)) - return {}; - else if (identifier_lookup.isFunctionLookup() && !isFunctionExpressionNodeType(node_type)) - return {}; - - if (!resolve_full_identifier && identifier_lookup.identifier.isCompound() && identifier_lookup.isExpressionLookup()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return it->second; -} - -bool QueryAnalyzer::tryBindIdentifierToAliases(const IdentifierLookup & identifier_lookup, const IdentifierResolveScope & scope) -{ - return scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME) != nullptr || scope.aliases.array_join_aliases.contains(identifier_lookup.identifier.front()); -} - -/** Resolve identifier from scope aliases. - * - * Resolve strategy: - * 1. If alias is registered in current expressions that are in resolve process and if top expression is not part of bottom expression with the same alias subtree - * throw cyclic aliases exception. - * Otherwise prevent cache usage for identifier lookup and return nullptr. - * - * This is special scenario where identifier has name the same as alias name in one of its parent expressions including itself. - * In such case we cannot resolve identifier from aliases because of recursion. It is client responsibility to register and deregister alias - * names during expressions resolve. - * - * We must prevent cache usage for lookup because lookup outside of expression is supposed to return other value. - * Example: SELECT (id + 1) AS id, id + 2. Lookup for id inside (id + 1) as id should return id from table, but lookup (id + 2) should return - * (id + 1) AS id. - * - * Below cases should work: - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * SELECT (id + 1) AS id FROM test_table; - * SELECT (1 + (1 + id)) AS id FROM test_table; - * - * Below cases should throw cyclic aliases exception: - * SELECT (id + b) AS id, id as b FROM test_table; - * SELECT (1 + b + 1 + id) AS id, b as c, id as b FROM test_table; - * - * 2. Depending on IdentifierLookupContext get alias name to node map from IdentifierResolveScope. - * 3. Try to bind identifier to alias name in map. If there are no such binding return nullptr. - * 4. If node in map is not resolved, resolve it. It is important in case of compound expressions. - * Example: SELECT value.a, cast('(1)', 'Tuple(a UInt64)') AS value; - * - * Special case if node is identifier node. - * Example: SELECT value, id AS value FROM test_table; - * - * Add node in current scope expressions in resolve process stack. - * Try to resolve identifier. - * If identifier is resolved, depending on lookup context, erase entry from expression or lambda map. Check QueryExpressionsAliasVisitor documentation. - * Pop node from current scope expressions in resolve process stack. - * - * 5. If identifier is compound and identifier lookup is in expression context, use `tryResolveIdentifierFromCompoundExpression`. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromAliases(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - const auto & identifier_bind_part = identifier_lookup.identifier.front(); - - auto * it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FIRST_NAME); - if (it == nullptr) - return {}; - - QueryTreeNodePtr & alias_node = *it; - - if (!alias_node) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node with alias {} is not valid. In scope {}", - identifier_bind_part, - scope.scope_node->formatASTForErrorMessage()); - - if (auto root_expression_with_alias = scope.expressions_in_resolve_process_stack.getExpressionWithAlias(identifier_bind_part)) - { - const auto top_expression = scope.expressions_in_resolve_process_stack.getTop(); - - if (!isNodePartOfTree(top_expression.get(), root_expression_with_alias.get())) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - scope.non_cached_identifier_lookups_during_expression_resolve.insert(identifier_lookup); - return {}; - } - - auto node_type = alias_node->getNodeType(); - - /// Resolve expression if necessary - if (node_type == QueryTreeNodeType::IDENTIFIER) - { - scope.pushExpressionNode(alias_node); - - auto & alias_identifier_node = alias_node->as(); - auto identifier = alias_identifier_node.getIdentifier(); - auto lookup_result = tryResolveIdentifier(IdentifierLookup{identifier, identifier_lookup.lookup_context}, scope, identifier_resolve_settings); - if (!lookup_result.resolved_identifier) - { - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(identifier, scope, true, false, false, valid_identifiers); - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {} identifier '{}'. In scope {}{}", - toStringLowercase(identifier_lookup.lookup_context), - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - alias_node = lookup_result.resolved_identifier; - scope.popExpressionNode(); - } - else if (node_type == QueryTreeNodeType::FUNCTION) - { - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - else if (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION) - { - if (identifier_resolve_settings.allow_to_resolve_subquery_during_identifier_resolution) - resolveExpressionNode(alias_node, scope, false /*allow_lambda_expression*/, identifier_lookup.isTableExpressionLookup() /*allow_table_expression*/); - } - - if (identifier_lookup.identifier.isCompound() && alias_node) - { - if (identifier_lookup.isExpressionLookup()) - { - return tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - 1 /*identifier_bind_size*/, - alias_node, - {} /* compound_expression_source */, - scope, - identifier_resolve_settings.allow_to_check_join_tree /* can_be_not_found */); - } - else if (identifier_lookup.isFunctionLookup() || identifier_lookup.isTableExpressionLookup()) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Compound identifier '{}' cannot be resolved as {}. In scope {}", - identifier_lookup.identifier.getFullName(), - identifier_lookup.isFunctionLookup() ? "function" : "table expression", - scope.scope_node->formatASTForErrorMessage()); - } - } - - return alias_node; -} - -/** Resolve identifier from table columns. - * - * 1. If table column nodes are empty or identifier is not expression lookup return nullptr. - * 2. If identifier full name match table column use column. Save information that we resolve identifier using full name. - * 3. Else if identifier binds to table column, use column. - * 4. Try to resolve column ALIAS expression if it exists. - * 5. If identifier was compound and was not resolved using full name during step 1 use `tryResolveIdentifierFromCompoundExpression`. - * This can be the case with compound ALIAS columns. - * - * Example: - * CREATE TABLE test_table (id UInt64, value Tuple(id UInt64, value String), alias_value ALIAS value.id) ENGINE=TinyLog; - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableColumns(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - if (scope.column_name_to_column_node.empty() || !identifier_lookup.isExpressionLookup()) - return {}; - - const auto & identifier = identifier_lookup.identifier; - auto it = scope.column_name_to_column_node.find(identifier.getFullName()); - bool full_column_name_match = it != scope.column_name_to_column_node.end(); - - if (!full_column_name_match) - { - it = scope.column_name_to_column_node.find(identifier_lookup.identifier[0]); - if (it == scope.column_name_to_column_node.end()) - return {}; - } - - if (it->second->hasExpression()) - resolveExpressionNode(it->second->getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - QueryTreeNodePtr result = it->second; - - if (!full_column_name_match && identifier.isCompound()) - return tryResolveIdentifierFromCompoundExpression(identifier_lookup.identifier, 1 /*identifier_bind_size*/, it->second, {}, scope); - - return result; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - if (parts_size == 1 && path_start == table_name) - return true; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return true; - else - return false; - } - - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier)) || table_expression_data.canBindIdentifier(IdentifierView(identifier))) - return true; - - if (identifier.getPartsSize() == 1) - return false; - - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return true; - - if (identifier.getPartsSize() == 2) - return false; - - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return true; - - return false; -} - -bool QueryAnalyzer::tryBindIdentifierToTableExpressions(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node_to_ignore, - const IdentifierResolveScope & scope) -{ - bool can_bind_identifier_to_table_expression = false; - - for (const auto & [table_expression_node, _] : scope.table_expression_node_to_data) - { - if (table_expression_node.get() == table_expression_node_to_ignore.get()) - continue; - - can_bind_identifier_to_table_expression = tryBindIdentifierToTableExpression(identifier_lookup, table_expression_node, scope); - if (can_bind_identifier_to_table_expression) - break; - } - - return can_bind_identifier_to_table_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromStorage( - const Identifier & identifier, - const QueryTreeNodePtr & table_expression_node, - const TableExpressionData & table_expression_data, - IdentifierResolveScope & scope, - size_t identifier_column_qualifier_parts, - bool can_be_not_found) -{ - auto identifier_without_column_qualifier = identifier; - identifier_without_column_qualifier.popFirst(identifier_column_qualifier_parts); - - /** Compound identifier cannot be resolved directly from storage if storage is not table. - * - * Example: SELECT test_table.id.value1.value2 FROM test_table; - * In table storage column test_table.id.value1.value2 will exists. - * - * Example: SELECT test_subquery.compound_expression.value FROM (SELECT compound_expression AS value) AS test_subquery; - * Here there is no column with name test_subquery.compound_expression.value, and additional wrap in tuple element is required. - */ - - QueryTreeNodePtr result_expression; - bool match_full_identifier = false; - - const auto & identifier_full_name = identifier_without_column_qualifier.getFullName(); - auto it = table_expression_data.column_name_to_column_node.find(identifier_full_name); - bool can_resolve_directly_from_storage = it != table_expression_data.column_name_to_column_node.end(); - if (can_resolve_directly_from_storage && table_expression_data.subcolumn_names.contains(identifier_full_name)) - { - /** In the case when we have an ARRAY JOIN, we should not resolve subcolumns directly from storage. - * For example, consider the following SQL query: - * SELECT ProfileEvents.Values FROM system.query_log ARRAY JOIN ProfileEvents - * In this case, ProfileEvents.Values should also be array joined, not directly resolved from storage. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - if (nearest_query_scope_query_node && nearest_query_scope_query_node->getJoinTree()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - can_resolve_directly_from_storage = false; - } - - if (can_resolve_directly_from_storage) - { - match_full_identifier = true; - result_expression = it->second; - } - else - { - it = table_expression_data.column_name_to_column_node.find(identifier_without_column_qualifier.at(0)); - if (it != table_expression_data.column_name_to_column_node.end()) - result_expression = it->second; - } - - bool clone_is_needed = true; - - String table_expression_source = table_expression_data.table_expression_description; - if (!table_expression_data.table_expression_name.empty()) - table_expression_source += " with name " + table_expression_data.table_expression_name; - - if (result_expression && !match_full_identifier && identifier_without_column_qualifier.isCompound()) - { - size_t identifier_bind_size = identifier_column_qualifier_parts + 1; - result_expression = tryResolveIdentifierFromCompoundExpression(identifier, - identifier_bind_size, - result_expression, - table_expression_source, - scope, - can_be_not_found); - if (can_be_not_found && !result_expression) - return {}; - clone_is_needed = false; - } - - if (!result_expression) - { - QueryTreeNodes nested_column_nodes; - DataTypes nested_types; - Array nested_names_array; - - for (const auto & [column_name, _] : table_expression_data.column_names_and_types) - { - Identifier column_name_identifier_without_last_part(column_name); - auto column_name_identifier_last_part = column_name_identifier_without_last_part.getParts().back(); - column_name_identifier_without_last_part.popLast(); - - if (identifier_without_column_qualifier.getFullName() != column_name_identifier_without_last_part.getFullName()) - continue; - - auto column_node_it = table_expression_data.column_name_to_column_node.find(column_name); - if (column_node_it == table_expression_data.column_name_to_column_node.end()) - continue; - - const auto & column_node = column_node_it->second; - const auto & column_type = column_node->getColumnType(); - const auto * column_type_array = typeid_cast(column_type.get()); - if (!column_type_array) - continue; - - nested_column_nodes.push_back(column_node); - nested_types.push_back(column_type_array->getNestedType()); - nested_names_array.push_back(Field(std::move(column_name_identifier_last_part))); - } - - if (!nested_types.empty()) - { - auto nested_function_node = std::make_shared("nested"); - auto & nested_function_node_arguments = nested_function_node->getArguments().getNodes(); - - auto nested_function_names_array_type = std::make_shared(std::make_shared()); - auto nested_function_names_constant_node = std::make_shared(std::move(nested_names_array), - std::move(nested_function_names_array_type)); - nested_function_node_arguments.push_back(std::move(nested_function_names_constant_node)); - nested_function_node_arguments.insert(nested_function_node_arguments.end(), - nested_column_nodes.begin(), - nested_column_nodes.end()); - - auto nested_function = FunctionFactory::instance().get(nested_function_node->getFunctionName(), scope.context); - nested_function_node->resolveAsFunction(nested_function->build(nested_function_node->getArgumentColumns())); - - clone_is_needed = false; - result_expression = std::move(nested_function_node); - } - } - - if (!result_expression) - { - if (can_be_not_found) - return {}; - std::unordered_set valid_identifiers; - collectTableExpressionValidIdentifiersForTypoCorrection(identifier, - table_expression_node, - table_expression_data, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Identifier '{}' cannot be resolved from {}. In scope {}{}", - identifier.getFullName(), - table_expression_source, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (clone_is_needed) - result_expression = result_expression->clone(); - - auto qualified_identifier = identifier; - - for (size_t i = 0; i < identifier_column_qualifier_parts; ++i) - { - auto qualified_identifier_with_removed_part = qualified_identifier; - qualified_identifier_with_removed_part.popFirst(); - - if (qualified_identifier_with_removed_part.empty()) - break; - - IdentifierLookup column_identifier_lookup = {qualified_identifier_with_removed_part, IdentifierLookupContext::EXPRESSION}; - if (tryBindIdentifierToAliases(column_identifier_lookup, scope)) - break; - - if (table_expression_data.should_qualify_columns && - tryBindIdentifierToTableExpressions(column_identifier_lookup, table_expression_node, scope)) - break; - - qualified_identifier = std::move(qualified_identifier_with_removed_part); - } - - auto qualified_identifier_full_name = qualified_identifier.getFullName(); - node_to_projection_name.emplace(result_expression, std::move(qualified_identifier_full_name)); - - return result_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromTableExpression(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - auto table_expression_node_type = table_expression_node->getNodeType(); - - if (table_expression_node_type != QueryTreeNodeType::TABLE && - table_expression_node_type != QueryTreeNodeType::TABLE_FUNCTION && - table_expression_node_type != QueryTreeNodeType::QUERY && - table_expression_node_type != QueryTreeNodeType::UNION) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & identifier = identifier_lookup.identifier; - const auto & path_start = identifier.getParts().front(); - - auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - if (identifier_lookup.isTableExpressionLookup()) - { - size_t parts_size = identifier_lookup.identifier.getPartsSize(); - if (parts_size != 1 && parts_size != 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected identifier '{}' to contain 1 or 2 parts to be resolved as table expression. In scope {}", - identifier_lookup.identifier.getFullName(), - table_expression_node->formatASTForErrorMessage()); - - const auto & table_name = table_expression_data.table_name; - const auto & database_name = table_expression_data.database_name; - - if (parts_size == 1 && path_start == table_name) - return table_expression_node; - else if (parts_size == 2 && path_start == database_name && identifier[1] == table_name) - return table_expression_node; - else - return {}; - } - - /** If identifier first part binds to some column start or table has full identifier name. Then we can try to find whole identifier in table. - * 1. Try to bind identifier first part to column in table, if true get full identifier from table or throw exception. - * 2. Try to bind identifier first part to table name or storage alias, if true remove first part and try to get full identifier from table or throw exception. - * Storage alias works for subquery, table function as well. - * 3. Try to bind identifier first parts to database name and table name, if true remove first two parts and try to get full identifier from table or throw exception. - */ - if (table_expression_data.hasFullIdentifierName(IdentifierView(identifier))) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/); - - if (table_expression_data.canBindIdentifier(IdentifierView(identifier))) - { - /** This check is insufficient to determine whether and identifier can be resolved from table expression. - * A further check will be performed in `tryResolveIdentifierFromStorage` to see if we have such a subcolumn. - * In cases where the subcolumn cannot be found we want to have `nullptr` instead of exception. - * So, we set `can_be_not_found = true` to have an attempt to resolve the identifier from another table expression. - * Example: `SELECT t.t from (SELECT 1 as t) AS a FULL JOIN (SELECT 1 as t) as t ON a.t = t.t;` - * Initially, we will try to resolve t.t from `a` because `t.` is bound to `1 as t`. However, as it is not a nested column, we will need to resolve it from the second table expression. - */ - auto resolved_identifier = tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 0 /*identifier_column_qualifier_parts*/, true /*can_be_not_found*/); - if (resolved_identifier) - return resolved_identifier; - } - - if (identifier.getPartsSize() == 1) - return {}; - - const auto & table_name = table_expression_data.table_name; - if ((!table_name.empty() && path_start == table_name) || (table_expression_node->hasAlias() && path_start == table_expression_node->getAlias())) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 1 /*identifier_column_qualifier_parts*/); - - if (identifier.getPartsSize() == 2) - return {}; - - const auto & database_name = table_expression_data.database_name; - if (!database_name.empty() && path_start == database_name && identifier[1] == table_name) - return tryResolveIdentifierFromStorage(identifier, table_expression_node, table_expression_data, scope, 2 /*identifier_column_qualifier_parts*/); - - return {}; -} - -QueryTreeNodePtr checkIsMissedObjectJSONSubcolumn(const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier) -{ - if (left_resolved_identifier && right_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT - && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL" && right_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (left_resolved_identifier && left_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & left_resolved_column = left_resolved_identifier->as(); - if (left_resolved_column.getValueStringRepresentation() == "NULL") - return left_resolved_identifier; - } - else if (right_resolved_identifier && right_resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - { - auto & right_resolved_column = right_resolved_identifier->as(); - if (right_resolved_column.getValueStringRepresentation() == "NULL") - return right_resolved_identifier; - } - return {}; -} - -/// Used to replace columns that changed type because of JOIN to their original type -class ReplaceColumnsVisitor : public InDepthQueryTreeVisitor -{ -public: - explicit ReplaceColumnsVisitor(const QueryTreeNodePtrWithHashMap & replacement_map_, const ContextPtr & context_) - : replacement_map(replacement_map_) - , context(context_) - {} - - /// Apply replacement transitively, because column may change it's type twice, one to have a supertype and then because of `joun_use_nulls` - static QueryTreeNodePtr findTransitiveReplacement(QueryTreeNodePtr node, const QueryTreeNodePtrWithHashMap & replacement_map_) - { - auto it = replacement_map_.find(node); - QueryTreeNodePtr result_node = nullptr; - for (; it != replacement_map_.end(); it = replacement_map_.find(result_node)) - { - if (result_node && result_node->isEqual(*it->second)) - { - Strings map_dump; - for (const auto & [k, v]: replacement_map_) - map_dump.push_back(fmt::format("{} -> {} (is_equals: {}, is_same: {})", - k.node->dumpTree(), v->dumpTree(), k.node->isEqual(*v), k.node == v)); - throw Exception(ErrorCodes::LOGICAL_ERROR, "Infinite loop in query tree replacement map: {}", fmt::join(map_dump, "; ")); - } - chassert(it->second); - - result_node = it->second; - } - return result_node; - } - - void visitImpl(QueryTreeNodePtr & node) - { - if (auto replacement_node = findTransitiveReplacement(node, replacement_map)) - node = replacement_node; - - if (auto * function_node = node->as(); function_node && function_node->isResolved()) - rerunFunctionResolve(function_node, context); - } - - /// We want to re-run resolve for function _after_ its arguments are replaced - bool shouldTraverseTopToBottom() const { return false; } - - bool needChildVisit(QueryTreeNodePtr & /* parent */, QueryTreeNodePtr & child) - { - /// Visit only expressions, but not subqueries - return child->getNodeType() == QueryTreeNodeType::IDENTIFIER - || child->getNodeType() == QueryTreeNodeType::LIST - || child->getNodeType() == QueryTreeNodeType::FUNCTION - || child->getNodeType() == QueryTreeNodeType::COLUMN; - } - -private: - const QueryTreeNodePtrWithHashMap & replacement_map; - const ContextPtr & context; -}; - -/// Compare resolved identifiers considering columns that become nullable after JOIN -bool resolvedIdenfiersFromJoinAreEquals( - const QueryTreeNodePtr & left_resolved_identifier, - const QueryTreeNodePtr & right_resolved_identifier, - const IdentifierResolveScope & scope) -{ - auto left_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(left_resolved_identifier, scope.join_columns_with_changed_types); - const auto & left_resolved_to_compare = left_original_node ? left_original_node : left_resolved_identifier; - - auto right_original_node = ReplaceColumnsVisitor::findTransitiveReplacement(right_resolved_identifier, scope.join_columns_with_changed_types); - const auto & right_resolved_to_compare = right_original_node ? right_original_node : right_resolved_identifier; - - return left_resolved_to_compare->isEqual(*right_resolved_to_compare, IQueryTreeNode::CompareOptions{.compare_aliases = false}); -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_join_node = table_expression_node->as(); - auto left_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getLeftTableExpression(), scope); - auto right_resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_join_node.getRightTableExpression(), scope); - - if (!identifier_lookup.isExpressionLookup()) - { - if (left_resolved_identifier && right_resolved_identifier) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.dump(), - scope.scope_node->formatASTForErrorMessage()); - - return left_resolved_identifier ? left_resolved_identifier : right_resolved_identifier; - } - - bool join_node_in_resolve_process = scope.table_expressions_in_resolve_process.contains(table_expression_node.get()); - - std::unordered_map join_using_column_name_to_column_node; - - if (!join_node_in_resolve_process && from_join_node.isUsingJoinExpression()) - { - auto & join_using_list = from_join_node.getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & column_node = join_using_node->as(); - join_using_column_name_to_column_node.emplace(column_node.getColumnName(), std::static_pointer_cast(join_using_node)); - } - } - - auto check_nested_column_not_in_using = [&join_using_column_name_to_column_node, &identifier_lookup](const QueryTreeNodePtr & node) - { - /** tldr: When an identifier is resolved into the function `nested` or `getSubcolumn`, and - * some column in its argument is in the USING list and its type has to be updated, we throw an error to avoid overcomplication. - * - * Identifiers can be resolved into functions in case of nested or subcolumns. - * For example `t.t.t` can be resolved into `getSubcolumn(t, 't.t')` function in case of `t` is `Tuple`. - * So, `t` in USING list is resolved from JOIN itself and has supertype of columns from left and right table. - * But `t` in `getSubcolumn` argument is still resolved from table and we need to update its type. - * - * Example: - * - * SELECT t.t FROM ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t UInt32, s1 String), s1 String) as t - * ) AS a FULL JOIN ( - * SELECT ((1, 's'), 's') :: Tuple(t Tuple(t Int32, s2 String), s2 String) as t - * ) AS b USING t; - * - * Result type of `t` is `Tuple(Tuple(Int64, String), String)` (different type and no names for subcolumns), - * so it may be tricky to have a correct type for `t.t` that is resolved into getSubcolumn(t, 't'). - * - * It can be more complicated in case of Nested subcolumns, in that case in query: - * SELECT t FROM ... JOIN ... USING (t.t) - * Here, `t` is resolved into function `nested(['t', 's'], t.t, t.s) so, `t.t` should be from JOIN and `t.s` should be from table. - * - * Updating type accordingly is pretty complicated, so just forbid such cases. - * - * While it still may work for storages that support selecting subcolumns directly without `getSubcolumn` function: - * SELECT t, t.t, toTypeName(t), toTypeName(t.t) FROM t1 AS a FULL JOIN t2 AS b USING t.t; - * We just support it as a best-effort: `t` will have original type from table, but `t.t` will have super-type from JOIN. - * Probably it's good to prohibit such cases as well, but it's not clear how to check it in general case. - */ - if (node->getNodeType() != QueryTreeNodeType::FUNCTION) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {}, expected function node", node->getNodeType()); - - const auto & function_argument_nodes = node->as().getArguments().getNodes(); - for (const auto & argument_node : function_argument_nodes) - { - if (argument_node->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_name = argument_node->as().getColumnName(); - if (join_using_column_name_to_column_node.contains(column_name)) - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "Cannot select subcolumn for identifier '{}' while joining using column '{}'", - identifier_lookup.identifier, column_name); - } - else if (argument_node->getNodeType() == QueryTreeNodeType::CONSTANT) - { - continue; - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected node type {} for argument node in {}", - argument_node->getNodeType(), node->formatASTForErrorMessage()); - } - } - }; - - std::optional resolved_side; - QueryTreeNodePtr resolved_identifier; - - JoinKind join_kind = from_join_node.getKind(); - - /// If columns from left or right table were missed Object(Nullable('json')) subcolumns, they will be replaced - /// to ConstantNode(NULL), which can't be cast to ColumnNode, so we resolve it here. - if (auto missed_subcolumn_identifier = checkIsMissedObjectJSONSubcolumn(left_resolved_identifier, right_resolved_identifier)) - return missed_subcolumn_identifier; - - if (left_resolved_identifier && right_resolved_identifier) - { - auto using_column_node_it = join_using_column_name_to_column_node.end(); - if (left_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN && right_resolved_identifier->getNodeType() == QueryTreeNodeType::COLUMN) - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto & right_resolved_column = right_resolved_identifier->as(); - if (left_resolved_column.getColumnName() == right_resolved_column.getColumnName()) - using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - } - else - { - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(left_resolved_identifier); - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - check_nested_column_not_in_using(right_resolved_identifier); - } - - if (using_column_node_it != join_using_column_name_to_column_node.end()) - { - JoinTableSide using_column_inner_column_table_side = isRight(join_kind) ? JoinTableSide::Right : JoinTableSide::Left; - auto & using_column_node = using_column_node_it->second->as(); - auto & using_expression_list = using_column_node.getExpression()->as(); - - size_t inner_column_node_index = using_column_inner_column_table_side == JoinTableSide::Left ? 0 : 1; - const auto & inner_column_node = using_expression_list.getNodes().at(inner_column_node_index); - - auto result_column_node = inner_column_node->clone(); - auto & result_column = result_column_node->as(); - result_column.setColumnType(using_column_node.getColumnType()); - - const auto & join_using_left_column = using_expression_list.getNodes().at(0); - if (!result_column_node->isEqual(*join_using_left_column)) - scope.join_columns_with_changed_types[result_column_node] = join_using_left_column; - - resolved_identifier = std::move(result_column_node); - } - else if (resolvedIdenfiersFromJoinAreEquals(left_resolved_identifier, right_resolved_identifier, scope)) - { - const auto & identifier_path_part = identifier_lookup.identifier.front(); - auto * left_resolved_identifier_column = left_resolved_identifier->as(); - auto * right_resolved_identifier_column = right_resolved_identifier->as(); - - if (left_resolved_identifier_column && right_resolved_identifier_column) - { - const auto & left_column_source_alias = left_resolved_identifier_column->getColumnSource()->getAlias(); - const auto & right_column_source_alias = right_resolved_identifier_column->getColumnSource()->getAlias(); - - /** If column from right table was resolved using alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one JOIN system.one AS A ON A.dummy = system.one.dummy; - * - * If alias is specified for left table, and alias is not specified for right table and identifier was resolved - * without using left table alias, we prefer column from right table. - * - * Example: SELECT dummy FROM system.one AS A JOIN system.one ON A.dummy = system.one.dummy; - * - * Otherwise we prefer column from left table. - */ - bool column_resolved_using_right_alias = identifier_path_part == right_column_source_alias; - bool column_resolved_without_using_left_alias = !left_column_source_alias.empty() - && right_column_source_alias.empty() - && identifier_path_part != left_column_source_alias; - if (column_resolved_using_right_alias || column_resolved_without_using_left_alias) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - } - else if (scope.joins_count == 1 && scope.context->getSettingsRef().single_join_prefer_left_table) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - } - else - { - throw Exception(ErrorCodes::AMBIGUOUS_IDENTIFIER, - "JOIN {} ambiguous identifier '{}'. In scope {}", - table_expression_node->formatASTForErrorMessage(), - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - else if (left_resolved_identifier) - { - resolved_side = JoinTableSide::Left; - resolved_identifier = left_resolved_identifier; - - if (left_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(left_resolved_identifier); - } - else - { - auto & left_resolved_column = left_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(left_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*left_resolved_column.getColumnType())) - { - auto left_resolved_column_clone = std::static_pointer_cast(left_resolved_column.clone()); - left_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(left_resolved_column_clone); - - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - else if (right_resolved_identifier) - { - resolved_side = JoinTableSide::Right; - resolved_identifier = right_resolved_identifier; - - if (right_resolved_identifier->getNodeType() != QueryTreeNodeType::COLUMN) - { - check_nested_column_not_in_using(right_resolved_identifier); - } - else - { - auto & right_resolved_column = right_resolved_identifier->as(); - auto using_column_node_it = join_using_column_name_to_column_node.find(right_resolved_column.getColumnName()); - if (using_column_node_it != join_using_column_name_to_column_node.end() && - !using_column_node_it->second->getColumnType()->equals(*right_resolved_column.getColumnType())) - { - auto right_resolved_column_clone = std::static_pointer_cast(right_resolved_column.clone()); - right_resolved_column_clone->setColumnType(using_column_node_it->second->getColumnType()); - resolved_identifier = std::move(right_resolved_column_clone); - if (!resolved_identifier->isEqual(*using_column_node_it->second)) - scope.join_columns_with_changed_types[resolved_identifier] = using_column_node_it->second; - } - } - } - - if (join_node_in_resolve_process || !resolved_identifier) - return resolved_identifier; - - if (scope.join_use_nulls) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier); - auto nullable_resolved_identifier = convertJoinedColumnTypeToNullIfNeeded(resolved_identifier, join_kind, resolved_side, scope); - if (nullable_resolved_identifier) - { - resolved_identifier = nullable_resolved_identifier; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(resolved_identifier, projection_name_it->second); - } - } - } - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::matchArrayJoinSubcolumns( - const QueryTreeNodePtr & array_join_column_inner_expression, - const ColumnNode & array_join_column_expression_typed, - const QueryTreeNodePtr & resolved_expression, - IdentifierResolveScope & scope) -{ - const auto * resolved_function = resolved_expression->as(); - if (!resolved_function || resolved_function->getFunctionName() != "getSubcolumn") - return {}; - - const auto * array_join_parent_column = array_join_column_inner_expression.get(); - - /** If both resolved and array-joined expressions are subcolumns, try to match them: - * For example, in `SELECT t.map.values FROM (SELECT * FROM tbl) ARRAY JOIN t.map` - * Identifier `t.map.values` is resolved into `getSubcolumn(t, 'map.values')` and t.map is resolved into `getSubcolumn(t, 'map')` - * Since we need to perform array join on `getSubcolumn(t, 'map')`, `t.map.values` should become `getSubcolumn(getSubcolumn(t, 'map'), 'values')` - * - * Note: It doesn't work when subcolumn in ARRAY JOIN is transformed by another expression, for example - * SELECT c.map, c.map.values FROM (SELECT * FROM tbl) ARRAY JOIN mapApply(x -> x, t.map); - */ - String array_join_subcolumn_prefix; - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "getSubcolumn") - { - const auto & argument_nodes = array_join_column_inner_expression_function->getArguments().getNodes(); - if (argument_nodes.size() == 2 && argument_nodes.at(1)->getNodeType() == QueryTreeNodeType::CONSTANT) - { - const auto & constant_node = argument_nodes.at(1)->as(); - const auto & constant_node_value = constant_node.getValue(); - if (constant_node_value.getType() == Field::Types::String) - { - array_join_subcolumn_prefix = constant_node_value.get() + "."; - array_join_parent_column = argument_nodes.at(0).get(); - } - } - } - - const auto & argument_nodes = resolved_function->getArguments().getNodes(); - if (argument_nodes.size() != 2 && !array_join_parent_column->isEqual(*argument_nodes.at(0))) - return {}; - - const auto * second_argument = argument_nodes.at(1)->as(); - if (!second_argument || second_argument->getValue().getType() != Field::Types::String) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected constant string as second argument of getSubcolumn function {}", resolved_function->dumpTree()); - - const auto & resolved_subcolumn_path = second_argument->getValue().get(); - if (!startsWith(resolved_subcolumn_path, array_join_subcolumn_prefix)) - return {}; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(array_join_column_expression_typed.getColumn(), array_join_column_expression_typed.getColumnSource())); - get_subcolumn_function->getArguments().getNodes().push_back( - std::make_shared(resolved_subcolumn_path.substr(array_join_subcolumn_prefix.size()))); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - return function_query_node; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveExpressionFromArrayJoinExpressions(const QueryTreeNodePtr & resolved_expression, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & array_join_node = table_expression_node->as(); - const auto & array_join_column_expressions_list = array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions_list.getNodes(); - - QueryTreeNodePtr array_join_resolved_expression; - - /** Special case when qualified or unqualified identifier point to array join expression without alias. - * - * CREATE TABLE test_table (id UInt64, value String, value_array Array(UInt8)) ENGINE=TinyLog; - * SELECT id, value, value_array, test_table.value_array, default.test_table.value_array FROM test_table ARRAY JOIN value_array; - * - * value_array, test_table.value_array, default.test_table.value_array must be resolved into array join expression. - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - if (array_join_column_expression_typed.hasAlias()) - continue; - - auto & array_join_column_inner_expression = array_join_column_expression_typed.getExpressionOrThrow(); - auto * array_join_column_inner_expression_function = array_join_column_inner_expression->as(); - - if (array_join_column_inner_expression_function && - array_join_column_inner_expression_function->getFunctionName() == "nested" && - array_join_column_inner_expression_function->getArguments().getNodes().size() > 1 && - isTuple(array_join_column_expression_typed.getResultType())) - { - const auto & nested_function_arguments = array_join_column_inner_expression_function->getArguments().getNodes(); - size_t nested_function_arguments_size = nested_function_arguments.size(); - - const auto & nested_keys_names_constant_node = nested_function_arguments[0]->as(); - const auto & nested_keys_names = nested_keys_names_constant_node.getValue().get(); - size_t nested_keys_names_size = nested_keys_names.size(); - - if (nested_keys_names_size == nested_function_arguments_size - 1) - { - for (size_t i = 1; i < nested_function_arguments_size; ++i) - { - if (!nested_function_arguments[i]->isEqual(*resolved_expression)) - continue; - - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - - const auto & nested_key_name = nested_keys_names[i - 1].get(); - Identifier nested_identifier = Identifier(nested_key_name); - auto tuple_element_function = wrapExpressionNodeInTupleElement(array_join_column, nested_identifier); - resolveFunction(tuple_element_function, scope); - - array_join_resolved_expression = std::move(tuple_element_function); - break; - } - } - } - - if (array_join_resolved_expression) - break; - - if (array_join_column_inner_expression->isEqual(*resolved_expression)) - { - array_join_resolved_expression = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - break; - } - - /// When we select subcolumn of array joined column it also should be array joined - array_join_resolved_expression = matchArrayJoinSubcolumns(array_join_column_inner_expression, array_join_column_expression_typed, resolved_expression, scope); - if (array_join_resolved_expression) - break; - } - return array_join_resolved_expression; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromArrayJoin(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & table_expression_node, - IdentifierResolveScope & scope) -{ - const auto & from_array_join_node = table_expression_node->as(); - auto resolved_identifier = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, from_array_join_node.getTableExpression(), scope); - - if (scope.table_expressions_in_resolve_process.contains(table_expression_node.get()) || !identifier_lookup.isExpressionLookup()) - return resolved_identifier; - - const auto & array_join_column_expressions = from_array_join_node.getJoinExpressions(); - const auto & array_join_column_expressions_nodes = array_join_column_expressions.getNodes(); - - /** Allow JOIN with USING with ARRAY JOIN. - * - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN [1,2,3] AS id INNER JOIN test_table_2 AS t2 USING (id); - * SELECT * FROM test_table_1 AS t1 ARRAY JOIN t1.id AS id INNER JOIN test_table_2 AS t2 USING (id); - */ - for (const auto & array_join_column_expression : array_join_column_expressions_nodes) - { - auto & array_join_column_expression_typed = array_join_column_expression->as(); - - IdentifierView identifier_view(identifier_lookup.identifier); - - if (identifier_view.isCompound() && from_array_join_node.hasAlias() && identifier_view.front() == from_array_join_node.getAlias()) - identifier_view.popFirst(); - - const auto & alias_or_name = array_join_column_expression_typed.hasAlias() - ? array_join_column_expression_typed.getAlias() - : array_join_column_expression_typed.getColumnName(); - - if (identifier_view.front() == alias_or_name) - identifier_view.popFirst(); - else if (identifier_view.getFullName() == alias_or_name) - identifier_view.popFirst(identifier_view.getPartsSize()); /// Clear - else - continue; - - if (identifier_view.empty()) - { - auto array_join_column = std::make_shared(array_join_column_expression_typed.getColumn(), - array_join_column_expression_typed.getColumnSource()); - return array_join_column; - } - - auto compound_expr = tryResolveIdentifierFromCompoundExpression( - identifier_lookup.identifier, - identifier_lookup.identifier.getPartsSize() - identifier_view.getPartsSize() /*identifier_bind_size*/, - array_join_column_expression, - {} /* compound_expression_source */, - scope, - true /* can_be_not_found */); - - if (compound_expr) - return compound_expr; - } - - if (!resolved_identifier) - return nullptr; - - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(resolved_identifier, table_expression_node, scope); - if (array_join_resolved_expression) - resolved_identifier = std::move(array_join_resolved_expression); - - return resolved_identifier; -} - -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTreeNode(const IdentifierLookup & identifier_lookup, - const QueryTreeNodePtr & join_tree_node, - IdentifierResolveScope & scope) -{ - auto join_tree_node_type = join_tree_node->getNodeType(); - - switch (join_tree_node_type) - { - case QueryTreeNodeType::JOIN: - return tryResolveIdentifierFromJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::ARRAY_JOIN: - return tryResolveIdentifierFromArrayJoin(identifier_lookup, join_tree_node, scope); - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - [[fallthrough]]; - case QueryTreeNodeType::TABLE: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - { - /** Edge case scenario when subquery in FROM node try to resolve identifier from parent scopes, when FROM is not resolved. - * SELECT subquery.b AS value FROM (SELECT value, 1 AS b) AS subquery; - * TODO: This can be supported - */ - if (scope.table_expressions_in_resolve_process.contains(join_tree_node.get())) - return {}; - - return tryResolveIdentifierFromTableExpression(identifier_lookup, join_tree_node, scope); - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Scope FROM section expected table, table function, query, union, join or array join. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } -} - -/** Resolve identifier from scope join tree. - * - * 1. If identifier is in function lookup context return nullptr. - * 2. Try to resolve identifier from table columns. - * 3. If there is no FROM section return nullptr. - * 4. If identifier is in table lookup context, check if it has 1 or 2 parts, otherwise throw exception. - * If identifier has 2 parts try to match it with database_name and table_name. - * If identifier has 1 part try to match it with table_name, then try to match it with table alias. - * 5. If identifier is in expression lookup context, we first need to bind identifier to some table column using identifier first part. - * Start with identifier first part, if it match some column name in table try to get column with full identifier name. - * TODO: Need to check if it is okay to throw exception if compound identifier first part bind to column but column is not valid. - */ -QueryTreeNodePtr QueryAnalyzer::tryResolveIdentifierFromJoinTree(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope) -{ - if (identifier_lookup.isFunctionLookup()) - return {}; - - /// Try to resolve identifier from table columns - if (auto resolved_identifier = tryResolveIdentifierFromTableColumns(identifier_lookup, scope)) - return resolved_identifier; - - if (scope.expression_join_tree_node) - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, scope.expression_join_tree_node, scope); - - auto * query_scope_node = scope.scope_node->as(); - if (!query_scope_node || !query_scope_node->getJoinTree()) - return {}; - - const auto & join_tree_node = query_scope_node->getJoinTree(); - return tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_tree_node, scope); -} - -/** Try resolve identifier in current scope parent scopes. - * - * TODO: If column is matched, throw exception that nested subqueries are not supported. - * - * If initial scope is expression. Then try to resolve identifier in parent scopes until query scope is hit. - * For query scope resolve strategy is same as if initial scope if query. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifierInParentScopes(const IdentifierLookup & identifier_lookup, IdentifierResolveScope & scope) -{ - bool initial_scope_is_query = scope.scope_node->getNodeType() == QueryTreeNodeType::QUERY; - bool initial_scope_is_expression = !initial_scope_is_query; - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_parent_scopes = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - IdentifierResolveScope * scope_to_check = scope.parent_scope; - - if (initial_scope_is_expression) - { - while (scope_to_check != nullptr) - { - auto resolve_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - if (resolve_result.resolved_identifier) - return resolve_result; - - bool scope_was_query = scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY; - scope_to_check = scope_to_check->parent_scope; - - if (scope_was_query) - break; - } - } - - if (!scope.context->getSettingsRef().enable_global_with_statement) - return {}; - - /** Nested subqueries cannot access outer subqueries table expressions from JOIN tree because - * that can prevent resolution of table expression from CTE. - * - * Example: WITH a AS (SELECT number FROM numbers(1)), b AS (SELECT number FROM a) SELECT * FROM a as l, b as r; - */ - if (identifier_lookup.isTableExpressionLookup()) - identifier_resolve_settings.allow_to_check_join_tree = false; - - while (scope_to_check != nullptr) - { - auto lookup_result = tryResolveIdentifier(identifier_lookup, *scope_to_check, identifier_resolve_settings); - const auto & resolved_identifier = lookup_result.resolved_identifier; - - scope_to_check = scope_to_check->parent_scope; - - if (resolved_identifier) - { - auto * subquery_node = resolved_identifier->as(); - auto * union_node = resolved_identifier->as(); - - bool is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - bool is_table_from_expression_arguments = lookup_result.resolve_place == IdentifierResolvePlace::EXPRESSION_ARGUMENTS && - resolved_identifier->getNodeType() == QueryTreeNodeType::TABLE; - bool is_valid_table_expression = is_cte || is_table_from_expression_arguments; - - /** From parent scopes we can resolve table identifiers only as CTE. - * Example: SELECT (SELECT 1 FROM a) FROM test_table AS a; - * - * During child scope table identifier resolve a, table node test_table with alias a from parent scope - * is invalid. - */ - if (identifier_lookup.isTableExpressionLookup() && !is_valid_table_expression) - continue; - - if (is_valid_table_expression || resolved_identifier->as()) - { - return lookup_result; - } - else if (auto * resolved_function = resolved_identifier->as()) - { - /// Special case: scalar subquery was executed and replaced by __getScalar function. - /// Handle it as a constant. - if (resolved_function->getFunctionName() == "__getScalar") - return lookup_result; - } - - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Resolve identifier '{}' from parent scope only supported for constants and CTE. Actual {} node type {}. In scope {}", - identifier_lookup.identifier.getFullName(), - resolved_identifier->formatASTForErrorMessage(), - resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - return {}; -} - -/** Resolve identifier in scope. - * - * If identifier was resolved resolve identified lookup status will be updated. - * - * Steps: - * 1. Register identifier lookup in scope identifier lookup to resolve status table. - * If entry is already registered and is not resolved, that means that we have cyclic aliases for identifier. - * Example: SELECT a AS b, b AS a; - * Try resolve identifier in current scope: - * 3. Try resolve identifier from expression arguments. - * - * If prefer_column_name_to_alias = true. - * 4. Try to resolve identifier from join tree. - * 5. Try to resolve identifier from aliases. - * Otherwise. - * 4. Try to resolve identifier from aliases. - * 5. Try to resolve identifier from join tree. - * - * 6. If it is table identifier lookup try to lookup identifier in current scope CTEs. - * - * 7. If identifier is not resolved in current scope, try to resolve it in parent scopes. - * 8. If identifier is not resolved from parent scopes and it is table identifier lookup try to lookup identifier - * in database catalog. - * - * Same is not done for functions because function resolution is more complex, and in case of aggregate functions requires not only name - * but also argument types, it is responsibility of resolve function method to handle resolution of function name. - * - * 9. If identifier was not resolved, or identifier caching was disabled remove it from identifier lookup to resolve status table. - * - * It is okay for identifier to be not resolved, in case we want first try to lookup identifier in one context, - * then if there is no identifier in this context, try to lookup in another context. - * Example: Try to lookup identifier as expression, if it is not found, lookup as function. - * Example: Try to lookup identifier as expression, if it is not found, lookup as table. - */ -IdentifierResolveResult QueryAnalyzer::tryResolveIdentifier(const IdentifierLookup & identifier_lookup, - IdentifierResolveScope & scope, - IdentifierResolveSettings identifier_resolve_settings) -{ - auto it = scope.identifier_lookup_to_resolve_state.find(identifier_lookup); - if (it != scope.identifier_lookup_to_resolve_state.end()) - { - if (it->second.cyclic_identifier_resolve) - throw Exception(ErrorCodes::CYCLIC_ALIASES, - "Cyclic aliases for identifier '{}'. In scope {}", - identifier_lookup.identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (!it->second.resolve_result.isResolved()) - it->second.cyclic_identifier_resolve = true; - - if (it->second.resolve_result.isResolved() && - scope.use_identifier_lookup_to_result_cache && - !scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) && - (!it->second.resolve_result.isResolvedFromCTEs() || !ctes_in_resolve_process.contains(identifier_lookup.identifier.getFullName()))) - return it->second.resolve_result; - } - else - { - auto [insert_it, _] = scope.identifier_lookup_to_resolve_state.insert({identifier_lookup, IdentifierResolveState()}); - it = insert_it; - } - - /// Resolve identifier from current scope - - IdentifierResolveResult resolve_result; - resolve_result.resolved_identifier = tryResolveIdentifierFromExpressionArguments(identifier_lookup, scope); - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::EXPRESSION_ARGUMENTS; - - if (!resolve_result.resolved_identifier) - { - bool prefer_column_name_to_alias = scope.context->getSettingsRef().prefer_column_name_to_alias; - - if (identifier_lookup.isExpressionLookup()) - { - /* For aliases from ARRAY JOIN we prefer column from join tree: - * SELECT id FROM ( SELECT ... ) AS subquery ARRAY JOIN [0] AS id INNER JOIN second_table USING (id) - * In the example, identifier `id` should be resolved into one from USING (id) column. - */ - - auto * alias_it = scope.aliases.find(identifier_lookup, ScopeAliases::FindOption::FULL_NAME); - if (alias_it && (*alias_it)->getNodeType() == QueryTreeNodeType::COLUMN) - { - const auto & column_node = (*alias_it)->as(); - if (column_node.getColumnSource()->getNodeType() == QueryTreeNodeType::ARRAY_JOIN) - prefer_column_name_to_alias = true; - } - } - - if (unlikely(prefer_column_name_to_alias)) - { - if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - - if (!resolve_result.resolved_identifier) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - } - else - { - resolve_result.resolved_identifier = tryResolveIdentifierFromAliases(identifier_lookup, scope, identifier_resolve_settings); - - if (resolve_result.resolved_identifier) - { - resolve_result.resolve_place = IdentifierResolvePlace::ALIASES; - } - else if (identifier_resolve_settings.allow_to_check_join_tree) - { - resolve_result.resolved_identifier = tryResolveIdentifierFromJoinTree(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::JOIN_TREE; - } - } - } - - if (!resolve_result.resolved_identifier && identifier_lookup.isTableExpressionLookup()) - { - auto full_name = identifier_lookup.identifier.getFullName(); - auto cte_query_node_it = scope.cte_name_to_query_node.find(full_name); - - /// CTE may reference table expressions with the same name, e.g.: - /// - /// WITH test1 AS (SELECT * FROM test1) SELECT * FROM test1; - /// - /// Since we don't support recursive CTEs, `test1` identifier inside of CTE - /// references to table .test1. - /// This means that the example above is equivalent to the following query: - /// - /// SELECT * FROM test1; - /// - /// To accomplish this behaviour it's not allowed to resolve identifiers to - /// CTE that is being resolved. - if (cte_query_node_it != scope.cte_name_to_query_node.end() - && !ctes_in_resolve_process.contains(full_name)) - { - resolve_result.resolved_identifier = cte_query_node_it->second; - resolve_result.resolve_place = IdentifierResolvePlace::CTE; - } - } - - /// Try to resolve identifier from parent scopes - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_parent_scopes) - { - resolve_result = tryResolveIdentifierInParentScopes(identifier_lookup, scope); - - if (resolve_result.resolved_identifier) - resolve_result.resolved_from_parent_scopes = true; - } - - /// Try to resolve table identifier from database catalog - - if (!resolve_result.resolved_identifier && identifier_resolve_settings.allow_to_check_database_catalog && identifier_lookup.isTableExpressionLookup()) - { - resolve_result.resolved_identifier = tryResolveTableIdentifierFromDatabaseCatalog(identifier_lookup.identifier, scope.context); - - if (resolve_result.resolved_identifier) - resolve_result.resolve_place = IdentifierResolvePlace::DATABASE_CATALOG; - } - - bool was_cyclic_identifier_resolve = it->second.cyclic_identifier_resolve; - if (!was_cyclic_identifier_resolve) - it->second.resolve_result = resolve_result; - it->second.cyclic_identifier_resolve = false; - - /** If identifier was not resolved, or during expression resolution identifier was explicitly added into non cached set, - * or identifier caching was disabled in resolve scope we remove identifier lookup result from identifier lookup to result table. - */ - if (!was_cyclic_identifier_resolve && (!resolve_result.resolved_identifier || - scope.non_cached_identifier_lookups_during_expression_resolve.contains(identifier_lookup) || - !scope.use_identifier_lookup_to_result_cache)) - scope.identifier_lookup_to_resolve_state.erase(it); - - return resolve_result; -} - -/// Resolve query tree nodes functions implementation - -/** Qualify column nodes with projection names. - * - * Example: SELECT * FROM test_table AS t1, test_table AS t2; - */ -void QueryAnalyzer::qualifyColumnNodesWithProjectionNames(const QueryTreeNodes & column_nodes, - const QueryTreeNodePtr & table_expression_node, - const IdentifierResolveScope & scope) -{ - /// Build additional column qualification parts array - std::vector additional_column_qualification_parts; - - if (table_expression_node->hasAlias()) - additional_column_qualification_parts = {table_expression_node->getAlias()}; - else if (auto * table_node = table_expression_node->as()) - additional_column_qualification_parts = {table_node->getStorageID().getDatabaseName(), table_node->getStorageID().getTableName()}; - - size_t additional_column_qualification_parts_size = additional_column_qualification_parts.size(); - const auto & table_expression_data = scope.getTableExpressionDataOrThrow(table_expression_node); - - /** For each matched column node iterate over additional column qualifications and apply them if column needs to be qualified. - * To check if column needs to be qualified we check if column name can bind to any other table expression in scope or to scope aliases. - */ - std::vector column_qualified_identifier_parts; - - for (const auto & column_node : column_nodes) - { - const auto & column_name = column_node->as().getColumnName(); - column_qualified_identifier_parts = Identifier(column_name).getParts(); - - /// Iterate over additional column qualifications and apply them if needed - for (size_t i = 0; i < additional_column_qualification_parts_size; ++i) - { - auto identifier_to_check = Identifier(column_qualified_identifier_parts); - IdentifierLookup identifier_lookup{identifier_to_check, IdentifierLookupContext::EXPRESSION}; - bool need_to_qualify = table_expression_data.should_qualify_columns; - if (need_to_qualify) - need_to_qualify = tryBindIdentifierToTableExpressions(identifier_lookup, table_expression_node, scope); - - if (tryBindIdentifierToAliases(identifier_lookup, scope)) - need_to_qualify = true; - - if (need_to_qualify) - { - /** Add last qualification part that was not used into column qualified identifier. - * If additional column qualification parts consists from [database_name, table_name]. - * On first iteration if column is needed to be qualified to qualify it with table_name. - * On second iteration if column is needed to be qualified to qualify it with database_name. - */ - size_t part_index_to_use_for_qualification = additional_column_qualification_parts_size - i - 1; - const auto & part_to_use = additional_column_qualification_parts[part_index_to_use_for_qualification]; - column_qualified_identifier_parts.insert(column_qualified_identifier_parts.begin(), part_to_use); - } - else - { - break; - } - } - - auto qualified_node_name = Identifier(column_qualified_identifier_parts).getFullName(); - node_to_projection_name.emplace(column_node, qualified_node_name); - } -} - -/// Build get columns options for matcher -GetColumnsOptions QueryAnalyzer::buildGetColumnsOptions(QueryTreeNodePtr & matcher_node, const ContextPtr & context) -{ - auto & matcher_node_typed = matcher_node->as(); - UInt8 get_columns_options_kind = GetColumnsOptions::AllPhysicalAndAliases; - - if (matcher_node_typed.isAsteriskMatcher()) - { - get_columns_options_kind = GetColumnsOptions::Ordinary; - - const auto & settings = context->getSettingsRef(); - - if (settings.asterisk_include_alias_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Aliases; - - if (settings.asterisk_include_materialized_columns) - get_columns_options_kind |= GetColumnsOptions::Kind::Materialized; - } - - return GetColumnsOptions(static_cast(get_columns_options_kind)); -} - -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::getMatchedColumnNodesWithNames(const QueryTreeNodePtr & matcher_node, - const QueryTreeNodePtr & table_expression_node, - const NamesAndTypes & matched_columns, - const IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - /** Use resolved columns from table expression data in nearest query scope if available. - * It is important for ALIAS columns to use column nodes with resolved ALIAS expression. - */ - const TableExpressionData * table_expression_data = nullptr; - const auto * nearest_query_scope = scope.getNearestQueryScope(); - if (nearest_query_scope) - table_expression_data = &nearest_query_scope->getTableExpressionDataOrThrow(table_expression_node); - - QueryTreeNodes matched_column_nodes; - - for (const auto & column : matched_columns) - { - const auto & column_name = column.name; - if (!matcher_node_typed.isMatchingColumn(column_name)) - continue; - - if (table_expression_data) - { - auto column_node_it = table_expression_data->column_name_to_column_node.find(column_name); - if (column_node_it != table_expression_data->column_name_to_column_node.end()) - { - matched_column_nodes.emplace_back(column_node_it->second); - continue; - } - } - - matched_column_nodes.emplace_back(std::make_shared(column, table_expression_node)); - } - - const auto & qualify_matched_column_nodes_scope = nearest_query_scope ? *nearest_query_scope : scope; - qualifyColumnNodesWithProjectionNames(matched_column_nodes, table_expression_node, qualify_matched_column_nodes_scope); - - QueryAnalyzer::QueryTreeNodesWithNames matched_column_nodes_with_names; - matched_column_nodes_with_names.reserve(matched_column_nodes.size()); - - for (auto && matched_column_node : matched_column_nodes) - { - auto column_name = matched_column_node->as().getColumnName(); - matched_column_nodes_with_names.emplace_back(std::move(matched_column_node), std::move(column_name)); - } - - return matched_column_nodes_with_names; -} - -bool hasTableExpressionInJoinTree(const QueryTreeNodePtr & join_tree_node, const QueryTreeNodePtr & table_expression) -{ - QueryTreeNodes nodes_to_process; - nodes_to_process.push_back(join_tree_node); - - while (!nodes_to_process.empty()) - { - auto node_to_process = std::move(nodes_to_process.back()); - nodes_to_process.pop_back(); - if (node_to_process == table_expression) - return true; - - if (node_to_process->getNodeType() == QueryTreeNodeType::JOIN) - { - const auto & join_node = node_to_process->as(); - nodes_to_process.push_back(join_node.getLeftTableExpression()); - nodes_to_process.push_back(join_node.getRightTableExpression()); - } - } - return false; -} - -/// Columns that resolved from matcher can also match columns from JOIN USING. -/// In that case we update type to type of column in USING section. -/// TODO: It's not completely correct for qualified matchers, so t1.* should be resolved to left table column type. -/// But in planner we do not distinguish such cases. -void QueryAnalyzer::updateMatchedColumnsFromJoinUsing( - QueryTreeNodesWithNames & result_matched_column_nodes_with_names, - const QueryTreeNodePtr & source_table_expression, - IdentifierResolveScope & scope) -{ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "There are no table sources. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - const auto & join_tree = nearest_query_scope_query_node->getJoinTree(); - - const auto * join_node = join_tree->as(); - if (join_node && join_node->isUsingJoinExpression()) - { - const auto & join_using_list = join_node->getJoinExpression()->as(); - const auto & join_using_nodes = join_using_list.getNodes(); - - for (auto & [matched_column_node, _] : result_matched_column_nodes_with_names) - { - auto & matched_column_node_typed = matched_column_node->as(); - const auto & matched_column_name = matched_column_node_typed.getColumnName(); - - for (const auto & join_using_node : join_using_nodes) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (matched_column_name != join_using_column_name) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - auto it = node_to_projection_name.find(matched_column_node); - - if (hasTableExpressionInJoinTree(join_node->getLeftTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(0); - else if (hasTableExpressionInJoinTree(join_node->getRightTableExpression(), source_table_expression)) - matched_column_node = join_using_column_nodes.at(1); - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Cannot find column {} in JOIN USING section {}", - matched_column_node->dumpTree(), join_node->dumpTree()); - - matched_column_node = matched_column_node->clone(); - if (it != node_to_projection_name.end()) - node_to_projection_name.emplace(matched_column_node, it->second); - - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - } - } - } -} - -/** Resolve qualified tree matcher. - * - * First try to match qualified identifier to expression. If qualified identifier matched expression node then - * if expression is compound match it column names using matcher `isMatchingColumn` method, if expression is not compound, throw exception. - * If qualified identifier did not match expression in query tree, try to lookup qualified identifier in table context. - */ -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveQualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isQualified()); - - auto expression_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::EXPRESSION}; - auto expression_identifier_resolve_result = tryResolveIdentifier(expression_identifier_lookup, scope); - auto expression_query_tree_node = expression_identifier_resolve_result.resolved_identifier; - - /// Try to resolve unqualified matcher for query expression - - if (expression_query_tree_node) - { - auto result_type = expression_query_tree_node->getResultType(); - - while (true) - { - if (const auto * array_type = typeid_cast(result_type.get())) - result_type = array_type->getNestedType(); - else if (const auto * map_type = typeid_cast(result_type.get())) - result_type = map_type->getNestedType(); - else - break; - } - - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Qualified matcher {} find non compound expression {} with type {}. Expected tuple or array of tuples. In scope {}", - matcher_node->formatASTForErrorMessage(), - expression_query_tree_node->formatASTForErrorMessage(), - expression_query_tree_node->getResultType()->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - auto qualified_matcher_element_identifier = matcher_node_typed.getQualifiedIdentifier(); - for (const auto & element_name : element_names) - { - if (!matcher_node_typed.isMatchingColumn(element_name)) - continue; - - auto get_subcolumn_function = std::make_shared("getSubcolumn"); - get_subcolumn_function->getArguments().getNodes().push_back(expression_query_tree_node); - get_subcolumn_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = get_subcolumn_function; - resolveFunction(function_query_node, scope); - - qualified_matcher_element_identifier.push_back(element_name); - node_to_projection_name.emplace(function_query_node, qualified_matcher_element_identifier.getFullName()); - qualified_matcher_element_identifier.pop_back(); - - matched_expression_nodes_with_column_names.emplace_back(std::move(function_query_node), element_name); - } - - return matched_expression_nodes_with_column_names; - } - - /// Try to resolve qualified matcher for table expression - - IdentifierResolveSettings identifier_resolve_settings; - identifier_resolve_settings.allow_to_check_cte = false; - identifier_resolve_settings.allow_to_check_database_catalog = false; - - auto table_identifier_lookup = IdentifierLookup{matcher_node_typed.getQualifiedIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, identifier_resolve_settings); - auto table_expression_node = table_identifier_resolve_result.resolved_identifier; - - if (!table_expression_node) - { - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Qualified matcher {} does not find table. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - NamesAndTypes matched_columns; - - auto * table_expression_query_node = table_expression_node->as(); - auto * table_expression_union_node = table_expression_node->as(); - auto * table_expression_table_node = table_expression_node->as(); - auto * table_expression_table_function_node = table_expression_node->as(); - - if (table_expression_query_node || table_expression_union_node) - { - matched_columns = table_expression_query_node ? table_expression_query_node->getProjectionColumns() - : table_expression_union_node->computeProjectionColumns(); - } - else if (table_expression_table_node || table_expression_table_function_node) - { - const auto & storage_snapshot = table_expression_table_node ? table_expression_table_node->getStorageSnapshot() - : table_expression_table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - matched_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Invalid table expression node {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto result_matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression_node, - matched_columns, - scope); - - updateMatchedColumnsFromJoinUsing(result_matched_column_nodes_with_names, table_expression_node, scope); - - return result_matched_column_nodes_with_names; -} - -/// Resolve non qualified matcher, using scope join tree node. -QueryAnalyzer::QueryTreeNodesWithNames QueryAnalyzer::resolveUnqualifiedMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - assert(matcher_node_typed.isUnqualified()); - - /** There can be edge case if matcher is inside lambda expression. - * Try to find parent query expression using parent scopes. - */ - auto * nearest_query_scope = scope.getNearestQueryScope(); - auto * nearest_query_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - - /// If there are no parent query scope or query scope does not have join tree - if (!nearest_query_scope_query_node || !nearest_query_scope_query_node->getJoinTree()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unqualified matcher {} cannot be resolved. There are no table sources. In scope {}", - matcher_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** For unqualifited matcher resolve we build table expressions stack from JOIN tree and then process it. - * For table, table function, query, union table expressions add matched columns into table expressions columns stack. - * For array join continue processing. - * For join node combine last left and right table expressions columns on stack together. It is important that if JOIN has USING - * we must add USING columns before combining left and right table expressions columns. Columns from left and right table - * expressions that have same names as columns in USING clause must be skipped. - */ - - auto table_expressions_stack = buildTableExpressionsStack(nearest_query_scope_query_node->getJoinTree()); - std::vector table_expressions_column_nodes_with_names_stack; - - std::unordered_set table_expression_column_names_to_skip; - - QueryTreeNodesWithNames result; - - if (matcher_node_typed.getMatcherType() == MatcherNodeType::COLUMNS_LIST) - { - auto identifiers = matcher_node_typed.getColumnsIdentifiers(); - result.reserve(identifiers.size()); - - for (const auto & identifier : identifiers) - { - auto resolve_result = tryResolveIdentifier(IdentifierLookup{identifier, IdentifierLookupContext::EXPRESSION}, scope); - if (!resolve_result.isResolved()) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Unknown identifier '{}' inside COLUMNS matcher. In scope {}", - identifier.getFullName(), scope.dump()); - - // TODO: Introduce IdentifierLookupContext::COLUMN and get rid of this check - auto * resolved_column = resolve_result.resolved_identifier->as(); - if (!resolved_column) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "Identifier '{}' inside COLUMNS matcher must resolve into a column, but got {}. In scope {}", - identifier.getFullName(), - resolve_result.resolved_identifier->getNodeTypeName(), - scope.scope_node->formatASTForErrorMessage()); - result.emplace_back(resolve_result.resolved_identifier, resolved_column->getColumnName()); - } - return result; - } - - result.resize(matcher_node_typed.getColumnsIdentifiers().size()); - - for (auto & table_expression : table_expressions_stack) - { - bool table_expression_in_resolve_process = nearest_query_scope->table_expressions_in_resolve_process.contains(table_expression.get()); - - if (auto * array_join_node = table_expression->as()) - { - if (table_expressions_column_nodes_with_names_stack.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 1 table expressions on stack before ARRAY JOIN processing"); - - if (table_expression_in_resolve_process) - continue; - - auto & table_expression_column_nodes_with_names = table_expressions_column_nodes_with_names_stack.back(); - - for (auto & [table_expression_column_node, _] : table_expression_column_nodes_with_names) - { - auto array_join_resolved_expression = tryResolveExpressionFromArrayJoinExpressions(table_expression_column_node, - table_expression, - scope); - if (array_join_resolved_expression) - table_expression_column_node = std::move(array_join_resolved_expression); - } - - continue; - } - - auto * join_node = table_expression->as(); - - if (join_node) - { - size_t table_expressions_column_nodes_with_names_stack_size = table_expressions_column_nodes_with_names_stack.size(); - if (table_expressions_column_nodes_with_names_stack_size < 2) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected at least 2 table expressions on stack before JOIN processing. Actual {}", - table_expressions_column_nodes_with_names_stack_size); - - auto right_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - auto left_table_expression_columns = std::move(table_expressions_column_nodes_with_names_stack.back()); - table_expressions_column_nodes_with_names_stack.pop_back(); - - table_expression_column_names_to_skip.clear(); - - QueryTreeNodesWithNames matched_expression_nodes_with_column_names; - - /** If there is JOIN with USING we need to match only single USING column and do not use left table expression - * and right table expression column with same name. - * - * Example: SELECT id FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING (id); - */ - if (!table_expression_in_resolve_process && join_node->isUsingJoinExpression()) - { - auto & join_using_list = join_node->getJoinExpression()->as(); - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto & join_using_column_node = join_using_node->as(); - const auto & join_using_column_name = join_using_column_node.getColumnName(); - - if (!matcher_node_typed.isMatchingColumn(join_using_column_name)) - continue; - - const auto & join_using_column_nodes_list = join_using_column_node.getExpressionOrThrow()->as(); - const auto & join_using_column_nodes = join_using_column_nodes_list.getNodes(); - - /** If column doesn't exists in the table, then do not match column from USING clause. - * Example: SELECT a + 1 AS id, * FROM (SELECT 1 AS a) AS t1 JOIN (SELECT 2 AS id) AS t2 USING (id); - * In this case `id` is not present in the left table expression, - * so asterisk should return `id` from the right table expression. - */ - auto is_column_from_parent_scope = [&scope](const QueryTreeNodePtr & using_node_from_table) - { - const auto & using_column_from_table = using_node_from_table->as(); - auto table_expression_data_it = scope.table_expression_node_to_data.find(using_column_from_table.getColumnSource()); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - { - const auto & table_expression_data = table_expression_data_it->second; - const auto & column_name = using_column_from_table.getColumnName(); - return !table_expression_data.column_name_to_column_node.contains(column_name); - } - return false; - }; - - if (is_column_from_parent_scope(join_using_column_nodes.at(0)) || - is_column_from_parent_scope(join_using_column_nodes.at(1))) - continue; - - QueryTreeNodePtr matched_column_node; - - if (isRight(join_node->getKind())) - matched_column_node = join_using_column_nodes.at(1); - else - matched_column_node = join_using_column_nodes.at(0); - - matched_column_node = matched_column_node->clone(); - matched_column_node->as().setColumnType(join_using_column_node.getResultType()); - if (!matched_column_node->isEqual(*join_using_column_nodes.at(0))) - scope.join_columns_with_changed_types[matched_column_node] = join_using_column_nodes.at(0); - - table_expression_column_names_to_skip.insert(join_using_column_name); - matched_expression_nodes_with_column_names.emplace_back(std::move(matched_column_node), join_using_column_name); - } - } - - for (auto && left_table_column_with_name : left_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(left_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(left_table_column_with_name)); - } - - for (auto && right_table_column_with_name : right_table_expression_columns) - { - if (table_expression_column_names_to_skip.contains(right_table_column_with_name.second)) - continue; - - matched_expression_nodes_with_column_names.push_back(std::move(right_table_column_with_name)); - } - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_expression_nodes_with_column_names)); - continue; - } - - if (table_expression_in_resolve_process) - { - table_expressions_column_nodes_with_names_stack.emplace_back(); - continue; - } - - auto * table_node = table_expression->as(); - auto * table_function_node = table_expression->as(); - auto * query_node = table_expression->as(); - auto * union_node = table_expression->as(); - - NamesAndTypes table_expression_columns; - - if (query_node || union_node) - { - table_expression_columns = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - } - else if (table_node || table_function_node) - { - const auto & storage_snapshot - = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - auto get_columns_options = buildGetColumnsOptions(matcher_node, scope.context); - auto storage_columns_list = storage_snapshot->getColumns(get_columns_options); - table_expression_columns = NamesAndTypes(storage_columns_list.begin(), storage_columns_list.end()); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Unqualified matcher {} resolve unexpected table expression. In scope {}", - matcher_node_typed.formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto matched_column_nodes_with_names = getMatchedColumnNodesWithNames(matcher_node, - table_expression, - table_expression_columns, - scope); - - table_expressions_column_nodes_with_names_stack.push_back(std::move(matched_column_nodes_with_names)); - } - - for (auto & table_expression_column_nodes_with_names : table_expressions_column_nodes_with_names_stack) - { - for (auto && table_expression_column_node_with_name : table_expression_column_nodes_with_names) - result.push_back(std::move(table_expression_column_node_with_name)); - } - - return result; -} - - -/** Resolve query tree matcher. Check MatcherNode.h for detailed matcher description. Check ColumnTransformers.h for detailed transformers description. - * - * 1. Populate matched expression nodes resolving qualified or unqualified matcher. - * 2. Apply column transformers to matched expression nodes. For strict column transformers save used column names. - * 3. Validate strict column transformers. - */ -ProjectionNames QueryAnalyzer::resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope) -{ - auto & matcher_node_typed = matcher_node->as(); - - QueryTreeNodesWithNames matched_expression_nodes_with_names; - - if (matcher_node_typed.isQualified()) - matched_expression_nodes_with_names = resolveQualifiedMatcher(matcher_node, scope); - else - matched_expression_nodes_with_names = resolveUnqualifiedMatcher(matcher_node, scope); - - if (scope.join_use_nulls) - { - /** If we are resolving matcher came from the result of JOIN and `join_use_nulls` is set, - * we need to convert joined column type to Nullable. - * We are taking the nearest JoinNode to check to which table column belongs, - * because for LEFT/RIGHT join, we convert only the corresponding side. - */ - const auto * nearest_query_scope = scope.getNearestQueryScope(); - const QueryNode * nearest_scope_query_node = nearest_query_scope ? nearest_query_scope->scope_node->as() : nullptr; - const QueryTreeNodePtr & nearest_scope_join_tree = nearest_scope_query_node ? nearest_scope_query_node->getJoinTree() : nullptr; - const JoinNode * nearest_scope_join_node = nearest_scope_join_tree ? nearest_scope_join_tree->as() : nullptr; - if (nearest_scope_join_node) - { - for (auto & [node, node_name] : matched_expression_nodes_with_names) - { - auto join_identifier_side = getColumnSideFromJoinTree(node, *nearest_scope_join_node); - auto projection_name_it = node_to_projection_name.find(node); - auto nullable_node = convertJoinedColumnTypeToNullIfNeeded(node, nearest_scope_join_node->getKind(), join_identifier_side, scope); - if (nullable_node) - { - node = nullable_node; - /// Set the same projection name for new nullable node - if (projection_name_it != node_to_projection_name.end()) - { - node_to_projection_name.emplace(node, projection_name_it->second); - } - } - } - } - } - - if (!scope.expressions_in_resolve_process_stack.hasAggregateFunction()) - { - for (auto & [node, _] : matched_expression_nodes_with_names) - { - auto it = scope.nullable_group_by_keys.find(node); - if (it != scope.nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - } - } - } - - std::unordered_map> strict_transformer_to_used_column_names; - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - auto * except_transformer = transformer->as(); - auto * replace_transformer = transformer->as(); - - if (except_transformer && except_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(except_transformer, std::unordered_set()); - else if (replace_transformer && replace_transformer->isStrict()) - strict_transformer_to_used_column_names.emplace(replace_transformer, std::unordered_set()); - } - - ListNodePtr list = std::make_shared(); - ProjectionNames result_projection_names; - ProjectionNames node_projection_names; - - for (auto & [node, column_name] : matched_expression_nodes_with_names) - { - bool apply_transformer_was_used = false; - bool replace_transformer_was_used = false; - bool execute_apply_transformer = false; - bool execute_replace_transformer = false; - - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - else - result_projection_names.push_back(column_name); - - for (const auto & transformer : matcher_node_typed.getColumnTransformers().getNodes()) - { - if (auto * apply_transformer = transformer->as()) - { - const auto & expression_node = apply_transformer->getExpressionNode(); - apply_transformer_was_used = true; - - if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::LAMBDA) - { - auto lambda_expression_to_resolve = expression_node->clone(); - IdentifierResolveScope lambda_scope(expression_node, &scope /*parent_scope*/); - node_projection_names = resolveLambda(expression_node, lambda_expression_to_resolve, {node}, lambda_scope); - auto & lambda_expression_to_resolve_typed = lambda_expression_to_resolve->as(); - node = lambda_expression_to_resolve_typed.getExpression(); - } - else if (apply_transformer->getApplyTransformerType() == ApplyColumnTransformerType::FUNCTION) - { - auto function_to_resolve_untyped = expression_node->clone(); - auto & function_to_resolve_typed = function_to_resolve_untyped->as(); - function_to_resolve_typed.getArguments().getNodes().push_back(node); - node_projection_names = resolveFunction(function_to_resolve_untyped, scope); - node = function_to_resolve_untyped; - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unsupported apply matcher expression type. Expected lambda or function apply transformer. Actual {}. In scope {}", - transformer->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - execute_apply_transformer = true; - } - else if (auto * except_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - if (except_transformer->isColumnMatching(column_name)) - { - if (except_transformer->isStrict()) - strict_transformer_to_used_column_names[except_transformer].insert(column_name); - - node = {}; - break; - } - } - else if (auto * replace_transformer = transformer->as()) - { - if (apply_transformer_was_used || replace_transformer_was_used) - continue; - - auto replace_expression = replace_transformer->findReplacementExpression(column_name); - if (!replace_expression) - continue; - - replace_transformer_was_used = true; - - if (replace_transformer->isStrict()) - strict_transformer_to_used_column_names[replace_transformer].insert(column_name); - - node = replace_expression->clone(); - node_projection_names = resolveExpressionNode(node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** If replace expression resolved as single node, we want to use replace column name as result projection name, instead - * of using replace expression projection name. - * - * Example: SELECT * REPLACE id + 5 AS id FROM test_table; - */ - if (node_projection_names.size() == 1) - node_projection_names[0] = column_name; - - execute_replace_transformer = true; - } - - if (execute_apply_transformer || execute_replace_transformer) - { - if (auto * node_list = node->as()) - { - auto & node_list_nodes = node_list->getNodes(); - size_t node_list_nodes_size = node_list_nodes.size(); - - if (node_list_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "{} transformer {} resolved as list node with size {}. Expected 1. In scope {}", - execute_apply_transformer ? "APPLY" : "REPLACE", - transformer->formatASTForErrorMessage(), - node_list_nodes_size, - scope.scope_node->formatASTForErrorMessage()); - - node = node_list_nodes[0]; - } - - if (node_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Matcher node expected 1 projection name. Actual {}", node_projection_names.size()); - - result_projection_names.back() = std::move(node_projection_names[0]); - node_to_projection_name.emplace(node, result_projection_names.back()); - node_projection_names.clear(); - } - } - - if (node) - list->getNodes().push_back(node); - else - result_projection_names.pop_back(); - } - - for (auto & [strict_transformer, used_column_names] : strict_transformer_to_used_column_names) - { - auto strict_transformer_type = strict_transformer->getTransformerType(); - const Names * strict_transformer_column_names = nullptr; - - switch (strict_transformer_type) - { - case ColumnTransfomerType::EXCEPT: - { - const auto * except_transformer = static_cast(strict_transformer); - const auto & except_names = except_transformer->getExceptColumnNames(); - - if (except_names.size() != used_column_names.size()) - strict_transformer_column_names = &except_transformer->getExceptColumnNames(); - - break; - } - case ColumnTransfomerType::REPLACE: - { - const auto * replace_transformer = static_cast(strict_transformer); - const auto & replacement_names = replace_transformer->getReplacementsNames(); - - if (replacement_names.size() != used_column_names.size()) - strict_transformer_column_names = &replace_transformer->getReplacementsNames(); - - break; - } - default: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expected strict EXCEPT or REPLACE column transformer. Actual type {}. In scope {}", - toString(strict_transformer_type), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (!strict_transformer_column_names) - continue; - - Names non_matched_column_names; - size_t strict_transformer_column_names_size = strict_transformer_column_names->size(); - for (size_t i = 0; i < strict_transformer_column_names_size; ++i) - { - const auto & column_name = (*strict_transformer_column_names)[i]; - if (used_column_names.find(column_name) == used_column_names.end()) - non_matched_column_names.push_back(column_name); - } - - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Strict {} column transformer {} expects following column(s) : {}. In scope {}", - toString(strict_transformer_type), - strict_transformer->formatASTForErrorMessage(), - fmt::join(non_matched_column_names, ", "), - scope.scope_node->formatASTForErrorMessage()); - } - - auto original_ast = matcher_node->getOriginalAST(); - matcher_node = std::move(list); - if (original_ast) - matcher_node->setOriginalAST(original_ast); - - return result_projection_names; -} - -/** Resolve window function window node. - * - * Node can be identifier or window node. - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - * Example: SELECT count(*) OVER (PARTITION BY id); - * - * If node has parent window name specified, then parent window definition is searched in nearest query scope WINDOW section. - * If node is identifier, than node is replaced with window definition. - * If node is window, that window node is merged with parent window node. - * - * Window node PARTITION BY and ORDER BY parts are resolved. - * If window node has frame begin OFFSET or frame end OFFSET specified, they are resolved, and window node frame constants are updated. - * Window node frame is validated. - */ -ProjectionName QueryAnalyzer::resolveWindow(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - std::string parent_window_name; - auto * identifier_node = node->as(); - - ProjectionName result_projection_name; - QueryTreeNodePtr parent_window_node; - - if (identifier_node) - parent_window_name = identifier_node->getIdentifier().getFullName(); - else if (auto * window_node = node->as()) - parent_window_name = window_node->getParentWindowName(); - - if (!parent_window_name.empty()) - { - auto * nearest_query_scope = scope.getNearestQueryScope(); - - if (!nearest_query_scope) - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Window '{}' does not exist.", parent_window_name); - - auto & scope_window_name_to_window_node = nearest_query_scope->window_name_to_window_node; - - auto window_node_it = scope_window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope_window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - nearest_query_scope->scope_node->formatASTForErrorMessage()); - - parent_window_node = window_node_it->second; - - if (identifier_node) - { - node = parent_window_node->clone(); - result_projection_name = parent_window_name; - } - else - { - mergeWindowWithParentWindow(node, parent_window_node, scope); - } - } - - auto & window_node = node->as(); - window_node.setParentWindowName({}); - - ProjectionNames partition_by_projection_names = resolveExpressionNodeList(window_node.getPartitionByNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - ProjectionNames order_by_projection_names = resolveSortNodeList(window_node.getOrderByNode(), scope); - - ProjectionNames frame_begin_offset_projection_names; - ProjectionNames frame_end_offset_projection_names; - - if (window_node.hasFrameBeginOffset()) - { - frame_begin_offset_projection_names = resolveExpressionNode(window_node.getFrameBeginOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_begin_constant_node = window_node.getFrameBeginOffsetNode()->as(); - if (!window_frame_begin_constant_node || !isNativeNumber(removeNullable(window_frame_begin_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameBeginOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().begin_offset = window_frame_begin_constant_node->getValue(); - if (frame_begin_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_begin_offset_projection_names.size()); - } - - if (window_node.hasFrameEndOffset()) - { - frame_end_offset_projection_names = resolveExpressionNode(window_node.getFrameEndOffsetNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - const auto * window_frame_end_constant_node = window_node.getFrameEndOffsetNode()->as(); - if (!window_frame_end_constant_node || !isNativeNumber(removeNullable(window_frame_end_constant_node->getResultType()))) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window frame begin OFFSET expression must be constant with numeric type. Actual {}. In scope {}", - window_node.getFrameEndOffsetNode()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - window_node.getWindowFrame().end_offset = window_frame_end_constant_node->getValue(); - if (frame_end_offset_projection_names.size() != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Window FRAME begin offset expected 1 projection name. Actual {}", - frame_end_offset_projection_names.size()); - } - - window_node.getWindowFrame().checkValid(); - - if (result_projection_name.empty()) - { - result_projection_name = calculateWindowProjectionName(node, - parent_window_node, - parent_window_name, - partition_by_projection_names, - order_by_projection_names, - frame_begin_offset_projection_names.empty() ? "" : frame_begin_offset_projection_names.front(), - frame_end_offset_projection_names.empty() ? "" : frame_end_offset_projection_names.front()); - } - - return result_projection_name; -} - -/** Resolve lambda function. - * This function modified lambda_node during resolve. It is caller responsibility to clone lambda before resolve - * if it is needed for later use. - * - * Lambda body expression result projection names is used as lambda projection names. - * - * Lambda expression can be resolved into list node. It is caller responsibility to handle it properly. - * - * lambda_node - node that must have LambdaNode type. - * lambda_node_to_resolve - lambda node to resolve that must have LambdaNode type. - * arguments - lambda arguments. - * scope - lambda scope. It is client responsibility to create it. - * - * Resolve steps: - * 1. Validate arguments. - * 2. Register lambda node in lambdas in resolve process. This is necessary to prevent recursive lambda resolving. - * 3. Initialize scope with lambda aliases. - * 4. Validate lambda argument names, and scope expressions. - * 5. Resolve lambda body expression. - * 6. Deregister lambda node from lambdas in resolve process. - */ -ProjectionNames QueryAnalyzer::resolveLambda(const QueryTreeNodePtr & lambda_node, - const QueryTreeNodePtr & lambda_node_to_resolve, - const QueryTreeNodes & lambda_arguments, - IdentifierResolveScope & scope) -{ - auto & lambda_to_resolve = lambda_node_to_resolve->as(); - auto & lambda_arguments_nodes = lambda_to_resolve.getArguments().getNodes(); - size_t lambda_arguments_nodes_size = lambda_arguments_nodes.size(); - - /** Register lambda as being resolved, to prevent recursive lambdas resolution. - * Example: WITH (x -> x + lambda_2(x)) AS lambda_1, (x -> x + lambda_1(x)) AS lambda_2 SELECT 1; - */ - auto it = lambdas_in_resolve_process.find(lambda_node.get()); - if (it != lambdas_in_resolve_process.end()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive lambda {}. In scope {}", - lambda_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - lambdas_in_resolve_process.emplace(lambda_node.get()); - - size_t arguments_size = lambda_arguments.size(); - if (lambda_arguments_nodes_size != arguments_size) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} expect {} arguments. Actual {}. In scope {}", - lambda_to_resolve.formatASTForErrorMessage(), - lambda_arguments_nodes_size, - arguments_size, - scope.scope_node->formatASTForErrorMessage()); - - /// Initialize aliases in lambda scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - visitor.visit(lambda_to_resolve.getExpression()); - - /** Replace lambda arguments with new arguments. - * Additionally validate that there are no aliases with same name as lambda arguments. - * Arguments are registered in current scope expression_argument_name_to_node map. - */ - QueryTreeNodes lambda_new_arguments_nodes; - lambda_new_arguments_nodes.reserve(lambda_arguments_nodes_size); - - for (size_t i = 0; i < lambda_arguments_nodes_size; ++i) - { - auto & lambda_argument_node = lambda_arguments_nodes[i]; - const auto * lambda_argument_identifier = lambda_argument_node->as(); - const auto * lambda_argument_column = lambda_argument_node->as(); - if (!lambda_argument_identifier && !lambda_argument_column) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected IDENTIFIER or COLUMN as lambda argument, got {}", lambda_node->dumpTree()); - const auto & lambda_argument_name = lambda_argument_identifier ? lambda_argument_identifier->getIdentifier().getFullName() - : lambda_argument_column->getColumnName(); - - bool has_expression_node = scope.aliases.alias_name_to_expression_node->contains(lambda_argument_name); - bool has_alias_node = scope.aliases.alias_name_to_lambda_node.contains(lambda_argument_name); - - if (has_expression_node || has_alias_node) - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Alias name '{}' inside lambda {} cannot have same name as lambda argument. In scope {}", - lambda_argument_name, - lambda_argument_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - - scope.expression_argument_name_to_node.emplace(lambda_argument_name, lambda_arguments[i]); - lambda_new_arguments_nodes.push_back(lambda_arguments[i]); - } - - lambda_to_resolve.getArguments().getNodes() = std::move(lambda_new_arguments_nodes); - - /// Lambda body expression is resolved as standard query expression node. - auto result_projection_names = resolveExpressionNode(lambda_to_resolve.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - lambdas_in_resolve_process.erase(lambda_node.get()); - - return result_projection_names; -} - -namespace -{ -void checkFunctionNodeHasEmptyNullsAction(FunctionNode const & node) -{ - if (node.getNullsAction() != NullsAction::EMPTY) - throw Exception( - ErrorCodes::SYNTAX_ERROR, - "Function with name '{}' cannot use {} NULLS", - node.getFunctionName(), - node.getNullsAction() == NullsAction::IGNORE_NULLS ? "IGNORE" : "RESPECT"); -} -} - -/** Resolve function node in scope. - * During function node resolve, function node can be replaced with another expression (if it match lambda or sql user defined function), - * with constant (if it allow constant folding), or with expression list. It is caller responsibility to handle such cases appropriately. - * - * Steps: - * 1. Resolve function parameters. Validate that each function parameter must be constant node. - * 2. Try to lookup function as lambda in current scope. If it is lambda we can skip `in` and `count` special handling. - * 3. If function is count function, that take unqualified ASTERISK matcher, remove it from its arguments. Example: SELECT count(*) FROM test_table; - * 4. If function is `IN` function, then right part of `IN` function is replaced as subquery. - * 5. Resolve function arguments list, lambda expressions are allowed as function arguments. - * For `IN` function table expressions are allowed as function arguments. - * 6. Initialize argument_columns, argument_types, function_lambda_arguments_indexes arrays from function arguments. - * 7. If function name identifier was not resolved as function in current scope, try to lookup lambda from sql user defined functions factory. - * 8. If function was resolve as lambda from step 2 or 7, then resolve lambda using function arguments and replace function node with lambda result. - * After than function node is resolved. - * 9. If function was not resolved during step 6 as lambda, then try to resolve function as window function or executable user defined function - * or ordinary function or aggregate function. - * - * If function is resolved as window function or executable user defined function or aggregate function, function node is resolved - * no additional special handling is required. - * - * 8. If function was resolved as non aggregate function. Then if some of function arguments are lambda expressions, their result types need to be initialized and - * they must be resolved. - * 9. If function is suitable for constant folding, try to perform constant folding for function node. - */ -ProjectionNames QueryAnalyzer::resolveFunction(QueryTreeNodePtr & node, IdentifierResolveScope & scope) -{ - FunctionNodePtr function_node_ptr = std::static_pointer_cast(node); - auto function_name = function_node_ptr->getFunctionName(); - - /// Resolve function parameters - - auto parameters_projection_names = resolveExpressionNodeList(function_node_ptr->getParametersNode(), - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - - /// Convert function parameters into constant parameters array - - Array parameters; - - auto & parameters_nodes = function_node_ptr->getParameters().getNodes(); - parameters.reserve(parameters_nodes.size()); - - for (auto & parameter_node : parameters_nodes) - { - const auto * constant_node = parameter_node->as(); - if (!constant_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Parameter for function '{}' expected to have constant value. Actual {}. In scope {}", - function_name, - parameter_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - parameters.push_back(constant_node->getValue()); - } - - //// If function node is not window function try to lookup function node name as lambda identifier. - QueryTreeNodePtr lambda_expression_untyped; - if (!function_node_ptr->isWindowFunction()) - { - auto function_lookup_result = tryResolveIdentifier({Identifier{function_name}, IdentifierLookupContext::FUNCTION}, scope); - lambda_expression_untyped = function_lookup_result.resolved_identifier; - } - - bool is_special_function_in = false; - bool is_special_function_dict_get = false; - bool is_special_function_join_get = false; - bool is_special_function_exists = false; - bool is_special_function_if = false; - - if (!lambda_expression_untyped) - { - is_special_function_in = isNameOfInFunction(function_name); - is_special_function_dict_get = functionIsDictGet(function_name); - is_special_function_join_get = functionIsJoinGet(function_name); - is_special_function_exists = function_name == "exists"; - is_special_function_if = function_name == "if"; - - auto function_name_lowercase = Poco::toLower(function_name); - - /** Special handling for count and countState functions. - * - * Example: SELECT count(*) FROM test_table - * Example: SELECT countState(*) FROM test_table; - */ - if (function_node_ptr->getArguments().getNodes().size() == 1 && - (function_name_lowercase == "count" || function_name_lowercase == "countstate")) - { - auto * matcher_node = function_node_ptr->getArguments().getNodes().front()->as(); - if (matcher_node && matcher_node->isUnqualified()) - function_node_ptr->getArguments().getNodes().clear(); - } - } - - /** Special functions dictGet and its variations and joinGet can be executed when first argument is identifier. - * Example: SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Try to resolve identifier as expression identifier and if it is resolved use it. - * Example: WITH 'dict_name' AS identifier SELECT dictGet(identifier, 'value', toUInt64(0)); - * - * Otherwise replace identifier with identifier full name constant. - * Validation that dictionary exists or table exists will be performed during function `getReturnType` method call. - */ - if ((is_special_function_dict_get || is_special_function_join_get) && - !function_node_ptr->getArguments().getNodes().empty() && - function_node_ptr->getArguments().getNodes()[0]->getNodeType() == QueryTreeNodeType::IDENTIFIER) - { - auto & first_argument = function_node_ptr->getArguments().getNodes()[0]; - auto & first_argument_identifier = first_argument->as(); - auto identifier = first_argument_identifier.getIdentifier(); - - IdentifierLookup identifier_lookup{identifier, IdentifierLookupContext::EXPRESSION}; - auto resolve_result = tryResolveIdentifier(identifier_lookup, scope); - - if (resolve_result.isResolved()) - { - first_argument = std::move(resolve_result.resolved_identifier); - } - else - { - size_t parts_size = identifier.getPartsSize(); - if (parts_size < 1 || parts_size > 2) - throw Exception(ErrorCodes::INVALID_IDENTIFIER, - "Expected {} function first argument identifier to contain 1 or 2 parts. Actual '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_special_function_dict_get) - { - scope.context->getExternalDictionariesLoader().assertDictionaryStructureExists(identifier.getFullName(), scope.context); - } - else - { - auto table_node = tryResolveTableIdentifierFromDatabaseCatalog(identifier, scope.context); - if (!table_node) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} first argument expected table identifier '{}'. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node_typed = table_node->as(); - if (!std::dynamic_pointer_cast(table_node_typed.getStorage())) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Function {} table '{}' should have engine StorageJoin. In scope {}", - function_name, - identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - first_argument = std::make_shared(identifier.getFullName()); - } - } - - if (is_special_function_exists) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /// Rewrite EXISTS (subquery) into 1 IN (SELECT 1 FROM (subquery) LIMIT 1). - auto & exists_subquery_argument = function_node_ptr->getArguments().getNodes().at(0); - - auto constant_data_type = std::make_shared(); - - auto in_subquery = std::make_shared(Context::createCopy(scope.context)); - in_subquery->setIsSubquery(true); - in_subquery->getProjection().getNodes().push_back(std::make_shared(1UL, constant_data_type)); - in_subquery->getJoinTree() = exists_subquery_argument; - in_subquery->getLimit() = std::make_shared(1UL, constant_data_type); - - function_node_ptr = std::make_shared("in"); - function_node_ptr->getArguments().getNodes() = {std::make_shared(1UL, constant_data_type), in_subquery}; - node = function_node_ptr; - function_name = "in"; - is_special_function_in = true; - } - - if (is_special_function_if && !function_node_ptr->getArguments().getNodes().empty()) - { - checkFunctionNodeHasEmptyNullsAction(*function_node_ptr); - /** Handle special case with constant If function, even if some of the arguments are invalid. - * - * SELECT if(hasColumnInTable('system', 'numbers', 'not_existing_column'), not_existing_column, 5) FROM system.numbers; - */ - auto & if_function_arguments = function_node_ptr->getArguments().getNodes(); - auto if_function_condition = if_function_arguments[0]; - resolveExpressionNode(if_function_condition, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto constant_condition = tryExtractConstantFromConditionNode(if_function_condition); - - if (constant_condition.has_value() && if_function_arguments.size() == 3) - { - QueryTreeNodePtr constant_if_result_node; - QueryTreeNodePtr possibly_invalid_argument_node; - - if (*constant_condition) - { - possibly_invalid_argument_node = if_function_arguments[2]; - constant_if_result_node = if_function_arguments[1]; - } - else - { - possibly_invalid_argument_node = if_function_arguments[1]; - constant_if_result_node = if_function_arguments[2]; - } - - bool apply_constant_if_optimization = false; - - try - { - resolveExpressionNode(possibly_invalid_argument_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - } - catch (...) - { - apply_constant_if_optimization = true; - } - - if (apply_constant_if_optimization) - { - auto result_projection_names = resolveExpressionNode(constant_if_result_node, - scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - node = std::move(constant_if_result_node); - return result_projection_names; - } - } - } - - /// Resolve function arguments - bool allow_table_expressions = is_special_function_in; - auto arguments_projection_names = resolveExpressionNodeList(function_node_ptr->getArgumentsNode(), - scope, - true /*allow_lambda_expression*/, - allow_table_expressions /*allow_table_expression*/); - - /// Mask arguments if needed - if (!scope.context->getSettingsRef().format_display_secrets_in_show_and_select) - { - if (FunctionSecretArgumentsFinder::Result secret_arguments = FunctionSecretArgumentsFinderTreeNode(*function_node_ptr).getResult(); secret_arguments.count) - { - auto & argument_nodes = function_node_ptr->getArgumentsNode()->as().getNodes(); - - for (size_t n = secret_arguments.start; n < secret_arguments.start + secret_arguments.count; ++n) - { - if (auto * constant = argument_nodes[n]->as()) - { - auto mask = scope.projection_mask_map->insert({constant->getTreeHash(), scope.projection_mask_map->size() + 1}).first->second; - constant->setMaskId(mask); - arguments_projection_names[n] = "[HIDDEN id: " + std::to_string(mask) + "]"; - } - } - } - } - - auto & function_node = *function_node_ptr; - - /// Replace right IN function argument if it is table or table function with subquery that read ordinary columns - if (is_special_function_in) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - if (scope.context->getSettingsRef().transform_null_in) - { - static constexpr std::array, 4> in_function_to_replace_null_in_function_map = - {{ - {"in", "nullIn"}, - {"notIn", "notNullIn"}, - {"globalIn", "globalNullIn"}, - {"globalNotIn", "globalNotNullIn"}, - }}; - - for (const auto & [in_function_name, in_function_name_to_replace] : in_function_to_replace_null_in_function_map) - { - if (function_name == in_function_name) - { - function_name = in_function_name_to_replace; - break; - } - } - } - - auto & function_in_arguments_nodes = function_node.getArguments().getNodes(); - if (function_in_arguments_nodes.size() != 2) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Function '{}' expects 2 arguments", function_name); - - auto & in_second_argument = function_in_arguments_nodes[1]; - auto * table_node = in_second_argument->as(); - auto * table_function_node = in_second_argument->as(); - - if (table_node) - { - /// If table is already prepared set, we do not replace it with subquery. - /// If table is not a StorageSet, we'll create plan to build set in the Planner. - } - else if (table_function_node) - { - const auto & storage_snapshot = table_function_node->getStorageSnapshot(); - auto columns_to_select = storage_snapshot->getColumns(GetColumnsOptions(GetColumnsOptions::Ordinary)); - - size_t columns_to_select_size = columns_to_select.size(); - - auto column_nodes_to_select = std::make_shared(); - column_nodes_to_select->getNodes().reserve(columns_to_select_size); - - NamesAndTypes projection_columns; - projection_columns.reserve(columns_to_select_size); - - for (auto & column : columns_to_select) - { - column_nodes_to_select->getNodes().emplace_back(std::make_shared(column, in_second_argument)); - projection_columns.emplace_back(column.name, column.type); - } - - auto in_second_argument_query_node = std::make_shared(Context::createCopy(scope.context)); - in_second_argument_query_node->setIsSubquery(true); - in_second_argument_query_node->getProjectionNode() = std::move(column_nodes_to_select); - in_second_argument_query_node->getJoinTree() = std::move(in_second_argument); - in_second_argument_query_node->resolveProjectionColumns(std::move(projection_columns)); - - in_second_argument = std::move(in_second_argument_query_node); - } - else - { - /// Replace storage with values storage of insertion block - if (StoragePtr storage = scope.context->getViewSource()) - { - QueryTreeNodePtr table_expression; - /// Process possibly nested sub-selects - for (auto * query_node = in_second_argument->as(); query_node; query_node = table_expression->as()) - table_expression = extractLeftTableExpression(query_node->getJoinTree()); - - if (table_expression) - { - if (auto * query_table_node = table_expression->as()) - { - if (query_table_node->getStorageID().getFullNameNotQuoted() == storage->getStorageID().getFullNameNotQuoted()) - { - auto replacement_table_expression = std::make_shared(storage, scope.context); - if (std::optional table_expression_modifiers = query_table_node->getTableExpressionModifiers()) - replacement_table_expression->setTableExpressionModifiers(*table_expression_modifiers); - in_second_argument = in_second_argument->cloneAndReplace(table_expression, std::move(replacement_table_expression)); - } - } - } - } - - resolveExpressionNode(in_second_argument, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - } - } - - /// Initialize function argument columns - - ColumnsWithTypeAndName argument_columns; - DataTypes argument_types; - bool all_arguments_constants = true; - std::vector function_lambda_arguments_indexes; - - auto & function_arguments = function_node.getArguments().getNodes(); - size_t function_arguments_size = function_arguments.size(); - - for (size_t function_argument_index = 0; function_argument_index < function_arguments_size; ++function_argument_index) - { - auto & function_argument = function_arguments[function_argument_index]; - - ColumnWithTypeAndName argument_column; - argument_column.name = arguments_projection_names[function_argument_index]; - - /** If function argument is lambda, save lambda argument index and initialize argument type as DataTypeFunction - * where function argument types are initialized with empty array of lambda arguments size. - */ - if (const auto * lambda_node = function_argument->as()) - { - size_t lambda_arguments_size = lambda_node->getArguments().getNodes().size(); - argument_column.type = std::make_shared(DataTypes(lambda_arguments_size, nullptr), nullptr); - function_lambda_arguments_indexes.push_back(function_argument_index); - } - else if (is_special_function_in && function_argument_index == 1) - { - argument_column.type = std::make_shared(); - } - else - { - argument_column.type = function_argument->getResultType(); - } - - if (!argument_column.type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' argument is not resolved. In scope {}", - function_name, - scope.scope_node->formatASTForErrorMessage()); - - bool argument_is_constant = false; - const auto * constant_node = function_argument->as(); - if (constant_node) - { - argument_column.column = constant_node->getResultType()->createColumnConst(1, constant_node->getValue()); - argument_column.type = constant_node->getResultType(); - argument_is_constant = true; - } - else if (const auto * get_scalar_function_node = function_argument->as(); - get_scalar_function_node && get_scalar_function_node->getFunctionName() == "__getScalar") - { - /// Allow constant folding through getScalar - const auto * get_scalar_const_arg = get_scalar_function_node->getArguments().getNodes().at(0)->as(); - if (get_scalar_const_arg && scope.context->hasQueryContext()) - { - auto query_context = scope.context->getQueryContext(); - auto scalar_string = toString(get_scalar_const_arg->getValue()); - if (query_context->hasScalar(scalar_string)) - { - auto scalar = query_context->getScalar(scalar_string); - argument_column.column = ColumnConst::create(scalar.getByPosition(0).column, 1); - argument_column.type = get_scalar_function_node->getResultType(); - argument_is_constant = true; - } - } - } - - all_arguments_constants &= argument_is_constant; - - argument_types.push_back(argument_column.type); - argument_columns.emplace_back(std::move(argument_column)); - } - - /// Calculate function projection name - ProjectionNames result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - - /** Try to resolve function as - * 1. Lambda function in current scope. Example: WITH (x -> x + 1) AS lambda SELECT lambda(1); - * 2. Lambda function from sql user defined functions. - * 3. Special `untuple` function. - * 4. Special `grouping` function. - * 5. Window function. - * 6. Executable user defined function. - * 7. Ordinary function. - * 8. Aggregate function. - * - * TODO: Provide better error hints. - */ - if (!function_node.isWindowFunction()) - { - if (!lambda_expression_untyped) - lambda_expression_untyped = tryGetLambdaFromSQLUserDefinedFunctions(function_node.getFunctionName(), scope.context); - - /** If function is resolved as lambda. - * Clone lambda before resolve. - * Initialize lambda arguments as function arguments. - * Resolve lambda and then replace function node with resolved lambda expression body. - * Example: WITH (x -> x + 1) AS lambda SELECT lambda(value) FROM test_table; - * Result: SELECT value + 1 FROM test_table; - */ - if (lambda_expression_untyped) - { - auto * lambda_expression = lambda_expression_untyped->as(); - if (!lambda_expression) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function identifier '{}' must be resolved as lambda. Actual {}. In scope {}", - function_node.getFunctionName(), - lambda_expression_untyped->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - if (!parameters.empty()) - { - throw Exception( - ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_node.formatASTForErrorMessage()); - } - - auto lambda_expression_clone = lambda_expression_untyped->clone(); - - IdentifierResolveScope lambda_scope(lambda_expression_clone, &scope /*parent_scope*/); - ProjectionNames lambda_projection_names = resolveLambda(lambda_expression_untyped, lambda_expression_clone, function_arguments, lambda_scope); - - auto & resolved_lambda = lambda_expression_clone->as(); - node = resolved_lambda.getExpression(); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(lambda_projection_names); - - return result_projection_names; - } - - if (function_name == "untuple") - { - /// Special handling of `untuple` function - - if (function_arguments.size() != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' must have 1 argument. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - - checkFunctionNodeHasEmptyNullsAction(function_node); - - const auto & untuple_argument = function_arguments[0]; - /// Handle this special case first as `getResultType()` might return nullptr - if (untuple_argument->as()) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Function untuple can't have lambda-expressions as arguments"); - - auto result_type = untuple_argument->getResultType(); - const auto * tuple_data_type = typeid_cast(result_type.get()); - if (!tuple_data_type) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Function 'untuple' argument must have compound type. Actual type {}. In scope {}", - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & element_names = tuple_data_type->getElementNames(); - - auto result_list = std::make_shared(); - result_list->getNodes().reserve(element_names.size()); - - for (const auto & element_name : element_names) - { - auto tuple_element_function = std::make_shared("tupleElement"); - tuple_element_function->getArguments().getNodes().push_back(untuple_argument); - tuple_element_function->getArguments().getNodes().push_back(std::make_shared(element_name)); - - QueryTreeNodePtr function_query_node = tuple_element_function; - resolveFunction(function_query_node, scope); - - result_list->getNodes().push_back(std::move(function_query_node)); - } - - auto untuple_argument_projection_name = arguments_projection_names.at(0); - result_projection_names.clear(); - - for (const auto & element_name : element_names) - { - if (node->hasAlias()) - result_projection_names.push_back(node->getAlias() + '.' + element_name); - else - result_projection_names.push_back(fmt::format("tupleElement({}, '{}')", untuple_argument_projection_name, element_name)); - } - - node = std::move(result_list); - return result_projection_names; - } - else if (function_name == "grouping") - { - /// It is responsibility of planner to perform additional handling of grouping function - if (function_arguments_size == 0) - throw Exception(ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING expects at least one argument"); - else if (function_arguments_size > 64) - throw Exception(ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, - "Function GROUPING can have up to 64 arguments, but {} provided", - function_arguments_size); - checkFunctionNodeHasEmptyNullsAction(function_node); - - bool force_grouping_standard_compatibility = scope.context->getSettingsRef().force_grouping_standard_compatibility; - auto grouping_function = std::make_shared(force_grouping_standard_compatibility); - auto grouping_function_adaptor = std::make_shared(std::move(grouping_function)); - function_node.resolveAsFunction(grouping_function_adaptor->build(argument_columns)); - - return result_projection_names; - } - } - - if (function_node.isWindowFunction()) - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - throw Exception(ErrorCodes::UNKNOWN_AGGREGATE_FUNCTION, "Aggregate function with name '{}' does not exist. In scope {}{}", - function_name, scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(AggregateFunctionFactory::instance().getHints(function_name))); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Window function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsWindowFunction(std::move(aggregate_function)); - - bool window_node_is_identifier = function_node.getWindowNode()->getNodeType() == QueryTreeNodeType::IDENTIFIER; - ProjectionName window_projection_name = resolveWindow(function_node.getWindowNode(), scope); - - if (window_node_is_identifier) - result_projection_names[0] += " OVER " + window_projection_name; - else - result_projection_names[0] += " OVER (" + window_projection_name + ')'; - - return result_projection_names; - } - - FunctionOverloadResolverPtr function = UserDefinedExecutableFunctionFactory::instance().tryGet(function_name, scope.context, parameters); /// NOLINT(readability-static-accessed-through-instance) - bool is_executable_udf = true; - - IdentifierResolveScope::ResolvedFunctionsCache * function_cache = nullptr; - - if (!function) - { - /// This is a hack to allow a query like `select randConstant(), randConstant(), randConstant()`. - /// Function randConstant() would return the same value for the same arguments (in scope). - - auto hash = function_node_ptr->getTreeHash(); - function_cache = &scope.functions_cache[hash]; - if (!function_cache->resolver) - function_cache->resolver = FunctionFactory::instance().tryGet(function_name, scope.context); - - function = function_cache->resolver; - - is_executable_udf = false; - } - - if (function) - { - checkFunctionNodeHasEmptyNullsAction(function_node); - } - else - { - if (!AggregateFunctionFactory::instance().isAggregateFunctionName(function_name)) - { - std::vector possible_function_names; - - auto function_names = UserDefinedExecutableFunctionFactory::instance().getRegisteredNames(scope.context); /// NOLINT(readability-static-accessed-through-instance) - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = UserDefinedSQLFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = FunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - function_names = AggregateFunctionFactory::instance().getAllRegisteredNames(); - possible_function_names.insert(possible_function_names.end(), function_names.begin(), function_names.end()); - - for (auto & [name, lambda_node] : scope.aliases.alias_name_to_lambda_node) - { - if (lambda_node->getNodeType() == QueryTreeNodeType::LAMBDA) - possible_function_names.push_back(name); - } - - auto hints = NamePrompter<2>::getHints(function_name, possible_function_names); - - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Function with name '{}' does not exist. In scope {}{}", - function_name, - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - if (!function_lambda_arguments_indexes.empty()) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Aggregate function '{}' does not support lambda arguments", - function_name); - - auto action = function_node_ptr->getNullsAction(); - std::string aggregate_function_name = rewriteAggregateFunctionNameIfNeeded(function_name, action, scope.context); - - AggregateFunctionProperties properties; - auto aggregate_function - = AggregateFunctionFactory::instance().get(aggregate_function_name, action, argument_types, parameters, properties); - - function_node.resolveAsAggregateFunction(std::move(aggregate_function)); - - return result_projection_names; - } - - /// Executable UDFs may have parameters. They are checked in UserDefinedExecutableFunctionFactory. - if (!parameters.empty() && !is_executable_udf) - { - throw Exception(ErrorCodes::FUNCTION_CANNOT_HAVE_PARAMETERS, "Function {} is not parametric", function_name); - } - - /** For lambda arguments we need to initialize lambda argument types DataTypeFunction using `getLambdaArgumentTypes` function. - * Then each lambda arguments are initialized with columns, where column source is lambda. - * This information is important for later steps of query processing. - * Example: SELECT arrayMap(x -> x + 1, [1, 2, 3]). - * lambda node x -> x + 1 identifier x is resolved as column where source is lambda node. - */ - bool has_lambda_arguments = !function_lambda_arguments_indexes.empty(); - if (has_lambda_arguments) - { - function->getLambdaArgumentTypes(argument_types); - - ProjectionNames lambda_projection_names; - for (auto & function_lambda_argument_index : function_lambda_arguments_indexes) - { - auto & lambda_argument = function_arguments[function_lambda_argument_index]; - auto lambda_to_resolve = lambda_argument->clone(); - auto & lambda_to_resolve_typed = lambda_to_resolve->as(); - - const auto & lambda_argument_names = lambda_to_resolve_typed.getArgumentNames(); - size_t lambda_arguments_size = lambda_to_resolve_typed.getArguments().getNodes().size(); - - const auto * function_data_type = typeid_cast(argument_types[function_lambda_argument_index].get()); - if (!function_data_type) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}' expected function data type for lambda argument with index {}. Actual {}. In scope {}", - function_name, - function_lambda_argument_index, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - const auto & function_data_type_argument_types = function_data_type->getArgumentTypes(); - size_t function_data_type_arguments_size = function_data_type_argument_types.size(); - if (function_data_type_arguments_size != lambda_arguments_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Function '{}" - "' function data type for lambda argument with index {} arguments size mismatch. " - "Actual {}. Expected {}. In scope {}", - function_name, - function_data_type_arguments_size, - lambda_arguments_size, - argument_types[function_lambda_argument_index]->getName(), - scope.scope_node->formatASTForErrorMessage()); - - QueryTreeNodes lambda_arguments; - lambda_arguments.reserve(lambda_arguments_size); - - for (size_t i = 0; i < lambda_arguments_size; ++i) - { - const auto & argument_type = function_data_type_argument_types[i]; - auto column_name_and_type = NameAndTypePair{lambda_argument_names[i], argument_type}; - lambda_arguments.push_back(std::make_shared(std::move(column_name_and_type), lambda_to_resolve)); - } - - IdentifierResolveScope lambda_scope(lambda_to_resolve, &scope /*parent_scope*/); - lambda_projection_names = resolveLambda(lambda_argument, lambda_to_resolve, lambda_arguments, lambda_scope); - - if (auto * lambda_list_node_result = lambda_to_resolve_typed.getExpression()->as()) - { - size_t lambda_list_node_result_nodes_size = lambda_list_node_result->getNodes().size(); - - if (lambda_list_node_result_nodes_size != 1) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Lambda as function argument resolved as list node with size {}. Expected 1. In scope {}", - lambda_list_node_result_nodes_size, - lambda_to_resolve->formatASTForErrorMessage()); - - lambda_to_resolve_typed.getExpression() = lambda_list_node_result->getNodes().front(); - } - - if (arguments_projection_names.at(function_lambda_argument_index) == PROJECTION_NAME_PLACEHOLDER) - { - size_t lambda_projection_names_size =lambda_projection_names.size(); - if (lambda_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Lambda argument inside function expected to have 1 projection name. Actual {}", - lambda_projection_names_size); - - WriteBufferFromOwnString lambda_argument_projection_name_buffer; - lambda_argument_projection_name_buffer << "lambda("; - lambda_argument_projection_name_buffer << "tuple("; - - size_t lambda_argument_names_size = lambda_argument_names.size(); - - for (size_t i = 0; i < lambda_argument_names_size; ++i) - { - const auto & lambda_argument_name = lambda_argument_names[i]; - lambda_argument_projection_name_buffer << lambda_argument_name; - - if (i + 1 != lambda_argument_names_size) - lambda_argument_projection_name_buffer << ", "; - } - - lambda_argument_projection_name_buffer << "), "; - lambda_argument_projection_name_buffer << lambda_projection_names[0]; - lambda_argument_projection_name_buffer << ")"; - - lambda_projection_names.clear(); - - arguments_projection_names[function_lambda_argument_index] = lambda_argument_projection_name_buffer.str(); - } - - auto lambda_resolved_type = std::make_shared(function_data_type_argument_types, lambda_to_resolve_typed.getExpression()->getResultType()); - lambda_to_resolve_typed.resolve(lambda_resolved_type); - - argument_types[function_lambda_argument_index] = lambda_resolved_type; - argument_columns[function_lambda_argument_index].type = lambda_resolved_type; - function_arguments[function_lambda_argument_index] = std::move(lambda_to_resolve); - } - - /// Recalculate function projection name after lambda resolution - result_projection_names = { calculateFunctionProjectionName(node, parameters_projection_names, arguments_projection_names) }; - } - - /** Create SET column for special function IN to allow constant folding - * if left and right arguments are constants. - * - * Example: SELECT * FROM test_table LIMIT 1 IN 1; - */ - if (is_special_function_in) - { - const auto * first_argument_constant_node = function_arguments[0]->as(); - const auto * second_argument_constant_node = function_arguments[1]->as(); - - if (first_argument_constant_node && second_argument_constant_node) - { - const auto & first_argument_constant_type = first_argument_constant_node->getResultType(); - const auto & second_argument_constant_literal = second_argument_constant_node->getValue(); - const auto & second_argument_constant_type = second_argument_constant_node->getResultType(); - - const auto & settings = scope.context->getSettingsRef(); - - auto result_block = getSetElementsForConstantValue(first_argument_constant_type, - second_argument_constant_literal, - second_argument_constant_type, - settings.transform_null_in); - - SizeLimits size_limits_for_set = {settings.max_rows_in_set, settings.max_bytes_in_set, settings.set_overflow_mode}; - - auto set = std::make_shared(size_limits_for_set, 0, settings.transform_null_in); - - set->setHeader(result_block.cloneEmpty().getColumnsWithTypeAndName()); - set->insertFromBlock(result_block.getColumnsWithTypeAndName()); - set->finishInsert(); - - auto future_set = std::make_shared(std::move(set)); - - /// Create constant set column for constant folding - - auto column_set = ColumnSet::create(1, std::move(future_set)); - argument_columns[1].column = ColumnConst::create(std::move(column_set), 1); - } - - argument_columns[1].type = std::make_shared(); - } - - std::shared_ptr constant_value; - - try - { - FunctionBasePtr function_base; - if (function_cache) - { - auto & cached_function = function_cache->function_base; - if (!cached_function) - cached_function = function->build(argument_columns); - - function_base = cached_function; - } - else - function_base = function->build(argument_columns); - - /// Do not constant fold get scalar functions - bool disable_constant_folding = function_name == "__getScalar" || function_name == "shardNum" || - function_name == "shardCount" || function_name == "hostName" || function_name == "tcpPort"; - - /** If function is suitable for constant folding try to convert it to constant. - * Example: SELECT plus(1, 1); - * Result: SELECT 2; - */ - if (function_base->isSuitableForConstantFolding() && !disable_constant_folding) - { - auto result_type = function_base->getResultType(); - auto executable_function = function_base->prepare(argument_columns); - - ColumnPtr column; - - if (all_arguments_constants) - { - size_t num_rows = function_arguments.empty() ? 0 : argument_columns.front().column->size(); - column = executable_function->execute(argument_columns, result_type, num_rows, true); - } - else - { - column = function_base->getConstantResultForNonConstArguments(argument_columns, result_type); - } - - if (column && column->getDataType() != result_type->getColumnType()) - throw Exception( - ErrorCodes::LOGICAL_ERROR, - "Unexpected return type from {}. Expected {}. Got {}", - function->getName(), - result_type->getColumnType(), - column->getDataType()); - - /** Do not perform constant folding if there are aggregate or arrayJoin functions inside function. - * Example: SELECT toTypeName(sum(number)) FROM numbers(10); - */ - if (column && isColumnConst(*column) && !typeid_cast(column.get())->getDataColumn().isDummy() && - !hasAggregateFunctionNodes(node) && !hasFunctionNode(node, "arrayJoin") && - /// Sanity check: do not convert large columns to constants - column->byteSize() < 1_MiB) - { - /// Replace function node with result constant node - Field column_constant_value; - column->get(0, column_constant_value); - constant_value = std::make_shared(std::move(column_constant_value), result_type); - } - } - - function_node.resolveAsFunction(std::move(function_base)); - } - catch (Exception & e) - { - e.addMessage("In scope {}", scope.scope_node->formatASTForErrorMessage()); - throw; - } - - if (constant_value) - node = std::make_shared(std::move(constant_value), node); - - return result_projection_names; -} - -/** Resolve expression node. - * Argument node can be replaced with different node, or even with list node in case of matcher resolution. - * Example: SELECT * FROM test_table; - * * - is matcher node, and it can be resolved into ListNode. - * - * Steps: - * 1. If node has alias, replace node with its value in scope alias map. Register alias in expression_aliases_in_resolve_process, to prevent resolving identifier - * which can bind to expression alias name. Check tryResolveIdentifierFromAliases documentation for additional explanation. - * Example: - * SELECT id AS id FROM test_table; - * SELECT value.value1 AS value FROM test_table; - * - * 2. Call specific resolve method depending on node type. - * - * If allow_table_expression = true and node is query node, then it is not evaluated as scalar subquery. - * Although if node is identifier that is resolved into query node that query is evaluated as scalar subquery. - * SELECT id, (SELECT 1) AS c FROM test_table WHERE a IN c; - * SELECT id, FROM test_table WHERE a IN (SELECT 1); - * - * 3. Special case identifier node. - * Try resolve it as expression identifier. - * Then if allow_lambda_expression = true try to resolve it as function. - * Then if allow_table_expression = true try to resolve it as table expression. - * - * 4. If node has alias, update its value in scope alias map. Deregister alias from expression_aliases_in_resolve_process. - */ -ProjectionNames QueryAnalyzer::resolveExpressionNode(QueryTreeNodePtr & node, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression, bool ignore_alias) -{ - checkStackSize(); - - auto resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - { - /** There can be edge case, when subquery for IN function is resolved multiple times in different context. - * SELECT id IN (subquery AS value), value FROM test_table; - * When we start to resolve `value` identifier, subquery is already resolved but constant folding is not performed. - */ - auto node_type = node->getNodeType(); - if (!allow_table_expression && (node_type == QueryTreeNodeType::QUERY || node_type == QueryTreeNodeType::UNION)) - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - } - - return resolved_expression_it->second; - } - - String node_alias = node->getAlias(); - ProjectionNames result_projection_names; - - if (node_alias.empty()) - { - auto projection_name_it = node_to_projection_name.find(node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - else - { - result_projection_names.push_back(node_alias); - } - - bool is_duplicated_alias = scope.aliases.nodes_with_duplicated_aliases.contains(node); - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.insert({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - /** Do not use alias table if node has alias same as some other node. - * Example: WITH x -> x + 1 AS lambda SELECT 1 AS lambda; - * During 1 AS lambda resolve if we use alias table we replace node with x -> x + 1 AS lambda. - * - * Do not use alias table if allow_table_expression = true and we resolve query node directly. - * Example: SELECT a FROM test_table WHERE id IN (SELECT 1) AS a; - * To support both (SELECT 1) AS expression in projection and (SELECT 1) as subquery in IN, do not use - * alias table because in alias table subquery could be evaluated as scalar. - */ - bool use_alias_table = !ignore_alias; - if (is_duplicated_alias || (allow_table_expression && isSubqueryNodeType(node->getNodeType()))) - use_alias_table = false; - - if (!node_alias.empty() && use_alias_table) - { - /** Node could be potentially resolved by resolving other nodes. - * SELECT b, a as b FROM test_table; - * - * To resolve b we need to resolve a. - */ - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - node = it->second; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - node = it->second; - } - } - - scope.pushExpressionNode(node); - - auto node_type = node->getNodeType(); - - switch (node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & identifier_node = node->as(); - auto unresolved_identifier = identifier_node.getIdentifier(); - auto resolve_identifier_expression_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier_node = resolve_identifier_expression_result.resolved_identifier; - - if (resolved_identifier_node && result_projection_names.empty() && - (resolve_identifier_expression_result.isResolvedFromJoinTree() || resolve_identifier_expression_result.isResolvedFromExpressionArguments())) - { - auto projection_name_it = node_to_projection_name.find(resolved_identifier_node); - if (projection_name_it != node_to_projection_name.end()) - result_projection_names.push_back(projection_name_it->second); - } - - if (!resolved_identifier_node && allow_lambda_expression) - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::FUNCTION}, scope).resolved_identifier; - - if (!resolved_identifier_node && allow_table_expression) - { - resolved_identifier_node = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::TABLE_EXPRESSION}, scope).resolved_identifier; - - if (resolved_identifier_node) - { - /// If table identifier is resolved as CTE clone it and resolve - auto * subquery_node = resolved_identifier_node->as(); - auto * union_node = resolved_identifier_node->as(); - bool resolved_as_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - - if (resolved_as_cte) - { - resolved_identifier_node = resolved_identifier_node->clone(); - subquery_node = resolved_identifier_node->as(); - union_node = resolved_identifier_node->as(); - - std::string_view cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - if (subquery_node) - subquery_node->setIsCTE(false); - else - union_node->setIsCTE(false); - - IdentifierResolveScope subquery_scope(resolved_identifier_node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - /// CTE is being resolved, it's required to forbid to resolve to it again - /// because recursive CTEs are not supported, e.g.: - /// - /// WITH test1 AS (SELECT i + 1, j + 1 FROM test1) SELECT toInt64(4) i, toInt64(5) j FROM numbers(3) WHERE (i, j) IN test1; - /// - /// In this example argument of function `in` is being resolve here. If CTE `test1` is not forbidden, - /// `test1` is resolved to CTE (not to the table) in `initializeQueryJoinTreeNode` function. - ctes_in_resolve_process.insert(cte_name); - - if (subquery_node) - resolveQuery(resolved_identifier_node, subquery_scope); - else - resolveUnion(resolved_identifier_node, subquery_scope); - - ctes_in_resolve_process.erase(cte_name); - } - } - } - - if (!resolved_identifier_node) - { - std::string message_clarification; - if (allow_lambda_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::FUNCTION); - - if (allow_table_expression) - message_clarification = std::string(" or ") + toStringLowercase(IdentifierLookupContext::TABLE_EXPRESSION); - - std::unordered_set valid_identifiers; - collectScopeWithParentScopesValidIdentifiersForTypoCorrection(unresolved_identifier, - scope, - true, - allow_lambda_expression, - allow_table_expression, - valid_identifiers); - - auto hints = collectIdentifierTypoHints(unresolved_identifier, valid_identifiers); - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, "Unknown {}{} identifier '{}' in scope {}{}", - toStringLowercase(IdentifierLookupContext::EXPRESSION), - message_clarification, - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage(), - getHintsErrorMessageSuffix(hints)); - } - - node = std::move(resolved_identifier_node); - - if (node->getNodeType() == QueryTreeNodeType::LIST) - { - result_projection_names.clear(); - resolved_expression_it = resolved_expressions.find(node); - if (resolved_expression_it != resolved_expressions.end()) - return resolved_expression_it->second; - else - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier '{}' resolve into list node and list node projection names are not initialized. In scope {}", - unresolved_identifier.getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_projection_names.empty()) - result_projection_names.push_back(unresolved_identifier.getFullName()); - - break; - } - case QueryTreeNodeType::MATCHER: - { - result_projection_names = resolveMatcher(node, scope); - break; - } - case QueryTreeNodeType::LIST: - { - /** Edge case if list expression has alias. - * Matchers cannot have aliases, but `untuple` function can. - * Example: SELECT a, untuple(CAST(('hello', 1) AS Tuple(name String, count UInt32))) AS a; - * During resolveFunction `untuple` function is replaced by list of 2 constants 'hello', 1. - */ - result_projection_names = resolveExpressionNodeList(node, scope, allow_lambda_expression, allow_lambda_expression); - break; - } - case QueryTreeNodeType::CONSTANT: - { - if (result_projection_names.empty()) - { - const auto & constant_node = node->as(); - result_projection_names.push_back(constant_node.getValueStringRepresentation()); - } - - /// Already resolved - break; - } - case QueryTreeNodeType::COLUMN: - { - auto & column_node = node->as(); - if (column_node.hasExpression()) - resolveExpressionNode(column_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (result_projection_names.empty()) - result_projection_names.push_back(column_node.getColumnName()); - - break; - } - case QueryTreeNodeType::FUNCTION: - { - auto function_projection_names = resolveFunction(node, scope); - - if (result_projection_names.empty() || node->getNodeType() == QueryTreeNodeType::LIST) - result_projection_names = std::move(function_projection_names); - - break; - } - case QueryTreeNodeType::LAMBDA: - { - if (!allow_lambda_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Lambda {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - if (result_projection_names.empty()) - result_projection_names.push_back(PROJECTION_NAME_PLACEHOLDER); - - /// Lambda must be resolved by caller - break; - } - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - IdentifierResolveScope subquery_scope(node, &scope /*parent_scope*/); - subquery_scope.subquery_depth = scope.subquery_depth + 1; - - std::string projection_name = "_subquery_" + std::to_string(subquery_counter); - ++subquery_counter; - - if (node_type == QueryTreeNodeType::QUERY) - resolveQuery(node, subquery_scope); - else - resolveUnion(node, subquery_scope); - - if (!allow_table_expression) - evaluateScalarSubqueryIfNeeded(node, subquery_scope); - - if (result_projection_names.empty()) - result_projection_names.push_back(std::move(projection_name)); - - break; - } - case QueryTreeNodeType::TABLE: - { - if (!allow_table_expression) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Table {} is not allowed in expression context. In scope {}", - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto & table_node = node->as(); - result_projection_names.push_back(table_node.getStorageID().getFullNameNotQuoted()); - - break; - } - case QueryTreeNodeType::TRANSFORMER: - [[fallthrough]]; - case QueryTreeNodeType::SORT: - [[fallthrough]]; - case QueryTreeNodeType::INTERPOLATE: - [[fallthrough]]; - case QueryTreeNodeType::WINDOW: - [[fallthrough]]; - case QueryTreeNodeType::TABLE_FUNCTION: - [[fallthrough]]; - case QueryTreeNodeType::ARRAY_JOIN: - [[fallthrough]]; - case QueryTreeNodeType::JOIN: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "{} {} is not allowed in expression context. In scope {}", - node->getNodeType(), - node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - validateTreeSize(node, scope.context->getSettingsRef().max_expanded_ast_elements, node_to_tree_size); - - /// Lambda can be inside the aggregate function, so we should check parent scopes. - /// Most likely only the root scope can have an arrgegate function, but let's check all just in case. - bool in_aggregate_function_scope = false; - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - in_aggregate_function_scope = in_aggregate_function_scope || scope_ptr->expressions_in_resolve_process_stack.hasAggregateFunction(); - - if (!in_aggregate_function_scope) - { - for (const auto * scope_ptr = &scope; scope_ptr; scope_ptr = scope_ptr->parent_scope) - { - auto it = scope_ptr->nullable_group_by_keys.find(node); - if (it != scope_ptr->nullable_group_by_keys.end()) - { - node = it->node->clone(); - node->convertToNullable(); - break; - } - } - } - - /** Update aliases after expression node was resolved. - * Do not update node in alias table if we resolve it for duplicate alias. - */ - if (!node_alias.empty() && use_alias_table && !scope.group_by_use_nulls) - { - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - it->second = node; - - if (allow_lambda_expression) - { - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - it->second = node; - } - } - - if (is_duplicated_alias) - scope.non_cached_identifier_lookups_during_expression_resolve.erase({Identifier{node_alias}, IdentifierLookupContext::EXPRESSION}); - - if (!ignore_alias) - resolved_expressions.emplace(node, result_projection_names); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - return result_projection_names; -} - -/** Resolve expression node list. - * If expression is CTE subquery node it is skipped. - * If expression is resolved in list, it is flattened into initial node list. - * - * Such examples must work: - * Example: CREATE TABLE test_table (id UInt64, value UInt64) ENGINE=TinyLog; SELECT plus(*) FROM test_table; - * Example: SELECT *** FROM system.one; - */ -ProjectionNames QueryAnalyzer::resolveExpressionNodeList(QueryTreeNodePtr & node_list, IdentifierResolveScope & scope, bool allow_lambda_expression, bool allow_table_expression) -{ - auto & node_list_typed = node_list->as(); - size_t node_list_size = node_list_typed.getNodes().size(); - - QueryTreeNodes result_nodes; - result_nodes.reserve(node_list_size); - - ProjectionNames result_projection_names; - - for (auto & node : node_list_typed.getNodes()) - { - auto node_to_resolve = node; - auto expression_node_projection_names = resolveExpressionNode(node_to_resolve, scope, allow_lambda_expression, allow_table_expression); - size_t expected_projection_names_size = 1; - if (auto * expression_list = node_to_resolve->as()) - { - expected_projection_names_size = expression_list->getNodes().size(); - for (auto & expression_list_node : expression_list->getNodes()) - result_nodes.push_back(expression_list_node); - } - else - { - result_nodes.push_back(std::move(node_to_resolve)); - } - - if (expression_node_projection_names.size() != expected_projection_names_size) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Expression nodes list expected {} projection names. Actual {}", - expected_projection_names_size, - expression_node_projection_names.size()); - - result_projection_names.insert(result_projection_names.end(), expression_node_projection_names.begin(), expression_node_projection_names.end()); - expression_node_projection_names.clear(); - } - - node_list_typed.getNodes() = std::move(result_nodes); - - return result_projection_names; -} - -/** Resolve sort columns nodes list. - */ -ProjectionNames QueryAnalyzer::resolveSortNodeList(QueryTreeNodePtr & sort_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames result_projection_names; - ProjectionNames sort_expression_projection_names; - ProjectionNames fill_from_expression_projection_names; - ProjectionNames fill_to_expression_projection_names; - ProjectionNames fill_step_expression_projection_names; - - auto & sort_node_list_typed = sort_node_list->as(); - for (auto & node : sort_node_list_typed.getNodes()) - { - auto & sort_node = node->as(); - sort_expression_projection_names = resolveExpressionNode(sort_node.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (auto * sort_column_list_node = sort_node.getExpression()->as()) - { - size_t sort_column_list_node_size = sort_column_list_node->getNodes().size(); - if (sort_column_list_node_size != 1) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Sort column node expression resolved into list with size {}. Expected 1. In scope {}", - sort_column_list_node_size, - scope.scope_node->formatASTForErrorMessage()); - } - - sort_node.getExpression() = sort_column_list_node->getNodes().front(); - } - - size_t sort_expression_projection_names_size = sort_expression_projection_names.size(); - if (sort_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort expression expected 1 projection name. Actual {}", - sort_expression_projection_names_size); - - if (sort_node.hasFillFrom()) - { - fill_from_expression_projection_names = resolveExpressionNode(sort_node.getFillFrom(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillFrom()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL FROM expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_from_expression_projection_names_size = fill_from_expression_projection_names.size(); - if (fill_from_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL FROM expression expected 1 projection name. Actual {}", - fill_from_expression_projection_names_size); - } - - if (sort_node.hasFillTo()) - { - fill_to_expression_projection_names = resolveExpressionNode(sort_node.getFillTo(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillTo()->as(); - if (!constant_node || !isColumnedAsNumber(constant_node->getResultType())) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL TO expression must be constant with numeric type. Actual {}. In scope {}", - sort_node.getFillFrom()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_to_expression_projection_names_size = fill_to_expression_projection_names.size(); - if (fill_to_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort node FILL TO expression expected 1 projection name. Actual {}", - fill_to_expression_projection_names_size); - } - - if (sort_node.hasFillStep()) - { - fill_step_expression_projection_names = resolveExpressionNode(sort_node.getFillStep(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - const auto * constant_node = sort_node.getFillStep()->as(); - if (!constant_node) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - bool is_number = isColumnedAsNumber(constant_node->getResultType()); - bool is_interval = WhichDataType(constant_node->getResultType()).isInterval(); - if (!is_number && !is_interval) - throw Exception(ErrorCodes::INVALID_WITH_FILL_EXPRESSION, - "Sort FILL STEP expression must be constant with numeric or interval type. Actual {}. In scope {}", - sort_node.getFillStep()->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - size_t fill_step_expression_projection_names_size = fill_step_expression_projection_names.size(); - if (fill_step_expression_projection_names_size != 1) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Sort FILL STEP expression expected 1 projection name. Actual {}", - fill_step_expression_projection_names_size); - } - - auto sort_column_projection_name = calculateSortColumnProjectionName(node, - sort_expression_projection_names[0], - fill_from_expression_projection_names.empty() ? "" : fill_from_expression_projection_names.front(), - fill_to_expression_projection_names.empty() ? "" : fill_to_expression_projection_names.front(), - fill_step_expression_projection_names.empty() ? "" : fill_step_expression_projection_names.front()); - - result_projection_names.push_back(std::move(sort_column_projection_name)); - - sort_expression_projection_names.clear(); - fill_from_expression_projection_names.clear(); - fill_to_expression_projection_names.clear(); - fill_step_expression_projection_names.clear(); - } - - return result_projection_names; -} - -namespace -{ - -void expandTuplesInList(QueryTreeNodes & key_list) -{ - QueryTreeNodes expanded_keys; - expanded_keys.reserve(key_list.size()); - for (auto const & key : key_list) - { - if (auto * function = key->as(); function != nullptr && function->getFunctionName() == "tuple") - { - std::copy(function->getArguments().begin(), function->getArguments().end(), std::back_inserter(expanded_keys)); - } - else - expanded_keys.push_back(key); - } - key_list = std::move(expanded_keys); -} - -} - -/** Resolve GROUP BY clause. - */ -void QueryAnalyzer::resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope) -{ - if (query_node_typed.isGroupByWithGroupingSets()) - { - for (auto & grouping_sets_keys_list_node : query_node_typed.getGroupBy().getNodes()) - { - replaceNodesWithPositionalArguments(grouping_sets_keys_list_node, query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(grouping_sets_keys_list_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = grouping_sets_keys_list_node->as().getNodes(); - expandTuplesInList(group_by_list); - } - - if (scope.group_by_use_nulls) - { - for (const auto & grouping_set : query_node_typed.getGroupBy().getNodes()) - { - for (const auto & group_by_elem : grouping_set->as()->getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } - } - else - { - replaceNodesWithPositionalArguments(query_node_typed.getGroupByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getGroupByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. - // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) - auto & group_by_list = query_node_typed.getGroupBy().getNodes(); - expandTuplesInList(group_by_list); - - if (scope.group_by_use_nulls) - { - for (const auto & group_by_elem : query_node_typed.getGroupBy().getNodes()) - scope.nullable_group_by_keys.insert(group_by_elem); - } - } -} - -/** Resolve interpolate columns nodes list. - */ -void QueryAnalyzer::resolveInterpolateColumnsNodeList(QueryTreeNodePtr & interpolate_node_list, IdentifierResolveScope & scope) -{ - auto & interpolate_node_list_typed = interpolate_node_list->as(); - - for (auto & interpolate_node : interpolate_node_list_typed.getNodes()) - { - auto & interpolate_node_typed = interpolate_node->as(); - - auto * column_to_interpolate = interpolate_node_typed.getExpression()->as(); - if (!column_to_interpolate) - throw Exception(ErrorCodes::LOGICAL_ERROR, "INTERPOLATE can work only for indentifiers, but {} is found", - interpolate_node_typed.getExpression()->formatASTForErrorMessage()); - auto column_to_interpolate_name = column_to_interpolate->getIdentifier().getFullName(); - - resolveExpressionNode(interpolate_node_typed.getExpression(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool is_column_constant = interpolate_node_typed.getExpression()->getNodeType() == QueryTreeNodeType::CONSTANT; - - auto & interpolation_to_resolve = interpolate_node_typed.getInterpolateExpression(); - IdentifierResolveScope interpolate_scope(interpolation_to_resolve, &scope /*parent_scope*/); - - auto fake_column_node = std::make_shared(NameAndTypePair(column_to_interpolate_name, interpolate_node_typed.getExpression()->getResultType()), interpolate_node_typed.getExpression()); - if (is_column_constant) - interpolate_scope.expression_argument_name_to_node.emplace(column_to_interpolate_name, fake_column_node); - - resolveExpressionNode(interpolation_to_resolve, interpolate_scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (is_column_constant) - interpolation_to_resolve = interpolation_to_resolve->cloneAndReplace(fake_column_node, interpolate_node_typed.getExpression()); - } -} - -/** Resolve window nodes list. - */ -void QueryAnalyzer::resolveWindowNodeList(QueryTreeNodePtr & window_node_list, IdentifierResolveScope & scope) -{ - auto & window_node_list_typed = window_node_list->as(); - for (auto & node : window_node_list_typed.getNodes()) - resolveWindow(node, scope); -} - -NamesAndTypes QueryAnalyzer::resolveProjectionExpressionNodeList(QueryTreeNodePtr & projection_node_list, IdentifierResolveScope & scope) -{ - ProjectionNames projection_names = resolveExpressionNodeList(projection_node_list, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - auto projection_nodes = projection_node_list->as().getNodes(); - size_t projection_nodes_size = projection_nodes.size(); - - NamesAndTypes projection_columns; - projection_columns.reserve(projection_nodes_size); - - for (size_t i = 0; i < projection_nodes_size; ++i) - { - auto projection_node = projection_nodes[i]; - - if (!isExpressionNodeType(projection_node->getNodeType())) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Projection node must be constant, function, column, query or union"); - - projection_columns.emplace_back(projection_names[i], projection_node->getResultType()); - } - - return projection_columns; -} - -/** Initialize query join tree node. - * - * 1. Resolve identifiers. - * 2. Register table, table function, query, union, join, array join nodes in scope table expressions in resolve process. - */ -void QueryAnalyzer::initializeQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope) -{ - std::deque join_tree_node_ptrs_to_process_queue; - join_tree_node_ptrs_to_process_queue.push_back(&join_tree_node); - - while (!join_tree_node_ptrs_to_process_queue.empty()) - { - auto * current_join_tree_node_ptr = join_tree_node_ptrs_to_process_queue.front(); - join_tree_node_ptrs_to_process_queue.pop_front(); - - auto & current_join_tree_node = *current_join_tree_node_ptr; - auto current_join_tree_node_type = current_join_tree_node->getNodeType(); - - switch (current_join_tree_node_type) - { - case QueryTreeNodeType::IDENTIFIER: - { - auto & from_table_identifier = current_join_tree_node->as(); - auto table_identifier_lookup = IdentifierLookup{from_table_identifier.getIdentifier(), IdentifierLookupContext::TABLE_EXPRESSION}; - - auto from_table_identifier_alias = from_table_identifier.getAlias(); - - IdentifierResolveSettings resolve_settings; - /// In join tree initialization ignore join tree as identifier lookup source - resolve_settings.allow_to_check_join_tree = false; - /** Disable resolve of subquery during identifier resolution. - * Example: SELECT * FROM (SELECT 1) AS t1, t1; - * During `t1` identifier resolution we resolve it into subquery SELECT 1, but we want to disable - * subquery resolution at this stage, because JOIN TREE of parent query is not resolved. - */ - resolve_settings.allow_to_resolve_subquery_during_identifier_resolution = false; - - scope.pushExpressionNode(current_join_tree_node); - - auto table_identifier_resolve_result = tryResolveIdentifier(table_identifier_lookup, scope, resolve_settings); - - scope.popExpressionNode(); - bool expression_was_root = scope.expressions_in_resolve_process_stack.empty(); - if (expression_was_root) - scope.non_cached_identifier_lookups_during_expression_resolve.clear(); - - auto resolved_identifier = table_identifier_resolve_result.resolved_identifier; - - if (!resolved_identifier) - throw Exception(ErrorCodes::UNKNOWN_TABLE, - "Unknown table expression identifier '{}' in scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - - resolved_identifier = resolved_identifier->clone(); - - /// Update alias name to table expression map - auto table_expression_it = scope.aliases.alias_name_to_table_expression_node.find(from_table_identifier_alias); - if (table_expression_it != scope.aliases.alias_name_to_table_expression_node.end()) - table_expression_it->second = resolved_identifier; - - auto table_expression_modifiers = from_table_identifier.getTableExpressionModifiers(); - - auto * resolved_identifier_query_node = resolved_identifier->as(); - auto * resolved_identifier_union_node = resolved_identifier->as(); - - if (resolved_identifier_query_node || resolved_identifier_union_node) - { - if (table_expression_modifiers.has_value()) - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Table expression modifiers {} are not supported for subquery {}", - table_expression_modifiers->formatForErrorMessage(), - resolved_identifier->formatASTForErrorMessage()); - } - } - else if (auto * resolved_identifier_table_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else if (auto * resolved_identifier_table_function_node = resolved_identifier->as()) - { - if (table_expression_modifiers.has_value()) - resolved_identifier_table_function_node->setTableExpressionModifiers(*table_expression_modifiers); - } - else - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifier in JOIN TREE '{}' resolved into unexpected table expression. In scope {}", - from_table_identifier.getIdentifier().getFullName(), - scope.scope_node->formatASTForErrorMessage()); - } - - auto current_join_tree_node_alias = current_join_tree_node->getAlias(); - resolved_identifier->setAlias(current_join_tree_node_alias); - current_join_tree_node = resolved_identifier; - - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::QUERY: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::UNION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::TABLE: - { - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - auto & array_join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&array_join.getTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - break; - } - case QueryTreeNodeType::JOIN: - { - auto & join = current_join_tree_node->as(); - join_tree_node_ptrs_to_process_queue.push_back(&join.getLeftTableExpression()); - join_tree_node_ptrs_to_process_queue.push_back(&join.getRightTableExpression()); - scope.table_expressions_in_resolve_process.insert(current_join_tree_node.get()); - ++scope.joins_count; - break; - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, UNION, ARRAY JOIN or JOIN. Actual {} {}. In scope {}", - current_join_tree_node->getNodeTypeName(), - current_join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - } -} - -/// Initialize table expression data for table expression node -void QueryAnalyzer::initializeTableExpressionData(const QueryTreeNodePtr & table_expression_node, IdentifierResolveScope & scope) -{ - auto * table_node = table_expression_node->as(); - auto * query_node = table_expression_node->as(); - auto * union_node = table_expression_node->as(); - auto * table_function_node = table_expression_node->as(); - - if (!table_node && !table_function_node && !query_node && !union_node) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Unexpected table expression. Expected table, table function, query or union node. Actual {}. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - - auto table_expression_data_it = scope.table_expression_node_to_data.find(table_expression_node); - if (table_expression_data_it != scope.table_expression_node_to_data.end()) - return; - - TableExpressionData table_expression_data; - - if (table_node) - { - if (!table_node->getTemporaryTableName().empty()) - { - table_expression_data.table_name = table_node->getTemporaryTableName(); - table_expression_data.table_expression_name = table_node->getTemporaryTableName(); - } - else - { - const auto & table_storage_id = table_node->getStorageID(); - table_expression_data.database_name = table_storage_id.database_name; - table_expression_data.table_name = table_storage_id.table_name; - table_expression_data.table_expression_name = table_storage_id.getFullNameNotQuoted(); - } - - table_expression_data.table_expression_description = "table"; - } - else if (query_node || union_node) - { - table_expression_data.table_name = query_node ? query_node->getCTEName() : union_node->getCTEName(); - table_expression_data.table_expression_description = "subquery"; - } - else if (table_function_node) - { - table_expression_data.table_expression_description = "table_function"; - } - - if (table_expression_node->hasAlias()) - table_expression_data.table_expression_name = table_expression_node->getAlias(); - - if (table_node || table_function_node) - { - const auto & storage_snapshot = table_node ? table_node->getStorageSnapshot() : table_function_node->getStorageSnapshot(); - - auto get_column_options = GetColumnsOptions(GetColumnsOptions::All).withExtendedObjects().withVirtuals(); - if (storage_snapshot->storage.supportsSubcolumns()) - get_column_options.withSubcolumns(); - - auto column_names_and_types = storage_snapshot->getColumns(get_column_options); - table_expression_data.column_names_and_types = NamesAndTypes(column_names_and_types.begin(), column_names_and_types.end()); - - const auto & columns_description = storage_snapshot->metadata->getColumns(); - - std::vector> alias_columns_to_resolve; - ColumnNameToColumnNodeMap column_name_to_column_node; - column_name_to_column_node.reserve(column_names_and_types.size()); - - /** For ALIAS columns in table we must additionally analyze ALIAS expressions. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + 5); - * - * To do that we collect alias columns and build table column name to column node map. - * For each alias column we build identifier resolve scope, initialize it with table column name to node map - * and resolve alias column. - */ - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - for (const auto & subcolumn : columns_description.getSubcolumns(column_name_and_type.name)) - table_expression_data.subcolumn_names.insert(subcolumn.name); - const auto & column_default = columns_description.getDefault(column_name_and_type.name); - - if (column_default && column_default->kind == ColumnDefaultKind::Alias) - { - auto alias_expression = buildQueryTree(column_default->expression, scope.context); - auto column_node = std::make_shared(column_name_and_type, std::move(alias_expression), table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - alias_columns_to_resolve.emplace_back(column_name_and_type.name, column_node); - } - else - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - for (auto & [alias_column_to_resolve_name, alias_column_to_resolve] : alias_columns_to_resolve) - { - /** Alias column could be potentially resolved during resolve of other ALIAS column. - * Example: CREATE TABLE test_table (id UInt64, alias_value_1 ALIAS id + alias_value_2, alias_value_2 ALIAS id + 5) ENGINE=TinyLog; - * - * During resolve of alias_value_1, alias_value_2 column will be resolved. - */ - alias_column_to_resolve = column_name_to_column_node[alias_column_to_resolve_name]; - - IdentifierResolveScope alias_column_resolve_scope(alias_column_to_resolve, nullptr /*parent_scope*/); - alias_column_resolve_scope.column_name_to_column_node = std::move(column_name_to_column_node); - alias_column_resolve_scope.context = scope.context; - - /// Initialize aliases in alias column scope - QueryExpressionsAliasVisitor visitor(alias_column_resolve_scope.aliases); - visitor.visit(alias_column_to_resolve->getExpression()); - - resolveExpressionNode(alias_column_resolve_scope.scope_node, - alias_column_resolve_scope, - false /*allow_lambda_expression*/, - false /*allow_table_expression*/); - auto & resolved_expression = alias_column_to_resolve->getExpression(); - if (!resolved_expression->getResultType()->equals(*alias_column_to_resolve->getResultType())) - resolved_expression = buildCastFunction(resolved_expression, alias_column_to_resolve->getResultType(), scope.context, true); - column_name_to_column_node = std::move(alias_column_resolve_scope.column_name_to_column_node); - column_name_to_column_node[alias_column_to_resolve_name] = alias_column_to_resolve; - } - - table_expression_data.column_name_to_column_node = std::move(column_name_to_column_node); - } - else if (query_node || union_node) - { - table_expression_data.column_names_and_types = query_node ? query_node->getProjectionColumns() : union_node->computeProjectionColumns(); - table_expression_data.column_name_to_column_node.reserve(table_expression_data.column_names_and_types.size()); - - for (const auto & column_name_and_type : table_expression_data.column_names_and_types) - { - auto column_node = std::make_shared(column_name_and_type, table_expression_node); - table_expression_data.column_name_to_column_node.emplace(column_name_and_type.name, column_node); - } - } - - table_expression_data.column_identifier_first_parts.reserve(table_expression_data.column_name_to_column_node.size()); - - for (auto & [column_name, _] : table_expression_data.column_name_to_column_node) - { - Identifier column_name_identifier(column_name); - table_expression_data.column_identifier_first_parts.insert(column_name_identifier.at(0)); - } - - if (auto * scope_query_node = scope.scope_node->as()) - { - auto left_table_expression = extractLeftTableExpression(scope_query_node->getJoinTree()); - if (table_expression_node.get() == left_table_expression.get() && - scope.joins_count == 1 && - scope.context->getSettingsRef().single_join_prefer_left_table) - table_expression_data.should_qualify_columns = false; - } - - scope.table_expression_node_to_data.emplace(table_expression_node, std::move(table_expression_data)); -} - -bool findIdentifier(const FunctionNode & function) -{ - for (const auto & argument : function.getArguments()) - { - if (argument->as()) - return true; - if (const auto * f = argument->as(); f && findIdentifier(*f)) - return true; - } - return false; -} - -/// Resolve table function node in scope -void QueryAnalyzer::resolveTableFunction(QueryTreeNodePtr & table_function_node, - IdentifierResolveScope & scope, - QueryExpressionsAliasVisitor & expressions_visitor, - bool nested_table_function) -{ - auto & table_function_node_typed = table_function_node->as(); - - if (!nested_table_function) - expressions_visitor.visit(table_function_node_typed.getArgumentsNode()); - - const auto & table_function_name = table_function_node_typed.getTableFunctionName(); - - auto & scope_context = scope.context; - - TableFunctionPtr table_function_ptr = TableFunctionFactory::instance().tryGet(table_function_name, scope_context); - if (!table_function_ptr) - { - String database_name = scope_context->getCurrentDatabase(); - String table_name; - - auto function_ast = table_function_node->toAST(); - Identifier table_identifier{table_function_name}; - if (table_identifier.getPartsSize() == 1) - { - table_name = table_identifier[0]; - } - else if (table_identifier.getPartsSize() == 2) - { - database_name = table_identifier[0]; - table_name = table_identifier[1]; - } - - auto parametrized_view_storage = scope_context->getQueryContext()->buildParametrizedViewStorage(function_ast, database_name, table_name); - if (parametrized_view_storage) - { - auto fake_table_node = std::make_shared(parametrized_view_storage, scope_context); - fake_table_node->setAlias(table_function_node->getAlias()); - table_function_node = fake_table_node; - return; - } - - auto hints = TableFunctionFactory::instance().getHints(table_function_name); - if (!hints.empty()) - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}. Maybe you meant: {}", - table_function_name, - DB::toString(hints)); - else - throw Exception(ErrorCodes::UNKNOWN_FUNCTION, - "Unknown table function {}", - table_function_name); - } - - QueryTreeNodes result_table_function_arguments; - - auto skip_analysis_arguments_indexes = table_function_ptr->skipAnalysisForArguments(table_function_node, scope_context); - - auto & table_function_arguments = table_function_node_typed.getArguments().getNodes(); - size_t table_function_arguments_size = table_function_arguments.size(); - - for (size_t table_function_argument_index = 0; table_function_argument_index < table_function_arguments_size; ++table_function_argument_index) - { - auto & table_function_argument = table_function_arguments[table_function_argument_index]; - - auto skip_argument_index_it = std::find(skip_analysis_arguments_indexes.begin(), - skip_analysis_arguments_indexes.end(), - table_function_argument_index); - if (skip_argument_index_it != skip_analysis_arguments_indexes.end()) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - if (auto * identifier_node = table_function_argument->as()) - { - const auto & unresolved_identifier = identifier_node->getIdentifier(); - auto identifier_resolve_result = tryResolveIdentifier({unresolved_identifier, IdentifierLookupContext::EXPRESSION}, scope); - auto resolved_identifier = std::move(identifier_resolve_result.resolved_identifier); - - if (resolved_identifier && resolved_identifier->getNodeType() == QueryTreeNodeType::CONSTANT) - result_table_function_arguments.push_back(std::move(resolved_identifier)); - else - result_table_function_arguments.push_back(table_function_argument); - - continue; - } - else if (auto * table_function_argument_function = table_function_argument->as()) - { - const auto & table_function_argument_function_name = table_function_argument_function->getFunctionName(); - if (TableFunctionFactory::instance().isTableFunctionName(table_function_argument_function_name)) - { - auto table_function_node_to_resolve_typed = std::make_shared(table_function_argument_function_name); - table_function_node_to_resolve_typed->getArgumentsNode() = table_function_argument_function->getArgumentsNode(); - - QueryTreeNodePtr table_function_node_to_resolve = std::move(table_function_node_to_resolve_typed); - resolveTableFunction(table_function_node_to_resolve, scope, expressions_visitor, true /*nested_table_function*/); - - result_table_function_arguments.push_back(std::move(table_function_node_to_resolve)); - continue; - } - } - - /** Table functions arguments can contain expressions with invalid identifiers. - * We cannot skip analysis for such arguments, because some table functions cannot provide - * information if analysis for argument should be skipped until other arguments will be resolved. - * - * Example: SELECT key from remote('127.0.0.{1,2}', view(select number AS key from numbers(2)), cityHash64(key)); - * Example: SELECT id from remote('127.0.0.{1,2}', 'default', 'test_table', cityHash64(id)); - */ - try - { - resolveExpressionNode(table_function_argument, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - catch (const Exception & exception) - { - if (exception.code() == ErrorCodes::UNKNOWN_IDENTIFIER) - { - result_table_function_arguments.push_back(table_function_argument); - continue; - } - - throw; - } - - if (auto * expression_list = table_function_argument->as()) - { - for (auto & expression_list_node : expression_list->getNodes()) - result_table_function_arguments.push_back(expression_list_node); - } - else - { - result_table_function_arguments.push_back(table_function_argument); - } - } - - table_function_node_typed.getArguments().getNodes() = std::move(result_table_function_arguments); - - auto table_function_ast = table_function_node_typed.toAST(); - table_function_ptr->parseArguments(table_function_ast, scope_context); - - - uint64_t use_structure_from_insertion_table_in_table_functions = scope_context->getSettingsRef().use_structure_from_insertion_table_in_table_functions; - if (!nested_table_function && - use_structure_from_insertion_table_in_table_functions && - scope_context->hasInsertionTable() && - table_function_ptr->needStructureHint()) - { - const auto & insertion_table = scope_context->getInsertionTable(); - if (!insertion_table.empty()) - { - const auto & insert_columns = DatabaseCatalog::instance() - .getTable(insertion_table, scope_context) - ->getInMemoryMetadataPtr() - ->getColumns(); - const auto & insert_column_names = scope_context->hasInsertionTableColumnNames() ? *scope_context->getInsertionTableColumnNames() : insert_columns.getOrdinary().getNames(); - DB::ColumnsDescription structure_hint; - - bool use_columns_from_insert_query = true; - - /// Insert table matches columns against SELECT expression by position, so we want to map - /// insert table columns to table function columns through names from SELECT expression. - - auto insert_column_name_it = insert_column_names.begin(); - auto insert_column_names_end = insert_column_names.end(); /// end iterator of the range covered by possible asterisk - auto virtual_column_names = table_function_ptr->getVirtualsToCheckBeforeUsingStructureHint(); - bool asterisk = false; - const auto & expression_list = scope.scope_node->as().getProjection(); - auto expression = expression_list.begin(); - - /// We want to go through SELECT expression list and correspond each expression to column in insert table - /// which type will be used as a hint for the file structure inference. - for (; expression != expression_list.end() && insert_column_name_it != insert_column_names_end; ++expression) - { - if (auto * identifier_node = (*expression)->as()) - { - - if (!virtual_column_names.contains(identifier_node->getIdentifier().getFullName())) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - ColumnDescription column = insert_columns.get(*insert_column_name_it); - column.name = identifier_node->getIdentifier().getFullName(); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else if (auto * matcher_node = (*expression)->as(); matcher_node && matcher_node->getMatcherType() == MatcherNodeType::ASTERISK) - { - if (asterisk) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Only one asterisk can be used in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - if (!structure_hint.empty()) - { - if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Asterisk cannot be mixed with column list in INSERT SELECT query."); - - use_columns_from_insert_query = false; - break; - } - - asterisk = true; - } - else if (auto * function = (*expression)->as()) - { - if (use_structure_from_insertion_table_in_table_functions == 2 && findIdentifier(*function)) - { - use_columns_from_insert_query = false; - break; - } - - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - else - { - /// Once we hit asterisk we want to find end of the range covered by asterisk - /// contributing every further SELECT expression to the tail of insert structure - if (asterisk) - --insert_column_names_end; - else - ++insert_column_name_it; - } - } - - if (use_structure_from_insertion_table_in_table_functions == 2 && !asterisk) - { - /// For input function we should check if input format supports reading subset of columns. - if (table_function_ptr->getName() == "input") - use_columns_from_insert_query = FormatFactory::instance().checkIfFormatSupportsSubsetOfColumns(scope.context->getInsertFormat(), scope.context); - else - use_columns_from_insert_query = table_function_ptr->supportsReadingSubsetOfColumns(scope.context); - } - - if (use_columns_from_insert_query) - { - if (expression == expression_list.end()) - { - /// Append tail of insert structure to the hint - if (asterisk) - { - for (; insert_column_name_it != insert_column_names_end; ++insert_column_name_it) - { - ColumnDescription column = insert_columns.get(*insert_column_name_it); - /// Change ephemeral columns to default columns. - column.default_desc.kind = ColumnDefaultKind::Default; - structure_hint.add(std::move(column)); - } - } - - if (!structure_hint.empty()) - table_function_ptr->setStructureHint(structure_hint); - - } else if (use_structure_from_insertion_table_in_table_functions == 1) - throw Exception(ErrorCodes::NUMBER_OF_COLUMNS_DOESNT_MATCH, "Number of columns in insert table less than required by SELECT expression."); - } - } - } - - auto table_function_storage = scope_context->getQueryContext()->executeTableFunction(table_function_ast, table_function_ptr); - table_function_node_typed.resolve(std::move(table_function_ptr), std::move(table_function_storage), scope_context, std::move(skip_analysis_arguments_indexes)); -} - -/// Resolve array join node in scope -void QueryAnalyzer::resolveArrayJoin(QueryTreeNodePtr & array_join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & array_join_node_typed = array_join_node->as(); - resolveQueryJoinTreeNode(array_join_node_typed.getTableExpression(), scope, expressions_visitor); - - std::unordered_set array_join_column_names; - - /// Wrap array join expressions into column nodes, where array join expression is inner expression - - auto & array_join_nodes = array_join_node_typed.getJoinExpressions().getNodes(); - size_t array_join_nodes_size = array_join_nodes.size(); - - if (array_join_nodes_size == 0) - throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, - "ARRAY JOIN requires at least single expression"); - - std::vector array_join_column_expressions; - array_join_column_expressions.reserve(array_join_nodes_size); - - for (auto & array_join_expression : array_join_nodes) - { - auto array_join_expression_alias = array_join_expression->getAlias(); - - for (const auto & elem : array_join_nodes) - { - if (elem->hasAlias()) - scope.aliases.array_join_aliases.insert(elem->getAlias()); - - for (auto & child : elem->getChildren()) - { - if (child) - expressions_visitor.visit(child); - } - } - - std::string identifier_full_name; - - if (auto * identifier_node = array_join_expression->as()) - identifier_full_name = identifier_node->getIdentifier().getFullName(); - - resolveExpressionNode(array_join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/, true /*ignore_alias*/); - - auto process_array_join_expression = [&](QueryTreeNodePtr & expression) - { - auto result_type = expression->getResultType(); - bool is_array_type = isArray(result_type); - bool is_map_type = isMap(result_type); - - if (!is_array_type && !is_map_type) - throw Exception(ErrorCodes::TYPE_MISMATCH, - "ARRAY JOIN {} requires expression {} with Array or Map type. Actual {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - expression->formatASTForErrorMessage(), - result_type->getName(), - scope.scope_node->formatASTForErrorMessage()); - - if (is_map_type) - result_type = assert_cast(*result_type).getNestedType(); - - result_type = assert_cast(*result_type).getNestedType(); - - String array_join_column_name; - - if (!array_join_expression_alias.empty()) - { - array_join_column_name = array_join_expression_alias; - } - else if (auto * array_join_expression_inner_column = array_join_expression->as()) - { - array_join_column_name = array_join_expression_inner_column->getColumnName(); - } - else if (!identifier_full_name.empty()) - { - array_join_column_name = identifier_full_name; - } - else - { - array_join_column_name = "__array_join_expression_" + std::to_string(array_join_expressions_counter); - ++array_join_expressions_counter; - } - - if (array_join_column_names.contains(array_join_column_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "ARRAY JOIN {} multiple columns with name {}. In scope {}", - array_join_node_typed.formatASTForErrorMessage(), - array_join_column_name, - scope.scope_node->formatASTForErrorMessage()); - array_join_column_names.emplace(array_join_column_name); - - NameAndTypePair array_join_column(array_join_column_name, result_type); - auto array_join_column_node = std::make_shared(std::move(array_join_column), expression, array_join_node); - array_join_column_node->setAlias(array_join_expression_alias); - array_join_column_expressions.push_back(std::move(array_join_column_node)); - }; - - // Support ARRAY JOIN COLUMNS(...). COLUMNS transformer is resolved to list of columns. - if (auto * columns_list = array_join_expression->as()) - { - for (auto & array_join_subexpression : columns_list->getNodes()) - process_array_join_expression(array_join_subexpression); - } - else - { - process_array_join_expression(array_join_expression); - } - } - - array_join_nodes = std::move(array_join_column_expressions); -} - -void QueryAnalyzer::checkDuplicateTableNamesOrAlias(const QueryTreeNodePtr & join_node, QueryTreeNodePtr & left_table_expr, QueryTreeNodePtr & right_table_expr, IdentifierResolveScope & scope) -{ - Names column_names; - if (!scope.context->getSettingsRef().joined_subquery_requires_alias) - return; - - if (join_node->as().getKind() != JoinKind::Paste) - return; - - auto * left_node = left_table_expr->as(); - auto * right_node = right_table_expr->as(); - - if (!left_node && !right_node) - return; - - if (left_node) - for (const auto & name_and_type : left_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - if (right_node) - for (const auto & name_and_type : right_node->getProjectionColumns()) - column_names.push_back(name_and_type.name); - - if (column_names.empty()) - throw Exception(ErrorCodes::LOGICAL_ERROR, "Names of projection columns cannot be empty"); - - std::sort(column_names.begin(), column_names.end()); - for (size_t i = 0; i < column_names.size() - 1; i++) // Check if there is no any duplicates because it will lead to broken result - if (column_names[i] == column_names[i+1]) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Name of columns and aliases should be unique for this query (you can add/change aliases to avoid duplication)" - "While processing '{}'", join_node->formatASTForErrorMessage()); -} - -/// Resolve join node in scope -void QueryAnalyzer::resolveJoin(QueryTreeNodePtr & join_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto & join_node_typed = join_node->as(); - - resolveQueryJoinTreeNode(join_node_typed.getLeftTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getLeftTableExpression(), scope); - - resolveQueryJoinTreeNode(join_node_typed.getRightTableExpression(), scope, expressions_visitor); - validateJoinTableExpressionWithoutAlias(join_node, join_node_typed.getRightTableExpression(), scope); - - if (!join_node_typed.getLeftTableExpression()->hasAlias() && !join_node_typed.getRightTableExpression()->hasAlias()) - checkDuplicateTableNamesOrAlias(join_node, join_node_typed.getLeftTableExpression(), join_node_typed.getRightTableExpression(), scope); - - if (join_node_typed.isOnJoinExpression()) - { - expressions_visitor.visit(join_node_typed.getJoinExpression()); - auto join_expression = join_node_typed.getJoinExpression(); - resolveExpressionNode(join_expression, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - join_node_typed.getJoinExpression() = std::move(join_expression); - } - else if (join_node_typed.isUsingJoinExpression()) - { - auto & join_using_list = join_node_typed.getJoinExpression()->as(); - std::unordered_set join_using_identifiers; - - for (auto & join_using_node : join_using_list.getNodes()) - { - auto * identifier_node = join_using_node->as(); - if (!identifier_node) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} USING clause expected identifier. Actual {}", - join_node_typed.formatASTForErrorMessage(), - join_using_node->formatASTForErrorMessage()); - - const auto & identifier_full_name = identifier_node->getIdentifier().getFullName(); - - if (join_using_identifiers.contains(identifier_full_name)) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "JOIN {} identifier '{}' appears more than once in USING clause", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name); - - join_using_identifiers.insert(identifier_full_name); - - const auto & settings = scope.context->getSettingsRef(); - - /** While resolving JOIN USING identifier, try to resolve identifier from parent subquery projection. - * Example: SELECT a + 1 AS b FROM (SELECT 1 AS a) t1 JOIN (SELECT 2 AS b) USING b - * In this case `b` is not in the left table expression, but it is in the parent subquery projection. - */ - auto try_resolve_identifier_from_query_projection = [this](const String & identifier_full_name_, - const QueryTreeNodePtr & left_table_expression, - const IdentifierResolveScope & scope_) -> QueryTreeNodePtr - { - const QueryNode * query_node = scope_.scope_node ? scope_.scope_node->as() : nullptr; - if (!query_node) - return nullptr; - - const auto & projection_list = query_node->getProjection(); - for (const auto & projection_node : projection_list.getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name_ == projection_node->getAlias()) - { - auto left_subquery = std::make_shared(query_node->getMutableContext()); - left_subquery->getProjection().getNodes().push_back(projection_node->clone()); - left_subquery->getJoinTree() = left_table_expression; - - IdentifierResolveScope left_subquery_scope(left_subquery, nullptr /*parent_scope*/); - resolveQuery(left_subquery, left_subquery_scope); - - const auto & resolved_nodes = left_subquery->getProjection().getNodes(); - if (resolved_nodes.size() == 1) - { - /// Create ColumnNode with expression from parent projection - return std::make_shared( - NameAndTypePair{identifier_full_name_, resolved_nodes.front()->getResultType()}, - resolved_nodes.front(), left_table_expression); - } - } - } - return nullptr; - }; - - QueryTreeNodePtr result_left_table_expression = nullptr; - /** With `analyzer_compatibility_join_using_top_level_identifier` alias in projection has higher priority than column from left table. - * But if aliased expression cannot be resolved from left table, we get UNKNOW_IDENTIFIER error, - * despite the fact that column from USING could be resolved from left table. - * It's compatibility with a default behavior for old analyzer. - */ - if (settings.analyzer_compatibility_join_using_top_level_identifier) - result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - IdentifierLookup identifier_lookup{identifier_node->getIdentifier(), IdentifierLookupContext::EXPRESSION}; - if (!result_left_table_expression) - result_left_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getLeftTableExpression(), scope); - - /** Here we may try to resolve identifier from projection in case it's not resolved from left table expression - * and analyzer_compatibility_join_using_top_level_identifier is disabled. - * For now we do not do this, because not all corner cases are clear. - * But let's at least mention it in error message - */ - /// if (!settings.analyzer_compatibility_join_using_top_level_identifier && !result_left_table_expression) - /// result_left_table_expression = try_resolve_identifier_from_query_projection(identifier_full_name, join_node_typed.getLeftTableExpression(), scope); - - if (!result_left_table_expression) - { - String extra_message; - const QueryNode * query_node = scope.scope_node ? scope.scope_node->as() : nullptr; - if (settings.analyzer_compatibility_join_using_top_level_identifier && query_node) - { - for (const auto & projection_node : query_node->getProjection().getNodes()) - { - if (projection_node->hasAlias() && identifier_full_name == projection_node->getAlias()) - { - extra_message = fmt::format( - ", but alias '{}' is present in SELECT list." - " You may try to SET analyzer_compatibility_join_using_top_level_identifier = 1, to allow to use it in USING clause", - projection_node->formatASTForErrorMessage()); - break; - } - } - } - - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from left table expression{}. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - extra_message, - scope.scope_node->formatASTForErrorMessage()); - } - - if (result_left_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from left table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto result_right_table_expression = tryResolveIdentifierFromJoinTreeNode(identifier_lookup, join_node_typed.getRightTableExpression(), scope); - if (!result_right_table_expression) - throw Exception(ErrorCodes::UNKNOWN_IDENTIFIER, - "JOIN {} using identifier '{}' cannot be resolved from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - if (result_right_table_expression->getNodeType() != QueryTreeNodeType::COLUMN) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "JOIN {} using identifier '{}' must be resolved into column node from right table expression. In scope {}", - join_node_typed.formatASTForErrorMessage(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - auto expression_types = DataTypes{result_left_table_expression->getResultType(), result_right_table_expression->getResultType()}; - DataTypePtr common_type = tryGetLeastSupertype(expression_types); - - if (!common_type) - throw Exception(ErrorCodes::NO_COMMON_TYPE, - "JOIN {} cannot infer common type for {} and {} in USING for identifier '{}'. In scope {}", - join_node_typed.formatASTForErrorMessage(), - result_left_table_expression->getResultType()->getName(), - result_right_table_expression->getResultType()->getName(), - identifier_full_name, - scope.scope_node->formatASTForErrorMessage()); - - NameAndTypePair join_using_column(identifier_full_name, common_type); - ListNodePtr join_using_expression = std::make_shared(QueryTreeNodes{result_left_table_expression, result_right_table_expression}); - auto join_using_column_node = std::make_shared(std::move(join_using_column), std::move(join_using_expression), join_node); - join_using_node = std::move(join_using_column_node); - } - } -} - -/** Resolve query join tree. - * - * Query join tree must be initialized before calling this function. - */ -void QueryAnalyzer::resolveQueryJoinTreeNode(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope, QueryExpressionsAliasVisitor & expressions_visitor) -{ - auto from_node_type = join_tree_node->getNodeType(); - - switch (from_node_type) - { - case QueryTreeNodeType::QUERY: - [[fallthrough]]; - case QueryTreeNodeType::UNION: - { - resolveExpressionNode(join_tree_node, scope, false /*allow_lambda_expression*/, true /*allow_table_expression*/); - break; - } - case QueryTreeNodeType::TABLE_FUNCTION: - { - resolveTableFunction(join_tree_node, scope, expressions_visitor, false /*nested_table_function*/); - break; - } - case QueryTreeNodeType::TABLE: - { - break; - } - case QueryTreeNodeType::ARRAY_JOIN: - { - resolveArrayJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::JOIN: - { - resolveJoin(join_tree_node, scope, expressions_visitor); - break; - } - case QueryTreeNodeType::IDENTIFIER: - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Identifiers in FROM section must be already resolved. Node {}, scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - default: - { - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Query FROM section expected table, table function, query, ARRAY JOIN or JOIN. Actual {}. In scope {}", - join_tree_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - auto join_tree_node_type = join_tree_node->getNodeType(); - if (isTableExpressionNodeType(join_tree_node_type)) - { - validateTableExpressionModifiers(join_tree_node, scope); - initializeTableExpressionData(join_tree_node, scope); - - auto & query_node = scope.scope_node->as(); - auto & mutable_context = query_node.getMutableContext(); - - if (!mutable_context->isDistributed()) - { - bool is_distributed = false; - - if (auto * table_node = join_tree_node->as()) - is_distributed = table_node->getStorage()->isRemote(); - else if (auto * table_function_node = join_tree_node->as()) - is_distributed = table_function_node->getStorage()->isRemote(); - - mutable_context->setDistributed(is_distributed); - } - } - - auto add_table_expression_alias_into_scope = [&](const QueryTreeNodePtr & table_expression_node) - { - const auto & alias_name = table_expression_node->getAlias(); - if (alias_name.empty()) - return; - - auto [it, inserted] = scope.aliases.alias_name_to_table_expression_node.emplace(alias_name, table_expression_node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Duplicate aliases {} for table expressions in FROM section are not allowed. Try to register {}. Already registered {}.", - alias_name, - table_expression_node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage()); - }; - - add_table_expression_alias_into_scope(join_tree_node); - scope.table_expressions_in_resolve_process.erase(join_tree_node.get()); -} - -/** Resolve query. - * This function modifies query node during resolve. It is caller responsibility to clone query node before resolve - * if it is needed for later use. - * - * query_node - query_tree_node that must have QueryNode type. - * scope - query scope. It is caller responsibility to create it. - * - * Resolve steps: - * 1. Validate subqueries depth, perform GROUP BY validation that does not depend on information about aggregate functions. - * 2. Initialize query scope with aliases. - * 3. Register CTE subqueries from WITH section in scope and remove them from WITH section. - * 4. Resolve JOIN TREE. - * 5. Resolve projection columns. - * 6. Resolve expressions in other query parts. - * 7. Validate nodes with duplicate aliases. - * 8. Validate aggregate functions, GROUPING function, window functions. - * 9. Remove WITH and WINDOW sections from query. - * 10. Remove aliases from expression and lambda nodes. - * 11. Resolve query tree node with projection columns. - */ -void QueryAnalyzer::resolveQuery(const QueryTreeNodePtr & query_node, IdentifierResolveScope & scope) -{ - size_t max_subquery_depth = scope.context->getSettingsRef().max_subquery_depth; - if (max_subquery_depth && scope.subquery_depth > max_subquery_depth) - throw Exception(ErrorCodes::TOO_DEEP_SUBQUERIES, - "Too deep subqueries. Maximum: {}", - max_subquery_depth); - - auto & query_node_typed = query_node->as(); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.insert(query_node_typed.getCTEName()); - - bool is_rollup_or_cube = query_node_typed.isGroupByWithRollup() || query_node_typed.isGroupByWithCube(); - - if (query_node_typed.isGroupByWithGroupingSets() - && query_node_typed.isGroupByWithTotals() - && query_node_typed.getGroupBy().getNodes().size() != 1) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and GROUPING SETS are not supported together"); - - if (query_node_typed.isGroupByWithGroupingSets() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "GROUPING SETS are not supported together with ROLLUP and CUBE"); - - if (query_node_typed.isGroupByWithRollup() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithCube())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "ROLLUP is not supported together with GROUPING SETS and CUBE"); - - if (query_node_typed.isGroupByWithCube() && (query_node_typed.isGroupByWithGroupingSets() || query_node_typed.isGroupByWithRollup())) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "CUBE is not supported together with GROUPING SETS and ROLLUP"); - - if (query_node_typed.hasHaving() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of HAVING"); - - if (query_node_typed.hasQualify() && query_node_typed.isGroupByWithTotals() && is_rollup_or_cube) - throw Exception(ErrorCodes::NOT_IMPLEMENTED, "WITH TOTALS and WITH ROLLUP or CUBE are not supported together in presence of QUALIFY"); - - /// Initialize aliases in query node scope - QueryExpressionsAliasVisitor visitor(scope.aliases); - - if (query_node_typed.hasWith()) - visitor.visit(query_node_typed.getWithNode()); - - if (!query_node_typed.getProjection().getNodes().empty()) - visitor.visit(query_node_typed.getProjectionNode()); - - if (query_node_typed.getPrewhere()) - visitor.visit(query_node_typed.getPrewhere()); - - if (query_node_typed.getWhere()) - visitor.visit(query_node_typed.getWhere()); - - if (query_node_typed.hasGroupBy()) - visitor.visit(query_node_typed.getGroupByNode()); - - if (query_node_typed.hasHaving()) - visitor.visit(query_node_typed.getHaving()); - - if (query_node_typed.hasWindow()) - visitor.visit(query_node_typed.getWindowNode()); - - if (query_node_typed.hasQualify()) - visitor.visit(query_node_typed.getQualify()); - - if (query_node_typed.hasOrderBy()) - visitor.visit(query_node_typed.getOrderByNode()); - - if (query_node_typed.hasInterpolate()) - visitor.visit(query_node_typed.getInterpolate()); - - if (query_node_typed.hasLimitByLimit()) - visitor.visit(query_node_typed.getLimitByLimit()); - - if (query_node_typed.hasLimitByOffset()) - visitor.visit(query_node_typed.getLimitByOffset()); - - if (query_node_typed.hasLimitBy()) - visitor.visit(query_node_typed.getLimitByNode()); - - if (query_node_typed.hasLimit()) - visitor.visit(query_node_typed.getLimit()); - - if (query_node_typed.hasOffset()) - visitor.visit(query_node_typed.getOffset()); - - /// Register CTE subqueries and remove them from WITH section - - auto & with_nodes = query_node_typed.getWith().getNodes(); - - for (auto & node : with_nodes) - { - auto * subquery_node = node->as(); - auto * union_node = node->as(); - - bool subquery_is_cte = (subquery_node && subquery_node->isCTE()) || (union_node && union_node->isCTE()); - if (!subquery_is_cte) - continue; - - const auto & cte_name = subquery_node ? subquery_node->getCTEName() : union_node->getCTEName(); - - auto [_, inserted] = scope.cte_name_to_query_node.emplace(cte_name, node); - if (!inserted) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "CTE with name {} already exists. In scope {}", - cte_name, - scope.scope_node->formatASTForErrorMessage()); - } - - /** WITH section can be safely removed, because WITH section only can provide aliases to query expressions - * and CTE for other sections to use. - * - * Example: WITH 1 AS constant, (x -> x + 1) AS lambda, a AS (SELECT * FROM test_table); - */ - query_node_typed.getWith().getNodes().clear(); - - for (auto & window_node : query_node_typed.getWindow().getNodes()) - { - auto & window_node_typed = window_node->as(); - auto parent_window_name = window_node_typed.getParentWindowName(); - if (!parent_window_name.empty()) - { - auto window_node_it = scope.window_name_to_window_node.find(parent_window_name); - if (window_node_it == scope.window_name_to_window_node.end()) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' does not exist. In scope {}", - parent_window_name, - scope.scope_node->formatASTForErrorMessage()); - - mergeWindowWithParentWindow(window_node, window_node_it->second, scope); - window_node_typed.setParentWindowName({}); - } - - auto [_, inserted] = scope.window_name_to_window_node.emplace(window_node_typed.getAlias(), window_node); - if (!inserted) - throw Exception(ErrorCodes::BAD_ARGUMENTS, - "Window '{}' is already defined. In scope {}", - window_node_typed.getAlias(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** Disable identifier cache during JOIN TREE resolve. - * Depending on JOIN expression section, identifier with same name - * can be resolved in different columns. - * - * Example: SELECT id FROM test_table AS t1 INNER JOIN test_table AS t2 ON t1.id = t2.id INNER JOIN test_table AS t3 ON t1.id = t3.id - * In first join expression ON t1.id = t2.id t1.id is resolved into test_table.id column. - * In second join expression ON t1.id = t3.id t1.id must be resolved into test_table.id column after first JOIN. - */ - scope.use_identifier_lookup_to_result_cache = false; - - if (query_node_typed.getJoinTree()) - { - TableExpressionsAliasVisitor table_expressions_visitor(scope); - table_expressions_visitor.visit(query_node_typed.getJoinTree()); - - initializeQueryJoinTreeNode(query_node_typed.getJoinTree(), scope); - scope.aliases.alias_name_to_table_expression_node.clear(); - - resolveQueryJoinTreeNode(query_node_typed.getJoinTree(), scope, visitor); - } - - if (!scope.group_by_use_nulls) - scope.use_identifier_lookup_to_result_cache = true; - - /// Resolve query node sections. - - NamesAndTypes projection_columns; - - if (!scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - if (auto & prewhere_node = query_node_typed.getPrewhere()) - { - resolveExpressionNode(prewhere_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - /** Expressions in PREWHERE with JOIN should not change their type. - * Example: SELECT * FROM t1 JOIN t2 USING (a) PREWHERE a = 1 - * Column `a` in PREWHERE should be resolved from the left table - * and should not change its type to Nullable or to the supertype of `a` from t1 and t2. - * Here's a more complicated example where the column is somewhere inside an expression: - * SELECT a + 1 as b FROM t1 JOIN t2 USING (id) PREWHERE b = 1 - * The expression `a + 1 as b` in the projection and in PREWHERE should have different `a`. - */ - prewhere_node = prewhere_node->clone(); - ReplaceColumnsVisitor replace_visitor(scope.join_columns_with_changed_types, scope.context); - replace_visitor.visit(prewhere_node); - } - - if (query_node_typed.getWhere()) - resolveExpressionNode(query_node_typed.getWhere(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasGroupBy()) - resolveGroupByNode(query_node_typed, scope); - - if (scope.group_by_use_nulls) - { - resolved_expressions.clear(); - /// Clone is needed cause aliases share subtrees. - /// If not clone, the same (shared) subtree could be resolved again with different (Nullable) type - /// See 03023_group_by_use_nulls_analyzer_crashes - for (auto & [key, node] : scope.aliases.alias_name_to_expression_node_before_group_by) - scope.aliases.alias_name_to_expression_node_after_group_by[key] = node->clone(); - - scope.aliases.alias_name_to_expression_node = &scope.aliases.alias_name_to_expression_node_after_group_by; - } - - if (query_node_typed.hasHaving()) - resolveExpressionNode(query_node_typed.getHaving(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasWindow()) - resolveWindowNodeList(query_node_typed.getWindowNode(), scope); - - if (query_node_typed.hasQualify()) - resolveExpressionNode(query_node_typed.getQualify(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - - if (query_node_typed.hasOrderBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getOrderByNode(), query_node_typed.getProjection().getNodes(), scope); - - const auto & settings = scope.context->getSettingsRef(); - - expandOrderByAll(query_node_typed, settings); - resolveSortNodeList(query_node_typed.getOrderByNode(), scope); - } - - if (query_node_typed.hasInterpolate()) - resolveInterpolateColumnsNodeList(query_node_typed.getInterpolate(), scope); - - if (query_node_typed.hasLimitByLimit()) - { - resolveExpressionNode(query_node_typed.getLimitByLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByLimit(), "LIMIT BY LIMIT", scope); - } - - if (query_node_typed.hasLimitByOffset()) - { - resolveExpressionNode(query_node_typed.getLimitByOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimitByOffset(), "LIMIT BY OFFSET", scope); - } - - if (query_node_typed.hasLimitBy()) - { - replaceNodesWithPositionalArguments(query_node_typed.getLimitByNode(), query_node_typed.getProjection().getNodes(), scope); - - resolveExpressionNodeList(query_node_typed.getLimitByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - } - - if (query_node_typed.hasLimit()) - { - resolveExpressionNode(query_node_typed.getLimit(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getLimit(), "LIMIT", scope); - } - - if (query_node_typed.hasOffset()) - { - resolveExpressionNode(query_node_typed.getOffset(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); - convertLimitOffsetExpression(query_node_typed.getOffset(), "OFFSET", scope); - } - - if (scope.group_by_use_nulls) - { - projection_columns = resolveProjectionExpressionNodeList(query_node_typed.getProjectionNode(), scope); - if (query_node_typed.getProjection().getNodes().empty()) - throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED, - "Empty list of columns in projection. In scope {}", - scope.scope_node->formatASTForErrorMessage()); - } - - /** Resolve nodes with duplicate aliases. - * Table expressions cannot have duplicate aliases. - * - * Such nodes during scope aliases collection are placed into duplicated array. - * After scope nodes are resolved, we can compare node with duplicate alias with - * node from scope alias table. - */ - for (const auto & node_with_duplicated_alias : scope.aliases.cloned_nodes_with_duplicated_aliases) - { - auto node = node_with_duplicated_alias; - auto node_alias = node->getAlias(); - - /// Add current alias to non cached set, because in case of cyclic alias identifier should not be substituted from cache. - /// See 02896_cyclic_aliases_crash. - resolveExpressionNode(node, scope, true /*allow_lambda_expression*/, false /*allow_table_expression*/); - - bool has_node_in_alias_table = false; - - auto it = scope.aliases.alias_name_to_expression_node->find(node_alias); - if (it != scope.aliases.alias_name_to_expression_node->end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - it = scope.aliases.alias_name_to_lambda_node.find(node_alias); - if (it != scope.aliases.alias_name_to_lambda_node.end()) - { - has_node_in_alias_table = true; - - if (!it->second->isEqual(*node)) - throw Exception(ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS, - "Multiple expressions {} and {} for alias {}. In scope {}", - node->formatASTForErrorMessage(), - it->second->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - } - - if (!has_node_in_alias_table) - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Node {} with duplicate alias {} does not exist in alias table. In scope {}", - node->formatASTForErrorMessage(), - node_alias, - scope.scope_node->formatASTForErrorMessage()); - - node->removeAlias(); - } - - expandGroupByAll(query_node_typed); - - validateFilters(query_node); - validateAggregates(query_node, { .group_by_use_nulls = scope.group_by_use_nulls }); - - for (const auto & column : projection_columns) - { - if (isNotCreatable(column.type)) - throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, - "Invalid projection column with type {}. In scope {}", - column.type->getName(), - scope.scope_node->formatASTForErrorMessage()); - } - - /** WINDOW section can be safely removed, because WINDOW section can only provide window definition to window functions. - * - * Example: SELECT count(*) OVER w FROM test_table WINDOW w AS (PARTITION BY id); - */ - query_node_typed.getWindow().getNodes().clear(); - - /// Remove aliases from expression and lambda nodes - - for (auto & [_, node] : *scope.aliases.alias_name_to_expression_node) - node->removeAlias(); - - for (auto & [_, node] : scope.aliases.alias_name_to_lambda_node) - node->removeAlias(); - - query_node_typed.resolveProjectionColumns(std::move(projection_columns)); - - if (query_node_typed.isCTE()) - ctes_in_resolve_process.erase(query_node_typed.getCTEName()); -} - -void QueryAnalyzer::resolveUnion(const QueryTreeNodePtr & union_node, IdentifierResolveScope & scope) -{ - auto & union_node_typed = union_node->as(); - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.insert(union_node_typed.getCTEName()); - - auto & queries_nodes = union_node_typed.getQueries().getNodes(); - - std::optional recursive_cte_table; - TableNodePtr recursive_cte_table_node; - - if (union_node_typed.isCTE() && union_node_typed.isRecursiveCTE()) - { - auto & non_recursive_query = queries_nodes[0]; - bool non_recursive_query_is_query_node = non_recursive_query->getNodeType() == QueryTreeNodeType::QUERY; - auto & non_recursive_query_mutable_context = non_recursive_query_is_query_node ? non_recursive_query->as().getMutableContext() - : non_recursive_query->as().getMutableContext(); - - IdentifierResolveScope non_recursive_subquery_scope(non_recursive_query, &scope /*parent_scope*/); - non_recursive_subquery_scope.subquery_depth = scope.subquery_depth + 1; - - if (non_recursive_query_is_query_node) - resolveQuery(non_recursive_query, non_recursive_subquery_scope); - else - resolveUnion(non_recursive_query, non_recursive_subquery_scope); - - auto temporary_table_columns = non_recursive_query_is_query_node - ? non_recursive_query->as().getProjectionColumns() - : non_recursive_query->as().computeProjectionColumns(); - - auto temporary_table_holder = std::make_shared( - non_recursive_query_mutable_context, - ColumnsDescription{NamesAndTypesList{temporary_table_columns.begin(), temporary_table_columns.end()}}, - ConstraintsDescription{}, - nullptr /*query*/, - true /*create_for_global_subquery*/); - auto temporary_table_storage = temporary_table_holder->getTable(); - - recursive_cte_table_node = std::make_shared(temporary_table_storage, non_recursive_query_mutable_context); - recursive_cte_table_node->setTemporaryTableName(union_node_typed.getCTEName()); - - recursive_cte_table.emplace(std::move(temporary_table_holder), std::move(temporary_table_storage), std::move(temporary_table_columns)); - } - - size_t queries_nodes_size = queries_nodes.size(); - for (size_t i = recursive_cte_table.has_value(); i < queries_nodes_size; ++i) - { - auto & query_node = queries_nodes[i]; - - IdentifierResolveScope subquery_scope(query_node, &scope /*parent_scope*/); - - if (recursive_cte_table_node) - subquery_scope.expression_argument_name_to_node[union_node_typed.getCTEName()] = recursive_cte_table_node; - - auto query_node_type = query_node->getNodeType(); - - if (query_node_type == QueryTreeNodeType::QUERY) - { - resolveQuery(query_node, subquery_scope); - } - else if (query_node_type == QueryTreeNodeType::UNION) - { - resolveUnion(query_node, subquery_scope); - } - else - { - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "UNION unsupported node {}. In scope {}", - query_node->formatASTForErrorMessage(), - scope.scope_node->formatASTForErrorMessage()); - } - } - - if (recursive_cte_table && isStorageUsedInTree(recursive_cte_table->storage, union_node.get())) - { - if (union_node_typed.getUnionMode() != SelectUnionMode::UNION_ALL) - throw Exception(ErrorCodes::UNSUPPORTED_METHOD, - "Recursive CTE subquery {} with {} union mode is unsupported, only UNION ALL union mode is supported", - union_node_typed.formatASTForErrorMessage(), - toString(union_node_typed.getUnionMode())); - - union_node_typed.setRecursiveCTETable(std::move(*recursive_cte_table)); - } - - if (union_node_typed.isCTE()) - ctes_in_resolve_process.erase(union_node_typed.getCTEName()); -} - -} - -QueryAnalysisPass::QueryAnalysisPass(QueryTreeNodePtr table_expression_, bool only_analyze_) - : table_expression(std::move(table_expression_)) - , only_analyze(only_analyze_) -{} - -QueryAnalysisPass::QueryAnalysisPass(bool only_analyze_) : only_analyze(only_analyze_) {} - -void QueryAnalysisPass::run(QueryTreeNodePtr & query_tree_node, ContextPtr context) -{ - QueryAnalyzer analyzer(only_analyze); - analyzer.resolve(query_tree_node, table_expression, context); - createUniqueTableAliases(query_tree_node, table_expression, context); -} - } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f2e10a27b75..7d678add6d2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -215,6 +215,7 @@ add_object_library(clickhouse_databases_mysql Databases/MySQL) add_object_library(clickhouse_disks Disks) add_object_library(clickhouse_analyzer Analyzer) add_object_library(clickhouse_analyzer_passes Analyzer/Passes) +add_object_library(clickhouse_analyzer_passes Analyzer/QueryAnalysis) add_object_library(clickhouse_planner Planner) add_object_library(clickhouse_interpreters Interpreters) add_object_library(clickhouse_interpreters_cache Interpreters/Cache) From f40db2c4b2a0289d8eb60b25646399fe9da5c58a Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Mon, 27 May 2024 16:39:21 +0000 Subject: [PATCH 099/211] Fixing style. --- src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp b/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp index 041e0d1fefb..d38fcf79bd8 100644 --- a/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp +++ b/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp @@ -6,6 +6,11 @@ namespace DB { + namespace ErrorCodes + { + extern const int LOGICAL_ERROR; + } + IdentifierResolveScope::IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) : scope_node(std::move(scope_node_)) , parent_scope(parent_scope_) From 270cf6b6aa084c54b28ab3146870e9f457bb07b5 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 28 May 2024 09:49:52 +0000 Subject: [PATCH 100/211] Identation. --- .../QueryAnalysis/IdentifierResolveScope.cpp | 350 +++++++++--------- 1 file changed, 175 insertions(+), 175 deletions(-) diff --git a/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp b/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp index d38fcf79bd8..006b0b01c51 100644 --- a/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp +++ b/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp @@ -6,179 +6,179 @@ namespace DB { - namespace ErrorCodes - { - extern const int LOGICAL_ERROR; - } - - IdentifierResolveScope::IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) - : scope_node(std::move(scope_node_)) - , parent_scope(parent_scope_) - { - if (parent_scope) - { - subquery_depth = parent_scope->subquery_depth; - context = parent_scope->context; - projection_mask_map = parent_scope->projection_mask_map; - } - else - projection_mask_map = std::make_shared>(); - - if (auto * union_node = scope_node->as()) - { - context = union_node->getContext(); - } - else if (auto * query_node = scope_node->as()) - { - context = query_node->getContext(); - group_by_use_nulls = context->getSettingsRef().group_by_use_nulls && - (query_node->isGroupByWithGroupingSets() || query_node->isGroupByWithRollup() || query_node->isGroupByWithCube()); - } - - if (context) - join_use_nulls = context->getSettingsRef().join_use_nulls; - else if (parent_scope) - join_use_nulls = parent_scope->join_use_nulls; - - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - [[maybe_unused]] const IdentifierResolveScope * IdentifierResolveScope::getNearestQueryScope() const - { - const IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - IdentifierResolveScope * IdentifierResolveScope::getNearestQueryScope() - { - IdentifierResolveScope * scope_to_check = this; - while (scope_to_check != nullptr) - { - if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) - break; - - scope_to_check = scope_to_check->parent_scope; - } - - return scope_to_check; - } - - AnalysisTableExpressionData & IdentifierResolveScope::getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - const AnalysisTableExpressionData & IdentifierResolveScope::getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const - { - auto it = table_expression_node_to_data.find(table_expression_node); - if (it == table_expression_node_to_data.end()) - { - throw Exception(ErrorCodes::LOGICAL_ERROR, - "Table expression {} data must be initialized. In scope {}", - table_expression_node->formatASTForErrorMessage(), - scope_node->formatASTForErrorMessage()); - } - - return it->second; - } - - void IdentifierResolveScope::pushExpressionNode(const QueryTreeNodePtr & node) - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.push(node); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; - } - - void IdentifierResolveScope::popExpressionNode() - { - bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); - expressions_in_resolve_process_stack.pop(); - if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) - aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_after_group_by; - } - - /// Dump identifier resolve scope - [[maybe_unused]] void IdentifierResolveScope::dump(WriteBuffer & buffer) const - { - buffer << "Scope node " << scope_node->formatASTForErrorMessage() << '\n'; - buffer << "Identifier lookup to resolve state " << identifier_lookup_to_resolve_state.size() << '\n'; - for (const auto & [identifier, state] : identifier_lookup_to_resolve_state) - { - buffer << "Identifier " << identifier.dump() << " resolve result "; - state.resolve_result.dump(buffer); - buffer << '\n'; - } - - buffer << "Expression argument name to node " << expression_argument_name_to_node.size() << '\n'; - for (const auto & [alias_name, node] : expression_argument_name_to_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to expression node table size " << aliases.alias_name_to_expression_node->size() << '\n'; - for (const auto & [alias_name, node] : *aliases.alias_name_to_expression_node) - buffer << "Alias name " << alias_name << " expression node " << node->dumpTree() << '\n'; - - buffer << "Alias name to function node table size " << aliases.alias_name_to_lambda_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_lambda_node) - buffer << "Alias name " << alias_name << " lambda node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Alias name to table expression node table size " << aliases.alias_name_to_table_expression_node.size() << '\n'; - for (const auto & [alias_name, node] : aliases.alias_name_to_table_expression_node) - buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "CTE name to query node table size " << cte_name_to_query_node.size() << '\n'; - for (const auto & [cte_name, node] : cte_name_to_query_node) - buffer << "CTE name " << cte_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "WINDOW name to window node table size " << window_name_to_window_node.size() << '\n'; - for (const auto & [window_name, node] : window_name_to_window_node) - buffer << "CTE name " << window_name << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Nodes with duplicated aliases size " << aliases.nodes_with_duplicated_aliases.size() << '\n'; - for (const auto & node : aliases.nodes_with_duplicated_aliases) - buffer << "Alias name " << node->getAlias() << " node " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Expression resolve process stack " << '\n'; - expressions_in_resolve_process_stack.dump(buffer); - - buffer << "Table expressions in resolve process size " << table_expressions_in_resolve_process.size() << '\n'; - for (const auto & node : table_expressions_in_resolve_process) - buffer << "Table expression " << node->formatASTForErrorMessage() << '\n'; - - buffer << "Non cached identifier lookups during expression resolve " << non_cached_identifier_lookups_during_expression_resolve.size() << '\n'; - for (const auto & identifier_lookup : non_cached_identifier_lookups_during_expression_resolve) - buffer << "Identifier lookup " << identifier_lookup.dump() << '\n'; - - buffer << "Table expression node to data " << table_expression_node_to_data.size() << '\n'; - for (const auto & [table_expression_node, table_expression_data] : table_expression_node_to_data) - buffer << "Table expression node " << table_expression_node->formatASTForErrorMessage() << " data " << table_expression_data.dump() << '\n'; - - buffer << "Use identifier lookup to result cache " << use_identifier_lookup_to_result_cache << '\n'; - buffer << "Subquery depth " << subquery_depth << '\n'; - } - - [[maybe_unused]] String IdentifierResolveScope::dump() const - { - WriteBufferFromOwnString buffer; - dump(buffer); - - return buffer.str(); - } +namespace ErrorCodes +{ + extern const int LOGICAL_ERROR; +} + +IdentifierResolveScope::IdentifierResolveScope(QueryTreeNodePtr scope_node_, IdentifierResolveScope * parent_scope_) + : scope_node(std::move(scope_node_)) + , parent_scope(parent_scope_) +{ + if (parent_scope) + { + subquery_depth = parent_scope->subquery_depth; + context = parent_scope->context; + projection_mask_map = parent_scope->projection_mask_map; + } + else + projection_mask_map = std::make_shared>(); + + if (auto * union_node = scope_node->as()) + { + context = union_node->getContext(); + } + else if (auto * query_node = scope_node->as()) + { + context = query_node->getContext(); + group_by_use_nulls = context->getSettingsRef().group_by_use_nulls && + (query_node->isGroupByWithGroupingSets() || query_node->isGroupByWithRollup() || query_node->isGroupByWithCube()); + } + + if (context) + join_use_nulls = context->getSettingsRef().join_use_nulls; + else if (parent_scope) + join_use_nulls = parent_scope->join_use_nulls; + + aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; +} + +[[maybe_unused]] const IdentifierResolveScope * IdentifierResolveScope::getNearestQueryScope() const +{ + const IdentifierResolveScope * scope_to_check = this; + while (scope_to_check != nullptr) + { + if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) + break; + + scope_to_check = scope_to_check->parent_scope; + } + + return scope_to_check; +} + +IdentifierResolveScope * IdentifierResolveScope::getNearestQueryScope() +{ + IdentifierResolveScope * scope_to_check = this; + while (scope_to_check != nullptr) + { + if (scope_to_check->scope_node->getNodeType() == QueryTreeNodeType::QUERY) + break; + + scope_to_check = scope_to_check->parent_scope; + } + + return scope_to_check; +} + +AnalysisTableExpressionData & IdentifierResolveScope::getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) +{ + auto it = table_expression_node_to_data.find(table_expression_node); + if (it == table_expression_node_to_data.end()) + { + throw Exception(ErrorCodes::LOGICAL_ERROR, + "Table expression {} data must be initialized. In scope {}", + table_expression_node->formatASTForErrorMessage(), + scope_node->formatASTForErrorMessage()); + } + + return it->second; +} + +const AnalysisTableExpressionData & IdentifierResolveScope::getTableExpressionDataOrThrow(const QueryTreeNodePtr & table_expression_node) const +{ + auto it = table_expression_node_to_data.find(table_expression_node); + if (it == table_expression_node_to_data.end()) + { + throw Exception(ErrorCodes::LOGICAL_ERROR, + "Table expression {} data must be initialized. In scope {}", + table_expression_node->formatASTForErrorMessage(), + scope_node->formatASTForErrorMessage()); + } + + return it->second; +} + +void IdentifierResolveScope::pushExpressionNode(const QueryTreeNodePtr & node) +{ + bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); + expressions_in_resolve_process_stack.push(node); + if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) + aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_before_group_by; +} + +void IdentifierResolveScope::popExpressionNode() +{ + bool had_aggregate_function = expressions_in_resolve_process_stack.hasAggregateFunction(); + expressions_in_resolve_process_stack.pop(); + if (group_by_use_nulls && had_aggregate_function != expressions_in_resolve_process_stack.hasAggregateFunction()) + aliases.alias_name_to_expression_node = &aliases.alias_name_to_expression_node_after_group_by; +} + +/// Dump identifier resolve scope +[[maybe_unused]] void IdentifierResolveScope::dump(WriteBuffer & buffer) const +{ + buffer << "Scope node " << scope_node->formatASTForErrorMessage() << '\n'; + buffer << "Identifier lookup to resolve state " << identifier_lookup_to_resolve_state.size() << '\n'; + for (const auto & [identifier, state] : identifier_lookup_to_resolve_state) + { + buffer << "Identifier " << identifier.dump() << " resolve result "; + state.resolve_result.dump(buffer); + buffer << '\n'; + } + + buffer << "Expression argument name to node " << expression_argument_name_to_node.size() << '\n'; + for (const auto & [alias_name, node] : expression_argument_name_to_node) + buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; + + buffer << "Alias name to expression node table size " << aliases.alias_name_to_expression_node->size() << '\n'; + for (const auto & [alias_name, node] : *aliases.alias_name_to_expression_node) + buffer << "Alias name " << alias_name << " expression node " << node->dumpTree() << '\n'; + + buffer << "Alias name to function node table size " << aliases.alias_name_to_lambda_node.size() << '\n'; + for (const auto & [alias_name, node] : aliases.alias_name_to_lambda_node) + buffer << "Alias name " << alias_name << " lambda node " << node->formatASTForErrorMessage() << '\n'; + + buffer << "Alias name to table expression node table size " << aliases.alias_name_to_table_expression_node.size() << '\n'; + for (const auto & [alias_name, node] : aliases.alias_name_to_table_expression_node) + buffer << "Alias name " << alias_name << " node " << node->formatASTForErrorMessage() << '\n'; + + buffer << "CTE name to query node table size " << cte_name_to_query_node.size() << '\n'; + for (const auto & [cte_name, node] : cte_name_to_query_node) + buffer << "CTE name " << cte_name << " node " << node->formatASTForErrorMessage() << '\n'; + + buffer << "WINDOW name to window node table size " << window_name_to_window_node.size() << '\n'; + for (const auto & [window_name, node] : window_name_to_window_node) + buffer << "CTE name " << window_name << " node " << node->formatASTForErrorMessage() << '\n'; + + buffer << "Nodes with duplicated aliases size " << aliases.nodes_with_duplicated_aliases.size() << '\n'; + for (const auto & node : aliases.nodes_with_duplicated_aliases) + buffer << "Alias name " << node->getAlias() << " node " << node->formatASTForErrorMessage() << '\n'; + + buffer << "Expression resolve process stack " << '\n'; + expressions_in_resolve_process_stack.dump(buffer); + + buffer << "Table expressions in resolve process size " << table_expressions_in_resolve_process.size() << '\n'; + for (const auto & node : table_expressions_in_resolve_process) + buffer << "Table expression " << node->formatASTForErrorMessage() << '\n'; + + buffer << "Non cached identifier lookups during expression resolve " << non_cached_identifier_lookups_during_expression_resolve.size() << '\n'; + for (const auto & identifier_lookup : non_cached_identifier_lookups_during_expression_resolve) + buffer << "Identifier lookup " << identifier_lookup.dump() << '\n'; + + buffer << "Table expression node to data " << table_expression_node_to_data.size() << '\n'; + for (const auto & [table_expression_node, table_expression_data] : table_expression_node_to_data) + buffer << "Table expression node " << table_expression_node->formatASTForErrorMessage() << " data " << table_expression_data.dump() << '\n'; + + buffer << "Use identifier lookup to result cache " << use_identifier_lookup_to_result_cache << '\n'; + buffer << "Subquery depth " << subquery_depth << '\n'; +} + +[[maybe_unused]] String IdentifierResolveScope::dump() const +{ + WriteBufferFromOwnString buffer; + dump(buffer); + + return buffer.str(); +} } From aff54469fde1b34cd17eb6834079a23cccdedfaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mar=C3=ADn?= Date: Tue, 28 May 2024 12:19:20 +0200 Subject: [PATCH 101/211] Update 02232_dist_insert_send_logs_level_hung.sh --- .../0_stateless/02232_dist_insert_send_logs_level_hung.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/queries/0_stateless/02232_dist_insert_send_logs_level_hung.sh b/tests/queries/0_stateless/02232_dist_insert_send_logs_level_hung.sh index 32e58795bb0..618dc83c223 100755 --- a/tests/queries/0_stateless/02232_dist_insert_send_logs_level_hung.sh +++ b/tests/queries/0_stateless/02232_dist_insert_send_logs_level_hung.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash -# Tags: long, no-parallel, disable +# Tags: long, no-parallel, disabled # Tag: no-parallel - too heavy # Tag: long - too heavy -# Tag: disable Takes too long to be always run in CI +# Tag: disabled - Always takes 4+ minutes, in serial mode, which is too much to be always run in CI # This is the regression test when remote peer send some logs for INSERT, # it is easy to archive using materialized views, with small block size. From 16fb16ae2654cd6c59b64699f3438b3a33462c4c Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 12:28:15 +0200 Subject: [PATCH 102/211] Add code documentation for all flavours of fromReadable --- src/Functions/fromReadableDecimalSize.cpp | 62 +++++++++++++++-------- src/Functions/fromReadableSize.cpp | 60 +++++++++++++++------- 2 files changed, 82 insertions(+), 40 deletions(-) diff --git a/src/Functions/fromReadableDecimalSize.cpp b/src/Functions/fromReadableDecimalSize.cpp index 5093e31685d..5e1f4990a7c 100644 --- a/src/Functions/fromReadableDecimalSize.cpp +++ b/src/Functions/fromReadableDecimalSize.cpp @@ -8,7 +8,6 @@ namespace DB namespace { -// ISO/IEC 80000-13 binary units const std::unordered_map scale_factors = { {"b", 1L}, @@ -47,29 +46,50 @@ using FunctionFromReadableDecimalSize = FunctionFromReadable; using FunctionFromReadableDecimalSizeOrZero = FunctionFromReadable; + +FunctionDocumentation fromReadableDecimalSize_documentation { + .description = "Given a string containing the readable representation of a byte size with decimal units this function returns the corresponding number of bytes.", + .syntax = "fromReadableDecimalSize(x)", + .arguments = {{"x", "Readable size with decimal units ([String](../../sql-reference/data-types/string.md))"}}, + .returned_value = "Number of bytes, rounded up to the nearest integer ([UInt64](../../sql-reference/data-types/int-uint.md))", + .examples = { + {"example_integer", "SELECT fromReadableDecimalSize('1 KB')", "1024"}, + {"example_decimal", "SELECT fromReadableDecimalSize('1.1 KB')", "1127"}, + }, + .categories = {"OtherFunctions"}, +}; + +FunctionDocumentation fromReadableDecimalSizeOrNull_documentation { + .description = "Given a string containing the readable representation of a byte size with decimal units this function returns the corresponding number of bytes, or `NULL` if unable to parse the value.", + .syntax = "fromReadableDecimalSizeOrNull(x)", + .arguments = {{"x", "Readable size with decimal units ([String](../../sql-reference/data-types/string.md))"}}, + .returned_value = "Number of bytes, rounded up to the nearest integer, or NULL if unable to parse the input (Nullable([UInt64](../../sql-reference/data-types/int-uint.md)))", + .examples = { + {"example_integer", "SELECT fromReadableDecimalSizeOrNull('1 KiB')", "1024"}, + {"example_decimal", "SELECT fromReadableDecimalSizeOrNull('1.1 KiB')", "1127"}, + {"example_null", "SELECT fromReadableDecimalSizeOrNull('invalid')", "NULL"}, + }, + .categories = {"OtherFunctions"}, +}; + +FunctionDocumentation fromReadableDecimalSizeOrZero_documentation { + .description = "Given a string containing the readable representation of a byte size with decimal units this function returns the corresponding number of bytes, or 0 if unable to parse the value.", + .syntax = "formatReadableSizeOrZero(x)", + .arguments = {{"x", "Readable size with decimal units ([String](../../sql-reference/data-types/string.md))"}}, + .returned_value = "Number of bytes, rounded up to the nearest integer, or 0 if unable to parse the input ([UInt64](../../sql-reference/data-types/int-uint.md))", + .examples = { + {"example_integer", "SELECT fromReadableDecimalSizeOrZero('1 KiB')", "1024"}, + {"example_decimal", "SELECT fromReadableDecimalSizeOrZero('1.1 KiB')", "1127"}, + {"example_null", "SELECT fromReadableDecimalSizeOrZero('invalid')", "0"}, + }, + .categories = {"OtherFunctions"}, +}; } REGISTER_FUNCTION(FromReadableDecimalSize) { - factory.registerFunction(FunctionDocumentation - { - .description=R"( -Given a string containing the readable representation of a byte size, this function returns the corresponding number of bytes: -[example:basic_binary] -[example:basic_decimal] - -Accepts readable sizes up to the Exabyte (EB/EiB). - -)", - .examples{ - {"basic_binary", "SELECT fromReadableSize('1 KiB')", "1024"}, - {"basic_decimal", "SELECT fromReadableSize('1.523 KB')", "1523"}, - }, - .categories{"OtherFunctions"} - } - ); - factory.registerFunction(); - factory.registerFunction(); + factory.registerFunction(fromReadableDecimalSize_documentation); + factory.registerFunction(fromReadableDecimalSizeOrNull_documentation); + factory.registerFunction(fromReadableDecimalSizeOrZero_documentation); } - } diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index 841417e0e87..0dc21f2ae71 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -1,6 +1,7 @@ #include #include #include +#include "Common/FunctionDocumentation.h" namespace DB { @@ -49,28 +50,49 @@ using FunctionFromReadableSize = FunctionFromReadable; using FunctionFromReadableSizeOrZero = FunctionFromReadable; +FunctionDocumentation fromReadableSize_documentation { + .description = "Given a string containing the readable representation of a byte size with ISO/IEC 80000-13 units this function returns the corresponding number of bytes.", + .syntax = "fromReadableSize(x)", + .arguments = {{"x", "Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md))"}}, + .returned_value = "Number of bytes, rounded up to the nearest integer ([UInt64](../../sql-reference/data-types/int-uint.md))", + .examples = { + {"example_integer", "SELECT fromReadableSize('1 KiB')", "1024"}, + {"example_decimal", "SELECT fromReadableSize('1.1 KiB')", "1127"}, + }, + .categories = {"OtherFunctions"}, +}; + +FunctionDocumentation fromReadableSizeOrNull_documentation { + .description = "Given a string containing the readable representation of a byte size with ISO/IEC 80000-13 units this function returns the corresponding number of bytes, or `NULL` if unable to parse the value.", + .syntax = "fromReadableSizeOrNull(x)", + .arguments = {{"x", "Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md))"}}, + .returned_value = "Number of bytes, rounded up to the nearest integer, or NULL if unable to parse the input (Nullable([UInt64](../../sql-reference/data-types/int-uint.md)))", + .examples = { + {"example_integer", "SELECT fromReadableSizeOrNull('1 KiB')", "1024"}, + {"example_decimal", "SELECT fromReadableSizeOrNull('1.1 KiB')", "1127"}, + {"example_null", "SELECT fromReadableSizeOrNull('invalid')", "NULL"}, + }, + .categories = {"OtherFunctions"}, +}; + +FunctionDocumentation fromReadableSizeOrZero_documentation { + .description = "Given a string containing the readable representation of a byte size with ISO/IEC 80000-13 units this function returns the corresponding number of bytes, or 0 if unable to parse the value.", + .syntax = "fromReadableSizeOrZero(x)", + .arguments = {{"x", "Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md))"}}, + .returned_value = "Number of bytes, rounded up to the nearest integer, or 0 if unable to parse the input ([UInt64](../../sql-reference/data-types/int-uint.md))", + .examples = { + {"example_integer", "SELECT fromReadableSizeOrZero('1 KiB')", "1024"}, + {"example_decimal", "SELECT fromReadableSizeOrZero('1.1 KiB')", "1127"}, + {"example_null", "SELECT fromReadableSizeOrZero('invalid')", "0"}, + }, + .categories = {"OtherFunctions"}, +}; } REGISTER_FUNCTION(FromReadableSize) { - factory.registerFunction(FunctionDocumentation - { - .description=R"( -Given a string containing the readable representation of a byte size, this function returns the corresponding number of bytes: -[example:basic_binary] -[example:basic_decimal] - -Accepts readable sizes up to the Exabyte (EB/EiB). - -)", - .examples{ - {"basic_binary", "SELECT fromReadableSize('1 KiB')", "1024"}, - {"basic_decimal", "SELECT fromReadableSize('1.523 KB')", "1523"}, - }, - .categories{"OtherFunctions"} - } - ); - factory.registerFunction(); - factory.registerFunction(); + factory.registerFunction(fromReadableSize_documentation); + factory.registerFunction(fromReadableSizeOrNull_documentation); + factory.registerFunction(fromReadableSizeOrZero_documentation); } } From e6354a985985925ec642a1b0c7d0b06a6a5c2a22 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Tue, 28 May 2024 10:31:29 +0000 Subject: [PATCH 103/211] Sync code back from private to public repo --- src/Disks/IO/CachedOnDiskReadBufferFromFile.h | 14 +------------- src/Interpreters/FilesystemCacheLog.cpp | 13 +------------ 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/src/Disks/IO/CachedOnDiskReadBufferFromFile.h b/src/Disks/IO/CachedOnDiskReadBufferFromFile.h index 3433698a162..7ca3c33bda6 100644 --- a/src/Disks/IO/CachedOnDiskReadBufferFromFile.h +++ b/src/Disks/IO/CachedOnDiskReadBufferFromFile.h @@ -129,19 +129,7 @@ private: ReadType read_type = ReadType::REMOTE_FS_READ_BYPASS_CACHE; - static String toString(ReadType type) - { - switch (type) - { - case ReadType::CACHED: - return "CACHED"; - case ReadType::REMOTE_FS_READ_BYPASS_CACHE: - return "REMOTE_FS_READ_BYPASS_CACHE"; - case ReadType::REMOTE_FS_READ_AND_PUT_IN_CACHE: - return "REMOTE_FS_READ_AND_PUT_IN_CACHE"; - } - UNREACHABLE(); - } + static String toString(ReadType type) { return String(magic_enum::enum_name(type)); } size_t first_offset = 0; String nextimpl_step_log_info; diff --git a/src/Interpreters/FilesystemCacheLog.cpp b/src/Interpreters/FilesystemCacheLog.cpp index 80fe1c3a8ef..90756f1c84a 100644 --- a/src/Interpreters/FilesystemCacheLog.cpp +++ b/src/Interpreters/FilesystemCacheLog.cpp @@ -15,18 +15,7 @@ namespace DB static String typeToString(FilesystemCacheLogElement::CacheType type) { - switch (type) - { - case FilesystemCacheLogElement::CacheType::READ_FROM_CACHE: - return "READ_FROM_CACHE"; - case FilesystemCacheLogElement::CacheType::READ_FROM_FS_AND_DOWNLOADED_TO_CACHE: - return "READ_FROM_FS_AND_DOWNLOADED_TO_CACHE"; - case FilesystemCacheLogElement::CacheType::READ_FROM_FS_BYPASSING_CACHE: - return "READ_FROM_FS_BYPASSING_CACHE"; - case FilesystemCacheLogElement::CacheType::WRITE_THROUGH_CACHE: - return "WRITE_THROUGH_CACHE"; - } - UNREACHABLE(); + return String(magic_enum::enum_name(type)); } ColumnsDescription FilesystemCacheLogElement::getColumnsDescription() From 25f4430fbc997d28184c0f3506075a2e2899e935 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 12:42:06 +0200 Subject: [PATCH 104/211] Add regular docs for formatReadableSize flavours --- .../functions/other-functions.md | 91 +++++++++++++++++-- src/Functions/fromReadableSize.cpp | 46 ++++++++-- 2 files changed, 122 insertions(+), 15 deletions(-) diff --git a/docs/en/sql-reference/functions/other-functions.md b/docs/en/sql-reference/functions/other-functions.md index db3454c20b1..e56e9ef6f87 100644 --- a/docs/en/sql-reference/functions/other-functions.md +++ b/docs/en/sql-reference/functions/other-functions.md @@ -796,22 +796,27 @@ Result: ## fromReadableSize -Given a string containing the readable representation of a byte size, this function returns the corresponding number of bytes. - - Accepts up to the Exabyte (EB/EiB) +Given a string containing the readable representation of a byte size with ISO/IEC 80000-13 units this function returns the corresponding number of bytes. + +**Syntax** + +```sql +fromReadableSize(x) +``` **Arguments** -- `val` : readable size. [String](../data-types/string) +- `x` : Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md)). **Returned value** -- Number of bytes represented by the readable size [Float64](../data-types/float.md). +- Number of bytes, rounded up to the nearest integer ([UInt64](../../sql-reference/data-types/int-uint.md)). -Example: +**Example** ```sql SELECT - arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KB']) AS readable_sizes, + arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB']) AS readable_sizes, fromReadableSize(readable_sizes) AS sizes ``` @@ -820,7 +825,79 @@ SELECT │ 1 B │ 1 │ │ 1 KiB │ 1024 │ │ 3 MiB │ 3145728 │ -│ 5.314 KB │ 5314 │ +│ 5.314 KiB │ 5442 │ +└────────────────┴─────────┘ +``` + +## fromReadableSizeOrNull + +Given a string containing the readable representation of a byte size with ISO/IEC 80000-13 units this function returns the corresponding number of bytes, or `NULL` if unable to parse the value. + +**Syntax** + +```sql +fromReadableSizeOrNull(x) +``` + +**Arguments** + +- `x` : Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md)). + +**Returned value** + +- Number of bytes, rounded up to the nearest integer, or NULL if unable to parse the input (Nullable([UInt64](../../sql-reference/data-types/int-uint.md))). + +**Example** + +```sql +SELECT + arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, + fromReadableSizeOrNull(readable_sizes) AS sizes +``` + +```text +┌─readable_sizes─┬───sizes─┐ +│ 1 B │ 1 │ +│ 1 KiB │ 1024 │ +│ 3 MiB │ 3145728 │ +│ 5.314 KiB │ 5442 │ +│ invalid │ ᴺᵁᴸᴸ │ +└────────────────┴─────────┘ +``` + +## fromReadableSizeOrZero + +Given a string containing the readable representation of a byte size with ISO/IEC 80000-13 units this function returns the corresponding number of bytes, or 0 if unable to parse the value. + +**Syntax** + +```sql +fromReadableSizeOrZero(x) +``` + +**Arguments** + +- `x` : Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md)). + +**Returned value** + +- Number of bytes, rounded up to the nearest integer, or 0 if unable to parse the input ([UInt64](../../sql-reference/data-types/int-uint.md)). + +**Example** + +```sql +SELECT + arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, + fromReadableSizeOrZero(readable_sizes) AS sizes +``` + +```text +┌─readable_sizes─┬───sizes─┐ +│ 1 B │ 1 │ +│ 1 KiB │ 1024 │ +│ 3 MiB │ 3145728 │ +│ 5.314 KiB │ 5442 │ +│ invalid │ 0 │ └────────────────┴─────────┘ ``` diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index 0dc21f2ae71..bc83c67ef6f 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -56,8 +56,18 @@ FunctionDocumentation fromReadableSize_documentation { .arguments = {{"x", "Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md))"}}, .returned_value = "Number of bytes, rounded up to the nearest integer ([UInt64](../../sql-reference/data-types/int-uint.md))", .examples = { - {"example_integer", "SELECT fromReadableSize('1 KiB')", "1024"}, - {"example_decimal", "SELECT fromReadableSize('1.1 KiB')", "1127"}, + { + "basic", + "SELECT arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB']) AS readable_sizes, fromReadableSize(readable_sizes) AS sizes;", + R"( +┌─readable_sizes─┬───sizes─┐ +│ 1 B │ 1 │ +│ 1 KiB │ 1024 │ +│ 3 MiB │ 3145728 │ +│ 5.314 KiB │ 5442 │ +└────────────────┴─────────┘ +)" + }, }, .categories = {"OtherFunctions"}, }; @@ -68,9 +78,19 @@ FunctionDocumentation fromReadableSizeOrNull_documentation { .arguments = {{"x", "Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md))"}}, .returned_value = "Number of bytes, rounded up to the nearest integer, or NULL if unable to parse the input (Nullable([UInt64](../../sql-reference/data-types/int-uint.md)))", .examples = { - {"example_integer", "SELECT fromReadableSizeOrNull('1 KiB')", "1024"}, - {"example_decimal", "SELECT fromReadableSizeOrNull('1.1 KiB')", "1127"}, - {"example_null", "SELECT fromReadableSizeOrNull('invalid')", "NULL"}, + { + "basic", + "SELECT arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, fromReadableSize(readable_sizes) AS sizes;", + R"( +┌─readable_sizes─┬───sizes─┐ +│ 1 B │ 1 │ +│ 1 KiB │ 1024 │ +│ 3 MiB │ 3145728 │ +│ 5.314 KiB │ 5442 │ +│ invalid │ ᴺᵁᴸᴸ │ +└────────────────┴─────────┘ +)" + }, }, .categories = {"OtherFunctions"}, }; @@ -81,9 +101,19 @@ FunctionDocumentation fromReadableSizeOrZero_documentation { .arguments = {{"x", "Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md))"}}, .returned_value = "Number of bytes, rounded up to the nearest integer, or 0 if unable to parse the input ([UInt64](../../sql-reference/data-types/int-uint.md))", .examples = { - {"example_integer", "SELECT fromReadableSizeOrZero('1 KiB')", "1024"}, - {"example_decimal", "SELECT fromReadableSizeOrZero('1.1 KiB')", "1127"}, - {"example_null", "SELECT fromReadableSizeOrZero('invalid')", "0"}, + { + "basic", + "SELECT arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, fromReadableSize(readable_sizes) AS sizes;", + R"( +┌─readable_sizes─┬───sizes─┐ +│ 1 B │ 1 │ +│ 1 KiB │ 1024 │ +│ 3 MiB │ 3145728 │ +│ 5.314 KiB │ 5442 │ +│ invalid │ 0 │ +└────────────────┴─────────┘ +)", + }, }, .categories = {"OtherFunctions"}, }; From 2324ff587c459e45c99f4d51dec4a404c8bd43be Mon Sep 17 00:00:00 2001 From: alesapin Date: Tue, 28 May 2024 12:44:19 +0200 Subject: [PATCH 105/211] Bump From a25c4676da90c8323c58e08e511dc0cb40a50d79 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 12:50:07 +0200 Subject: [PATCH 106/211] Update examples for fromReadableDecimalSize --- .../functions/other-functions.md | 107 ++++++++++++++++++ src/Functions/fromReadableDecimalSize.cpp | 43 +++++-- 2 files changed, 142 insertions(+), 8 deletions(-) diff --git a/docs/en/sql-reference/functions/other-functions.md b/docs/en/sql-reference/functions/other-functions.md index e56e9ef6f87..6b3b14f314b 100644 --- a/docs/en/sql-reference/functions/other-functions.md +++ b/docs/en/sql-reference/functions/other-functions.md @@ -901,6 +901,113 @@ SELECT └────────────────┴─────────┘ ``` +## fromReadableDecimalSize + +Given a string containing the readable representation of a byte size with decimal units this function returns the corresponding number of bytes. + +**Syntax** + +```sql +fromReadableDecimalSize(x) +``` + +**Arguments** + +- `x` : Readable size with decimal units ([String](../../sql-reference/data-types/string.md)). + +**Returned value** + +- Number of bytes, rounded up to the nearest integer ([UInt64](../../sql-reference/data-types/int-uint.md)). + +**Example** + +```sql +SELECT + arrayJoin(['1 B', '1 KB', '3 MB', '5.314 KB']) AS readable_sizes, + fromReadableDecimalSize(readable_sizes) AS sizes +``` + +```text +┌─readable_sizes─┬───sizes─┐ +│ 1 B │ 1 │ +│ 1 KB │ 1000 │ +│ 3 MB │ 3000000 │ +│ 5.314 KB │ 5314 │ +└────────────────┴─────────┘ +``` + +## fromReadableDecimalSizeOrNull + +Given a string containing the readable representation of a byte size with decimal units this function returns the corresponding number of bytes, or `NULL` if unable to parse the value. + +**Syntax** + +```sql +fromReadableDecimalSizeOrNull(x) +``` + +**Arguments** + +- `x` : Readable size with decimal units ([String](../../sql-reference/data-types/string.md)). + +**Returned value** + +- Number of bytes, rounded up to the nearest integer, or NULL if unable to parse the input (Nullable([UInt64](../../sql-reference/data-types/int-uint.md))). + +**Example** + +```sql +SELECT + arrayJoin(['1 B', '1 KB', '3 MB', '5.314 KB', 'invalid']) AS readable_sizes, + fromReadableDecimalSizeOrNull(readable_sizes) AS sizes +``` + +```text +┌─readable_sizes─┬───sizes─┐ +│ 1 B │ 1 │ +│ 1 KB │ 1000 │ +│ 3 MB │ 3000000 │ +│ 5.314 KB │ 5314 │ +│ invalid │ ᴺᵁᴸᴸ │ +└────────────────┴─────────┘ +``` + +## fromReadableDecimalSizeOrZero + +Given a string containing the readable representation of a byte size with decimal units this function returns the corresponding number of bytes, or 0 if unable to parse the value. + +**Syntax** + +```sql +fromReadableDecimalSizeOrZero(x) +``` + +**Arguments** + +- `x` : Readable size with decimal units ([String](../../sql-reference/data-types/string.md)). + +**Returned value** + +- Number of bytes, rounded up to the nearest integer, or 0 if unable to parse the input ([UInt64](../../sql-reference/data-types/int-uint.md)). + +**Example** + +```sql +SELECT + arrayJoin(['1 B', '1 KB', '3 MB', '5.314 KB', 'invalid']) AS readable_sizes, + fromReadableSizeOrZero(readable_sizes) AS sizes +``` + +```text +┌─readable_sizes─┬───sizes─┐ +│ 1 B │ 1 │ +│ 1 KB │ 1000 │ +│ 3 MB │ 3000000 │ +│ 5.314 KB │ 5000 │ +│ invalid │ 0 │ +└────────────────┴─────────┘ +``` + ## formatReadableQuantity Given a number, this function returns a rounded number with suffix (thousand, million, billion, etc.) as string. diff --git a/src/Functions/fromReadableDecimalSize.cpp b/src/Functions/fromReadableDecimalSize.cpp index 5e1f4990a7c..c1e4c7f4128 100644 --- a/src/Functions/fromReadableDecimalSize.cpp +++ b/src/Functions/fromReadableDecimalSize.cpp @@ -53,8 +53,17 @@ FunctionDocumentation fromReadableDecimalSize_documentation { .arguments = {{"x", "Readable size with decimal units ([String](../../sql-reference/data-types/string.md))"}}, .returned_value = "Number of bytes, rounded up to the nearest integer ([UInt64](../../sql-reference/data-types/int-uint.md))", .examples = { - {"example_integer", "SELECT fromReadableDecimalSize('1 KB')", "1024"}, - {"example_decimal", "SELECT fromReadableDecimalSize('1.1 KB')", "1127"}, + { + "basic", + "SELECT arrayJoin(['1 B', '1 KB', '3 MB', '5.314 KB']) AS readable_sizes, fromReadableDecimalSize(readable_sizes) AS sizes;", + R"( +┌─readable_sizes─┬───sizes─┐ +│ 1 B │ 1 │ +│ 1 KB │ 1000 │ +│ 3 MB │ 3000000 │ +│ 5.314 KB │ 5314 │ +└────────────────┴─────────┘)" + }, }, .categories = {"OtherFunctions"}, }; @@ -65,9 +74,18 @@ FunctionDocumentation fromReadableDecimalSizeOrNull_documentation { .arguments = {{"x", "Readable size with decimal units ([String](../../sql-reference/data-types/string.md))"}}, .returned_value = "Number of bytes, rounded up to the nearest integer, or NULL if unable to parse the input (Nullable([UInt64](../../sql-reference/data-types/int-uint.md)))", .examples = { - {"example_integer", "SELECT fromReadableDecimalSizeOrNull('1 KiB')", "1024"}, - {"example_decimal", "SELECT fromReadableDecimalSizeOrNull('1.1 KiB')", "1127"}, - {"example_null", "SELECT fromReadableDecimalSizeOrNull('invalid')", "NULL"}, + { + "basic", + "SELECT arrayJoin(['1 B', '1 KB', '3 MB', '5.314 KB', 'invalid']) AS readable_sizes, fromReadableSizeOrNull(readable_sizes) AS sizes;", + R"( +┌─readable_sizes─┬───sizes─┐ +│ 1 B │ 1 │ +│ 1 KB │ 1000 │ +│ 3 MB │ 3000000 │ +│ 5.314 KB │ 5314 │ +│ invalid │ ᴺᵁᴸᴸ │ +└────────────────┴─────────┘)" + }, }, .categories = {"OtherFunctions"}, }; @@ -78,9 +96,18 @@ FunctionDocumentation fromReadableDecimalSizeOrZero_documentation { .arguments = {{"x", "Readable size with decimal units ([String](../../sql-reference/data-types/string.md))"}}, .returned_value = "Number of bytes, rounded up to the nearest integer, or 0 if unable to parse the input ([UInt64](../../sql-reference/data-types/int-uint.md))", .examples = { - {"example_integer", "SELECT fromReadableDecimalSizeOrZero('1 KiB')", "1024"}, - {"example_decimal", "SELECT fromReadableDecimalSizeOrZero('1.1 KiB')", "1127"}, - {"example_null", "SELECT fromReadableDecimalSizeOrZero('invalid')", "0"}, + { + "basic", + "SELECT arrayJoin(['1 B', '1 KB', '3 MB', '5.314 KB', 'invalid']) AS readable_sizes, fromReadableSizeOrZero(readable_sizes) AS sizes;", + R"( +┌─readable_sizes─┬───sizes─┐ +│ 1 B │ 1 │ +│ 1 KB │ 1000 │ +│ 3 MB │ 3000000 │ +│ 5.314 KB │ 5000 │ +│ invalid │ 0 │ +└────────────────┴─────────┘)" + }, }, .categories = {"OtherFunctions"}, }; From da9ebd41a97485abddc7a700e9d015428e0e4b01 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 12:57:32 +0200 Subject: [PATCH 107/211] More tests for unusual cases --- .../queries/0_stateless/03166_fromReadableSize.reference | 3 +++ tests/queries/0_stateless/03166_fromReadableSize.sql | 9 +++++++++ .../0_stateless/03167_fromReadableDecimalSize.reference | 3 +++ .../0_stateless/03167_fromReadableDecimalSize.sql | 9 +++++++++ 4 files changed, 24 insertions(+) diff --git a/tests/queries/0_stateless/03166_fromReadableSize.reference b/tests/queries/0_stateless/03166_fromReadableSize.reference index ad6d0f23a30..9eb3487c183 100644 --- a/tests/queries/0_stateless/03166_fromReadableSize.reference +++ b/tests/queries/0_stateless/03166_fromReadableSize.reference @@ -14,6 +14,9 @@ 1024 1024 \N +3217 +3217 +1000 1 B 1 1 KiB 1024 1 MiB 1048576 diff --git a/tests/queries/0_stateless/03166_fromReadableSize.sql b/tests/queries/0_stateless/03166_fromReadableSize.sql index f99561e89b5..9115d06abec 100644 --- a/tests/queries/0_stateless/03166_fromReadableSize.sql +++ b/tests/queries/0_stateless/03166_fromReadableSize.sql @@ -32,6 +32,15 @@ SELECT fromReadableSize(materialize('1 KiB')); -- Output is NULL if NULL arg is passed SELECT fromReadableSize(NULL); +-- Can parse more decimal places than Float64's precision +SELECT fromReadableSize('3.14159265358979323846264338327950288419716939937510 KiB'); + +-- Can parse sizes prefixed with a plus sign +SELECT fromReadableSize('+3.1415 KiB'); + +-- Can parse amounts in scientific notation +SELECT fromReadableSize('10e2 B'); + -- ERRORS -- No arguments SELECT fromReadableSize(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } diff --git a/tests/queries/0_stateless/03167_fromReadableDecimalSize.reference b/tests/queries/0_stateless/03167_fromReadableDecimalSize.reference index dec92c16499..e0d2b6e0dc3 100644 --- a/tests/queries/0_stateless/03167_fromReadableDecimalSize.reference +++ b/tests/queries/0_stateless/03167_fromReadableDecimalSize.reference @@ -14,6 +14,9 @@ 1000 1000 \N +3142 +3142 +1000 1 B 1 1 KB 1000 1 MB 1000000 diff --git a/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql b/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql index 861347c6ab8..84d560c0ccb 100644 --- a/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql +++ b/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql @@ -32,6 +32,15 @@ SELECT fromReadableDecimalSize(materialize('1 KB')); -- Output is NULL if NULL arg is passed SELECT fromReadableDecimalSize(NULL); +-- Can parse more decimal places than Float64's precision +SELECT fromReadableDecimalSize('3.14159265358979323846264338327950288419716939937510 KB'); + +-- Can parse sizes prefixed with a plus sign +SELECT fromReadableDecimalSize('+3.1415 KB'); + +-- Can parse amounts in scientific notation +SELECT fromReadableDecimalSize('10e2 B'); + -- ERRORS -- No arguments SELECT fromReadableDecimalSize(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } From 60d45f54955cbc6a53d86cc10a57de86d726ad1f Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Tue, 28 May 2024 11:16:50 +0000 Subject: [PATCH 108/211] Move code from header into source file --- src/Disks/IO/CachedOnDiskReadBufferFromFile.cpp | 5 +++++ src/Disks/IO/CachedOnDiskReadBufferFromFile.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Disks/IO/CachedOnDiskReadBufferFromFile.cpp b/src/Disks/IO/CachedOnDiskReadBufferFromFile.cpp index 1fe369832ac..e9c642666d3 100644 --- a/src/Disks/IO/CachedOnDiskReadBufferFromFile.cpp +++ b/src/Disks/IO/CachedOnDiskReadBufferFromFile.cpp @@ -274,6 +274,11 @@ bool CachedOnDiskReadBufferFromFile::canStartFromCache(size_t current_offset, co return current_write_offset > current_offset; } +String CachedOnDiskReadBufferFromFile::toString(ReadType type) +{ + return String(magic_enum::enum_name(type)); +} + CachedOnDiskReadBufferFromFile::ImplementationBufferPtr CachedOnDiskReadBufferFromFile::getReadBufferForFileSegment(FileSegment & file_segment) { diff --git a/src/Disks/IO/CachedOnDiskReadBufferFromFile.h b/src/Disks/IO/CachedOnDiskReadBufferFromFile.h index 7ca3c33bda6..119fa166214 100644 --- a/src/Disks/IO/CachedOnDiskReadBufferFromFile.h +++ b/src/Disks/IO/CachedOnDiskReadBufferFromFile.h @@ -129,7 +129,7 @@ private: ReadType read_type = ReadType::REMOTE_FS_READ_BYPASS_CACHE; - static String toString(ReadType type) { return String(magic_enum::enum_name(type)); } + static String toString(ReadType type); size_t first_offset = 0; String nextimpl_step_log_info; From 52d77052d3ed3dd5c7ff56d246ba887717490c4b Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Tue, 28 May 2024 11:27:06 +0000 Subject: [PATCH 109/211] Remove generateUUIDv7NonMonotonic() and generateUUIDv7ThreadMonotonic() functions --- .../sql-reference/functions/uuid-functions.md | 143 ------------------ .../sql-reference/functions/uuid-functions.md | 107 ------------- src/Functions/generateUUIDv7.cpp | 108 ++++--------- .../0_stateless/02310_uuid_v7.reference | 15 -- tests/queries/0_stateless/02310_uuid_v7.sql | 19 +-- 5 files changed, 32 insertions(+), 360 deletions(-) diff --git a/docs/en/sql-reference/functions/uuid-functions.md b/docs/en/sql-reference/functions/uuid-functions.md index 2707f0bf8d4..86c3302a784 100644 --- a/docs/en/sql-reference/functions/uuid-functions.md +++ b/docs/en/sql-reference/functions/uuid-functions.md @@ -126,149 +126,6 @@ SELECT generateUUIDv7(1), generateUUIDv7(2); └──────────────────────────────────────┴──────────────────────────────────────┘ ``` -## generateUUIDv7ThreadMonotonic - -Generates a [UUID](../data-types/uuid.md) of [version 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04). - -The generated UUID contains the current Unix timestamp in milliseconds (48 bits), followed by version "7" (4 bits), a counter (42 bit) to distinguish UUIDs within a millisecond (including a variant field "2", 2 bit), and a random field (32 bits). -For any given timestamp (unix_ts_ms), the counter starts at a random value and is incremented by 1 for each new UUID until the timestamp changes. -In case the counter overflows, the timestamp field is incremented by 1 and the counter is reset to a random new start value. - -This function behaves like [generateUUIDv7](#generateUUIDv7) but gives no guarantee on counter monotony across different simultaneous requests. -Monotonicity within one timestamp is guaranteed only within the same thread calling this function to generate UUIDs. - -``` - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -| unix_ts_ms | -├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -| unix_ts_ms | ver | counter_high_bits | -├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -|var| counter_low_bits | -├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -| rand_b | -└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ -``` - -:::note -As of April 2024, version 7 UUIDs are in draft status and their layout may change in future. -::: - -**Syntax** - -``` sql -generateUUIDv7ThreadMonotonic([expr]) -``` - -**Arguments** - -- `expr` — An arbitrary [expression](../syntax.md#syntax-expressions) used to bypass [common subexpression elimination](../functions/index.md#common-subexpression-elimination) if the function is called multiple times in a query. The value of the expression has no effect on the returned UUID. Optional. - -**Returned value** - -A value of type UUIDv7. - -**Usage example** - -First, create a table with a column of type UUID, then insert a generated UUIDv7 into the table. - -``` sql -CREATE TABLE tab (uuid UUID) ENGINE = Memory; - -INSERT INTO tab SELECT generateUUIDv7ThreadMonotonic(); - -SELECT * FROM tab; -``` - -Result: - -```response -┌─────────────────────────────────uuid─┐ -│ 018f05e2-e3b2-70cb-b8be-64b09b626d32 │ -└──────────────────────────────────────┘ -``` - -**Example with multiple UUIDs generated per row** - -```sql -SELECT generateUUIDv7ThreadMonotonic(1), generateUUIDv7ThreadMonotonic(2); - -┌─generateUUIDv7ThreadMonotonic(1)─────┬─generateUUIDv7ThreadMonotonic(2)─────┐ -│ 018f05e1-14ee-7bc5-9906-207153b400b1 │ 018f05e1-14ee-7bc5-9906-2072b8e96758 │ -└──────────────────────────────────────┴──────────────────────────────────────┘ -``` - -## generateUUIDv7NonMonotonic - -Generates a [UUID](../data-types/uuid.md) of [version 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04). - -The generated UUID contains the current Unix timestamp in milliseconds (48 bits), followed by version "7" (4 bits) and a random field (76 bits, including a 2-bit variant field "2"). - -This function is the fastest `generateUUIDv7*` function but it gives no monotonicity guarantees within a timestamp. - -``` - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -| unix_ts_ms | -├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -| unix_ts_ms | ver | rand_a | -├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -|var| rand_b | -├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -| rand_b | -└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ -``` - -:::note -As of April 2024, version 7 UUIDs are in draft status and their layout may change in future. -::: - -**Syntax** - -``` sql -generateUUIDv7NonMonotonic([expr]) -``` - -**Arguments** - -- `expr` — An arbitrary [expression](../syntax.md#syntax-expressions) used to bypass [common subexpression elimination](../functions/index.md#common-subexpression-elimination) if the function is called multiple times in a query. The value of the expression has no effect on the returned UUID. Optional. - -**Returned value** - -A value of type UUIDv7. - -**Example** - -First, create a table with a column of type UUID, then insert a generated UUIDv7 into the table. - -``` sql -CREATE TABLE tab (uuid UUID) ENGINE = Memory; - -INSERT INTO tab SELECT generateUUIDv7NonMonotonic(); - -SELECT * FROM tab; -``` - -Result: - -```response -┌─────────────────────────────────uuid─┐ -│ 018f05af-f4a8-778f-beee-1bedbc95c93b │ -└──────────────────────────────────────┘ -``` - -**Example with multiple UUIDs generated per row** - -```sql -SELECT generateUUIDv7NonMonotonic(1), generateUUIDv7NonMonotonic(2); - -┌─generateUUIDv7NonMonotonic(1) ───────┬─generateUUIDv7(2)NonMonotonic────────┐ -│ 018f05b1-8c2e-7567-a988-48d09606ae8c │ 018f05b1-8c2e-7946-895b-fcd7635da9a0 │ -└──────────────────────────────────────┴──────────────────────────────────────┘ -``` - ## empty Checks whether the input UUID is empty. diff --git a/docs/ru/sql-reference/functions/uuid-functions.md b/docs/ru/sql-reference/functions/uuid-functions.md index a7fe6592338..7fe90263599 100644 --- a/docs/ru/sql-reference/functions/uuid-functions.md +++ b/docs/ru/sql-reference/functions/uuid-functions.md @@ -112,113 +112,6 @@ SELECT generateUUIDv7(1), generateUUIDv7(2) └──────────────────────────────────────┴──────────────────────────────────────┘ ``` -## generateUUIDv7ThreadMonotonic {#uuidv7threadmonotonic-function-generate} - -Генерирует идентификатор [UUID версии 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04). Генерируемый UUID состоит из 48-битной временной метки (Unix time в миллисекундах), маркеров версии 7 и варианта 2, монотонно возрастающего счётчика для данной временной метки и случайных данных в указанной ниже последовательности. Для каждой новой временной метки счётчик стартует с нового случайного значения, а для следующих UUIDv7 он увеличивается на единицу. В случае переполнения счётчика временная метка принудительно увеличивается на 1, и счётчик снова стартует со случайного значения. Данная функция является ускоренным аналогом функции `generateUUIDv7` за счёт потери гарантии монотонности счётчика при одной и той же метке времени между одновременно исполняемыми разными запросами. Монотонность счётчика гарантируется только в пределах одного треда, исполняющего данную функцию для генерации нескольких UUID. - -**Синтаксис** - -``` sql -generateUUIDv7ThreadMonotonic([x]) -``` - -**Аргументы** - -- `x` — [выражение](../syntax.md#syntax-expressions), возвращающее значение одного из [поддерживаемых типов данных](../data-types/index.md#data_types). Значение используется, чтобы избежать [склейки одинаковых выражений](index.md#common-subexpression-elimination), если функция вызывается несколько раз в одном запросе. Необязательный параметр. - -**Возвращаемое значение** - -Значение типа [UUID](../../sql-reference/functions/uuid-functions.md). - -**Пример использования** - -Этот пример демонстрирует, как создать таблицу с UUID-колонкой и добавить в нее сгенерированный UUIDv7. - -``` sql -CREATE TABLE t_uuid (x UUID) ENGINE=TinyLog - -INSERT INTO t_uuid SELECT generateUUIDv7ThreadMonotonic() - -SELECT * FROM t_uuid -``` - -``` text -┌────────────────────────────────────x─┐ -│ 018f05e2-e3b2-70cb-b8be-64b09b626d32 │ -└──────────────────────────────────────┘ -``` - -**Пример использования, для генерации нескольких значений в одной строке** - -```sql -SELECT generateUUIDv7ThreadMonotonic(1), generateUUIDv7ThreadMonotonic(7) - -┌─generateUUIDv7ThreadMonotonic(1)─────┬─generateUUIDv7ThreadMonotonic(2)─────┐ -│ 018f05e1-14ee-7bc5-9906-207153b400b1 │ 018f05e1-14ee-7bc5-9906-2072b8e96758 │ -└──────────────────────────────────────┴──────────────────────────────────────┘ -``` - -## generateUUIDv7NonMonotonic {#uuidv7nonmonotonic-function-generate} - -Генерирует идентификатор [UUID версии 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04). Генерируемый UUID состоит из 48-битной временной метки (Unix time в миллисекундах), маркеров версии 7 и варианта 2, и случайных данных в следующей последовательности: -``` - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -| unix_ts_ms | -├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -| unix_ts_ms | ver | rand_a | -├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -|var| rand_b | -├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -| rand_b | -└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ -``` -::::note -На апрель 2024 года UUIDv7 находится в статусе черновика и его раскладка по битам может в итоге измениться. -:::: - -**Синтаксис** - -``` sql -generateUUIDv7NonMonotonic([x]) -``` - -**Аргументы** - -- `x` — [выражение](../syntax.md#syntax-expressions), возвращающее значение одного из [поддерживаемых типов данных](../data-types/index.md#data_types). Значение используется, чтобы избежать [склейки одинаковых выражений](index.md#common-subexpression-elimination), если функция вызывается несколько раз в одном запросе. Необязательный параметр. - -**Возвращаемое значение** - -Значение типа [UUID](../../sql-reference/functions/uuid-functions.md). - -**Пример использования** - -Этот пример демонстрирует, как создать таблицу с UUID-колонкой и добавить в нее сгенерированный UUIDv7. - -``` sql -CREATE TABLE t_uuid (x UUID) ENGINE=TinyLog - -INSERT INTO t_uuid SELECT generateUUIDv7NonMonotonic() - -SELECT * FROM t_uuid -``` - -``` text -┌────────────────────────────────────x─┐ -│ 018f05af-f4a8-778f-beee-1bedbc95c93b │ -└──────────────────────────────────────┘ -``` - -**Пример использования, для генерации нескольких значений в одной строке** - -```sql -SELECT generateUUIDv7NonMonotonic(1), generateUUIDv7NonMonotonic(7) -┌─generateUUIDv7NonMonotonic(1)────────┬─generateUUIDv7NonMonotonic(2)────────┐ -│ 018f05b1-8c2e-7567-a988-48d09606ae8c │ 018f05b1-8c2e-7946-895b-fcd7635da9a0 │ -└──────────────────────────────────────┴──────────────────────────────────────┘ -``` - ## empty {#empty} Проверяет, является ли входной UUID пустым. diff --git a/src/Functions/generateUUIDv7.cpp b/src/Functions/generateUUIDv7.cpp index f2a82431c0a..b226c0840f4 100644 --- a/src/Functions/generateUUIDv7.cpp +++ b/src/Functions/generateUUIDv7.cpp @@ -73,20 +73,6 @@ void setVariant(UUID & uuid) UUIDHelpers::getLowBytes(uuid) = (UUIDHelpers::getLowBytes(uuid) & rand_b_bits_mask) | variant_2_mask; } -struct FillAllRandomPolicy -{ - static constexpr auto name = "generateUUIDv7NonMonotonic"; - static constexpr auto description = R"(Generates a UUID of version 7. The generated UUID contains the current Unix timestamp in milliseconds (48 bits), followed by version "7" (4 bits), and a random field (74 bit, including a 2-bit variant field "2") to distinguish UUIDs within a millisecond. This function is the fastest generateUUIDv7* function but it gives no monotonicity guarantees within a timestamp.)"; - struct Data - { - void generate(UUID & uuid, uint64_t ts) - { - setTimestampAndVersion(uuid, ts); - setVariant(uuid); - } - }; -}; - struct CounterFields { uint64_t last_timestamp = 0; @@ -133,44 +119,21 @@ struct CounterFields }; -struct GlobalCounterPolicy +struct Data { - static constexpr auto name = "generateUUIDv7"; - static constexpr auto description = R"(Generates a UUID of version 7. The generated UUID contains the current Unix timestamp in milliseconds (48 bits), followed by version "7" (4 bits), a counter (42 bit, including a variant field "2", 2 bit) to distinguish UUIDs within a millisecond, and a random field (32 bits). For any given timestamp (unix_ts_ms), the counter starts at a random value and is incremented by 1 for each new UUID until the timestamp changes. In case the counter overflows, the timestamp field is incremented by 1 and the counter is reset to a random new start value. Function generateUUIDv7 guarantees that the counter field within a timestamp increments monotonically across all function invocations in concurrently running threads and queries.)"; - /// Guarantee counter monotonicity within one timestamp across all threads generating UUIDv7 simultaneously. - struct Data + static inline CounterFields fields; + static inline SharedMutex mutex; /// works a little bit faster than std::mutex here + std::lock_guard guard; + + Data() + : guard(mutex) + {} + + void generate(UUID & uuid, uint64_t timestamp) { - static inline CounterFields fields; - static inline SharedMutex mutex; /// works a little bit faster than std::mutex here - std::lock_guard guard; - - Data() - : guard(mutex) - {} - - void generate(UUID & uuid, uint64_t timestamp) - { - fields.generate(uuid, timestamp); - } - }; -}; - -struct ThreadLocalCounterPolicy -{ - static constexpr auto name = "generateUUIDv7ThreadMonotonic"; - static constexpr auto description = R"(Generates a UUID of version 7. The generated UUID contains the current Unix timestamp in milliseconds (48 bits), followed by version "7" (4 bits), a counter (42 bit, including a variant field "2", 2 bit) to distinguish UUIDs within a millisecond, and a random field (32 bits). For any given timestamp (unix_ts_ms), the counter starts at a random value and is incremented by 1 for each new UUID until the timestamp changes. In case the counter overflows, the timestamp field is incremented by 1 and the counter is reset to a random new start value. This function behaves like generateUUIDv7 but gives no guarantee on counter monotony across different simultaneous requests. Monotonicity within one timestamp is guaranteed only within the same thread calling this function to generate UUIDs.)"; - - /// Guarantee counter monotonicity within one timestamp within the same thread. Faster than GlobalCounterPolicy if a query uses multiple threads. - struct Data - { - static inline thread_local CounterFields fields; - - void generate(UUID & uuid, uint64_t timestamp) - { - fields.generate(uuid, timestamp); - } - }; + fields.generate(uuid, timestamp); + } }; } @@ -181,11 +144,12 @@ DECLARE_AVX2_SPECIFIC_CODE(__VA_ARGS__) DECLARE_SEVERAL_IMPLEMENTATIONS( -template -class FunctionGenerateUUIDv7Base : public IFunction, public FillPolicy +class FunctionGenerateUUIDv7Base : public IFunction { public: - String getName() const final { return FillPolicy::name; } + static constexpr auto name = "generateUUIDv7"; + + String getName() const final { return name; } size_t getNumberOfArguments() const final { return 0; } bool isDeterministic() const override { return false; } bool isDeterministicInScopeOfQuery() const final { return false; } @@ -221,7 +185,7 @@ public: uint64_t timestamp = getTimestampMillisecond(); for (UUID & uuid : vec_to) { - typename FillPolicy::Data data; + Data data; data.generate(uuid, timestamp); } } @@ -231,19 +195,18 @@ public: ) // DECLARE_SEVERAL_IMPLEMENTATIONS #undef DECLARE_SEVERAL_IMPLEMENTATIONS -template -class FunctionGenerateUUIDv7Base : public TargetSpecific::Default::FunctionGenerateUUIDv7Base +class FunctionGenerateUUIDv7Base : public TargetSpecific::Default::FunctionGenerateUUIDv7Base { public: - using Self = FunctionGenerateUUIDv7Base; - using Parent = TargetSpecific::Default::FunctionGenerateUUIDv7Base; + using Self = FunctionGenerateUUIDv7Base; + using Parent = TargetSpecific::Default::FunctionGenerateUUIDv7Base; explicit FunctionGenerateUUIDv7Base(ContextPtr context) : selector(context) { selector.registerImplementation(); #if USE_MULTITARGET_CODE - using ParentAVX2 = TargetSpecific::AVX2::FunctionGenerateUUIDv7Base; + using ParentAVX2 = TargetSpecific::AVX2::FunctionGenerateUUIDv7Base; selector.registerImplementation(); #endif } @@ -262,27 +225,16 @@ private: ImplementationSelector selector; }; -template -void registerUUIDv7Generator(auto & factory) -{ - static constexpr auto doc_syntax_format = "{}([expression])"; - static constexpr auto example_format = "SELECT {}()"; - static constexpr auto multiple_example_format = "SELECT {f}(1), {f}(2)"; - - FunctionDocumentation::Description description = FillPolicy::description; - FunctionDocumentation::Syntax syntax = fmt::format(doc_syntax_format, FillPolicy::name); - FunctionDocumentation::Arguments arguments = {{"expression", "The expression is used to bypass common subexpression elimination if the function is called multiple times in a query but otherwise ignored. Optional."}}; - FunctionDocumentation::ReturnedValue returned_value = "A value of type UUID version 7."; - FunctionDocumentation::Examples examples = {{"single", fmt::format(example_format, FillPolicy::name), ""}, {"multiple", fmt::format(multiple_example_format, fmt::arg("f", FillPolicy::name)), ""}}; - FunctionDocumentation::Categories categories = {"UUID"}; - - factory.template registerFunction>({description, syntax, arguments, returned_value, examples, categories}, FunctionFactory::CaseInsensitive); -} - REGISTER_FUNCTION(GenerateUUIDv7) { - registerUUIDv7Generator(factory); - registerUUIDv7Generator(factory); - registerUUIDv7Generator(factory); + FunctionDocumentation::Description description = R"(Generates a UUID of version 7. The generated UUID contains the current Unix timestamp in milliseconds (48 bits), followed by version "7" (4 bits), a counter (42 bit, including a variant field "2", 2 bit) to distinguish UUIDs within a millisecond, and a random field (32 bits). For any given timestamp (unix_ts_ms), the counter starts at a random value and is incremented by 1 for each new UUID until the timestamp changes. In case the counter overflows, the timestamp field is incremented by 1 and the counter is reset to a random new start value. Function generateUUIDv7 guarantees that the counter field within a timestamp increments monotonically across all function invocations in concurrently running threads and queries.)"; + FunctionDocumentation::Syntax syntax = "SELECT generateUUIDv7()"; + FunctionDocumentation::Arguments arguments = {{"expression", "The expression is used to bypass common subexpression elimination if the function is called multiple times in a query but otherwise ignored. Optional."}}; + FunctionDocumentation::ReturnedValue returned_value = "A value of type UUID version 7."; + FunctionDocumentation::Examples examples = {{"single", "SELECT generateUUIDv7()", ""}, {"multiple", "SELECT generateUUIDv7(1), generateUUIDv7(2)", ""}}; + FunctionDocumentation::Categories categories = {"UUID"}; + + factory.registerFunction({description, syntax, arguments, returned_value, examples, categories}); } + } diff --git a/tests/queries/0_stateless/02310_uuid_v7.reference b/tests/queries/0_stateless/02310_uuid_v7.reference index ca4150bded2..1fa98ca522a 100644 --- a/tests/queries/0_stateless/02310_uuid_v7.reference +++ b/tests/queries/0_stateless/02310_uuid_v7.reference @@ -1,18 +1,3 @@ --- generateUUIDv7 -- -UUID -7 -2 -0 -0 -1 --- generateUUIDv7ThreadMonotonic -- -UUID -7 -2 -0 -0 -1 --- generateUUIDv7NonMonotonic -- UUID 7 2 diff --git a/tests/queries/0_stateless/02310_uuid_v7.sql b/tests/queries/0_stateless/02310_uuid_v7.sql index 0f12de07d20..e1aa3189d93 100644 --- a/tests/queries/0_stateless/02310_uuid_v7.sql +++ b/tests/queries/0_stateless/02310_uuid_v7.sql @@ -1,23 +1,8 @@ -SELECT '-- generateUUIDv7 --'; +-- Tests function generateUUIDv7 + SELECT toTypeName(generateUUIDv7()); SELECT substring(hex(generateUUIDv7()), 13, 1); -- check version bits SELECT bitAnd(bitShiftRight(toUInt128(generateUUIDv7()), 62), 3); -- check variant bits SELECT generateUUIDv7(1) = generateUUIDv7(2); SELECT generateUUIDv7() = generateUUIDv7(1); SELECT generateUUIDv7(1) = generateUUIDv7(1); - -SELECT '-- generateUUIDv7ThreadMonotonic --'; -SELECT toTypeName(generateUUIDv7ThreadMonotonic()); -SELECT substring(hex(generateUUIDv7ThreadMonotonic()), 13, 1); -- check version bits -SELECT bitAnd(bitShiftRight(toUInt128(generateUUIDv7ThreadMonotonic()), 62), 3); -- check variant bits -SELECT generateUUIDv7ThreadMonotonic(1) = generateUUIDv7ThreadMonotonic(2); -SELECT generateUUIDv7ThreadMonotonic() = generateUUIDv7ThreadMonotonic(1); -SELECT generateUUIDv7ThreadMonotonic(1) = generateUUIDv7ThreadMonotonic(1); - -SELECT '-- generateUUIDv7NonMonotonic --'; -SELECT toTypeName(generateUUIDv7NonMonotonic()); -SELECT substring(hex(generateUUIDv7NonMonotonic()), 13, 1); -- check version bits -SELECT bitAnd(bitShiftRight(toUInt128(generateUUIDv7NonMonotonic()), 62), 3); -- check variant bits -SELECT generateUUIDv7NonMonotonic(1) = generateUUIDv7NonMonotonic(2); -SELECT generateUUIDv7NonMonotonic() = generateUUIDv7NonMonotonic(1); -SELECT generateUUIDv7NonMonotonic(1) = generateUUIDv7NonMonotonic(1); From 75450140eeaa32f02e11ae87da942094ddb97163 Mon Sep 17 00:00:00 2001 From: Blargian Date: Tue, 28 May 2024 13:43:22 +0200 Subject: [PATCH 110/211] JSON functions update --- .../sql-reference/functions/json-functions.md | 509 ++++++++++++++---- 1 file changed, 398 insertions(+), 111 deletions(-) diff --git a/docs/en/sql-reference/functions/json-functions.md b/docs/en/sql-reference/functions/json-functions.md index 8359d5f9fbc..b9b725be7d7 100644 --- a/docs/en/sql-reference/functions/json-functions.md +++ b/docs/en/sql-reference/functions/json-functions.md @@ -4,13 +4,13 @@ sidebar_position: 105 sidebar_label: JSON --- -There are two sets of functions to parse JSON. - - `simpleJSON*` (`visitParam*`) is made to parse a special very limited subset of a JSON, but these functions are extremely fast. - - `JSONExtract*` is made to parse normal JSON. +There are two sets of functions to parse JSON: + - `simpleJSON*` (`visitParam*`) which is made for parsing a limited subset of JSON, but to do so extremely fast. + - `JSONExtract*` which is made for parsing normal JSON. -# simpleJSON/visitParam functions +# simpleJSON / visitParam functions -ClickHouse has special functions for working with simplified JSON. All these JSON functions are based on strong assumptions about what the JSON can be, but they try to do as little as possible to get the job done. +ClickHouse has special functions for working with simplified JSON. All these JSON functions are based on strong assumptions about what the JSON can be. They try to do as little as possible to get the job done as quickly as possible. The following assumptions are made: @@ -29,6 +29,8 @@ Checks whether there is a field named `field_name`. The result is `UInt8`. simpleJSONHas(json, field_name) ``` +Alias: `visitParamHas`. + **Parameters** - `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) @@ -36,7 +38,7 @@ simpleJSONHas(json, field_name) **Returned value** -It returns `1` if the field exists, `0` otherwise. +- Returns `1` if the field exists, `0` otherwise. [UInt8](../data-types/int-uint.md). **Example** @@ -55,6 +57,8 @@ SELECT simpleJSONHas(json, 'foo') FROM jsons; SELECT simpleJSONHas(json, 'bar') FROM jsons; ``` +Result: + ```response 1 0 @@ -69,6 +73,8 @@ Parses `UInt64` from the value of the field named `field_name`. If this is a str simpleJSONExtractUInt(json, field_name) ``` +Alias: `visitParamExtractUInt`. + **Parameters** - `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) @@ -76,7 +82,7 @@ simpleJSONExtractUInt(json, field_name) **Returned value** -It returns the number parsed from the field if the field exists and contains a number, `0` otherwise. +- Returns the number parsed from the field if the field exists and contains a number, `0` otherwise. [UInt64](../data-types/int-uint.md). **Example** @@ -98,6 +104,8 @@ INSERT INTO jsons VALUES ('{"baz":2}'); SELECT simpleJSONExtractUInt(json, 'foo') FROM jsons ORDER BY json; ``` +Result: + ```response 0 4 @@ -116,6 +124,8 @@ Parses `Int64` from the value of the field named `field_name`. If this is a stri simpleJSONExtractInt(json, field_name) ``` +Alias: `visitParamExtractInt`. + **Parameters** - `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) @@ -123,7 +133,7 @@ simpleJSONExtractInt(json, field_name) **Returned value** -It returns the number parsed from the field if the field exists and contains a number, `0` otherwise. +- Returns the number parsed from the field if the field exists and contains a number, `0` otherwise. [Int64](../data-types/int-uint.md). **Example** @@ -145,6 +155,8 @@ INSERT INTO jsons VALUES ('{"baz":2}'); SELECT simpleJSONExtractInt(json, 'foo') FROM jsons ORDER BY json; ``` +Result: + ```response 0 -4 @@ -163,6 +175,8 @@ Parses `Float64` from the value of the field named `field_name`. If this is a st simpleJSONExtractFloat(json, field_name) ``` +Alias: `visitParamExtractFloat`. + **Parameters** - `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) @@ -170,7 +184,7 @@ simpleJSONExtractFloat(json, field_name) **Returned value** -It returns the number parsed from the field if the field exists and contains a number, `0` otherwise. +- Returns the number parsed from the field if the field exists and contains a number, `0` otherwise. [Float64](../data-types/float.md/#float32-float64). **Example** @@ -192,6 +206,8 @@ INSERT INTO jsons VALUES ('{"baz":2}'); SELECT simpleJSONExtractFloat(json, 'foo') FROM jsons ORDER BY json; ``` +Result: + ```response 0 -4000 @@ -210,6 +226,8 @@ Parses a true/false value from the value of the field named `field_name`. The re simpleJSONExtractBool(json, field_name) ``` +Alias: `visitParamExtractBool`. + **Parameters** - `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) @@ -240,6 +258,8 @@ SELECT simpleJSONExtractBool(json, 'bar') FROM jsons ORDER BY json; SELECT simpleJSONExtractBool(json, 'foo') FROM jsons ORDER BY json; ``` +Result: + ```response 0 1 @@ -257,6 +277,8 @@ Returns the value of the field named `field_name` as a `String`, including separ simpleJSONExtractRaw(json, field_name) ``` +Alias: `visitParamExtractRaw`. + **Parameters** - `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) @@ -264,7 +286,7 @@ simpleJSONExtractRaw(json, field_name) **Returned value** -It returns the value of the field as a [`String`](../data-types/string.md#string), including separators if the field exists, or an empty `String` otherwise. +- Returns the value of the field as a string, including separators if the field exists, or an empty string otherwise. [`String`](../data-types/string.md#string) **Example** @@ -286,6 +308,8 @@ INSERT INTO jsons VALUES ('{"baz":2}'); SELECT simpleJSONExtractRaw(json, 'foo') FROM jsons ORDER BY json; ``` +Result: + ```response "-4e3" @@ -304,6 +328,8 @@ Parses `String` in double quotes from the value of the field named `field_name`. simpleJSONExtractString(json, field_name) ``` +Alias: `visitParamExtractString`. + **Parameters** - `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) @@ -311,7 +337,7 @@ simpleJSONExtractString(json, field_name) **Returned value** -It returns the value of a field as a [`String`](../data-types/string.md#string), including separators. The value is unescaped. It returns an empty `String`: if the field doesn't contain a double quoted string, if unescaping fails or if the field doesn't exist. +- Returns the unescaped value of a field as a string, including separators. An empty string is returned if the field doesn't contain a double quoted string, if unescaping fails or if the field doesn't exist. [String](../data-types/string.md). **Implementation details** @@ -336,6 +362,8 @@ INSERT INTO jsons VALUES ('{"foo":"hello}'); SELECT simpleJSONExtractString(json, 'foo') FROM jsons ORDER BY json; ``` +Result: + ```response \n\0 @@ -343,41 +371,13 @@ SELECT simpleJSONExtractString(json, 'foo') FROM jsons ORDER BY json; ``` -## visitParamHas - -This function is [an alias of `simpleJSONHas`](./json-functions#simplejsonhas). - -## visitParamExtractUInt - -This function is [an alias of `simpleJSONExtractUInt`](./json-functions#simplejsonextractuint). - -## visitParamExtractInt - -This function is [an alias of `simpleJSONExtractInt`](./json-functions#simplejsonextractint). - -## visitParamExtractFloat - -This function is [an alias of `simpleJSONExtractFloat`](./json-functions#simplejsonextractfloat). - -## visitParamExtractBool - -This function is [an alias of `simpleJSONExtractBool`](./json-functions#simplejsonextractbool). - -## visitParamExtractRaw - -This function is [an alias of `simpleJSONExtractRaw`](./json-functions#simplejsonextractraw). - -## visitParamExtractString - -This function is [an alias of `simpleJSONExtractString`](./json-functions#simplejsonextractstring). - # JSONExtract functions -The following functions are based on [simdjson](https://github.com/lemire/simdjson) designed for more complex JSON parsing requirements. +The following functions are based on [simdjson](https://github.com/lemire/simdjson), and designed for more complex JSON parsing requirements. ## isValidJSON(json) -Checks that passed string is a valid json. +Checks that passed string is valid JSON. Examples: @@ -386,30 +386,40 @@ SELECT isValidJSON('{"a": "hello", "b": [-100, 200.0, 300]}') = 1 SELECT isValidJSON('not a json') = 0 ``` -## JSONHas(json\[, indices_or_keys\]...) +## JSONHas -If the value exists in the JSON document, `1` will be returned. +If the value exists in the JSON document, `1` will be returned. If the value does not exist, `0` will be returned. -If the value does not exist, `0` will be returned. +**Syntax** -Examples: +```sql +JSONHas(json [, indices_or_keys]...) +``` + +**Parameters** + +- `json`: JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). + +`indices_or_keys` type: +- String = access object member by key. +- Positive integer = access the n-th member/key from the beginning. +- Negative integer = access the n-th member/key from the end. + +**Returned value** + +- Returns `1` if the value exists in `json`, otherwise `0`. [UInt8](../data-types/int-uint.md). + +**Examples** + +Query: ``` sql SELECT JSONHas('{"a": "hello", "b": [-100, 200.0, 300]}', 'b') = 1 SELECT JSONHas('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 4) = 0 ``` -`indices_or_keys` is a list of zero or more arguments each of them can be either string or integer. - -- String = access object member by key. -- Positive integer = access the n-th member/key from the beginning. -- Negative integer = access the n-th member/key from the end. - -Minimum index of the element is 1. Thus the element 0 does not exist. - -You may use integers to access both JSON arrays and JSON objects. - -So, for example: +The minimum index of the element is 1. Thus the element 0 does not exist. You may use integers to access both JSON arrays and JSON objects. For example: ``` sql SELECT JSONExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', 1) = 'a' @@ -419,26 +429,62 @@ SELECT JSONExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', -2) = 'a' SELECT JSONExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 1) = 'hello' ``` -## JSONLength(json\[, indices_or_keys\]...) +## JSONLength -Return the length of a JSON array or a JSON object. +Return the length of a JSON array or a JSON object. If the value does not exist or has the wrong type, `0` will be returned. -If the value does not exist or has a wrong type, `0` will be returned. +**Syntax** -Examples: +```sql +JSONLength(json [, indices_or_keys]...) +``` + +**Parameters** + +- `json`: JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). + +`indices_or_keys` type: +- String = access object member by key. +- Positive integer = access the n-th member/key from the beginning. +- Negative integer = access the n-th member/key from the end. + +**Returned value** + +- Returns the length of the JSON array or JSON object. Returns `0` if the value does not exist or has the wrong type. [UInt64](../data-types/int-uint.md). + +**Examples** ``` sql SELECT JSONLength('{"a": "hello", "b": [-100, 200.0, 300]}', 'b') = 3 SELECT JSONLength('{"a": "hello", "b": [-100, 200.0, 300]}') = 2 ``` -## JSONType(json\[, indices_or_keys\]...) +## JSONType -Return the type of a JSON value. +Return the type of a JSON value. If the value does not exist, `Null` will be returned. -If the value does not exist, `Null` will be returned. +**Syntax** -Examples: +```sql +JSONType(json [, indices_or_keys]...) +``` + +**Parameters** + +- `json`: JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). + +`indices_or_keys` type: +- String = access object member by key. +- Positive integer = access the n-th member/key from the beginning. +- Negative integer = access the n-th member/key from the end. + +**Returned value** + +- Returns the type of a JSON value as a string, otherwise if the value doesn't exists it returns `Null`. [String](../data-types/string.md). + +**Examples** ``` sql SELECT JSONType('{"a": "hello", "b": [-100, 200.0, 300]}') = 'Object' @@ -446,35 +492,191 @@ SELECT JSONType('{"a": "hello", "b": [-100, 200.0, 300]}', 'a') = 'String' SELECT JSONType('{"a": "hello", "b": [-100, 200.0, 300]}', 'b') = 'Array' ``` -## JSONExtractUInt(json\[, indices_or_keys\]...) +## JSONExtractUInt -## JSONExtractInt(json\[, indices_or_keys\]...) +Parses JSON and extracts a value of UInt type. -## JSONExtractFloat(json\[, indices_or_keys\]...) +**Syntax** -## JSONExtractBool(json\[, indices_or_keys\]...) - -Parses a JSON and extract a value. These functions are similar to `visitParam` functions. - -If the value does not exist or has a wrong type, `0` will be returned. - -Examples: - -``` sql -SELECT JSONExtractInt('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 1) = -100 -SELECT JSONExtractFloat('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 2) = 200.0 -SELECT JSONExtractUInt('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', -1) = 300 +```sql +JSONExtractUInt(json [, indices_or_keys]...) ``` -## JSONExtractString(json\[, indices_or_keys\]...) +**Parameters** -Parses a JSON and extract a string. This function is similar to `visitParamExtractString` functions. +- `json`: JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). -If the value does not exist or has a wrong type, an empty string will be returned. +`indices_or_keys` type: +- String = access object member by key. +- Positive integer = access the n-th member/key from the beginning. +- Negative integer = access the n-th member/key from the end. -The value is unescaped. If unescaping failed, it returns an empty string. +**Returned value** -Examples: +- Returns a UInt value if it exists, otherwise it returns `Null`. [UInt64](../data-types/string.md). + +**Examples** + +Query: + +``` sql +SELECT JSONExtractUInt('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', -1) as x, toTypeName(x); +``` + +Result: + +```response +┌───x─┬─toTypeName(x)─┐ +│ 300 │ UInt64 │ +└─────┴───────────────┘ +``` + +## JSONExtractInt + +Parses JSON and extracts a value of Int type. + +**Syntax** + +```sql +JSONExtractInt(json [, indices_or_keys]...) +``` + +**Parameters** + +- `json`: JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). + +`indices_or_keys` type: +- String = access object member by key. +- Positive integer = access the n-th member/key from the beginning. +- Negative integer = access the n-th member/key from the end. + +**Returned value** + +- Returns an Int value if it exists, otherwise it returns `Null`. [Int64](../data-types/string.md). + +**Examples** + +Query: + +``` sql +SELECT JSONExtractInt('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', -1) as x, toTypeName(x); +``` + +Result: + +```response +┌───x─┬─toTypeName(x)─┐ +│ 300 │ Int64 │ +└─────┴───────────────┘ +``` + +## JSONExtractFloat + +Parses JSON and extracts a value of Int type. + +**Syntax** + +```sql +JSONExtractFloat(json [, indices_or_keys]...) +``` + +**Parameters** + +- `json`: JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). + +`indices_or_keys` type: +- String = access object member by key. +- Positive integer = access the n-th member/key from the beginning. +- Negative integer = access the n-th member/key from the end. + +**Returned value** + +- Returns an Float value if it exists, otherwise it returns `Null`. [Float64](../data-types/string.md). + +**Examples** + +Query: + +``` sql +SELECT JSONExtractFloat('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 2) as x, toTypeName(x); +``` + +Result: + +```response +┌───x─┬─toTypeName(x)─┐ +│ 200 │ Float64 │ +└─────┴───────────────┘ +``` + +## JSONExtractBool + +Parses JSON and extracts a boolean value. If the value does not exist or has a wrong type, `0` will be returned. + +**Syntax** + +```sql +JSONExtractBool(json\[, indices_or_keys\]...) +``` + +**Parameters** + +- `json`: JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). + +`indices_or_keys` type: +- String = access object member by key. +- Positive integer = access the n-th member/key from the beginning. +- Negative integer = access the n-th member/key from the end. + +**Returned value** + +- Returns a Boolean value if it exists, otherwise it returns `0`. [Float64](../data-types/boolean.md). + +**Example** + +Query: + +``` sql +SELECT JSONExtractBool('{"passed": true}', 'passed'); +``` + +Result: + +```response +┌─JSONExtractBool('{"passed": true}', 'passed')─┐ +│ 1 │ +└───────────────────────────────────────────────┘ +``` + +## JSONExtractString + +Parses JSON and extracts a string. This function is similar to [`visitParamExtractString`](#simplejsonextractstring) functions. If the value does not exist or has a wrong type, an empty string will be returned. + +**Syntax** + +```sql +JSONExtractString(json [, indices_or_keys]...) +``` + +**Parameters** + +- `json`: JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). + +`indices_or_keys` type: +- String = access object member by key. +- Positive integer = access the n-th member/key from the beginning. +- Negative integer = access the n-th member/key from the end. + +**Returned value** + +- Returns an unescapated string from `json`. If unescaping failed, if the value does not exist or if it has a wrong type then it returns an empty string. [String](../data-types/string.md). + +**Examples** ``` sql SELECT JSONExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 'a') = 'hello' @@ -526,7 +728,7 @@ Parses a JSON string and extracts the keys. JSONExtractKeys(json[, a, b, c...]) ``` -**Arguments** +**Parameters** - `json` — [String](../data-types/string.md) with valid JSON. - `a, b, c...` — Comma-separated indices or keys that specify the path to the inner field in a nested JSON object. Each argument can be either a [String](../data-types/string.md) to get the field by the key or an [Integer](../data-types/int-uint.md) to get the N-th field (indexed from 1, negative integers count from the end). If not set, the whole JSON is parsed as the top-level object. Optional parameter. @@ -552,27 +754,63 @@ text └────────────────────────────────────────────────────────────┘ ``` -## JSONExtractRaw(json\[, indices_or_keys\]...) +## JSONExtractRaw -Returns a part of JSON as unparsed string. +Returns part of the JSON as an unparsed string. If the part does not exist or has the wrong type, an empty string will be returned. -If the part does not exist or has a wrong type, an empty string will be returned. +**Syntax** -Example: +```sql +JSONExtractRaw(json [, indices_or_keys]...) +``` + +**Parameters** + +- `json`: JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). + +`indices_or_keys` type: +- String = access object member by key. +- Positive integer = access the n-th member/key from the beginning. +- Negative integer = access the n-th member/key from the end. + +**Returned value** + +- Returns part of the JSON as an unparsed string. Otherwise, an empty string is returned if the part does not exist or has the wrong type. [String](../data-types/string.md). + +**Example** ``` sql SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300]}', 'b') = '[-100, 200.0, 300]'; ``` -## JSONExtractArrayRaw(json\[, indices_or_keys...\]) +## JSONExtractArrayRaw(json [, indices_or_keys...]) -Returns an array with elements of JSON array, each represented as unparsed string. +Returns an array with elements of JSON array, each represented as unparsed string. If the part does not exist or isn’t array, an empty array will be returned. -If the part does not exist or isn’t array, an empty array will be returned. +**Syntax** -Example: +```sql +JSONExtractArrayRaw(json [, indices_or_keys...]) +``` -``` sql +**Parameters** + +- `json`: JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). + +`indices_or_keys` type: +- String = access object member by key. +- Positive integer = access the n-th member/key from the beginning. +- Negative integer = access the n-th member/key from the end. + +**Returned value** + +- Returns an array with elements of JSON array, each represented as unparsed string. Otherwise, an empty array is returned if the part does not exist or is not an array. [Array](../data-types/array.md)([String](../data-types/string.md)). + +**Example** + +```sql SELECT JSONExtractArrayRaw('{"a": "hello", "b": [-100, 200.0, "hello"]}', 'b') = ['-100', '200.0', '"hello"']; ``` @@ -640,13 +878,30 @@ Result: └───────────────────────────────────────────────────────────────────────────────────────────────────────┘ ``` -## JSON_EXISTS(json, path) +## JSON_EXISTS -If the value exists in the JSON document, `1` will be returned. +If the value exists in the JSON document, `1` will be returned. If the value does not exist, `0` will be returned. -If the value does not exist, `0` will be returned. +**Syntax** -Examples: +```sql +JSON_EXISTS(json, path) +``` + +**Parameters** + +- `json`: A string with valid JSON. [String](../data-types/string.md). +- `path`: A string representing the path. [String](../data-types/string.md). + +:::note +Before version 21.11 the order of arguments was wrong, i.e. JSON_EXISTS(path, json) +::: + +**Returned value** + +- Returns `1` if the value exists in the JSON document, otherwise `0`. + +**Examples** ``` sql SELECT JSON_EXISTS('{"hello":1}', '$.hello'); @@ -655,17 +910,32 @@ SELECT JSON_EXISTS('{"hello":["world"]}', '$.hello[*]'); SELECT JSON_EXISTS('{"hello":["world"]}', '$.hello[0]'); ``` +## JSON_QUERY + +Parses a JSON and extract a value as a JSON array or JSON object. If the value does not exist, an empty string will be returned. + +**Syntax** + +```sql +JSON_QUERY(json, path) +``` + +**Parameters** + +- `json`: A string with valid JSON. [String](../data-types/string.md). +- `path`: A string representing the path. [String](../data-types/string.md). + :::note Before version 21.11 the order of arguments was wrong, i.e. JSON_EXISTS(path, json) ::: -## JSON_QUERY(json, path) +**Returned value** -Parses a JSON and extract a value as JSON array or JSON object. +- Returns the extracted value as a JSON array or JSON object. Otherwise it returns an empty string if the value does not exist. [String](../data-types/string.md). -If the value does not exist, an empty string will be returned. +**Example** -Example: +Query: ``` sql SELECT JSON_QUERY('{"hello":"world"}', '$.hello'); @@ -682,17 +952,38 @@ Result: [2] String ``` + +## JSON_VALUE + +Parses a JSON and extract a value as a JSON scalar. If the value does not exist, an empty string will be returned by default. + +This function is controlled by the following settings: + +- by SET `function_json_value_return_type_allow_nullable` = `true`, `NULL` will be returned. If the value is complex type (such as: struct, array, map), an empty string will be returned by default. +- by SET `function_json_value_return_type_allow_complex` = `true`, the complex value will be returned. + +**Syntax** + +```sql +JSON_VALUE(json, path) +``` + +**Parameters** + +- `json`: A string with valid JSON. [String](../data-types/string.md). +- `path`: A string representing the path. [String](../data-types/string.md). + :::note -Before version 21.11 the order of arguments was wrong, i.e. JSON_QUERY(path, json) +Before version 21.11 the order of arguments was wrong, i.e. JSON_EXISTS(path, json) ::: -## JSON_VALUE(json, path) +**Returned value** -Parses a JSON and extract a value as JSON scalar. +- Returns the extracted value as a JSON scalar if it exists, otherwise an empty string is returned. [String](../data-types/string.md). -If the value does not exist, an empty string will be returned by default, and by SET `function_json_value_return_type_allow_nullable` = `true`, `NULL` will be returned. If the value is complex type (such as: struct, array, map), an empty string will be returned by default, and by SET `function_json_value_return_type_allow_complex` = `true`, the complex value will be returned. +**Example** -Example: +Query: ``` sql SELECT JSON_VALUE('{"hello":"world"}', '$.hello'); @@ -712,10 +1003,6 @@ world String ``` -:::note -Before version 21.11 the order of arguments was wrong, i.e. JSON_VALUE(path, json) -::: - ## toJSONString Serializes a value to its JSON representation. Various data types and nested structures are supported. From 97092e7f0cd1440f92152d858d7a72919f6e200b Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Tue, 28 May 2024 13:48:38 +0200 Subject: [PATCH 111/211] Remove old time deprecated repo.clickhouse.com from docs --- docs/_includes/install/deb_repo.sh | 11 ----- docs/_includes/install/rpm_repo.sh | 7 ---- docs/_includes/install/tgz_repo.sh | 19 --------- docs/en/getting-started/install.md | 62 ----------------------------- docs/ru/getting-started/install.md | 63 ----------------------------- docs/zh/getting-started/install.md | 64 ------------------------------ 6 files changed, 226 deletions(-) delete mode 100644 docs/_includes/install/deb_repo.sh delete mode 100644 docs/_includes/install/rpm_repo.sh delete mode 100644 docs/_includes/install/tgz_repo.sh diff --git a/docs/_includes/install/deb_repo.sh b/docs/_includes/install/deb_repo.sh deleted file mode 100644 index 21106e9fc47..00000000000 --- a/docs/_includes/install/deb_repo.sh +++ /dev/null @@ -1,11 +0,0 @@ -sudo apt-get install apt-transport-https ca-certificates dirmngr -sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv E0C56BD4 - -echo "deb https://repo.clickhouse.com/deb/stable/ main/" | sudo tee \ - /etc/apt/sources.list.d/clickhouse.list -sudo apt-get update - -sudo apt-get install -y clickhouse-server clickhouse-client - -sudo service clickhouse-server start -clickhouse-client # or "clickhouse-client --password" if you set up a password. diff --git a/docs/_includes/install/rpm_repo.sh b/docs/_includes/install/rpm_repo.sh deleted file mode 100644 index e3fd1232047..00000000000 --- a/docs/_includes/install/rpm_repo.sh +++ /dev/null @@ -1,7 +0,0 @@ -sudo yum install yum-utils -sudo rpm --import https://repo.clickhouse.com/CLICKHOUSE-KEY.GPG -sudo yum-config-manager --add-repo https://repo.clickhouse.com/rpm/clickhouse.repo -sudo yum install clickhouse-server clickhouse-client - -sudo /etc/init.d/clickhouse-server start -clickhouse-client # or "clickhouse-client --password" if you set up a password. diff --git a/docs/_includes/install/tgz_repo.sh b/docs/_includes/install/tgz_repo.sh deleted file mode 100644 index 0994510755b..00000000000 --- a/docs/_includes/install/tgz_repo.sh +++ /dev/null @@ -1,19 +0,0 @@ -export LATEST_VERSION=$(curl -s https://repo.clickhouse.com/tgz/stable/ | \ - grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | sort -V -r | head -n 1) -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-common-static-$LATEST_VERSION.tgz -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-common-static-dbg-$LATEST_VERSION.tgz -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-server-$LATEST_VERSION.tgz -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-client-$LATEST_VERSION.tgz - -tar -xzvf clickhouse-common-static-$LATEST_VERSION.tgz -sudo clickhouse-common-static-$LATEST_VERSION/install/doinst.sh - -tar -xzvf clickhouse-common-static-dbg-$LATEST_VERSION.tgz -sudo clickhouse-common-static-dbg-$LATEST_VERSION/install/doinst.sh - -tar -xzvf clickhouse-server-$LATEST_VERSION.tgz -sudo clickhouse-server-$LATEST_VERSION/install/doinst.sh -sudo /etc/init.d/clickhouse-server start - -tar -xzvf clickhouse-client-$LATEST_VERSION.tgz -sudo clickhouse-client-$LATEST_VERSION/install/doinst.sh diff --git a/docs/en/getting-started/install.md b/docs/en/getting-started/install.md index 6525c29306a..8980e3ce521 100644 --- a/docs/en/getting-started/install.md +++ b/docs/en/getting-started/install.md @@ -110,25 +110,6 @@ sudo service clickhouse-server start clickhouse-client # or "clickhouse-client --password" if you've set up a password. ``` -
      -Deprecated Method for installing deb-packages - -``` bash -sudo apt-get install apt-transport-https ca-certificates dirmngr -sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv E0C56BD4 - -echo "deb https://repo.clickhouse.com/deb/stable/ main/" | sudo tee \ - /etc/apt/sources.list.d/clickhouse.list -sudo apt-get update - -sudo apt-get install -y clickhouse-server clickhouse-client - -sudo service clickhouse-server start -clickhouse-client # or "clickhouse-client --password" if you set up a password. -``` - -
      -
      Migration Method for installing the deb-packages @@ -240,22 +221,6 @@ sudo systemctl start clickhouse-keeper sudo systemctl status clickhouse-keeper ``` -
      - -Deprecated Method for installing rpm-packages - -``` bash -sudo yum install yum-utils -sudo rpm --import https://repo.clickhouse.com/CLICKHOUSE-KEY.GPG -sudo yum-config-manager --add-repo https://repo.clickhouse.com/rpm/clickhouse.repo -sudo yum install clickhouse-server clickhouse-client - -sudo /etc/init.d/clickhouse-server start -clickhouse-client # or "clickhouse-client --password" if you set up a password. -``` - -
      - You can replace `stable` with `lts` to use different [release kinds](/knowledgebase/production) based on your needs. Then run these commands to install packages: @@ -308,33 +273,6 @@ tar -xzvf "clickhouse-client-$LATEST_VERSION-${ARCH}.tgz" \ sudo "clickhouse-client-$LATEST_VERSION/install/doinst.sh" ``` -
      - -Deprecated Method for installing tgz archives - -``` bash -export LATEST_VERSION=$(curl -s https://repo.clickhouse.com/tgz/stable/ | \ - grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | sort -V -r | head -n 1) -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-common-static-$LATEST_VERSION.tgz -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-common-static-dbg-$LATEST_VERSION.tgz -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-server-$LATEST_VERSION.tgz -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-client-$LATEST_VERSION.tgz - -tar -xzvf clickhouse-common-static-$LATEST_VERSION.tgz -sudo clickhouse-common-static-$LATEST_VERSION/install/doinst.sh - -tar -xzvf clickhouse-common-static-dbg-$LATEST_VERSION.tgz -sudo clickhouse-common-static-dbg-$LATEST_VERSION/install/doinst.sh - -tar -xzvf clickhouse-server-$LATEST_VERSION.tgz -sudo clickhouse-server-$LATEST_VERSION/install/doinst.sh -sudo /etc/init.d/clickhouse-server start - -tar -xzvf clickhouse-client-$LATEST_VERSION.tgz -sudo clickhouse-client-$LATEST_VERSION/install/doinst.sh -``` -
      - For production environments, it’s recommended to use the latest `stable`-version. You can find its number on GitHub page https://github.com/ClickHouse/ClickHouse/tags with postfix `-stable`. ### From Docker Image {#from-docker-image} diff --git a/docs/ru/getting-started/install.md b/docs/ru/getting-started/install.md index 59650826659..aee445da843 100644 --- a/docs/ru/getting-started/install.md +++ b/docs/ru/getting-started/install.md @@ -38,26 +38,6 @@ sudo service clickhouse-server start clickhouse-client # or "clickhouse-client --password" if you've set up a password. ``` -
      - -Устаревший способ установки deb-пакетов - -``` bash -sudo apt-get install apt-transport-https ca-certificates dirmngr -sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv E0C56BD4 - -echo "deb https://repo.clickhouse.com/deb/stable/ main/" | sudo tee \ - /etc/apt/sources.list.d/clickhouse.list -sudo apt-get update - -sudo apt-get install -y clickhouse-server clickhouse-client - -sudo service clickhouse-server start -clickhouse-client # or "clickhouse-client --password" if you set up a password. -``` - -
      - Чтобы использовать различные [версии ClickHouse](../faq/operations/production.md) в зависимости от ваших потребностей, вы можете заменить `stable` на `lts` или `testing`. Также вы можете вручную скачать и установить пакеты из [репозитория](https://packages.clickhouse.com/deb/pool/stable). @@ -110,22 +90,6 @@ sudo systemctl status clickhouse-server clickhouse-client # илм "clickhouse-client --password" если установлен пароль ``` -
      - -Устаревший способ установки rpm-пакетов - -``` bash -sudo yum install yum-utils -sudo rpm --import https://repo.clickhouse.com/CLICKHOUSE-KEY.GPG -sudo yum-config-manager --add-repo https://repo.clickhouse.com/rpm/clickhouse.repo -sudo yum install clickhouse-server clickhouse-client - -sudo /etc/init.d/clickhouse-server start -clickhouse-client # or "clickhouse-client --password" if you set up a password. -``` - -
      - Для использования наиболее свежих версий нужно заменить `stable` на `testing` (рекомендуется для тестовых окружений). Также иногда доступен `prestable`. Для непосредственной установки пакетов необходимо выполнить следующие команды: @@ -178,33 +142,6 @@ tar -xzvf "clickhouse-client-$LATEST_VERSION-${ARCH}.tgz" \ sudo "clickhouse-client-$LATEST_VERSION/install/doinst.sh" ``` -
      - -Устаревший способ установки из архивов tgz - -``` bash -export LATEST_VERSION=$(curl -s https://repo.clickhouse.com/tgz/stable/ | \ - grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | sort -V -r | head -n 1) -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-common-static-$LATEST_VERSION.tgz -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-common-static-dbg-$LATEST_VERSION.tgz -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-server-$LATEST_VERSION.tgz -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-client-$LATEST_VERSION.tgz - -tar -xzvf clickhouse-common-static-$LATEST_VERSION.tgz -sudo clickhouse-common-static-$LATEST_VERSION/install/doinst.sh - -tar -xzvf clickhouse-common-static-dbg-$LATEST_VERSION.tgz -sudo clickhouse-common-static-dbg-$LATEST_VERSION/install/doinst.sh - -tar -xzvf clickhouse-server-$LATEST_VERSION.tgz -sudo clickhouse-server-$LATEST_VERSION/install/doinst.sh -sudo /etc/init.d/clickhouse-server start - -tar -xzvf clickhouse-client-$LATEST_VERSION.tgz -sudo clickhouse-client-$LATEST_VERSION/install/doinst.sh -``` -
      - Для продуктивных окружений рекомендуется использовать последнюю `stable`-версию. Её номер также можно найти на github с на вкладке https://github.com/ClickHouse/ClickHouse/tags c постфиксом `-stable`. ### Из Docker образа {#from-docker-image} diff --git a/docs/zh/getting-started/install.md b/docs/zh/getting-started/install.md index e65cfea62cd..7e4fb6826e4 100644 --- a/docs/zh/getting-started/install.md +++ b/docs/zh/getting-started/install.md @@ -38,26 +38,6 @@ sudo service clickhouse-server start clickhouse-client # or "clickhouse-client --password" if you've set up a password. ``` -
      - -Deprecated Method for installing deb-packages - -``` bash -sudo apt-get install apt-transport-https ca-certificates dirmngr -sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv E0C56BD4 - -echo "deb https://repo.clickhouse.com/deb/stable/ main/" | sudo tee \ - /etc/apt/sources.list.d/clickhouse.list -sudo apt-get update - -sudo apt-get install -y clickhouse-server clickhouse-client - -sudo service clickhouse-server start -clickhouse-client # or "clickhouse-client --password" if you set up a password. -``` - -
      - 如果您想使用最新的版本,请用`testing`替代`stable`(我们只推荐您用于测试环境)。 你也可以从这里手动下载安装包:[下载](https://packages.clickhouse.com/deb/pool/stable)。 @@ -95,22 +75,6 @@ sudo /etc/init.d/clickhouse-server start clickhouse-client # or "clickhouse-client --password" if you set up a password. ``` -
      - -Deprecated Method for installing rpm-packages - -``` bash -sudo yum install yum-utils -sudo rpm --import https://repo.clickhouse.com/CLICKHOUSE-KEY.GPG -sudo yum-config-manager --add-repo https://repo.clickhouse.com/rpm/clickhouse.repo -sudo yum install clickhouse-server clickhouse-client - -sudo /etc/init.d/clickhouse-server start -clickhouse-client # or "clickhouse-client --password" if you set up a password. -``` - -
      - 如果您想使用最新的版本,请用`testing`替代`stable`(我们只推荐您用于测试环境)。`prestable`有时也可用。 然后运行命令安装: @@ -164,34 +128,6 @@ tar -xzvf "clickhouse-client-$LATEST_VERSION-${ARCH}.tgz" \ sudo "clickhouse-client-$LATEST_VERSION/install/doinst.sh" ``` -
      - -Deprecated Method for installing tgz archives - -``` bash -export LATEST_VERSION=$(curl -s https://repo.clickhouse.com/tgz/stable/ | \ - grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | sort -V -r | head -n 1) -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-common-static-$LATEST_VERSION.tgz -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-common-static-dbg-$LATEST_VERSION.tgz -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-server-$LATEST_VERSION.tgz -curl -O https://repo.clickhouse.com/tgz/stable/clickhouse-client-$LATEST_VERSION.tgz - -tar -xzvf clickhouse-common-static-$LATEST_VERSION.tgz -sudo clickhouse-common-static-$LATEST_VERSION/install/doinst.sh - -tar -xzvf clickhouse-common-static-dbg-$LATEST_VERSION.tgz -sudo clickhouse-common-static-dbg-$LATEST_VERSION/install/doinst.sh - -tar -xzvf clickhouse-server-$LATEST_VERSION.tgz -sudo clickhouse-server-$LATEST_VERSION/install/doinst.sh -sudo /etc/init.d/clickhouse-server start - -tar -xzvf clickhouse-client-$LATEST_VERSION.tgz -sudo clickhouse-client-$LATEST_VERSION/install/doinst.sh -``` - -
      - 对于生产环境,建议使用最新的`stable`版本。你可以在GitHub页面https://github.com/ClickHouse/ClickHouse/tags找到它,它以后缀`-stable`标志。 ### `Docker`安装包 {#from-docker-image} From cfe2efa3ef89331d146836fc285aba4bfe1d835a Mon Sep 17 00:00:00 2001 From: sarielwxm <1059293451@qq.com> Date: Tue, 28 May 2024 19:48:53 +0800 Subject: [PATCH 112/211] fix test --- tests/queries/0_stateless/03147_table_function_loop.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/queries/0_stateless/03147_table_function_loop.sql b/tests/queries/0_stateless/03147_table_function_loop.sql index 092f0531a2b..af48e4b11e3 100644 --- a/tests/queries/0_stateless/03147_table_function_loop.sql +++ b/tests/queries/0_stateless/03147_table_function_loop.sql @@ -1,3 +1,5 @@ +-- Tags: no-parallel + SELECT * FROM loop(numbers(3)) LIMIT 10; SELECT * FROM loop (numbers(3)) LIMIT 10 settings max_block_size = 1; From 4499b44bd40d8ec559f8b04771dc904b74faa081 Mon Sep 17 00:00:00 2001 From: alesapin Date: Tue, 28 May 2024 13:52:22 +0200 Subject: [PATCH 113/211] Fix standalone build --- src/Coordination/Standalone/Context.cpp | 5 +++++ src/Coordination/Standalone/Context.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/Coordination/Standalone/Context.cpp b/src/Coordination/Standalone/Context.cpp index 4b14b038852..2af8a015c2d 100644 --- a/src/Coordination/Standalone/Context.cpp +++ b/src/Coordination/Standalone/Context.cpp @@ -478,4 +478,9 @@ bool Context::hasTraceCollector() const return false; } +bool Context::isBackgroundOperationContext() const +{ + return false; +} + } diff --git a/src/Coordination/Standalone/Context.h b/src/Coordination/Standalone/Context.h index 7e4d1794f7d..79a3e32a72d 100644 --- a/src/Coordination/Standalone/Context.h +++ b/src/Coordination/Standalone/Context.h @@ -170,6 +170,8 @@ public: const ServerSettings & getServerSettings() const; bool hasTraceCollector() const; + + bool isBackgroundOperationContext() const; }; } From 6c2da59c9a590ef6e4649ff127772527fbd85522 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 14:10:36 +0200 Subject: [PATCH 114/211] Add missing extern consts --- src/Functions/fromReadable.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 45a371f74d5..675bcaa3535 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -18,10 +18,12 @@ namespace DB namespace ErrorCodes { - extern const int UNEXPECTED_DATA_AFTER_PARSED_VALUE; + extern const int BAD_ARGUMENTS; extern const int CANNOT_PARSE_INPUT_ASSERTION_FAILED; + extern const int CANNOT_PARSE_NUMBER; extern const int CANNOT_PARSE_TEXT; extern const int ILLEGAL_COLUMN; + extern const int UNEXPECTED_DATA_AFTER_PARSED_VALUE; } enum class ErrorHandling : uint8_t From 9c85d6a8c7f2d83ac19c858ea7373d4375466616 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 14:10:54 +0200 Subject: [PATCH 115/211] Add missing pragma once --- src/Functions/fromReadable.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 675bcaa3535..2e77a1a1816 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -1,3 +1,5 @@ +#pragma once + #include #include From c8d00b3a789570a737b84707c3937911b66fb0bd Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 14:11:57 +0200 Subject: [PATCH 116/211] Fix style --- src/Functions/fromReadable.h | 6 ++---- src/Functions/fromReadableSize.cpp | 13 +++++-------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 2e77a1a1816..a5dabdacf0b 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -55,12 +55,10 @@ public: }; validateFunctionArgumentTypes(*this, arguments, args); DataTypePtr return_type = std::make_shared(); - if (error_handling == ErrorHandling::Null) { + if (error_handling == ErrorHandling::Null) return std::make_shared(return_type); - } else { + else return return_type; - } - } diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index bc83c67ef6f..c265b008d7d 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -65,8 +65,7 @@ FunctionDocumentation fromReadableSize_documentation { │ 1 KiB │ 1024 │ │ 3 MiB │ 3145728 │ │ 5.314 KiB │ 5442 │ -└────────────────┴─────────┘ -)" +└────────────────┴─────────┘)" }, }, .categories = {"OtherFunctions"}, @@ -80,7 +79,7 @@ FunctionDocumentation fromReadableSizeOrNull_documentation { .examples = { { "basic", - "SELECT arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, fromReadableSize(readable_sizes) AS sizes;", + "SELECT arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, fromReadableSize(readable_sizes) AS sizes;", R"( ┌─readable_sizes─┬───sizes─┐ │ 1 B │ 1 │ @@ -88,8 +87,7 @@ FunctionDocumentation fromReadableSizeOrNull_documentation { │ 3 MiB │ 3145728 │ │ 5.314 KiB │ 5442 │ │ invalid │ ᴺᵁᴸᴸ │ -└────────────────┴─────────┘ -)" +└────────────────┴─────────┘)" }, }, .categories = {"OtherFunctions"}, @@ -103,7 +101,7 @@ FunctionDocumentation fromReadableSizeOrZero_documentation { .examples = { { "basic", - "SELECT arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, fromReadableSize(readable_sizes) AS sizes;", + "SELECT arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, fromReadableSize(readable_sizes) AS sizes;", R"( ┌─readable_sizes─┬───sizes─┐ │ 1 B │ 1 │ @@ -111,8 +109,7 @@ FunctionDocumentation fromReadableSizeOrZero_documentation { │ 3 MiB │ 3145728 │ │ 5.314 KiB │ 5442 │ │ invalid │ 0 │ -└────────────────┴─────────┘ -)", +└────────────────┴─────────┘)", }, }, .categories = {"OtherFunctions"}, From eddc59f4a9fd2116bc6c48f9f490a122de37e4f1 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 14:19:49 +0200 Subject: [PATCH 117/211] Add comment to header explaining format and exceptions --- src/Functions/fromReadable.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index a5dabdacf0b..0bb188903f5 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -35,6 +35,21 @@ enum class ErrorHandling : uint8_t Null }; +/** fromReadble*Size - Returns the number of bytes corresponding to a given readable binary or decimal size. + * Examples: + * - `fromReadableSize('123 MiB')` + * - `fromReadableDecimalSize('123 MB')` + * Meant to be the inverse of `formatReadable*Size` with the following exceptions: + * - Number of bytes is returned as an unsigned integer amount instead of a float. Decimal points are rounded up to the nearest integer. + * - Negative numbers are not allowed as negative sizes don't make sense. + * Flavours: + * - fromReadableSize + * - fromReadableSizeOrNull + * - fromReadableSizeOrZero + * - fromReadableDecimalSize + * - fromReadableDecimalSizeOrNull + * - fromReadableDecimalSizeOrZero + */ template class FunctionFromReadable : public IFunction { From 7e2ad78f34ce4114e597b35330335eadef552f60 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 14:20:57 +0200 Subject: [PATCH 118/211] Get rid of trailing whitespace --- src/Functions/fromReadableSize.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index c265b008d7d..d1f010695c0 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -78,7 +78,7 @@ FunctionDocumentation fromReadableSizeOrNull_documentation { .returned_value = "Number of bytes, rounded up to the nearest integer, or NULL if unable to parse the input (Nullable([UInt64](../../sql-reference/data-types/int-uint.md)))", .examples = { { - "basic", + "basic", "SELECT arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, fromReadableSize(readable_sizes) AS sizes;", R"( ┌─readable_sizes─┬───sizes─┐ @@ -100,7 +100,7 @@ FunctionDocumentation fromReadableSizeOrZero_documentation { .returned_value = "Number of bytes, rounded up to the nearest integer, or 0 if unable to parse the input ([UInt64](../../sql-reference/data-types/int-uint.md))", .examples = { { - "basic", + "basic", "SELECT arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, fromReadableSize(readable_sizes) AS sizes;", R"( ┌─readable_sizes─┬───sizes─┐ From 038e3ad4f86857a1ab270d2cddeabc7d111415fd Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 14:29:06 +0200 Subject: [PATCH 119/211] Remove even more trailing whitespace --- src/Functions/fromReadable.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 0bb188903f5..28aaca86e8a 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -75,7 +75,7 @@ public: else return return_type; } - + ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { @@ -90,7 +90,7 @@ public: getName() ); } - + std::unordered_map scale_factors = Impl::getScaleFactors(); auto col_res = ColumnUInt64::create(input_rows_count); @@ -102,7 +102,7 @@ public: auto & res_data = col_res->getData(); for (size_t i = 0; i < input_rows_count; ++i) - { + { std::string_view str = col_str->getDataAt(i).toView(); try { From 67abbca5628b6f2d8121f949ceb7d21d78db5909 Mon Sep 17 00:00:00 2001 From: Blargian Date: Tue, 28 May 2024 14:37:54 +0200 Subject: [PATCH 120/211] More updates to formatting --- .../sql-reference/functions/json-functions.md | 154 ++++++++++++------ 1 file changed, 100 insertions(+), 54 deletions(-) diff --git a/docs/en/sql-reference/functions/json-functions.md b/docs/en/sql-reference/functions/json-functions.md index b9b725be7d7..28a044ea4d2 100644 --- a/docs/en/sql-reference/functions/json-functions.md +++ b/docs/en/sql-reference/functions/json-functions.md @@ -5,8 +5,8 @@ sidebar_label: JSON --- There are two sets of functions to parse JSON: - - `simpleJSON*` (`visitParam*`) which is made for parsing a limited subset of JSON, but to do so extremely fast. - - `JSONExtract*` which is made for parsing normal JSON. + - [`simpleJSON*` (`visitParam*`)](#simplejsonhas) which is made for parsing a limited subset of JSON extremely fast. + - [`JSONExtract*`](#isvalidjson) which is made for parsing ordinary JSON. # simpleJSON / visitParam functions @@ -33,8 +33,8 @@ Alias: `visitParamHas`. **Parameters** -- `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) -- `field_name`: The name of the field to search for. [String literal](../syntax#string) +- `json` — The JSON in which the field is searched for. [String](../data-types/string.md#string) +- `field_name` — The name of the field to search for. [String literal](../syntax#string) **Returned value** @@ -77,8 +77,8 @@ Alias: `visitParamExtractUInt`. **Parameters** -- `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) -- `field_name`: The name of the field to search for. [String literal](../syntax#string) +- `json` — The JSON in which the field is searched for. [String](../data-types/string.md#string) +- `field_name` — The name of the field to search for. [String literal](../syntax#string) **Returned value** @@ -128,8 +128,8 @@ Alias: `visitParamExtractInt`. **Parameters** -- `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) -- `field_name`: The name of the field to search for. [String literal](../syntax#string) +- `json` — The JSON in which the field is searched for. [String](../data-types/string.md#string) +- `field_name` — The name of the field to search for. [String literal](../syntax#string) **Returned value** @@ -179,8 +179,8 @@ Alias: `visitParamExtractFloat`. **Parameters** -- `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) -- `field_name`: The name of the field to search for. [String literal](../syntax#string) +- `json` — The JSON in which the field is searched for. [String](../data-types/string.md#string) +- `field_name` — The name of the field to search for. [String literal](../syntax#string) **Returned value** @@ -230,8 +230,8 @@ Alias: `visitParamExtractBool`. **Parameters** -- `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) -- `field_name`: The name of the field to search for. [String literal](../syntax#string) +- `json` — The JSON in which the field is searched for. [String](../data-types/string.md#string) +- `field_name` — The name of the field to search for. [String literal](../syntax#string) **Returned value** @@ -281,8 +281,8 @@ Alias: `visitParamExtractRaw`. **Parameters** -- `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) -- `field_name`: The name of the field to search for. [String literal](../syntax#string) +- `json` — The JSON in which the field is searched for. [String](../data-types/string.md#string) +- `field_name` — The name of the field to search for. [String literal](../syntax#string) **Returned value** @@ -332,8 +332,8 @@ Alias: `visitParamExtractString`. **Parameters** -- `json`: The JSON in which the field is searched for. [String](../data-types/string.md#string) -- `field_name`: The name of the field to search for. [String literal](../syntax#string) +- `json` — The JSON in which the field is searched for. [String](../data-types/string.md#string) +- `field_name` — The name of the field to search for. [String literal](../syntax#string) **Returned value** @@ -375,10 +375,16 @@ Result: The following functions are based on [simdjson](https://github.com/lemire/simdjson), and designed for more complex JSON parsing requirements. -## isValidJSON(json) +## isValidJSON Checks that passed string is valid JSON. +**Syntax** + +```sql +isValidJSON(json) +``` + Examples: ``` sql @@ -398,8 +404,8 @@ JSONHas(json [, indices_or_keys]...) **Parameters** -- `json`: JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `json` — JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -441,8 +447,8 @@ JSONLength(json [, indices_or_keys]...) **Parameters** -- `json`: JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `json` — JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -472,8 +478,8 @@ JSONType(json [, indices_or_keys]...) **Parameters** -- `json`: JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `json` — JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -504,8 +510,8 @@ JSONExtractUInt(json [, indices_or_keys]...) **Parameters** -- `json`: JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `json` — JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -544,8 +550,8 @@ JSONExtractInt(json [, indices_or_keys]...) **Parameters** -- `json`: JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `json` — JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -584,8 +590,8 @@ JSONExtractFloat(json [, indices_or_keys]...) **Parameters** -- `json`: JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `json` — JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -624,8 +630,8 @@ JSONExtractBool(json\[, indices_or_keys\]...) **Parameters** -- `json`: JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `json` — JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -634,7 +640,7 @@ JSONExtractBool(json\[, indices_or_keys\]...) **Returned value** -- Returns a Boolean value if it exists, otherwise it returns `0`. [Float64](../data-types/boolean.md). +- Returns a Boolean value if it exists, otherwise it returns `0`. [Bool](../data-types/boolean.md). **Example** @@ -664,8 +670,8 @@ JSONExtractString(json [, indices_or_keys]...) **Parameters** -- `json`: JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `json` — JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -686,16 +692,35 @@ SELECT JSONExtractString('{"abc":"\\u263"}', 'abc') = '' SELECT JSONExtractString('{"abc":"hello}', 'abc') = '' ``` -## JSONExtract(json\[, indices_or_keys...\], Return_type) +## JSONExtract -Parses a JSON and extract a value of the given ClickHouse data type. +Parses JSON and extracts a value of the given ClickHouse data type. This function is a generalized version of the previous `JSONExtract` functions. Meaning: -This is a generalization of the previous `JSONExtract` functions. -This means `JSONExtract(..., 'String')` returns exactly the same as `JSONExtractString()`, `JSONExtract(..., 'Float64')` returns exactly the same as `JSONExtractFloat()`. -Examples: +**Syntax** + +```sql +JSONExtract(json [, indices_or_keys...], return_type) +``` + +**Parameters** + +- `json` — JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `return_type` — A string specifying the type of the value to extract. [String](../data-types/string.md). + +`indices_or_keys` type: +- String = access object member by key. +- Positive integer = access the n-th member/key from the beginning. +- Negative integer = access the n-th member/key from the end. + +**Returned value** + +- Returns a value if it exists of the specified return type, otherwise it returns `0`, `Null`, or an empty-string depending on the specified return type. [UInt64](../data-types/int-uint.md), [Int64](../data-types/int-uint.md), [Float64](../data-types/float.md), [Bool](../data-types/boolean.md) or [String](../data-types/string.md). + +**Examples** ``` sql SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'Tuple(String, Array(Float64))') = ('hello',[-100,200,300]) @@ -708,11 +733,32 @@ SELECT JSONExtract('{"day": "Thursday"}', 'day', 'Enum8(\'Sunday\' = 0, \'Monday SELECT JSONExtract('{"day": 5}', 'day', 'Enum8(\'Sunday\' = 0, \'Monday\' = 1, \'Tuesday\' = 2, \'Wednesday\' = 3, \'Thursday\' = 4, \'Friday\' = 5, \'Saturday\' = 6)') = 'Friday' ``` -## JSONExtractKeysAndValues(json\[, indices_or_keys...\], Value_type) +## JSONExtractKeysAndValues -Parses key-value pairs from a JSON where the values are of the given ClickHouse data type. +Parses key-value pairs from JSON where the values are of the given ClickHouse data type. -Example: +**Syntax** + +```sql +JSONExtractKeysAndValues(json [, indices_or_keys...], value_type) +``` + +**Parameters** + +- `json` — JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `value_type` — A string specifying the type of the value to extract. [String](../data-types/string.md). + +`indices_or_keys` type: +- String = access object member by key. +- Positive integer = access the n-th member/key from the beginning. +- Negative integer = access the n-th member/key from the end. + +**Returned value** + +- Returns an array of parsed key-value pairs. [Array](../data-types/array.md)([Tuple](../data-types/tuple.md)(`value_type`)). + +**Example** ``` sql SELECT JSONExtractKeysAndValues('{"x": {"a": 5, "b": 7, "c": 11}}', 'x', 'Int8') = [('a',5),('b',7),('c',11)]; @@ -735,7 +781,7 @@ JSONExtractKeys(json[, a, b, c...]) **Returned value** -Array with the keys of the JSON. [Array](../data-types/array.md)([String](../data-types/string.md)). +- Returns an array with the keys of the JSON. [Array](../data-types/array.md)([String](../data-types/string.md)). **Example** @@ -766,8 +812,8 @@ JSONExtractRaw(json [, indices_or_keys]...) **Parameters** -- `json`: JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `json` — JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -784,7 +830,7 @@ JSONExtractRaw(json [, indices_or_keys]...) SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300]}', 'b') = '[-100, 200.0, 300]'; ``` -## JSONExtractArrayRaw(json [, indices_or_keys...]) +## JSONExtractArrayRaw Returns an array with elements of JSON array, each represented as unparsed string. If the part does not exist or isn’t array, an empty array will be returned. @@ -796,8 +842,8 @@ JSONExtractArrayRaw(json [, indices_or_keys...]) **Parameters** -- `json`: JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` : A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `json` — JSON string to parse. [String](../data-types/string.md). +- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -890,8 +936,8 @@ JSON_EXISTS(json, path) **Parameters** -- `json`: A string with valid JSON. [String](../data-types/string.md). -- `path`: A string representing the path. [String](../data-types/string.md). +- `json` — A string with valid JSON. [String](../data-types/string.md). +- `path` — A string representing the path. [String](../data-types/string.md). :::note Before version 21.11 the order of arguments was wrong, i.e. JSON_EXISTS(path, json) @@ -922,8 +968,8 @@ JSON_QUERY(json, path) **Parameters** -- `json`: A string with valid JSON. [String](../data-types/string.md). -- `path`: A string representing the path. [String](../data-types/string.md). +- `json` — A string with valid JSON. [String](../data-types/string.md). +- `path` — A string representing the path. [String](../data-types/string.md). :::note Before version 21.11 the order of arguments was wrong, i.e. JSON_EXISTS(path, json) @@ -970,8 +1016,8 @@ JSON_VALUE(json, path) **Parameters** -- `json`: A string with valid JSON. [String](../data-types/string.md). -- `path`: A string representing the path. [String](../data-types/string.md). +- `json` — A string with valid JSON. [String](../data-types/string.md). +- `path` — A string representing the path. [String](../data-types/string.md). :::note Before version 21.11 the order of arguments was wrong, i.e. JSON_EXISTS(path, json) From 75bb7525dabbcd97a9428b8543a18128838dff79 Mon Sep 17 00:00:00 2001 From: Blargian Date: Tue, 28 May 2024 14:48:10 +0200 Subject: [PATCH 121/211] Make headings subheadings to organize functions into two categories --- .../sql-reference/functions/json-functions.md | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/docs/en/sql-reference/functions/json-functions.md b/docs/en/sql-reference/functions/json-functions.md index 28a044ea4d2..c522789a863 100644 --- a/docs/en/sql-reference/functions/json-functions.md +++ b/docs/en/sql-reference/functions/json-functions.md @@ -5,10 +5,10 @@ sidebar_label: JSON --- There are two sets of functions to parse JSON: - - [`simpleJSON*` (`visitParam*`)](#simplejsonhas) which is made for parsing a limited subset of JSON extremely fast. - - [`JSONExtract*`](#isvalidjson) which is made for parsing ordinary JSON. + - [`simpleJSON*` (`visitParam*`)](#simplejson--visitparam-functions) which is made for parsing a limited subset of JSON extremely fast. + - [`JSONExtract*`](#jsonextract-functions) which is made for parsing ordinary JSON. -# simpleJSON / visitParam functions +## simpleJSON / visitParam functions ClickHouse has special functions for working with simplified JSON. All these JSON functions are based on strong assumptions about what the JSON can be. They try to do as little as possible to get the job done as quickly as possible. @@ -19,7 +19,7 @@ The following assumptions are made: 3. Fields are searched for on any nesting level, indiscriminately. If there are multiple matching fields, the first occurrence is used. 4. The JSON does not have space characters outside of string literals. -## simpleJSONHas +### simpleJSONHas Checks whether there is a field named `field_name`. The result is `UInt8`. @@ -63,7 +63,7 @@ Result: 1 0 ``` -## simpleJSONExtractUInt +### simpleJSONExtractUInt Parses `UInt64` from the value of the field named `field_name`. If this is a string field, it tries to parse a number from the beginning of the string. If the field does not exist, or it exists but does not contain a number, it returns `0`. @@ -114,7 +114,7 @@ Result: 5 ``` -## simpleJSONExtractInt +### simpleJSONExtractInt Parses `Int64` from the value of the field named `field_name`. If this is a string field, it tries to parse a number from the beginning of the string. If the field does not exist, or it exists but does not contain a number, it returns `0`. @@ -165,7 +165,7 @@ Result: 5 ``` -## simpleJSONExtractFloat +### simpleJSONExtractFloat Parses `Float64` from the value of the field named `field_name`. If this is a string field, it tries to parse a number from the beginning of the string. If the field does not exist, or it exists but does not contain a number, it returns `0`. @@ -216,7 +216,7 @@ Result: 5 ``` -## simpleJSONExtractBool +### simpleJSONExtractBool Parses a true/false value from the value of the field named `field_name`. The result is `UInt8`. @@ -267,7 +267,7 @@ Result: 0 ``` -## simpleJSONExtractRaw +### simpleJSONExtractRaw Returns the value of the field named `field_name` as a `String`, including separators. @@ -318,7 +318,7 @@ Result: {"def":[1,2,3]} ``` -## simpleJSONExtractString +### simpleJSONExtractString Parses `String` in double quotes from the value of the field named `field_name`. @@ -371,11 +371,11 @@ Result: ``` -# JSONExtract functions +## JSONExtract functions The following functions are based on [simdjson](https://github.com/lemire/simdjson), and designed for more complex JSON parsing requirements. -## isValidJSON +### isValidJSON Checks that passed string is valid JSON. @@ -392,7 +392,7 @@ SELECT isValidJSON('{"a": "hello", "b": [-100, 200.0, 300]}') = 1 SELECT isValidJSON('not a json') = 0 ``` -## JSONHas +### JSONHas If the value exists in the JSON document, `1` will be returned. If the value does not exist, `0` will be returned. @@ -435,7 +435,7 @@ SELECT JSONExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', -2) = 'a' SELECT JSONExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 1) = 'hello' ``` -## JSONLength +### JSONLength Return the length of a JSON array or a JSON object. If the value does not exist or has the wrong type, `0` will be returned. @@ -466,7 +466,7 @@ SELECT JSONLength('{"a": "hello", "b": [-100, 200.0, 300]}', 'b') = 3 SELECT JSONLength('{"a": "hello", "b": [-100, 200.0, 300]}') = 2 ``` -## JSONType +### JSONType Return the type of a JSON value. If the value does not exist, `Null` will be returned. @@ -498,7 +498,7 @@ SELECT JSONType('{"a": "hello", "b": [-100, 200.0, 300]}', 'a') = 'String' SELECT JSONType('{"a": "hello", "b": [-100, 200.0, 300]}', 'b') = 'Array' ``` -## JSONExtractUInt +### JSONExtractUInt Parses JSON and extracts a value of UInt type. @@ -538,7 +538,7 @@ Result: └─────┴───────────────┘ ``` -## JSONExtractInt +### JSONExtractInt Parses JSON and extracts a value of Int type. @@ -578,7 +578,7 @@ Result: └─────┴───────────────┘ ``` -## JSONExtractFloat +### JSONExtractFloat Parses JSON and extracts a value of Int type. @@ -618,7 +618,7 @@ Result: └─────┴───────────────┘ ``` -## JSONExtractBool +### JSONExtractBool Parses JSON and extracts a boolean value. If the value does not exist or has a wrong type, `0` will be returned. @@ -658,7 +658,7 @@ Result: └───────────────────────────────────────────────┘ ``` -## JSONExtractString +### JSONExtractString Parses JSON and extracts a string. This function is similar to [`visitParamExtractString`](#simplejsonextractstring) functions. If the value does not exist or has a wrong type, an empty string will be returned. @@ -692,7 +692,7 @@ SELECT JSONExtractString('{"abc":"\\u263"}', 'abc') = '' SELECT JSONExtractString('{"abc":"hello}', 'abc') = '' ``` -## JSONExtract +### JSONExtract Parses JSON and extracts a value of the given ClickHouse data type. This function is a generalized version of the previous `JSONExtract` functions. Meaning: @@ -733,7 +733,7 @@ SELECT JSONExtract('{"day": "Thursday"}', 'day', 'Enum8(\'Sunday\' = 0, \'Monday SELECT JSONExtract('{"day": 5}', 'day', 'Enum8(\'Sunday\' = 0, \'Monday\' = 1, \'Tuesday\' = 2, \'Wednesday\' = 3, \'Thursday\' = 4, \'Friday\' = 5, \'Saturday\' = 6)') = 'Friday' ``` -## JSONExtractKeysAndValues +### JSONExtractKeysAndValues Parses key-value pairs from JSON where the values are of the given ClickHouse data type. @@ -764,7 +764,7 @@ JSONExtractKeysAndValues(json [, indices_or_keys...], value_type) SELECT JSONExtractKeysAndValues('{"x": {"a": 5, "b": 7, "c": 11}}', 'x', 'Int8') = [('a',5),('b',7),('c',11)]; ``` -## JSONExtractKeys +### JSONExtractKeys Parses a JSON string and extracts the keys. @@ -800,7 +800,7 @@ text └────────────────────────────────────────────────────────────┘ ``` -## JSONExtractRaw +### JSONExtractRaw Returns part of the JSON as an unparsed string. If the part does not exist or has the wrong type, an empty string will be returned. @@ -830,7 +830,7 @@ JSONExtractRaw(json [, indices_or_keys]...) SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300]}', 'b') = '[-100, 200.0, 300]'; ``` -## JSONExtractArrayRaw +### JSONExtractArrayRaw Returns an array with elements of JSON array, each represented as unparsed string. If the part does not exist or isn’t array, an empty array will be returned. @@ -860,7 +860,7 @@ JSONExtractArrayRaw(json [, indices_or_keys...]) SELECT JSONExtractArrayRaw('{"a": "hello", "b": [-100, 200.0, "hello"]}', 'b') = ['-100', '200.0', '"hello"']; ``` -## JSONExtractKeysAndValuesRaw +### JSONExtractKeysAndValuesRaw Extracts raw data from a JSON object. @@ -924,7 +924,7 @@ Result: └───────────────────────────────────────────────────────────────────────────────────────────────────────┘ ``` -## JSON_EXISTS +### JSON_EXISTS If the value exists in the JSON document, `1` will be returned. If the value does not exist, `0` will be returned. @@ -956,7 +956,7 @@ SELECT JSON_EXISTS('{"hello":["world"]}', '$.hello[*]'); SELECT JSON_EXISTS('{"hello":["world"]}', '$.hello[0]'); ``` -## JSON_QUERY +### JSON_QUERY Parses a JSON and extract a value as a JSON array or JSON object. If the value does not exist, an empty string will be returned. @@ -999,7 +999,7 @@ Result: String ``` -## JSON_VALUE +### JSON_VALUE Parses a JSON and extract a value as a JSON scalar. If the value does not exist, an empty string will be returned by default. @@ -1049,7 +1049,7 @@ world String ``` -## toJSONString +### toJSONString Serializes a value to its JSON representation. Various data types and nested structures are supported. 64-bit [integers](../data-types/int-uint.md) or bigger (like `UInt64` or `Int128`) are enclosed in quotes by default. [output_format_json_quote_64bit_integers](../../operations/settings/settings.md#session_settings-output_format_json_quote_64bit_integers) controls this behavior. @@ -1095,7 +1095,7 @@ Result: - [output_format_json_quote_denormals](../../operations/settings/settings.md#settings-output_format_json_quote_denormals) -## JSONArrayLength +### JSONArrayLength Returns the number of elements in the outermost JSON array. The function returns NULL if input JSON string is invalid. @@ -1128,7 +1128,7 @@ SELECT ``` -## jsonMergePatch +### jsonMergePatch Returns the merged JSON object string which is formed by merging multiple JSON objects. From 09600eccbdac099280c7de5ca349058997c4698e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mar=C3=ADn?= Date: Tue, 28 May 2024 14:51:14 +0200 Subject: [PATCH 122/211] Fix flakiness of test_lost_part_other_replica --- tests/integration/test_lost_part/test.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/integration/test_lost_part/test.py b/tests/integration/test_lost_part/test.py index 382539df7de..2ae6ca93e05 100644 --- a/tests/integration/test_lost_part/test.py +++ b/tests/integration/test_lost_part/test.py @@ -143,7 +143,10 @@ def test_lost_part_other_replica(start_cluster): node1.query("CHECK TABLE mt1") node2.query("SYSTEM START REPLICATION QUEUES") - res, err = node1.query_and_get_answer_with_error("SYSTEM SYNC REPLICA mt1") + # Reduce timeout in sync replica since it might never finish with merge stopped and we don't want to wait 300s + res, err = node1.query_and_get_answer_with_error( + "SYSTEM SYNC REPLICA mt1", settings={"receive_timeout": 30} + ) print("result: ", res) print("error: ", res) @@ -157,11 +160,9 @@ def test_lost_part_other_replica(start_cluster): "SELECT * FROM system.replication_queue FORMAT Vertical" ) - assert node1.contains_in_log( - "Created empty part" - ), "Seems like empty part {} is not created or log message changed".format( - victim_part_from_the_middle - ) + assert node1.contains_in_log("Created empty part") or node1.contains_in_log( + f"Part {victim_part_from_the_middle} looks broken. Removing it and will try to fetch." + ), f"Seems like empty part {victim_part_from_the_middle} is not created or log message changed" assert_eq_with_retry(node2, "SELECT COUNT() FROM mt1", "4") assert_eq_with_retry(node2, "SELECT COUNT() FROM system.replication_queue", "0") From 32d22630c338ffb5beedb8f4d7c60a4f5746b67a Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 14:53:15 +0200 Subject: [PATCH 123/211] Change scale_factors to reference --- src/Functions/fromReadable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 28aaca86e8a..428b148002b 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -91,7 +91,7 @@ public: ); } - std::unordered_map scale_factors = Impl::getScaleFactors(); + const std::unordered_map & scale_factors = Impl::getScaleFactors(); auto col_res = ColumnUInt64::create(input_rows_count); From 1014a111565a62fdea57a929f0361b2fe4024649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mar=C3=ADn?= Date: Tue, 28 May 2024 15:06:56 +0200 Subject: [PATCH 124/211] Enforce proper log checks --- tests/integration/test_lost_part/test.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_lost_part/test.py b/tests/integration/test_lost_part/test.py index 2ae6ca93e05..b8e67551d79 100644 --- a/tests/integration/test_lost_part/test.py +++ b/tests/integration/test_lost_part/test.py @@ -90,7 +90,7 @@ def test_lost_part_same_replica(start_cluster): ) assert node1.contains_in_log( - "Created empty part" + f"Created empty part {victim_part_from_the_middle}" ), f"Seems like empty part {victim_part_from_the_middle} is not created or log message changed" assert node1.query("SELECT COUNT() FROM mt0") == "4\n" @@ -160,7 +160,9 @@ def test_lost_part_other_replica(start_cluster): "SELECT * FROM system.replication_queue FORMAT Vertical" ) - assert node1.contains_in_log("Created empty part") or node1.contains_in_log( + assert node1.contains_in_log( + f"Created empty part {victim_part_from_the_middle}" + ) or node1.contains_in_log( f"Part {victim_part_from_the_middle} looks broken. Removing it and will try to fetch." ), f"Seems like empty part {victim_part_from_the_middle} is not created or log message changed" From d529ff911c08177367ca14284bf8a23035a59c4e Mon Sep 17 00:00:00 2001 From: Nikita Taranov Date: Tue, 28 May 2024 15:08:21 +0100 Subject: [PATCH 125/211] better --- src/Interpreters/ConcurrentHashJoin.cpp | 36 ++++++++++++------------- src/Interpreters/ConcurrentHashJoin.h | 3 ++- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/Interpreters/ConcurrentHashJoin.cpp b/src/Interpreters/ConcurrentHashJoin.cpp index a82f568fa66..53987694e46 100644 --- a/src/Interpreters/ConcurrentHashJoin.cpp +++ b/src/Interpreters/ConcurrentHashJoin.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -13,14 +14,13 @@ #include #include #include +#include #include -#include -#include -#include #include - -#include -#include +#include +#include +#include +#include namespace CurrentMetrics { @@ -50,11 +50,11 @@ ConcurrentHashJoin::ConcurrentHashJoin( : context(context_) , table_join(table_join_) , slots(toPowerOfTwo(std::min(static_cast(slots_), 256))) - , pool( + , pool(std::make_unique( CurrentMetrics::ConcurrentHashJoinPoolThreads, CurrentMetrics::ConcurrentHashJoinPoolThreadsActive, CurrentMetrics::ConcurrentHashJoinPoolThreadsScheduled, - slots) + slots)) { hash_joins.resize(slots); @@ -62,7 +62,7 @@ ConcurrentHashJoin::ConcurrentHashJoin( { for (size_t i = 0; i < slots; ++i) { - pool.trySchedule( + pool->scheduleOrThrow( [&, idx = i, thread_group = CurrentThread::getGroup()]() { SCOPE_EXIT_SAFE({ @@ -72,11 +72,9 @@ ConcurrentHashJoin::ConcurrentHashJoin( if (thread_group) CurrentThread::attachToGroupIfDetached(thread_group); - setThreadName("ConcurrentJoin"); auto inner_hash_join = std::make_shared(); - inner_hash_join->data = std::make_unique( table_join_, right_sample_block, any_take_last_row_, 0, fmt::format("concurrent{}", idx)); /// Non zero `max_joined_block_rows` allows to process block partially and return not processed part. @@ -85,13 +83,12 @@ ConcurrentHashJoin::ConcurrentHashJoin( hash_joins[idx] = std::move(inner_hash_join); }); } - - pool.wait(); + pool->wait(); } catch (...) { tryLogCurrentException(__PRETTY_FUNCTION__); - pool.wait(); + pool->wait(); throw; } } @@ -102,7 +99,10 @@ ConcurrentHashJoin::~ConcurrentHashJoin() { for (size_t i = 0; i < slots; ++i) { - pool.trySchedule( + // Hash tables destruction may be very time-consuming. + // Without the following code, they would be destroyed in the current thread (i.e. sequentially). + // `InternalHashJoin` is moved here and will be destroyed in the destructor of the lambda function. + pool->scheduleOrThrow( [join = std::move(hash_joins[i]), thread_group = CurrentThread::getGroup()]() { SCOPE_EXIT_SAFE({ @@ -112,17 +112,15 @@ ConcurrentHashJoin::~ConcurrentHashJoin() if (thread_group) CurrentThread::attachToGroupIfDetached(thread_group); - setThreadName("ConcurrentJoin"); }); } - - pool.wait(); + pool->wait(); } catch (...) { tryLogCurrentException(__PRETTY_FUNCTION__); - pool.wait(); + pool->wait(); } } diff --git a/src/Interpreters/ConcurrentHashJoin.h b/src/Interpreters/ConcurrentHashJoin.h index bf165371b5b..c797ff27ece 100644 --- a/src/Interpreters/ConcurrentHashJoin.h +++ b/src/Interpreters/ConcurrentHashJoin.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace DB { @@ -66,7 +67,7 @@ private: ContextPtr context; std::shared_ptr table_join; size_t slots; - ThreadPool pool; + std::unique_ptr pool; std::vector> hash_joins; std::mutex totals_mutex; From c822a37cb87a14c030e90e8924e8588fb4ed7e9f Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 16:16:45 +0200 Subject: [PATCH 126/211] Throw exception on infinite & nan inputs, add corresponding tests --- src/Functions/fromReadable.h | 31 ++++++++++++----- .../03166_fromReadableSize.reference | 10 ++++++ .../0_stateless/03166_fromReadableSize.sql | 33 +++++++++++++++++-- .../03167_fromReadableDecimalSize.reference | 10 ++++++ .../03167_fromReadableDecimalSize.sql | 32 ++++++++++++++++-- 5 files changed, 103 insertions(+), 13 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 428b148002b..37c682a94a0 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace DB @@ -155,6 +156,16 @@ private: str ); } + // NaN propagation complicated the behaviour of the orNull & orZero flavours so we don't support it. + else if (std::isnan(base) || !std::isfinite(base)) + { + throw Exception( + ErrorCodes::BAD_ARGUMENTS, + "Invalid expression for function {} - Invalid numeric component: {}", + getName(), + base + ); + } else if (base < 0) { throw Exception( @@ -169,15 +180,6 @@ private: String unit; readStringUntilWhitespace(unit, buf); - if (!buf.eof()) - { - throw Exception( - ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, - "Invalid expression for function {} - Found trailing characters after readable size string (\"{}\")", - getName(), - str - ); - } boost::algorithm::to_lower(unit); auto iter = scale_factors.find(unit); if (iter == scale_factors.end()) @@ -189,6 +191,17 @@ private: unit ); } + + if (!buf.eof()) + { + throw Exception( + ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, + "Invalid expression for function {} - Found trailing characters after readable size string (\"{}\")", + getName(), + str + ); + } + Float64 num_bytes_with_decimals = base * iter->second; if (num_bytes_with_decimals > std::numeric_limits::max()) { diff --git a/tests/queries/0_stateless/03166_fromReadableSize.reference b/tests/queries/0_stateless/03166_fromReadableSize.reference index 9eb3487c183..6fb54d99171 100644 --- a/tests/queries/0_stateless/03166_fromReadableSize.reference +++ b/tests/queries/0_stateless/03166_fromReadableSize.reference @@ -17,6 +17,10 @@ 3217 3217 1000 +5 +2048 +8192 +0 0 0 1 B 1 1 KiB 1024 1 MiB 1048576 @@ -29,6 +33,9 @@ invalid \N 1KB \N 1 GiB \N 1 TiB with fries \N +NaN KiB \N +Inf KiB \N +0xa123 KiB \N 1 B 1 1 KiB 1024 1 MiB 1048576 @@ -41,3 +48,6 @@ invalid 0 1KB 0 1 GiB 0 1 TiB with fries 0 +NaN KiB 0 +Inf KiB 0 +0xa123 KiB 0 diff --git a/tests/queries/0_stateless/03166_fromReadableSize.sql b/tests/queries/0_stateless/03166_fromReadableSize.sql index 9115d06abec..2983280320c 100644 --- a/tests/queries/0_stateless/03166_fromReadableSize.sql +++ b/tests/queries/0_stateless/03166_fromReadableSize.sql @@ -41,6 +41,18 @@ SELECT fromReadableSize('+3.1415 KiB'); -- Can parse amounts in scientific notation SELECT fromReadableSize('10e2 B'); +-- Can parse floats with no decimal points +SELECT fromReadableSize('5. B'); + +-- Can parse numbers with leading zeroes +SELECT fromReadableSize('002 KiB'); + +-- Can parse octal-like +SELECT fromReadableSize('08 KiB'); + +-- Can parse various flavours of zero +SELECT fromReadableSize('0 KiB'), fromReadableSize('+0 KiB'), fromReadableSize('-0 KiB'); + -- ERRORS -- No arguments SELECT fromReadableSize(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } @@ -62,6 +74,23 @@ SELECT fromReadableSize('1 KB'); -- { serverError CANNOT_PARSE_TEXT } SELECT fromReadableSize('-1 KiB'); -- { serverError BAD_ARGUMENTS } -- Invalid input - Input too large to fit in UInt64 SELECT fromReadableSize('1000 EiB'); -- { serverError BAD_ARGUMENTS } +-- Invalid input - Hexadecimal is not supported +SELECT fromReadableSize('0xa123 KiB'); -- { serverError CANNOT_PARSE_TEXT } +-- Invalid input - NaN is not supported, with or without sign and with different capitalizations +SELECT fromReadableSize('nan KiB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('+nan KiB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('-nan KiB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('NaN KiB'); -- { serverError BAD_ARGUMENTS } +-- Invalid input - Infinite is not supported, with or without sign, in all its forms +SELECT fromReadableSize('inf KiB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('+inf KiB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('-inf KiB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('infinite KiB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('+infinite KiB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('-infinite KiB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('Inf KiB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableSize('Infinite KiB'); -- { serverError BAD_ARGUMENTS } + -- OR NULL @@ -72,7 +101,7 @@ SELECT -- Returns NULL on invalid values SELECT - arrayJoin(['invalid', '1 Joe', '1KB', ' 1 GiB', '1 TiB with fries']) AS readable_sizes, + arrayJoin(['invalid', '1 Joe', '1KB', ' 1 GiB', '1 TiB with fries', 'NaN KiB', 'Inf KiB', '0xa123 KiB']) AS readable_sizes, fromReadableSizeOrNull(readable_sizes) AS filesize; @@ -84,6 +113,6 @@ SELECT -- Returns NULL on invalid values SELECT - arrayJoin(['invalid', '1 Joe', '1KB', ' 1 GiB', '1 TiB with fries']) AS readable_sizes, + arrayJoin(['invalid', '1 Joe', '1KB', ' 1 GiB', '1 TiB with fries', 'NaN KiB', 'Inf KiB', '0xa123 KiB']) AS readable_sizes, fromReadableSizeOrZero(readable_sizes) AS filesize; diff --git a/tests/queries/0_stateless/03167_fromReadableDecimalSize.reference b/tests/queries/0_stateless/03167_fromReadableDecimalSize.reference index e0d2b6e0dc3..62620501de0 100644 --- a/tests/queries/0_stateless/03167_fromReadableDecimalSize.reference +++ b/tests/queries/0_stateless/03167_fromReadableDecimalSize.reference @@ -17,6 +17,10 @@ 3142 3142 1000 +5 +2000 +8000 +0 0 0 1 B 1 1 KB 1000 1 MB 1000000 @@ -29,6 +33,9 @@ invalid \N 1 KiB \N 1 GB \N 1 TB with fries \N +NaN KB \N +Inf KB \N +0xa123 KB \N 1 B 1 1 KB 1000 1 MB 1000000 @@ -41,3 +48,6 @@ invalid 0 1 KiB 0 1 GiB 0 1 TiB with fries 0 +NaN KB 0 +Inf KB 0 +0xa123 KB 0 diff --git a/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql b/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql index 84d560c0ccb..618f99b1d28 100644 --- a/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql +++ b/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql @@ -41,6 +41,18 @@ SELECT fromReadableDecimalSize('+3.1415 KB'); -- Can parse amounts in scientific notation SELECT fromReadableDecimalSize('10e2 B'); +-- Can parse floats with no decimal points +SELECT fromReadableDecimalSize('5. B'); + +-- Can parse numbers with leading zeroes +SELECT fromReadableDecimalSize('002 KB'); + +-- Can parse octal-like +SELECT fromReadableDecimalSize('08 KB'); + +-- Can parse various flavours of zero +SELECT fromReadableDecimalSize('0 KB'), fromReadableDecimalSize('+0 KB'), fromReadableDecimalSize('-0 KB'); + -- ERRORS -- No arguments SELECT fromReadableDecimalSize(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } @@ -62,6 +74,22 @@ SELECT fromReadableDecimalSize('1 KiB'); -- { serverError CANNOT_PARSE_TEXT } SELECT fromReadableDecimalSize('-1 KB'); -- { serverError BAD_ARGUMENTS } -- Invalid input - Input too large to fit in UInt64 SELECT fromReadableDecimalSize('1000 EB'); -- { serverError BAD_ARGUMENTS } +-- Invalid input - Hexadecimal is not supported +SELECT fromReadableDecimalSize('0xa123 KB'); -- { serverError CANNOT_PARSE_TEXT } +-- Invalid input - NaN is not supported, with or without sign and with different capitalizations +SELECT fromReadableDecimalSize('nan KB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableDecimalSize('+nan KB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableDecimalSize('-nan KB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableDecimalSize('NaN KB'); -- { serverError BAD_ARGUMENTS } +-- Invalid input - Infinite is not supported, with or without sign, in all its forms +SELECT fromReadableDecimalSize('inf KB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableDecimalSize('+inf KB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableDecimalSize('-inf KB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableDecimalSize('infinite KB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableDecimalSize('+infinite KB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableDecimalSize('-infinite KB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableDecimalSize('Inf KB'); -- { serverError BAD_ARGUMENTS } +SELECT fromReadableDecimalSize('Infinite KB'); -- { serverError BAD_ARGUMENTS } -- OR NULL @@ -72,7 +100,7 @@ SELECT -- Returns NULL on invalid values SELECT - arrayJoin(['invalid', '1 Joe', '1 KiB', ' 1 GB', '1 TB with fries']) AS readable_sizes, + arrayJoin(['invalid', '1 Joe', '1 KiB', ' 1 GB', '1 TB with fries', 'NaN KB', 'Inf KB', '0xa123 KB']) AS readable_sizes, fromReadableDecimalSizeOrNull(readable_sizes) AS filesize; @@ -84,6 +112,6 @@ SELECT -- Returns NULL on invalid values SELECT - arrayJoin(['invalid', '1 Joe', '1 KiB', ' 1 GiB', '1 TiB with fries']) AS readable_sizes, + arrayJoin(['invalid', '1 Joe', '1 KiB', ' 1 GiB', '1 TiB with fries', 'NaN KB', 'Inf KB', '0xa123 KB']) AS readable_sizes, fromReadableDecimalSizeOrZero(readable_sizes) AS filesize; From 6a729fbb7e4b0749ed9556e1978f60b90e4b3b46 Mon Sep 17 00:00:00 2001 From: Peignon Melvyn Date: Tue, 28 May 2024 16:25:08 +0200 Subject: [PATCH 127/211] Update view.md Remove mention of experimental settings. --- docs/en/sql-reference/statements/alter/view.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/en/sql-reference/statements/alter/view.md b/docs/en/sql-reference/statements/alter/view.md index 83e8e9311b4..fb7a5bd7c03 100644 --- a/docs/en/sql-reference/statements/alter/view.md +++ b/docs/en/sql-reference/statements/alter/view.md @@ -79,8 +79,6 @@ ORDER BY ts, event_type; │ 2020-01-03 00:00:00 │ imp │ │ 2 │ 0 │ └─────────────────────┴────────────┴─────────┴────────────┴──────┘ -SET allow_experimental_alter_materialized_view_structure=1; - ALTER TABLE mv MODIFY QUERY SELECT toStartOfDay(ts) ts, event_type, browser, count() events_cnt, @@ -178,7 +176,6 @@ SELECT * FROM mv; └───┘ ``` ```sql -set allow_experimental_alter_materialized_view_structure=1; ALTER TABLE mv MODIFY QUERY SELECT a * 2 as a FROM src_table; INSERT INTO src_table (a) VALUES (3), (4); SELECT * FROM mv; From 56e423f379dfc06b309a1ff68c48fa344f1df509 Mon Sep 17 00:00:00 2001 From: Francisco Javier Jurado Moreno <9376816+Beetelbrox@users.noreply.github.com> Date: Tue, 28 May 2024 16:29:15 +0200 Subject: [PATCH 128/211] Couple of style fixes --- src/Functions/fromReadable.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 37c682a94a0..6d8c071061a 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -147,7 +147,7 @@ private: } Float64 base = 0; - if (!tryReadFloatTextPrecise(base, buf)) // If we use the default (fast) tryReadFloatText this returns True on garbage input + if (!tryReadFloatTextPrecise(base, buf)) // If we use the default (fast) tryReadFloatText this returns True on garbage input so we use the Precise version { throw Exception( ErrorCodes::CANNOT_PARSE_NUMBER, @@ -156,7 +156,6 @@ private: str ); } - // NaN propagation complicated the behaviour of the orNull & orZero flavours so we don't support it. else if (std::isnan(base) || !std::isfinite(base)) { throw Exception( @@ -191,8 +190,7 @@ private: unit ); } - - if (!buf.eof()) + else if (!buf.eof()) { throw Exception( ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, From b553b4f7bc38bfb8794bdcb7d67ffe8e2e36a1d1 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 28 May 2024 14:51:46 +0000 Subject: [PATCH 129/211] Renamve QueryAnalysis ro Resolve --- src/Analyzer/{QueryAnalysis => Resolve}/ExpressionsStack.h | 0 src/Analyzer/{QueryAnalysis => Resolve}/IdentifierLookup.h | 0 .../{QueryAnalysis => Resolve}/IdentifierResolveScope.cpp | 0 src/Analyzer/{QueryAnalysis => Resolve}/IdentifierResolveScope.h | 0 src/Analyzer/{QueryAnalysis => Resolve}/QueryAnalysisPass.cpp | 0 src/Analyzer/{QueryAnalysis => Resolve}/QueryAnalyzer.cpp | 0 src/Analyzer/{QueryAnalysis => Resolve}/QueryAnalyzer.h | 0 .../{QueryAnalysis => Resolve}/QueryExpressionsAliasVisitor.h | 0 src/Analyzer/{QueryAnalysis => Resolve}/ScopeAliases.h | 0 src/Analyzer/{QueryAnalysis => Resolve}/TableExpressionData.h | 0 .../{QueryAnalysis => Resolve}/TableExpressionsAliasVisitor.h | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename src/Analyzer/{QueryAnalysis => Resolve}/ExpressionsStack.h (100%) rename src/Analyzer/{QueryAnalysis => Resolve}/IdentifierLookup.h (100%) rename src/Analyzer/{QueryAnalysis => Resolve}/IdentifierResolveScope.cpp (100%) rename src/Analyzer/{QueryAnalysis => Resolve}/IdentifierResolveScope.h (100%) rename src/Analyzer/{QueryAnalysis => Resolve}/QueryAnalysisPass.cpp (100%) rename src/Analyzer/{QueryAnalysis => Resolve}/QueryAnalyzer.cpp (100%) rename src/Analyzer/{QueryAnalysis => Resolve}/QueryAnalyzer.h (100%) rename src/Analyzer/{QueryAnalysis => Resolve}/QueryExpressionsAliasVisitor.h (100%) rename src/Analyzer/{QueryAnalysis => Resolve}/ScopeAliases.h (100%) rename src/Analyzer/{QueryAnalysis => Resolve}/TableExpressionData.h (100%) rename src/Analyzer/{QueryAnalysis => Resolve}/TableExpressionsAliasVisitor.h (100%) diff --git a/src/Analyzer/QueryAnalysis/ExpressionsStack.h b/src/Analyzer/Resolve/ExpressionsStack.h similarity index 100% rename from src/Analyzer/QueryAnalysis/ExpressionsStack.h rename to src/Analyzer/Resolve/ExpressionsStack.h diff --git a/src/Analyzer/QueryAnalysis/IdentifierLookup.h b/src/Analyzer/Resolve/IdentifierLookup.h similarity index 100% rename from src/Analyzer/QueryAnalysis/IdentifierLookup.h rename to src/Analyzer/Resolve/IdentifierLookup.h diff --git a/src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp b/src/Analyzer/Resolve/IdentifierResolveScope.cpp similarity index 100% rename from src/Analyzer/QueryAnalysis/IdentifierResolveScope.cpp rename to src/Analyzer/Resolve/IdentifierResolveScope.cpp diff --git a/src/Analyzer/QueryAnalysis/IdentifierResolveScope.h b/src/Analyzer/Resolve/IdentifierResolveScope.h similarity index 100% rename from src/Analyzer/QueryAnalysis/IdentifierResolveScope.h rename to src/Analyzer/Resolve/IdentifierResolveScope.h diff --git a/src/Analyzer/QueryAnalysis/QueryAnalysisPass.cpp b/src/Analyzer/Resolve/QueryAnalysisPass.cpp similarity index 100% rename from src/Analyzer/QueryAnalysis/QueryAnalysisPass.cpp rename to src/Analyzer/Resolve/QueryAnalysisPass.cpp diff --git a/src/Analyzer/QueryAnalysis/QueryAnalyzer.cpp b/src/Analyzer/Resolve/QueryAnalyzer.cpp similarity index 100% rename from src/Analyzer/QueryAnalysis/QueryAnalyzer.cpp rename to src/Analyzer/Resolve/QueryAnalyzer.cpp diff --git a/src/Analyzer/QueryAnalysis/QueryAnalyzer.h b/src/Analyzer/Resolve/QueryAnalyzer.h similarity index 100% rename from src/Analyzer/QueryAnalysis/QueryAnalyzer.h rename to src/Analyzer/Resolve/QueryAnalyzer.h diff --git a/src/Analyzer/QueryAnalysis/QueryExpressionsAliasVisitor.h b/src/Analyzer/Resolve/QueryExpressionsAliasVisitor.h similarity index 100% rename from src/Analyzer/QueryAnalysis/QueryExpressionsAliasVisitor.h rename to src/Analyzer/Resolve/QueryExpressionsAliasVisitor.h diff --git a/src/Analyzer/QueryAnalysis/ScopeAliases.h b/src/Analyzer/Resolve/ScopeAliases.h similarity index 100% rename from src/Analyzer/QueryAnalysis/ScopeAliases.h rename to src/Analyzer/Resolve/ScopeAliases.h diff --git a/src/Analyzer/QueryAnalysis/TableExpressionData.h b/src/Analyzer/Resolve/TableExpressionData.h similarity index 100% rename from src/Analyzer/QueryAnalysis/TableExpressionData.h rename to src/Analyzer/Resolve/TableExpressionData.h diff --git a/src/Analyzer/QueryAnalysis/TableExpressionsAliasVisitor.h b/src/Analyzer/Resolve/TableExpressionsAliasVisitor.h similarity index 100% rename from src/Analyzer/QueryAnalysis/TableExpressionsAliasVisitor.h rename to src/Analyzer/Resolve/TableExpressionsAliasVisitor.h From d4cf93a5bedf01b09de96a77cbd3d3fef1976145 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 28 May 2024 14:52:10 +0000 Subject: [PATCH 130/211] Renamve QueryAnalysis to Resolve --- src/Analyzer/Resolve/IdentifierResolveScope.cpp | 2 +- src/Analyzer/Resolve/IdentifierResolveScope.h | 8 ++++---- src/Analyzer/Resolve/QueryAnalysisPass.cpp | 2 +- src/Analyzer/Resolve/QueryAnalyzer.cpp | 8 ++++---- src/Analyzer/Resolve/QueryAnalyzer.h | 2 +- src/Analyzer/Resolve/QueryExpressionsAliasVisitor.h | 2 +- src/Analyzer/Resolve/ScopeAliases.h | 2 +- src/Analyzer/Resolve/TableExpressionsAliasVisitor.h | 2 +- src/CMakeLists.txt | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Analyzer/Resolve/IdentifierResolveScope.cpp b/src/Analyzer/Resolve/IdentifierResolveScope.cpp index 006b0b01c51..ae363b57047 100644 --- a/src/Analyzer/Resolve/IdentifierResolveScope.cpp +++ b/src/Analyzer/Resolve/IdentifierResolveScope.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/Analyzer/Resolve/IdentifierResolveScope.h b/src/Analyzer/Resolve/IdentifierResolveScope.h index 661d75014e7..ab2e27cc14d 100644 --- a/src/Analyzer/Resolve/IdentifierResolveScope.h +++ b/src/Analyzer/Resolve/IdentifierResolveScope.h @@ -4,10 +4,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include namespace DB { diff --git a/src/Analyzer/Resolve/QueryAnalysisPass.cpp b/src/Analyzer/Resolve/QueryAnalysisPass.cpp index b3de3e063b0..36c747555fc 100644 --- a/src/Analyzer/Resolve/QueryAnalysisPass.cpp +++ b/src/Analyzer/Resolve/QueryAnalysisPass.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include namespace DB diff --git a/src/Analyzer/Resolve/QueryAnalyzer.cpp b/src/Analyzer/Resolve/QueryAnalyzer.cpp index ab3c9c82826..d84626c4be6 100644 --- a/src/Analyzer/Resolve/QueryAnalyzer.cpp +++ b/src/Analyzer/Resolve/QueryAnalyzer.cpp @@ -56,10 +56,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include namespace ProfileEvents { diff --git a/src/Analyzer/Resolve/QueryAnalyzer.h b/src/Analyzer/Resolve/QueryAnalyzer.h index 579455b6faf..e2c4c8df46b 100644 --- a/src/Analyzer/Resolve/QueryAnalyzer.h +++ b/src/Analyzer/Resolve/QueryAnalyzer.h @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Analyzer/Resolve/QueryExpressionsAliasVisitor.h b/src/Analyzer/Resolve/QueryExpressionsAliasVisitor.h index 96c91ffab71..45d081e34ea 100644 --- a/src/Analyzer/Resolve/QueryExpressionsAliasVisitor.h +++ b/src/Analyzer/Resolve/QueryExpressionsAliasVisitor.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include namespace DB diff --git a/src/Analyzer/Resolve/ScopeAliases.h b/src/Analyzer/Resolve/ScopeAliases.h index 370ffc65625..baab843988b 100644 --- a/src/Analyzer/Resolve/ScopeAliases.h +++ b/src/Analyzer/Resolve/ScopeAliases.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include namespace DB { diff --git a/src/Analyzer/Resolve/TableExpressionsAliasVisitor.h b/src/Analyzer/Resolve/TableExpressionsAliasVisitor.h index 3191a0a97ac..cab79806465 100644 --- a/src/Analyzer/Resolve/TableExpressionsAliasVisitor.h +++ b/src/Analyzer/Resolve/TableExpressionsAliasVisitor.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7d678add6d2..2b5078111ee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -215,7 +215,7 @@ add_object_library(clickhouse_databases_mysql Databases/MySQL) add_object_library(clickhouse_disks Disks) add_object_library(clickhouse_analyzer Analyzer) add_object_library(clickhouse_analyzer_passes Analyzer/Passes) -add_object_library(clickhouse_analyzer_passes Analyzer/QueryAnalysis) +add_object_library(clickhouse_analyzer_passes Analyzer/Resolve) add_object_library(clickhouse_planner Planner) add_object_library(clickhouse_interpreters Interpreters) add_object_library(clickhouse_interpreters_cache Interpreters/Cache) From 81ca448d6b5ec595625c366d6db759747f42ed35 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Tue, 28 May 2024 15:20:23 +0000 Subject: [PATCH 131/211] Move fromReadable* docs after docs of formatReadable* functions --- .../functions/other-functions.md | 192 +++++++++--------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/docs/en/sql-reference/functions/other-functions.md b/docs/en/sql-reference/functions/other-functions.md index 6b3b14f314b..ff1236b302b 100644 --- a/docs/en/sql-reference/functions/other-functions.md +++ b/docs/en/sql-reference/functions/other-functions.md @@ -794,6 +794,102 @@ Result: └────────────────┴────────────┘ ``` +## formatReadableQuantity + +Given a number, this function returns a rounded number with suffix (thousand, million, billion, etc.) as string. + +**Syntax** + +```sql +formatReadableQuantity(x) +``` + +**Example** + +Query: + +```sql +SELECT + arrayJoin([1024, 1234 * 1000, (4567 * 1000) * 1000, 98765432101234]) AS number, + formatReadableQuantity(number) AS number_for_humans +``` + +Result: + +```text +┌─────────number─┬─number_for_humans─┐ +│ 1024 │ 1.02 thousand │ +│ 1234000 │ 1.23 million │ +│ 4567000000 │ 4.57 billion │ +│ 98765432101234 │ 98.77 trillion │ +└────────────────┴───────────────────┘ +``` + +## formatReadableTimeDelta + +Given a time interval (delta) in seconds, this function returns a time delta with year/month/day/hour/minute/second/millisecond/microsecond/nanosecond as string. + +**Syntax** + +```sql +formatReadableTimeDelta(column[, maximum_unit, minimum_unit]) +``` + +**Arguments** + +- `column` — A column with a numeric time delta. +- `maximum_unit` — Optional. Maximum unit to show. + - Acceptable values: `nanoseconds`, `microseconds`, `milliseconds`, `seconds`, `minutes`, `hours`, `days`, `months`, `years`. + - Default value: `years`. +- `minimum_unit` — Optional. Minimum unit to show. All smaller units are truncated. + - Acceptable values: `nanoseconds`, `microseconds`, `milliseconds`, `seconds`, `minutes`, `hours`, `days`, `months`, `years`. + - If explicitly specified value is bigger than `maximum_unit`, an exception will be thrown. + - Default value: `seconds` if `maximum_unit` is `seconds` or bigger, `nanoseconds` otherwise. + +**Example** + +```sql +SELECT + arrayJoin([100, 12345, 432546534]) AS elapsed, + formatReadableTimeDelta(elapsed) AS time_delta +``` + +```text +┌────elapsed─┬─time_delta ─────────────────────────────────────────────────────┐ +│ 100 │ 1 minute and 40 seconds │ +│ 12345 │ 3 hours, 25 minutes and 45 seconds │ +│ 432546534 │ 13 years, 8 months, 17 days, 7 hours, 48 minutes and 54 seconds │ +└────────────┴─────────────────────────────────────────────────────────────────┘ +``` + +```sql +SELECT + arrayJoin([100, 12345, 432546534]) AS elapsed, + formatReadableTimeDelta(elapsed, 'minutes') AS time_delta +``` + +```text +┌────elapsed─┬─time_delta ─────────────────────────────────────────────────────┐ +│ 100 │ 1 minute and 40 seconds │ +│ 12345 │ 205 minutes and 45 seconds │ +│ 432546534 │ 7209108 minutes and 54 seconds │ +└────────────┴─────────────────────────────────────────────────────────────────┘ +``` + +```sql +SELECT + arrayJoin([100, 12345, 432546534.00000006]) AS elapsed, + formatReadableTimeDelta(elapsed, 'minutes', 'nanoseconds') AS time_delta +``` + +```text +┌────────────elapsed─┬─time_delta─────────────────────────────────────┐ +│ 100 │ 1 minute and 40 seconds │ +│ 12345 │ 205 minutes and 45 seconds │ +│ 432546534.00000006 │ 7209108 minutes, 54 seconds and 60 nanoseconds │ +└────────────────────┴────────────────────────────────────────────────┘ +``` + ## fromReadableSize Given a string containing the readable representation of a byte size with ISO/IEC 80000-13 units this function returns the corresponding number of bytes. @@ -1008,102 +1104,6 @@ SELECT └────────────────┴─────────┘ ``` -## formatReadableQuantity - -Given a number, this function returns a rounded number with suffix (thousand, million, billion, etc.) as string. - -**Syntax** - -```sql -formatReadableQuantity(x) -``` - -**Example** - -Query: - -```sql -SELECT - arrayJoin([1024, 1234 * 1000, (4567 * 1000) * 1000, 98765432101234]) AS number, - formatReadableQuantity(number) AS number_for_humans -``` - -Result: - -```text -┌─────────number─┬─number_for_humans─┐ -│ 1024 │ 1.02 thousand │ -│ 1234000 │ 1.23 million │ -│ 4567000000 │ 4.57 billion │ -│ 98765432101234 │ 98.77 trillion │ -└────────────────┴───────────────────┘ -``` - -## formatReadableTimeDelta - -Given a time interval (delta) in seconds, this function returns a time delta with year/month/day/hour/minute/second/millisecond/microsecond/nanosecond as string. - -**Syntax** - -```sql -formatReadableTimeDelta(column[, maximum_unit, minimum_unit]) -``` - -**Arguments** - -- `column` — A column with a numeric time delta. -- `maximum_unit` — Optional. Maximum unit to show. - - Acceptable values: `nanoseconds`, `microseconds`, `milliseconds`, `seconds`, `minutes`, `hours`, `days`, `months`, `years`. - - Default value: `years`. -- `minimum_unit` — Optional. Minimum unit to show. All smaller units are truncated. - - Acceptable values: `nanoseconds`, `microseconds`, `milliseconds`, `seconds`, `minutes`, `hours`, `days`, `months`, `years`. - - If explicitly specified value is bigger than `maximum_unit`, an exception will be thrown. - - Default value: `seconds` if `maximum_unit` is `seconds` or bigger, `nanoseconds` otherwise. - -**Example** - -```sql -SELECT - arrayJoin([100, 12345, 432546534]) AS elapsed, - formatReadableTimeDelta(elapsed) AS time_delta -``` - -```text -┌────elapsed─┬─time_delta ─────────────────────────────────────────────────────┐ -│ 100 │ 1 minute and 40 seconds │ -│ 12345 │ 3 hours, 25 minutes and 45 seconds │ -│ 432546534 │ 13 years, 8 months, 17 days, 7 hours, 48 minutes and 54 seconds │ -└────────────┴─────────────────────────────────────────────────────────────────┘ -``` - -```sql -SELECT - arrayJoin([100, 12345, 432546534]) AS elapsed, - formatReadableTimeDelta(elapsed, 'minutes') AS time_delta -``` - -```text -┌────elapsed─┬─time_delta ─────────────────────────────────────────────────────┐ -│ 100 │ 1 minute and 40 seconds │ -│ 12345 │ 205 minutes and 45 seconds │ -│ 432546534 │ 7209108 minutes and 54 seconds │ -└────────────┴─────────────────────────────────────────────────────────────────┘ -``` - -```sql -SELECT - arrayJoin([100, 12345, 432546534.00000006]) AS elapsed, - formatReadableTimeDelta(elapsed, 'minutes', 'nanoseconds') AS time_delta -``` - -```text -┌────────────elapsed─┬─time_delta─────────────────────────────────────┐ -│ 100 │ 1 minute and 40 seconds │ -│ 12345 │ 205 minutes and 45 seconds │ -│ 432546534.00000006 │ 7209108 minutes, 54 seconds and 60 nanoseconds │ -└────────────────────┴────────────────────────────────────────────────┘ -``` - ## parseTimeDelta Parse a sequence of numbers followed by something resembling a time unit. From 990ce0b3ae38063821bba40be244519c5cc478b4 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Tue, 28 May 2024 15:32:34 +0000 Subject: [PATCH 132/211] Add cross-refs and make the description easier to digest --- .../functions/other-functions.md | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/docs/en/sql-reference/functions/other-functions.md b/docs/en/sql-reference/functions/other-functions.md index ff1236b302b..9ec9f68ada7 100644 --- a/docs/en/sql-reference/functions/other-functions.md +++ b/docs/en/sql-reference/functions/other-functions.md @@ -735,6 +735,8 @@ LIMIT 10 Given a size (number of bytes), this function returns a readable, rounded size with suffix (KB, MB, etc.) as string. +The opposite operations of this function are [fromReadableDecimalSize](#fromReadableDecimalSize), [fromReadableDecimalSizeOrZero](#fromReadableDecimalSizeOrZero), and [fromReadableDecimalSizeOrNull](#fromReadableDecimalSizeOrNull). + **Syntax** ```sql @@ -766,6 +768,8 @@ Result: Given a size (number of bytes), this function returns a readable, rounded size with suffix (KiB, MiB, etc.) as string. +The opposite operations of this function are [fromReadableSize](#fromReadableSize), [fromReadableSizeOrZero](#fromReadableSizeOrZero), and [fromReadableSizeOrNull](#fromReadableSizeOrNull). + **Syntax** ```sql @@ -892,7 +896,10 @@ SELECT ## fromReadableSize -Given a string containing the readable representation of a byte size with ISO/IEC 80000-13 units this function returns the corresponding number of bytes. +Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit (i.e. [ISO/IEC 80000-13](https://en.wikipedia.org/wiki/ISO/IEC_80000) unit), this function returns the corresponding number of bytes. +If the function is unable to parse the input value, it throws an exception. + +The opposite operation of this function is [formatReadableSize](#fromReadableSize). **Syntax** @@ -927,7 +934,10 @@ SELECT ## fromReadableSizeOrNull -Given a string containing the readable representation of a byte size with ISO/IEC 80000-13 units this function returns the corresponding number of bytes, or `NULL` if unable to parse the value. +Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit (i.e. [ISO/IEC 80000-13](https://en.wikipedia.org/wiki/ISO/IEC_80000) unit), this function returns the corresponding number of bytes. +If the function is unable to parse the input value, it returns `NULL`. + +The opposite operation of this function is [formatReadableSize](#fromReadableSize). **Syntax** @@ -963,7 +973,10 @@ SELECT ## fromReadableSizeOrZero -Given a string containing the readable representation of a byte size with ISO/IEC 80000-13 units this function returns the corresponding number of bytes, or 0 if unable to parse the value. +Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit (i.e. [ISO/IEC 80000-13](https://en.wikipedia.org/wiki/ISO/IEC_80000) unit), this function returns the corresponding number of bytes. +If the function is unable to parse the input value, it returns `0`. + +The opposite operation of this function is [formatReadableSize](#fromReadableSize). **Syntax** @@ -999,7 +1012,10 @@ SELECT ## fromReadableDecimalSize -Given a string containing the readable representation of a byte size with decimal units this function returns the corresponding number of bytes. +Given a string containing a byte size and `B`, `KB`, `MB`, etc. as a unit, this function returns the corresponding number of bytes. +If the function is unable to parse the input value, it throws an exception. + +The opposite operation of this function is [formatReadableDecimalSize](#formatReadableDecimalSize). **Syntax** @@ -1034,7 +1050,10 @@ SELECT ## fromReadableDecimalSizeOrNull -Given a string containing the readable representation of a byte size with decimal units this function returns the corresponding number of bytes, or `NULL` if unable to parse the value. +Given a string containing a byte size and `B`, `KB`, `MB`, etc. as a unit, this function returns the corresponding number of bytes. +If the function is unable to parse the input value, it returns `NULL`. + +The opposite operation of this function is [formatReadableDecimalSize](#formatReadableDecimalSize). **Syntax** @@ -1070,7 +1089,10 @@ SELECT ## fromReadableDecimalSizeOrZero -Given a string containing the readable representation of a byte size with decimal units this function returns the corresponding number of bytes, or 0 if unable to parse the value. +Given a string containing a byte size and `B`, `KB`, `MB`, etc. as a unit, this function returns the corresponding number of bytes. +If the function is unable to parse the input value, it returns `0`. + +The opposite operation of this function is [formatReadableDecimalSize](#formatReadableDecimalSize). **Syntax** From ff81473774558d4dbd8e594fbe6e9464a710ba10 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Tue, 28 May 2024 15:39:45 +0000 Subject: [PATCH 133/211] Improve encapsulation a bit and repair integer suffixes --- src/Functions/fromReadable.h | 4 +++- src/Functions/fromReadableDecimalSize.cpp | 24 ++++++++++---------- src/Functions/fromReadableSize.cpp | 27 +++++++++++------------ 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index 6d8c071061a..a2a7f7a8341 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -36,6 +36,8 @@ enum class ErrorHandling : uint8_t Null }; +using ScaleFactors = std::unordered_map; + /** fromReadble*Size - Returns the number of bytes corresponding to a given readable binary or decimal size. * Examples: * - `fromReadableSize('123 MiB')` @@ -92,7 +94,7 @@ public: ); } - const std::unordered_map & scale_factors = Impl::getScaleFactors(); + const ScaleFactors & scale_factors = Impl::getScaleFactors(); auto col_res = ColumnUInt64::create(input_rows_count); diff --git a/src/Functions/fromReadableDecimalSize.cpp b/src/Functions/fromReadableDecimalSize.cpp index c1e4c7f4128..8b2415d2b66 100644 --- a/src/Functions/fromReadableDecimalSize.cpp +++ b/src/Functions/fromReadableDecimalSize.cpp @@ -8,21 +8,21 @@ namespace DB namespace { -const std::unordered_map scale_factors = -{ - {"b", 1L}, - {"kb", 1000L}, - {"mb", 1000L * 1000L}, - {"gb", 1000L * 1000L * 1000L}, - {"tb", 1000L * 1000L * 1000L * 1000L}, - {"pb", 1000L * 1000L * 1000L * 1000L * 1000L}, - {"eb", 1000L * 1000L * 1000L * 1000L * 1000L * 1000L}, -}; - struct Impl { - static const std::unordered_map & getScaleFactors() + static const ScaleFactors & getScaleFactors() { + static const ScaleFactors scale_factors = + { + {"b", 1ull}, + {"kb", 1000ull}, + {"mb", 1000ull * 1000ull}, + {"gb", 1000ull * 1000ull * 1000ull}, + {"tb", 1000ull * 1000ull * 1000ull * 1000ull}, + {"pb", 1000ull * 1000ull * 1000ull * 1000ull * 1000ull}, + {"eb", 1000ull * 1000ull * 1000ull * 1000ull * 1000ull * 1000ull}, + }; + return scale_factors; } }; diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp index d1f010695c0..7d9eb77316f 100644 --- a/src/Functions/fromReadableSize.cpp +++ b/src/Functions/fromReadableSize.cpp @@ -9,25 +9,24 @@ namespace DB namespace { -// ISO/IEC 80000-13 binary units -const std::unordered_map scale_factors = -{ - {"b", 1L}, - {"kib", 1024L}, - {"mib", 1024L * 1024L}, - {"gib", 1024L * 1024L * 1024L}, - {"tib", 1024L * 1024L * 1024L * 1024L}, - {"pib", 1024L * 1024L * 1024L * 1024L * 1024L}, - {"eib", 1024L * 1024L * 1024L * 1024L * 1024L * 1024L}, -}; - struct Impl { - static const std::unordered_map & getScaleFactors() + static const ScaleFactors & getScaleFactors() { + // ISO/IEC 80000-13 binary units + static const ScaleFactors scale_factors = + { + {"b", 1ull}, + {"kib", 1024ull}, + {"mib", 1024ull * 1024ull}, + {"gib", 1024ull * 1024ull * 1024ull}, + {"tib", 1024ull * 1024ull * 1024ull * 1024ull}, + {"pib", 1024ull * 1024ull * 1024ull * 1024ull * 1024ull}, + {"eib", 1024ull * 1024ull * 1024ull * 1024ull * 1024ull * 1024ull}, + }; + return scale_factors; } - }; From 6d2d598e156b76096493b8764f0b9bb48bb710e6 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Tue, 28 May 2024 15:41:30 +0000 Subject: [PATCH 134/211] Fix GROUP BY (const CTE) in distributed queries. --- src/Planner/PlannerExpressionAnalysis.cpp | 4 ++++ .../02992_analyzer_group_by_const.reference | 2 ++ .../02992_analyzer_group_by_const.sql | 20 +++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/src/Planner/PlannerExpressionAnalysis.cpp b/src/Planner/PlannerExpressionAnalysis.cpp index 2a95234057c..201c4fa25ac 100644 --- a/src/Planner/PlannerExpressionAnalysis.cpp +++ b/src/Planner/PlannerExpressionAnalysis.cpp @@ -64,6 +64,10 @@ bool isDeterministicConstant(const ConstantNode & root) const auto * node = nodes.top(); nodes.pop(); + if (node->getNodeType() == QueryTreeNodeType::QUERY) + /// Allow scalar subqueries and IN; we send them to all the shards. + continue; + const auto * constant_node = node->as(); const auto * function_node = node->as(); if (constant_node) diff --git a/tests/queries/0_stateless/02992_analyzer_group_by_const.reference b/tests/queries/0_stateless/02992_analyzer_group_by_const.reference index ff61ab0a515..ea9492581c9 100644 --- a/tests/queries/0_stateless/02992_analyzer_group_by_const.reference +++ b/tests/queries/0_stateless/02992_analyzer_group_by_const.reference @@ -4,3 +4,5 @@ a|x String, Const(size = 1, String(size = 1)) String, Const(size = 1, String(size = 1)) 5128475243952187658 +0 0 +0 0 diff --git a/tests/queries/0_stateless/02992_analyzer_group_by_const.sql b/tests/queries/0_stateless/02992_analyzer_group_by_const.sql index f30a49887c7..ede6e0deed9 100644 --- a/tests/queries/0_stateless/02992_analyzer_group_by_const.sql +++ b/tests/queries/0_stateless/02992_analyzer_group_by_const.sql @@ -10,3 +10,23 @@ select dumpColumnStructure('x') GROUP BY 'x'; select dumpColumnStructure('x'); -- from https://github.com/ClickHouse/ClickHouse/pull/60046 SELECT cityHash64('limit', _CAST(materialize('World'), 'LowCardinality(String)')) FROM system.one GROUP BY GROUPING SETS ('limit'); + +WITH ( + SELECT dummy AS x + FROM system.one + ) AS y +SELECT + y, + min(dummy) +FROM remote('127.0.0.{1,2}', system.one) +GROUP BY y; + +WITH ( + SELECT dummy AS x + FROM system.one + ) AS y +SELECT + y, + min(dummy) +FROM remote('127.0.0.{2,3}', system.one) +GROUP BY y; From f99d514de61a50cfe38d82b35231601daed52a22 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Tue, 28 May 2024 15:45:05 +0000 Subject: [PATCH 135/211] Sync md and in-source docs --- src/Functions/fromReadableDecimalSize.cpp | 6 +++--- src/Functions/fromReadableSize.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Functions/fromReadableDecimalSize.cpp b/src/Functions/fromReadableDecimalSize.cpp index 8b2415d2b66..6efabe7267d 100644 --- a/src/Functions/fromReadableDecimalSize.cpp +++ b/src/Functions/fromReadableDecimalSize.cpp @@ -48,7 +48,7 @@ using FunctionFromReadableDecimalSizeOrZero = FunctionFromReadable; FunctionDocumentation fromReadableSize_documentation { - .description = "Given a string containing the readable representation of a byte size with ISO/IEC 80000-13 units this function returns the corresponding number of bytes.", + .description = "Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit (i.e. [ISO/IEC 80000-13](https://en.wikipedia.org/wiki/ISO/IEC_80000) unit), this function returns the corresponding number of bytes. If the function is unable to parse the input value, it throws an exception.", .syntax = "fromReadableSize(x)", .arguments = {{"x", "Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md))"}}, .returned_value = "Number of bytes, rounded up to the nearest integer ([UInt64](../../sql-reference/data-types/int-uint.md))", @@ -71,7 +71,7 @@ FunctionDocumentation fromReadableSize_documentation { }; FunctionDocumentation fromReadableSizeOrNull_documentation { - .description = "Given a string containing the readable representation of a byte size with ISO/IEC 80000-13 units this function returns the corresponding number of bytes, or `NULL` if unable to parse the value.", + .description = "Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit (i.e. [ISO/IEC 80000-13](https://en.wikipedia.org/wiki/ISO/IEC_80000) unit), this function returns the corresponding number of bytes. If the function is unable to parse the input value, it returns `NULL`", .syntax = "fromReadableSizeOrNull(x)", .arguments = {{"x", "Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md))"}}, .returned_value = "Number of bytes, rounded up to the nearest integer, or NULL if unable to parse the input (Nullable([UInt64](../../sql-reference/data-types/int-uint.md)))", @@ -93,7 +93,7 @@ FunctionDocumentation fromReadableSizeOrNull_documentation { }; FunctionDocumentation fromReadableSizeOrZero_documentation { - .description = "Given a string containing the readable representation of a byte size with ISO/IEC 80000-13 units this function returns the corresponding number of bytes, or 0 if unable to parse the value.", + .description = "Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit (i.e. [ISO/IEC 80000-13](https://en.wikipedia.org/wiki/ISO/IEC_80000) unit), this function returns the corresponding number of bytes. If the function is unable to parse the input value, it returns `0`", .syntax = "fromReadableSizeOrZero(x)", .arguments = {{"x", "Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md))"}}, .returned_value = "Number of bytes, rounded up to the nearest integer, or 0 if unable to parse the input ([UInt64](../../sql-reference/data-types/int-uint.md))", From 422e7b95cba0170be28a8e793ece241088892394 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Tue, 28 May 2024 15:53:30 +0000 Subject: [PATCH 136/211] Restrict exceptions to ClickHouse exceptions + cosmetics --- src/Functions/fromReadable.h | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h index a2a7f7a8341..386250a617b 100644 --- a/src/Functions/fromReadable.h +++ b/src/Functions/fromReadable.h @@ -82,7 +82,6 @@ public: ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { - const auto * col_str = checkAndGetColumn(arguments[0].column.get()); if (!col_str) { @@ -106,15 +105,18 @@ public: for (size_t i = 0; i < input_rows_count; ++i) { - std::string_view str = col_str->getDataAt(i).toView(); + std::string_view value = col_str->getDataAt(i).toView(); try { - auto num_bytes = parseReadableFormat(scale_factors, str); + UInt64 num_bytes = parseReadableFormat(scale_factors, value); res_data[i] = num_bytes; } - catch (...) + catch (const Exception &) { - if constexpr (error_handling == ErrorHandling::Exception) { throw; } + if constexpr (error_handling == ErrorHandling::Exception) + { + throw; + } else { res_data[i] = 0; @@ -129,12 +131,11 @@ public: return col_res; } - private: - UInt64 parseReadableFormat(const std::unordered_map & scale_factors, const std::string_view & str) const + UInt64 parseReadableFormat(const ScaleFactors & scale_factors, const std::string_view & value) const { - ReadBufferFromString buf(str); + ReadBufferFromString buf(value); // tryReadFloatText does seem to not raise any error when there is leading whitespace so we check it explicitly skipWhitespaceIfAny(buf); @@ -144,7 +145,7 @@ private: ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED, "Invalid expression for function {} - Leading whitespace is not allowed (\"{}\")", getName(), - str + value ); } @@ -155,7 +156,7 @@ private: ErrorCodes::CANNOT_PARSE_NUMBER, "Invalid expression for function {} - Unable to parse readable size numeric component (\"{}\")", getName(), - str + value ); } else if (std::isnan(base) || !std::isfinite(base)) @@ -198,7 +199,7 @@ private: ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, "Invalid expression for function {} - Found trailing characters after readable size string (\"{}\")", getName(), - str + value ); } From 6b8ca302d2a657ed45b8abc45cb91094179ec7e0 Mon Sep 17 00:00:00 2001 From: Sema Checherinda Date: Tue, 28 May 2024 17:58:32 +0200 Subject: [PATCH 137/211] test for TotalQpsLimitExceeded --- contrib/aws | 2 +- tests/integration/helpers/s3_mocks/broken_s3.py | 16 ++++++++++++++++ .../test_checking_s3_blobs_paranoid/test.py | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/contrib/aws b/contrib/aws index eb96e740453..deeaa9e7c5f 160000 --- a/contrib/aws +++ b/contrib/aws @@ -1 +1 @@ -Subproject commit eb96e740453ae27afa1f367ba19f99bdcb38484d +Subproject commit deeaa9e7c5fe690e3dacc4005d7ecfa7a66a32bb diff --git a/tests/integration/helpers/s3_mocks/broken_s3.py b/tests/integration/helpers/s3_mocks/broken_s3.py index 7d0127bc1c4..775424d66a7 100644 --- a/tests/integration/helpers/s3_mocks/broken_s3.py +++ b/tests/integration/helpers/s3_mocks/broken_s3.py @@ -195,6 +195,18 @@ class _ServerRuntime: ) request_handler.write_error(429, data) + class TotalQpsLimitExceededAction: + def inject_error(self, request_handler): + data = ( + '' + "" + "TotalQpsLimitExceeded" + "Please reduce your request rate." + "txfbd566d03042474888193-00608d7537" + "" + ) + request_handler.write_error(429, data) + class RedirectAction: def __init__(self, host="localhost", port=1): self.dst_host = _and_then(host, str) @@ -269,6 +281,10 @@ class _ServerRuntime: self.error_handler = _ServerRuntime.QpsLimitExceededAction( *self.action_args ) + elif self.action == "total_qps_limit_exceeded": + self.error_handler = _ServerRuntime.TotalQpsLimitExceededAction( + *self.action_args + ) else: self.error_handler = _ServerRuntime.Expected500ErrorAction() diff --git a/tests/integration/test_checking_s3_blobs_paranoid/test.py b/tests/integration/test_checking_s3_blobs_paranoid/test.py index a7fe02b16de..476f7c61b28 100644 --- a/tests/integration/test_checking_s3_blobs_paranoid/test.py +++ b/tests/integration/test_checking_s3_blobs_paranoid/test.py @@ -205,6 +205,7 @@ def test_upload_s3_fail_upload_part_when_multi_part_upload( [ ("slow_down", "DB::Exception: Slow Down."), ("qps_limit_exceeded", "DB::Exception: Please reduce your request rate."), + ("total_qps_limit_exceeded", "DB::Exception: Please reduce your request rate."), ( "connection_refused", "Poco::Exception. Code: 1000, e.code() = 111, Connection refused", From 304ca95c718b0ce9a3743f57182560bf5eeedaa8 Mon Sep 17 00:00:00 2001 From: Max K Date: Tue, 28 May 2024 18:14:44 +0200 Subject: [PATCH 138/211] Revert "Revert "CI: fix build_report selection in case of job reuse"" --- tests/ci/report.py | 50 +++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/tests/ci/report.py b/tests/ci/report.py index 8676c998afb..670a10f4561 100644 --- a/tests/ci/report.py +++ b/tests/ci/report.py @@ -401,30 +401,40 @@ class BuildResult: @classmethod def load_any(cls, build_name: str, pr_number: int, head_ref: str): # type: ignore """ - loads report from suitable report file with the following priority: - 1. report from PR with the same @pr_number - 2. report from branch with the same @head_ref - 3. report from the master - 4. any other report + loads build report from one of all available report files (matching the job digest) + with the following priority: + 1. report for the current PR @pr_number (might happen in PR' wf with or without job reuse) + 2. report for the current branch @head_ref (might happen in release/master' wf with or without job reuse) + 3. report for master branch (might happen in any workflow in case of job reuse) + 4. any other report (job reuse from another PR, if master report is not available yet) """ - reports = [] + pr_report = None + ref_report = None + master_report = None + any_report = None for file in Path(REPORT_PATH).iterdir(): if f"{build_name}.json" in file.name: - reports.append(file) - if not reports: - return None - file_path = None - for file in reports: - if pr_number and f"_{pr_number}_" in file.name: - file_path = file - break - if f"_{head_ref}_" in file.name: - file_path = file - break + any_report = file if "_master_" in file.name: - file_path = file - break - return cls.load_from_file(file_path or reports[-1]) + master_report = file + elif f"_{head_ref}_" in file.name: + ref_report = file + elif pr_number and f"_{pr_number}_" in file.name: + pr_report = file + + if not any_report: + return None + + if pr_report: + file_path = pr_report + elif ref_report: + file_path = ref_report + elif master_report: + file_path = master_report + else: + file_path = any_report + + return cls.load_from_file(file_path) @classmethod def load_from_file(cls, file: Union[Path, str]): # type: ignore From f48f3feafa27059ad5d3c85d2ae162f59ecd5034 Mon Sep 17 00:00:00 2001 From: Nikolay Degterinsky <43110995+evillique@users.noreply.github.com> Date: Tue, 28 May 2024 18:35:46 +0200 Subject: [PATCH 139/211] Unify SYSTEM query docs --- docs/en/sql-reference/statements/system.md | 68 +++++++++++----------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/docs/en/sql-reference/statements/system.md b/docs/en/sql-reference/statements/system.md index 9fec5420f97..7efbff1b42b 100644 --- a/docs/en/sql-reference/statements/system.md +++ b/docs/en/sql-reference/statements/system.md @@ -206,6 +206,32 @@ Enables background data distribution when inserting data into distributed tables SYSTEM START DISTRIBUTED SENDS [db.] [ON CLUSTER cluster_name] ``` +### STOP LISTEN + +Closes the socket and gracefully terminates the existing connections to the server on the specified port with the specified protocol. + +However, if the corresponding protocol settings were not specified in the clickhouse-server configuration, this command will have no effect. + +```sql +SYSTEM STOP LISTEN [ON CLUSTER cluster_name] [QUERIES ALL | QUERIES DEFAULT | QUERIES CUSTOM | TCP | TCP WITH PROXY | TCP SECURE | HTTP | HTTPS | MYSQL | GRPC | POSTGRESQL | PROMETHEUS | CUSTOM 'protocol'] +``` + +- If `CUSTOM 'protocol'` modifier is specified, the custom protocol with the specified name defined in the protocols section of the server configuration will be stopped. +- If `QUERIES ALL [EXCEPT .. [,..]]` modifier is specified, all protocols are stopped, unless specified with `EXCEPT` clause. +- If `QUERIES DEFAULT [EXCEPT .. [,..]]` modifier is specified, all default protocols are stopped, unless specified with `EXCEPT` clause. +- If `QUERIES CUSTOM [EXCEPT .. [,..]]` modifier is specified, all custom protocols are stopped, unless specified with `EXCEPT` clause. + +### START LISTEN + +Allows new connections to be established on the specified protocols. + +However, if the server on the specified port and protocol was not stopped using the SYSTEM STOP LISTEN command, this command will have no effect. + +```sql +SYSTEM START LISTEN [ON CLUSTER cluster_name] [QUERIES ALL | QUERIES DEFAULT | QUERIES CUSTOM | TCP | TCP WITH PROXY | TCP SECURE | HTTP | HTTPS | MYSQL | GRPC | POSTGRESQL | PROMETHEUS | CUSTOM 'protocol'] +``` + + ## Managing MergeTree Tables ClickHouse can manage background processes in [MergeTree](../../engines/table-engines/mergetree-family/mergetree.md) tables. @@ -463,30 +489,16 @@ Will do sync syscall. SYSTEM SYNC FILE CACHE [ON CLUSTER cluster_name] ``` +### UNLOAD PRIMARY KEY -## SYSTEM STOP LISTEN - -Closes the socket and gracefully terminates the existing connections to the server on the specified port with the specified protocol. - -However, if the corresponding protocol settings were not specified in the clickhouse-server configuration, this command will have no effect. +Unload the primary keys for the given table or for all tables. ```sql -SYSTEM STOP LISTEN [ON CLUSTER cluster_name] [QUERIES ALL | QUERIES DEFAULT | QUERIES CUSTOM | TCP | TCP WITH PROXY | TCP SECURE | HTTP | HTTPS | MYSQL | GRPC | POSTGRESQL | PROMETHEUS | CUSTOM 'protocol'] +SYSTEM UNLOAD PRIMARY KEY [db.]name ``` -- If `CUSTOM 'protocol'` modifier is specified, the custom protocol with the specified name defined in the protocols section of the server configuration will be stopped. -- If `QUERIES ALL [EXCEPT .. [,..]]` modifier is specified, all protocols are stopped, unless specified with `EXCEPT` clause. -- If `QUERIES DEFAULT [EXCEPT .. [,..]]` modifier is specified, all default protocols are stopped, unless specified with `EXCEPT` clause. -- If `QUERIES CUSTOM [EXCEPT .. [,..]]` modifier is specified, all custom protocols are stopped, unless specified with `EXCEPT` clause. - -## SYSTEM START LISTEN - -Allows new connections to be established on the specified protocols. - -However, if the server on the specified port and protocol was not stopped using the SYSTEM STOP LISTEN command, this command will have no effect. - ```sql -SYSTEM START LISTEN [ON CLUSTER cluster_name] [QUERIES ALL | QUERIES DEFAULT | QUERIES CUSTOM | TCP | TCP WITH PROXY | TCP SECURE | HTTP | HTTPS | MYSQL | GRPC | POSTGRESQL | PROMETHEUS | CUSTOM 'protocol'] +SYSTEM UNLOAD PRIMARY KEY ``` ## Managing Refreshable Materialized Views {#refreshable-materialized-views} @@ -495,7 +507,7 @@ Commands to control background tasks performed by [Refreshable Materialized View Keep an eye on [`system.view_refreshes`](../../operations/system-tables/view_refreshes.md) while using them. -### SYSTEM REFRESH VIEW +### REFRESH VIEW Trigger an immediate out-of-schedule refresh of a given view. @@ -503,7 +515,7 @@ Trigger an immediate out-of-schedule refresh of a given view. SYSTEM REFRESH VIEW [db.]name ``` -### SYSTEM STOP VIEW, SYSTEM STOP VIEWS +### STOP VIEW, STOP VIEWS Disable periodic refreshing of the given view or all refreshable views. If a refresh is in progress, cancel it too. @@ -514,7 +526,7 @@ SYSTEM STOP VIEW [db.]name SYSTEM STOP VIEWS ``` -### SYSTEM START VIEW, SYSTEM START VIEWS +### START VIEW, START VIEWS Enable periodic refreshing for the given view or all refreshable views. No immediate refresh is triggered. @@ -525,22 +537,10 @@ SYSTEM START VIEW [db.]name SYSTEM START VIEWS ``` -### SYSTEM CANCEL VIEW +### CANCEL VIEW If there's a refresh in progress for the given view, interrupt and cancel it. Otherwise do nothing. ```sql SYSTEM CANCEL VIEW [db.]name ``` - -### SYSTEM UNLOAD PRIMARY KEY - -Unload the primary keys for the given table or for all tables. - -```sql -SYSTEM UNLOAD PRIMARY KEY [db.]name -``` - -```sql -SYSTEM UNLOAD PRIMARY KEY -``` \ No newline at end of file From 087abfc14700d7a91696a73496444e77cab462a4 Mon Sep 17 00:00:00 2001 From: Max K Date: Tue, 28 May 2024 18:45:11 +0200 Subject: [PATCH 140/211] fix --- tests/ci/report.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ci/report.py b/tests/ci/report.py index 670a10f4561..03177cfdc3a 100644 --- a/tests/ci/report.py +++ b/tests/ci/report.py @@ -415,12 +415,12 @@ class BuildResult: for file in Path(REPORT_PATH).iterdir(): if f"{build_name}.json" in file.name: any_report = file - if "_master_" in file.name: - master_report = file - elif f"_{head_ref}_" in file.name: - ref_report = file - elif pr_number and f"_{pr_number}_" in file.name: - pr_report = file + if "_master_" in file.name: + master_report = file + elif f"_{head_ref}_" in file.name: + ref_report = file + elif pr_number and f"_{pr_number}_" in file.name: + pr_report = file if not any_report: return None From bc4d96481c55a799f60d4ba4ddb1bb18bf992b4a Mon Sep 17 00:00:00 2001 From: Jiebin Sun Date: Tue, 28 May 2024 23:52:19 +0800 Subject: [PATCH 141/211] Add isolated performance test --- tests/performance/sparse_column_filter.xml | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/performance/sparse_column_filter.xml diff --git a/tests/performance/sparse_column_filter.xml b/tests/performance/sparse_column_filter.xml new file mode 100644 index 00000000000..bc6a94a1cc4 --- /dev/null +++ b/tests/performance/sparse_column_filter.xml @@ -0,0 +1,42 @@ + + + + serialization + + sparse + + + + ratio + + 10 + 100 + 1000 + + + + + + CREATE TABLE test_{serialization}_{ratio} (id UInt64, u8 UInt8, u64 UInt64, str String) + ENGINE = MergeTree ORDER BY id + SETTINGS ratio_of_defaults_for_sparse_serialization = 0.8 + + + SYSTEM STOP MERGES test_{serialization}_{ratio} + + + INSERT INTO test_{serialization}_{ratio} SELECT + number, + number % {ratio} = 0 ? rand(1) : 0, + number % {ratio} = 0 ? rand(2) : 0, + number % {ratio} = 0 ? randomPrintableASCII(64, 3) : '' + FROM numbers(100000000) + + + SELECT str, COUNT(DISTINCT id) as i FROM test_{serialization}_{ratio} WHERE notEmpty(str) GROUP BY str ORDER BY i DESC LIMIT 10 + SELECT str, COUNT(DISTINCT u8) as u FROM test_{serialization}_{ratio} WHERE notEmpty(str) GROUP BY str ORDER BY u DESC LIMIT 10 + SELECT str, COUNT(DISTINCT u64) as u FROM test_{serialization}_{ratio} WHERE notEmpty(str) GROUP BY str ORDER BY u DESC LIMIT 10 + + + DROP TABLE IF EXISTS test_{serialization}_{ratio} + From d5989d8c3317e65d190cce873bbff56f8367db9d Mon Sep 17 00:00:00 2001 From: Alexander Tokmakov Date: Tue, 28 May 2024 20:12:35 +0200 Subject: [PATCH 142/211] Update Settings.h --- src/Core/Settings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Settings.h b/src/Core/Settings.h index f0389e7e2d5..7de86e8193e 100644 --- a/src/Core/Settings.h +++ b/src/Core/Settings.h @@ -394,7 +394,7 @@ class IColumn; M(Bool, allow_experimental_analyzer, true, "Allow experimental analyzer.", 0) \ M(Bool, analyzer_compatibility_join_using_top_level_identifier, false, "Force to resolve identifier in JOIN USING from projection (for example, in `SELECT a + 1 AS b FROM t1 JOIN t2 USING (b)` join will be performed by `t1.a + 1 = t2.b`, rather then `t1.b = t2.b`).", 0) \ M(Bool, prefer_global_in_and_join, false, "If enabled, all IN/JOIN operators will be rewritten as GLOBAL IN/JOIN. It's useful when the to-be-joined tables are only available on the initiator and we need to always scatter their data on-the-fly during distributed processing with the GLOBAL keyword. It's also useful to reduce the need to access the external sources joining external tables.", 0) \ - M(Bool, enable_vertical_final, true, "If enable, remove duplicated rows during FINAL by marking rows as deleted and filtering them later instead of merging rows", 0) \ + M(Bool, enable_vertical_final, false, "Not recommended. If enable, remove duplicated rows during FINAL by marking rows as deleted and filtering them later instead of merging rows", 0) \ \ \ /** Limits during query execution are part of the settings. \ From 5eb082ab39e5c2788cb60733a5ee0720a79bb7ac Mon Sep 17 00:00:00 2001 From: Alexander Tokmakov Date: Tue, 28 May 2024 20:50:29 +0200 Subject: [PATCH 143/211] Update FilterTransform.cpp --- src/Processors/Transforms/FilterTransform.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Processors/Transforms/FilterTransform.cpp b/src/Processors/Transforms/FilterTransform.cpp index 0793bb3db5b..e8e7f99ce53 100644 --- a/src/Processors/Transforms/FilterTransform.cpp +++ b/src/Processors/Transforms/FilterTransform.cpp @@ -14,6 +14,7 @@ namespace DB namespace ErrorCodes { extern const int ILLEGAL_TYPE_OF_COLUMN_FOR_FILTER; + extern const int LOGICAL_ERROR; } static void replaceFilterToConstant(Block & block, const String & filter_column_name) @@ -81,7 +82,11 @@ static std::unique_ptr combineFilterAndIndices( auto mutable_holder = ColumnUInt8::create(num_rows, 0); auto & data = mutable_holder->getData(); for (auto idx : selected_by_indices) + { + if (idx >= num_rows) + throw Exception(ErrorCodes::LOGICAL_ERROR, "Index {} out of range {}", idx, num_rows); data[idx] = 1; + } /// AND two filters auto * begin = data.data(); From 48b45842f1517fd873b5b29a7ec53e80750270fc Mon Sep 17 00:00:00 2001 From: Julia Kartseva Date: Mon, 20 May 2024 21:51:47 +0000 Subject: [PATCH 144/211] set directory removal flag in plain_rewritable disk --- .../MetadataStorageFromPlainObjectStorageOperations.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorageOperations.cpp b/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorageOperations.cpp index a28f4e7a882..8f0ba8f45c6 100644 --- a/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorageOperations.cpp +++ b/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorageOperations.cpp @@ -166,6 +166,8 @@ void MetadataStorageFromPlainObjectStorageRemoveDirectoryOperation::execute(std: auto object = StoredObject(object_key.serialize(), path / PREFIX_PATH_FILE_NAME); object_storage->removeObject(object); path_map.erase(path_it); + + removed = true; } void MetadataStorageFromPlainObjectStorageRemoveDirectoryOperation::undo(std::unique_lock &) From d4af1f3464dfe3ee9621766258de55dcaf53afdb Mon Sep 17 00:00:00 2001 From: Julia Kartseva Date: Sat, 18 May 2024 03:08:52 +0000 Subject: [PATCH 145/211] Add metrics for plain_rewritable metadata storage Metrics to track the number of directories created and removed by the plain_rewritable metadata storage, and the number of entries in the local-to-remote in-memory map. --- src/Common/CurrentMetrics.cpp | 5 ++ src/Common/ProfileEvents.cpp | 7 ++ src/Disks/ObjectStorages/IObjectStorage.cpp | 5 ++ src/Disks/ObjectStorages/IObjectStorage.h | 19 +++--- ...torageFromPlainObjectStorageOperations.cpp | 16 +++++ ...torageFromPlainRewritableObjectStorage.cpp | 8 +++ ...aStorageFromPlainRewritableObjectStorage.h | 1 + .../ObjectStorages/MetadataStorageMetrics.h | 24 +++++++ .../ObjectStorages/ObjectStorageFactory.cpp | 8 ++- .../PlainRewritableObjectStorage.h | 6 +- .../createMetadataStorageMetrics.h | 67 +++++++++++++++++++ 11 files changed, 155 insertions(+), 11 deletions(-) create mode 100644 src/Disks/ObjectStorages/MetadataStorageMetrics.h create mode 100644 src/Disks/ObjectStorages/createMetadataStorageMetrics.h diff --git a/src/Common/CurrentMetrics.cpp b/src/Common/CurrentMetrics.cpp index e73ac307a35..8eb7065dc63 100644 --- a/src/Common/CurrentMetrics.cpp +++ b/src/Common/CurrentMetrics.cpp @@ -174,6 +174,11 @@ M(ObjectStorageAzureThreads, "Number of threads in the AzureObjectStorage thread pool.") \ M(ObjectStorageAzureThreadsActive, "Number of threads in the AzureObjectStorage thread pool running a task.") \ M(ObjectStorageAzureThreadsScheduled, "Number of queued or active jobs in the AzureObjectStorage thread pool.") \ + \ + M(DiskPlainRewritableAzureDirectoryMapSize, "Number of local-to-remote path entries in the 'plain_rewritable' in-memory map for AzureObjectStorage.") \ + M(DiskPlainRewritableLocalDirectoryMapSize, "Number of local-to-remote path entries in the 'plain_rewritable' in-memory map for LocalObjectStorage.") \ + M(DiskPlainRewritableS3DirectoryMapSize, "Number of local-to-remote path entries in the 'plain_rewritable' in-memory map for S3ObjectStorage.") \ + \ M(MergeTreePartsLoaderThreads, "Number of threads in the MergeTree parts loader thread pool.") \ M(MergeTreePartsLoaderThreadsActive, "Number of threads in the MergeTree parts loader thread pool running a task.") \ M(MergeTreePartsLoaderThreadsScheduled, "Number of queued or active jobs in the MergeTree parts loader thread pool.") \ diff --git a/src/Common/ProfileEvents.cpp b/src/Common/ProfileEvents.cpp index 8c8e2163aad..9bb7bece0f0 100644 --- a/src/Common/ProfileEvents.cpp +++ b/src/Common/ProfileEvents.cpp @@ -417,6 +417,13 @@ The server successfully detected this situation and will download merged part fr M(DiskS3PutObject, "Number of DiskS3 API PutObject calls.") \ M(DiskS3GetObject, "Number of DiskS3 API GetObject calls.") \ \ + M(DiskPlainRewritableAzureDirectoryCreated, "Number of directories created by the 'plain_rewritable' metadata storage for AzureObjectStorage.") \ + M(DiskPlainRewritableAzureDirectoryRemoved, "Number of directories removed by the 'plain_rewritable' metadata storage for AzureObjectStorage.") \ + M(DiskPlainRewritableLocalDirectoryCreated, "Number of directories created by the 'plain_rewritable' metadata storage for LocalObjectStorage.") \ + M(DiskPlainRewritableLocalDirectoryRemoved, "Number of directories removed by the 'plain_rewritable' metadata storage for LocalObjectStorage.") \ + M(DiskPlainRewritableS3DirectoryCreated, "Number of directories created by the 'plain_rewritable' metadata storage for S3ObjectStorage.") \ + M(DiskPlainRewritableS3DirectoryRemoved, "Number of directories removed by the 'plain_rewritable' metadata storage for S3ObjectStorage.") \ + \ M(S3Clients, "Number of created S3 clients.") \ M(TinyS3Clients, "Number of S3 clients copies which reuse an existing auth provider from another client.") \ \ diff --git a/src/Disks/ObjectStorages/IObjectStorage.cpp b/src/Disks/ObjectStorages/IObjectStorage.cpp index fd1269df79b..ce5f06e8f25 100644 --- a/src/Disks/ObjectStorages/IObjectStorage.cpp +++ b/src/Disks/ObjectStorages/IObjectStorage.cpp @@ -18,6 +18,11 @@ namespace ErrorCodes extern const int LOGICAL_ERROR; } +const MetadataStorageMetrics & IObjectStorage::getMetadataStorageMetrics() const +{ + throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Method 'getMetadataStorageMetrics' is not implemented"); +} + bool IObjectStorage::existsOrHasAnyChild(const std::string & path) const { RelativePathsWithMetadata files; diff --git a/src/Disks/ObjectStorages/IObjectStorage.h b/src/Disks/ObjectStorages/IObjectStorage.h index b49dc839561..7bc9e4073db 100644 --- a/src/Disks/ObjectStorages/IObjectStorage.h +++ b/src/Disks/ObjectStorages/IObjectStorage.h @@ -13,17 +13,18 @@ #include #include -#include -#include -#include -#include -#include -#include #include #include -#include -#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include #include "config.h" #if USE_AZURE_BLOB_STORAGE @@ -115,6 +116,8 @@ public: virtual std::string getDescription() const = 0; + virtual const MetadataStorageMetrics & getMetadataStorageMetrics() const; + /// Object exists or not virtual bool exists(const StoredObject & object) const = 0; diff --git a/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorageOperations.cpp b/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorageOperations.cpp index 8f0ba8f45c6..7e4b1f69962 100644 --- a/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorageOperations.cpp +++ b/src/Disks/ObjectStorages/MetadataStorageFromPlainObjectStorageOperations.cpp @@ -52,11 +52,16 @@ void MetadataStorageFromPlainObjectStorageCreateDirectoryOperation::execute(std: [[maybe_unused]] auto result = path_map.emplace(path, std::move(key_prefix)); chassert(result.second); + auto metric = object_storage->getMetadataStorageMetrics().directory_map_size; + CurrentMetrics::add(metric, 1); writeString(path.string(), *buf); buf->finalize(); write_finalized = true; + + auto event = object_storage->getMetadataStorageMetrics().directory_created; + ProfileEvents::increment(event); } void MetadataStorageFromPlainObjectStorageCreateDirectoryOperation::undo(std::unique_lock &) @@ -65,6 +70,9 @@ void MetadataStorageFromPlainObjectStorageCreateDirectoryOperation::undo(std::un if (write_finalized) { path_map.erase(path); + auto metric = object_storage->getMetadataStorageMetrics().directory_map_size; + CurrentMetrics::sub(metric, 1); + object_storage->removeObject(StoredObject(object_key.serialize(), path / PREFIX_PATH_FILE_NAME)); } else if (write_created) @@ -165,9 +173,15 @@ void MetadataStorageFromPlainObjectStorageRemoveDirectoryOperation::execute(std: auto object_key = ObjectStorageKey::createAsRelative(key_prefix, PREFIX_PATH_FILE_NAME); auto object = StoredObject(object_key.serialize(), path / PREFIX_PATH_FILE_NAME); object_storage->removeObject(object); + path_map.erase(path_it); + auto metric = object_storage->getMetadataStorageMetrics().directory_map_size; + CurrentMetrics::sub(metric, 1); removed = true; + + auto event = object_storage->getMetadataStorageMetrics().directory_removed; + ProfileEvents::increment(event); } void MetadataStorageFromPlainObjectStorageRemoveDirectoryOperation::undo(std::unique_lock &) @@ -187,6 +201,8 @@ void MetadataStorageFromPlainObjectStorageRemoveDirectoryOperation::undo(std::un buf->finalize(); path_map.emplace(path, std::move(key_prefix)); + auto metric = object_storage->getMetadataStorageMetrics().directory_map_size; + CurrentMetrics::add(metric, 1); } } diff --git a/src/Disks/ObjectStorages/MetadataStorageFromPlainRewritableObjectStorage.cpp b/src/Disks/ObjectStorages/MetadataStorageFromPlainRewritableObjectStorage.cpp index 3e772271b99..cc77ca5364b 100644 --- a/src/Disks/ObjectStorages/MetadataStorageFromPlainRewritableObjectStorage.cpp +++ b/src/Disks/ObjectStorages/MetadataStorageFromPlainRewritableObjectStorage.cpp @@ -50,6 +50,8 @@ MetadataStorageFromPlainObjectStorage::PathMap loadPathPrefixMap(const std::stri res.first->second, remote_path.parent_path().string()); } + auto metric = object_storage->getMetadataStorageMetrics().directory_map_size; + CurrentMetrics::add(metric, result.size()); return result; } @@ -134,6 +136,12 @@ MetadataStorageFromPlainRewritableObjectStorage::MetadataStorageFromPlainRewrita object_storage->setKeysGenerator(keys_gen); } +MetadataStorageFromPlainRewritableObjectStorage::~MetadataStorageFromPlainRewritableObjectStorage() +{ + auto metric = object_storage->getMetadataStorageMetrics().directory_map_size; + CurrentMetrics::sub(metric, path_map->size()); +} + std::vector MetadataStorageFromPlainRewritableObjectStorage::getDirectChildrenOnDisk( const std::string & storage_key, const RelativePathsWithMetadata & remote_paths, const std::string & local_path) const { diff --git a/src/Disks/ObjectStorages/MetadataStorageFromPlainRewritableObjectStorage.h b/src/Disks/ObjectStorages/MetadataStorageFromPlainRewritableObjectStorage.h index 4415a68c24e..661968d7044 100644 --- a/src/Disks/ObjectStorages/MetadataStorageFromPlainRewritableObjectStorage.h +++ b/src/Disks/ObjectStorages/MetadataStorageFromPlainRewritableObjectStorage.h @@ -14,6 +14,7 @@ private: public: MetadataStorageFromPlainRewritableObjectStorage(ObjectStoragePtr object_storage_, String storage_path_prefix_); + ~MetadataStorageFromPlainRewritableObjectStorage() override; MetadataStorageType getType() const override { return MetadataStorageType::PlainRewritable; } diff --git a/src/Disks/ObjectStorages/MetadataStorageMetrics.h b/src/Disks/ObjectStorages/MetadataStorageMetrics.h new file mode 100644 index 00000000000..365fd3c8145 --- /dev/null +++ b/src/Disks/ObjectStorages/MetadataStorageMetrics.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +namespace DB +{ + +struct MetadataStorageMetrics +{ + const ProfileEvents::Event directory_created = ProfileEvents::end(); + const ProfileEvents::Event directory_removed = ProfileEvents::end(); + + CurrentMetrics::Metric directory_map_size = CurrentMetrics::end(); + + template + static MetadataStorageMetrics create() + { + return MetadataStorageMetrics{}; + } +}; + +} diff --git a/src/Disks/ObjectStorages/ObjectStorageFactory.cpp b/src/Disks/ObjectStorages/ObjectStorageFactory.cpp index d7884c2911b..8210255decb 100644 --- a/src/Disks/ObjectStorages/ObjectStorageFactory.cpp +++ b/src/Disks/ObjectStorages/ObjectStorageFactory.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -85,7 +86,9 @@ ObjectStoragePtr createObjectStorage( DataSourceDescription{DataSourceType::ObjectStorage, type, MetadataStorageType::PlainRewritable, /*description*/ ""} .toString()); - return std::make_shared>(std::forward(args)...); + auto metadata_storage_metrics = DB::MetadataStorageMetrics::create(); + return std::make_shared>( + std::move(metadata_storage_metrics), std::forward(args)...); } else return std::make_shared(std::forward(args)...); @@ -256,8 +259,9 @@ void registerS3PlainRewritableObjectStorage(ObjectStorageFactory & factory) auto client = getClient(config, config_prefix, context, *settings, true); auto key_generator = getKeyGenerator(uri, config, config_prefix); + auto metadata_storage_metrics = DB::MetadataStorageMetrics::create(); auto object_storage = std::make_shared>( - std::move(client), std::move(settings), uri, s3_capabilities, key_generator, name); + std::move(metadata_storage_metrics), std::move(client), std::move(settings), uri, s3_capabilities, key_generator, name); /// NOTE: should we still perform this check for clickhouse-disks? if (!skip_access_check) diff --git a/src/Disks/ObjectStorages/PlainRewritableObjectStorage.h b/src/Disks/ObjectStorages/PlainRewritableObjectStorage.h index 2b116cff443..5f000afe625 100644 --- a/src/Disks/ObjectStorages/PlainRewritableObjectStorage.h +++ b/src/Disks/ObjectStorages/PlainRewritableObjectStorage.h @@ -16,8 +16,9 @@ class PlainRewritableObjectStorage : public BaseObjectStorage { public: template - explicit PlainRewritableObjectStorage(Args &&... args) + explicit PlainRewritableObjectStorage(MetadataStorageMetrics && metadata_storage_metrics_, Args &&... args) : BaseObjectStorage(std::forward(args)...) + , metadata_storage_metrics(std::move(metadata_storage_metrics_)) /// A basic key generator is required for checking S3 capabilities, /// it will be reset later by metadata storage. , key_generator(createObjectStorageKeysGeneratorAsIsWithPrefix(BaseObjectStorage::getCommonKeyPrefix())) @@ -26,6 +27,8 @@ public: std::string getName() const override { return "PlainRewritable" + BaseObjectStorage::getName(); } + const MetadataStorageMetrics & getMetadataStorageMetrics() const override { return metadata_storage_metrics; } + bool isWriteOnce() const override { return false; } bool isPlain() const override { return true; } @@ -37,6 +40,7 @@ public: void setKeysGenerator(ObjectStorageKeysGeneratorPtr gen) override { key_generator = gen; } private: + MetadataStorageMetrics metadata_storage_metrics; ObjectStorageKeysGeneratorPtr key_generator; }; diff --git a/src/Disks/ObjectStorages/createMetadataStorageMetrics.h b/src/Disks/ObjectStorages/createMetadataStorageMetrics.h new file mode 100644 index 00000000000..6dddc227ade --- /dev/null +++ b/src/Disks/ObjectStorages/createMetadataStorageMetrics.h @@ -0,0 +1,67 @@ +#pragma once + +#if USE_AWS_S3 +# include +#endif +#if USE_AZURE_BLOB_STORAGE && !defined(CLICKHOUSE_KEEPER_STANDALONE_BUILD) +# include +#endif +#ifndef CLICKHOUSE_KEEPER_STANDALONE_BUILD +# include +#endif +#include + +namespace ProfileEvents +{ +extern const Event DiskPlainRewritableAzureDirectoryCreated; +extern const Event DiskPlainRewritableAzureDirectoryRemoved; +extern const Event DiskPlainRewritableLocalDirectoryCreated; +extern const Event DiskPlainRewritableLocalDirectoryRemoved; +extern const Event DiskPlainRewritableS3DirectoryCreated; +extern const Event DiskPlainRewritableS3DirectoryRemoved; +} + +namespace CurrentMetrics +{ +extern const Metric DiskPlainRewritableAzureDirectoryMapSize; +extern const Metric DiskPlainRewritableLocalDirectoryMapSize; +extern const Metric DiskPlainRewritableS3DirectoryMapSize; +} + +namespace DB +{ + +#if USE_AWS_S3 +template <> +inline MetadataStorageMetrics MetadataStorageMetrics::create() +{ + return MetadataStorageMetrics{ + .directory_created = ProfileEvents::DiskPlainRewritableS3DirectoryCreated, + .directory_removed = ProfileEvents::DiskPlainRewritableS3DirectoryRemoved, + .directory_map_size = CurrentMetrics::DiskPlainRewritableS3DirectoryMapSize}; +} +#endif + +#if USE_AZURE_BLOB_STORAGE && !defined(CLICKHOUSE_KEEPER_STANDALONE_BUILD) +template <> +inline MetadataStorageMetrics MetadataStorageMetrics::create() +{ + return MetadataStorageMetrics{ + .directory_created = ProfileEvents::DiskPlainRewritableAzureDirectoryCreated, + .directory_removed = ProfileEvents::DiskPlainRewritableAzureDirectoryRemoved, + .directory_map_size = CurrentMetrics::DiskPlainRewritableAzureDirectoryMapSize}; +} +#endif + +#ifndef CLICKHOUSE_KEEPER_STANDALONE_BUILD +template <> +inline MetadataStorageMetrics MetadataStorageMetrics::create() +{ + return MetadataStorageMetrics{ + .directory_created = ProfileEvents::DiskPlainRewritableLocalDirectoryCreated, + .directory_removed = ProfileEvents::DiskPlainRewritableLocalDirectoryRemoved, + .directory_map_size = CurrentMetrics::DiskPlainRewritableLocalDirectoryMapSize}; +} +#endif + +} From b11b9515a26c9635eb4ce82f783142687aa2825b Mon Sep 17 00:00:00 2001 From: Julia Kartseva Date: Thu, 23 May 2024 02:06:37 +0000 Subject: [PATCH 146/211] ENDPOINT_SUBPATH is unique for each instance in test_s3_plain_rewritable --- .../test_s3_plain_rewritable/test.py | 68 +++++++++---------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/tests/integration/test_s3_plain_rewritable/test.py b/tests/integration/test_s3_plain_rewritable/test.py index 67e3ec987a9..ce1f7222201 100644 --- a/tests/integration/test_s3_plain_rewritable/test.py +++ b/tests/integration/test_s3_plain_rewritable/test.py @@ -9,18 +9,6 @@ cluster = ClickHouseCluster(__file__) NUM_WORKERS = 5 -nodes = [] -for i in range(NUM_WORKERS): - name = "node{}".format(i + 1) - node = cluster.add_instance( - name, - main_configs=["configs/storage_conf.xml"], - env_variables={"ENDPOINT_SUBPATH": name}, - with_minio=True, - stay_alive=True, - ) - nodes.append(node) - MAX_ROWS = 1000 @@ -38,6 +26,17 @@ insert_values = ",".join( @pytest.fixture(scope="module", autouse=True) def start_cluster(): + for i in range(NUM_WORKERS): + cluster.add_instance( + f"node{i + 1}", + main_configs=["configs/storage_conf.xml"], + with_minio=True, + env_variables={"ENDPOINT_SUBPATH": f"node{i + 1}"}, + stay_alive=True, + # Override ENDPOINT_SUBPATH. + instance_env_variables=i > 0, + ) + try: cluster.start() yield cluster @@ -64,10 +63,10 @@ def test_insert(): gen_insert_values(random.randint(1, MAX_ROWS)) for _ in range(0, NUM_WORKERS) ] threads = [] + assert len(cluster.instances) == NUM_WORKERS for i in range(NUM_WORKERS): - t = threading.Thread( - target=create_insert, args=(nodes[i], insert_values_arr[i]) - ) + node = cluster.instances[f"node{i + 1}"] + t = threading.Thread(target=create_insert, args=(node, insert_values_arr[i])) threads.append(t) t.start() @@ -75,38 +74,34 @@ def test_insert(): t.join() for i in range(NUM_WORKERS): + node = cluster.instances[f"node{i + 1}"] assert ( - nodes[i].query("SELECT * FROM test ORDER BY id FORMAT Values") + node.query("SELECT * FROM test ORDER BY id FORMAT Values") == insert_values_arr[i] ) for i in range(NUM_WORKERS): - nodes[i].query("ALTER TABLE test MODIFY SETTING old_parts_lifetime = 59") + node = cluster.instances[f"node{i + 1}"] + node.query("ALTER TABLE test MODIFY SETTING old_parts_lifetime = 59") assert ( - nodes[i] - .query( + node.query( "SELECT engine_full from system.tables WHERE database = currentDatabase() AND name = 'test'" - ) - .find("old_parts_lifetime = 59") + ).find("old_parts_lifetime = 59") != -1 ) - nodes[i].query("ALTER TABLE test RESET SETTING old_parts_lifetime") + node.query("ALTER TABLE test RESET SETTING old_parts_lifetime") assert ( - nodes[i] - .query( + node.query( "SELECT engine_full from system.tables WHERE database = currentDatabase() AND name = 'test'" - ) - .find("old_parts_lifetime") + ).find("old_parts_lifetime") == -1 ) - nodes[i].query("ALTER TABLE test MODIFY COMMENT 'new description'") + node.query("ALTER TABLE test MODIFY COMMENT 'new description'") assert ( - nodes[i] - .query( + node.query( "SELECT comment from system.tables WHERE database = currentDatabase() AND name = 'test'" - ) - .find("new description") + ).find("new description") != -1 ) @@ -115,8 +110,9 @@ def test_insert(): def test_restart(): insert_values_arr = [] for i in range(NUM_WORKERS): + node = cluster.instances[f"node{i + 1}"] insert_values_arr.append( - nodes[i].query("SELECT * FROM test ORDER BY id FORMAT Values") + node.query("SELECT * FROM test ORDER BY id FORMAT Values") ) def restart(node): @@ -124,7 +120,7 @@ def test_restart(): threads = [] for i in range(NUM_WORKERS): - t = threading.Thread(target=restart, args=(nodes[i],)) + t = threading.Thread(target=restart, args=(node,)) threads.append(t) t.start() @@ -132,8 +128,9 @@ def test_restart(): t.join() for i in range(NUM_WORKERS): + node = cluster.instances[f"node{i + 1}"] assert ( - nodes[i].query("SELECT * FROM test ORDER BY id FORMAT Values") + node.query("SELECT * FROM test ORDER BY id FORMAT Values") == insert_values_arr[i] ) @@ -141,7 +138,8 @@ def test_restart(): @pytest.mark.order(2) def test_drop(): for i in range(NUM_WORKERS): - nodes[i].query("DROP TABLE IF EXISTS test SYNC") + node = cluster.instances[f"node{i + 1}"] + node.query("DROP TABLE IF EXISTS test SYNC") it = cluster.minio_client.list_objects( cluster.minio_bucket, "data/", recursive=True From 8662f89d21269eadc486b679cd4d5773ccc3a6ff Mon Sep 17 00:00:00 2001 From: Julia Kartseva Date: Thu, 23 May 2024 02:11:58 +0000 Subject: [PATCH 147/211] update test_s3_plain_rewritable --- .../test_s3_plain_rewritable/test.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/integration/test_s3_plain_rewritable/test.py b/tests/integration/test_s3_plain_rewritable/test.py index ce1f7222201..06967958631 100644 --- a/tests/integration/test_s3_plain_rewritable/test.py +++ b/tests/integration/test_s3_plain_rewritable/test.py @@ -11,6 +11,8 @@ NUM_WORKERS = 5 MAX_ROWS = 1000 +dirs_created = [] + def gen_insert_values(size): return ",".join( @@ -105,6 +107,22 @@ def test_insert(): != -1 ) + created = int( + node.query( + "SELECT value FROM system.events WHERE event = 'DiskPlainRewritableS3DirectoryCreated'" + ) + ) + assert created > 0 + dirs_created.append(created) + assert ( + int( + node.query( + "SELECT value FROM system.metrics WHERE metric = 'DiskPlainRewritableS3DirectoryMapSize'" + ) + ) + == created + ) + @pytest.mark.order(1) def test_restart(): @@ -141,6 +159,14 @@ def test_drop(): node = cluster.instances[f"node{i + 1}"] node.query("DROP TABLE IF EXISTS test SYNC") + removed = int( + node.query( + "SELECT value FROM system.events WHERE event = 'DiskPlainRewritableS3DirectoryRemoved'" + ) + ) + + assert dirs_created[i] == removed + it = cluster.minio_client.list_objects( cluster.minio_bucket, "data/", recursive=True ) From a0f18eba310c7d293f6a2c91fafbcd905fd05b9d Mon Sep 17 00:00:00 2001 From: Julia Kartseva Date: Sat, 25 May 2024 01:42:20 +0000 Subject: [PATCH 148/211] update plain_rewritable unit tests --- .../03008_local_plain_rewritable.sh | 36 +++++++++-------- .../0_stateless/03008_s3_plain_rewritable.sh | 40 ++++++++++--------- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/tests/queries/0_stateless/03008_local_plain_rewritable.sh b/tests/queries/0_stateless/03008_local_plain_rewritable.sh index 1761c7d79b1..5fac964a219 100755 --- a/tests/queries/0_stateless/03008_local_plain_rewritable.sh +++ b/tests/queries/0_stateless/03008_local_plain_rewritable.sh @@ -6,13 +6,13 @@ CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # shellcheck source=../shell_config.sh . "$CUR_DIR"/../shell_config.sh -${CLICKHOUSE_CLIENT} --query "drop table if exists test_mt sync" +${CLICKHOUSE_CLIENT} --query "drop table if exists 03008_test_local_mt sync" ${CLICKHOUSE_CLIENT} -nm --query " -create table test_mt (a Int32, b Int64, c Int64) +create table 03008_test_local_mt (a Int32, b Int64, c Int64) engine = MergeTree() partition by intDiv(a, 1000) order by tuple(a, b) settings disk = disk( - name = disk_s3_plain, + name = 03008_local_plain_rewritable, type = object_storage, object_storage_type = local, metadata_type = plain_rewritable, @@ -20,34 +20,36 @@ settings disk = disk( " ${CLICKHOUSE_CLIENT} -nm --query " -insert into test_mt (*) values (1, 2, 0), (2, 2, 2), (3, 1, 9), (4, 7, 7), (5, 10, 2), (6, 12, 5); -insert into test_mt (*) select number, number, number from numbers_mt(10000); +insert into 03008_test_local_mt (*) values (1, 2, 0), (2, 2, 2), (3, 1, 9), (4, 7, 7), (5, 10, 2), (6, 12, 5); +insert into 03008_test_local_mt (*) select number, number, number from numbers_mt(10000); " ${CLICKHOUSE_CLIENT} -nm --query " -select count(*) from test_mt; -select (*) from test_mt order by tuple(a, b) limit 10; +select count(*) from 03008_test_local_mt; +select (*) from 03008_test_local_mt order by tuple(a, b) limit 10; " -${CLICKHOUSE_CLIENT} --query "optimize table test_mt final" +${CLICKHOUSE_CLIENT} --query "optimize table 03008_test_local_mt final;" ${CLICKHOUSE_CLIENT} -nm --query " -alter table test_mt modify setting disk = 'disk_s3_plain', old_parts_lifetime = 3600; -select engine_full from system.tables WHERE database = currentDatabase() AND name = 'test_mt'; +alter table 03008_test_local_mt modify setting disk = '03008_local_plain_rewritable', old_parts_lifetime = 3600; +select engine_full from system.tables WHERE database = currentDatabase() AND name = '03008_test_local_mt'; " | grep -c "old_parts_lifetime = 3600" ${CLICKHOUSE_CLIENT} -nm --query " -select count(*) from test_mt; -select (*) from test_mt order by tuple(a, b) limit 10; +select count(*) from 03008_test_local_mt; +select (*) from 03008_test_local_mt order by tuple(a, b) limit 10; " ${CLICKHOUSE_CLIENT} -nm --query " -alter table test_mt update c = 0 where a % 2 = 1; -alter table test_mt add column d Int64 after c; -alter table test_mt drop column c; +alter table 03008_test_local_mt update c = 0 where a % 2 = 1; +alter table 03008_test_local_mt add column d Int64 after c; +alter table 03008_test_local_mt drop column c; " 2>&1 | grep -Fq "SUPPORT_IS_DISABLED" ${CLICKHOUSE_CLIENT} -nm --query " -truncate table test_mt; -select count(*) from test_mt; +truncate table 03008_test_local_mt; +select count(*) from 03008_test_local_mt; " + +${CLICKHOUSE_CLIENT} --query "drop table 03008_test_local_mt sync" diff --git a/tests/queries/0_stateless/03008_s3_plain_rewritable.sh b/tests/queries/0_stateless/03008_s3_plain_rewritable.sh index d72fc47f689..4d5989f6f12 100755 --- a/tests/queries/0_stateless/03008_s3_plain_rewritable.sh +++ b/tests/queries/0_stateless/03008_s3_plain_rewritable.sh @@ -7,47 +7,49 @@ CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # shellcheck source=../shell_config.sh . "$CUR_DIR"/../shell_config.sh -${CLICKHOUSE_CLIENT} --query "drop table if exists test_mt" +${CLICKHOUSE_CLIENT} --query "drop table if exists test_s3_mt" ${CLICKHOUSE_CLIENT} -nm --query " -create table test_mt (a Int32, b Int64, c Int64) engine = MergeTree() partition by intDiv(a, 1000) order by tuple(a, b) +create table test_s3_mt (a Int32, b Int64, c Int64) engine = MergeTree() partition by intDiv(a, 1000) order by tuple(a, b) settings disk = disk( - name = s3_plain_rewritable, + name = 03008_s3_plain_rewritable, type = s3_plain_rewritable, - endpoint = 'http://localhost:11111/test/test_mt/', + endpoint = 'http://localhost:11111/test/03008_test_s3_mt/', access_key_id = clickhouse, secret_access_key = clickhouse); " ${CLICKHOUSE_CLIENT} -nm --query " -insert into test_mt (*) values (1, 2, 0), (2, 2, 2), (3, 1, 9), (4, 7, 7), (5, 10, 2), (6, 12, 5); -insert into test_mt (*) select number, number, number from numbers_mt(10000); -select count(*) from test_mt; -select (*) from test_mt order by tuple(a, b) limit 10; +insert into test_s3_mt (*) values (1, 2, 0), (2, 2, 2), (3, 1, 9), (4, 7, 7), (5, 10, 2), (6, 12, 5); +insert into test_s3_mt (*) select number, number, number from numbers_mt(10000); +select count(*) from test_s3_mt; +select (*) from test_s3_mt order by tuple(a, b) limit 10; " -${CLICKHOUSE_CLIENT} --query "optimize table test_mt final" +${CLICKHOUSE_CLIENT} --query "optimize table test_s3_mt final" ${CLICKHOUSE_CLIENT} -m --query " -alter table test_mt add projection test_mt_projection (select * order by b)" 2>&1 | grep -Fq "SUPPORT_IS_DISABLED" +alter table test_s3_mt add projection test_s3_mt_projection (select * order by b)" 2>&1 | grep -Fq "SUPPORT_IS_DISABLED" ${CLICKHOUSE_CLIENT} -nm --query " -alter table test_mt update c = 0 where a % 2 = 1; -alter table test_mt add column d Int64 after c; -alter table test_mt drop column c; +alter table test_s3_mt update c = 0 where a % 2 = 1; +alter table test_s3_mt add column d Int64 after c; +alter table test_s3_mt drop column c; " 2>&1 | grep -Fq "SUPPORT_IS_DISABLED" ${CLICKHOUSE_CLIENT} -nm --query " -detach table test_mt; -attach table test_mt; +detach table test_s3_mt; +attach table test_s3_mt; " -${CLICKHOUSE_CLIENT} --query "drop table if exists test_mt_dst" +${CLICKHOUSE_CLIENT} --query "drop table if exists test_s3_mt_dst" ${CLICKHOUSE_CLIENT} -m --query " -create table test_mt_dst (a Int32, b Int64, c Int64) engine = MergeTree() partition by intDiv(a, 1000) order by tuple(a, b) -settings disk = 's3_plain_rewritable' +create table test_s3_mt_dst (a Int32, b Int64, c Int64) engine = MergeTree() partition by intDiv(a, 1000) order by tuple(a, b) +settings disk = '03008_s3_plain_rewritable' " ${CLICKHOUSE_CLIENT} -m --query " -alter table test_mt move partition 0 to table test_mt_dst" 2>&1 | grep -Fq "SUPPORT_IS_DISABLED" +alter table test_s3_mt move partition 0 to table test_s3_mt_dst" 2>&1 | grep -Fq "SUPPORT_IS_DISABLED" + +${CLICKHOUSE_CLIENT} --query "drop table test_s3_mt sync" From a3f4578864179e7e36c72e90aac93ef9861252ab Mon Sep 17 00:00:00 2001 From: Nikita Taranov Date: Tue, 28 May 2024 15:31:17 +0100 Subject: [PATCH 149/211] Revert "Merge pull request #54961 from ClickHouse/remove-test-hash_table_sizes_stats" This reverts commit 477922617c2823879383e2e75a73f98e2fc40346, reversing changes made to f23339b4be6cb4368b7f95073cb6bb0b95ce7370. --- .../02151_hash_table_sizes_stats.reference | 21 ++ .../02151_hash_table_sizes_stats.sh | 88 ++++++++ .../02151_hash_table_sizes_stats.testcases | 195 ++++++++++++++++++ 3 files changed, 304 insertions(+) create mode 100644 tests/queries/0_stateless/02151_hash_table_sizes_stats.reference create mode 100755 tests/queries/0_stateless/02151_hash_table_sizes_stats.sh create mode 100644 tests/queries/0_stateless/02151_hash_table_sizes_stats.testcases diff --git a/tests/queries/0_stateless/02151_hash_table_sizes_stats.reference b/tests/queries/0_stateless/02151_hash_table_sizes_stats.reference new file mode 100644 index 00000000000..712e2b058a4 --- /dev/null +++ b/tests/queries/0_stateless/02151_hash_table_sizes_stats.reference @@ -0,0 +1,21 @@ +1 +-- +1 +-- +1 +-- +1 +-- +1 +1 +-- +1 +-- +1 +1 +-- +1 +-- +1 +1 +-- diff --git a/tests/queries/0_stateless/02151_hash_table_sizes_stats.sh b/tests/queries/0_stateless/02151_hash_table_sizes_stats.sh new file mode 100755 index 00000000000..bf79e5f769d --- /dev/null +++ b/tests/queries/0_stateless/02151_hash_table_sizes_stats.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +# Tags: long, no-tsan + +# shellcheck disable=SC2154 + +CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +# shellcheck source=../shell_config.sh +. "$CURDIR"/../shell_config.sh + + +# tests rely on that all the rows are unique and max_threads divides table_size +table_size=1000005 +max_threads=5 + + +prepare_table() { + table_name="t_hash_table_sizes_stats_$RANDOM$RANDOM" + $CLICKHOUSE_CLIENT -q "DROP TABLE IF EXISTS $table_name;" + if [ -z "$1" ]; then + $CLICKHOUSE_CLIENT -q "CREATE TABLE $table_name(number UInt64) Engine=MergeTree() ORDER BY tuple() SETTINGS index_granularity = 8192, index_granularity_bytes = '10Mi';" + else + $CLICKHOUSE_CLIENT -q "CREATE TABLE $table_name(number UInt64) Engine=MergeTree() ORDER BY $1 SETTINGS index_granularity = 8192, index_granularity_bytes = '10Mi';" + fi + $CLICKHOUSE_CLIENT -q "SYSTEM STOP MERGES $table_name;" + for ((i = 1; i <= max_threads; i++)); do + cnt=$((table_size / max_threads)) + from=$(((i - 1) * cnt)) + $CLICKHOUSE_CLIENT -q "INSERT INTO $table_name SELECT * FROM numbers($from, $cnt);" + done +} + +prepare_table_with_sorting_key() { + prepare_table "$1" +} + +run_query() { + query_id="${CLICKHOUSE_DATABASE}_hash_table_sizes_stats_$RANDOM$RANDOM" + $CLICKHOUSE_CLIENT --query_id="$query_id" --multiquery -q " + SET max_block_size = $((table_size / 10)); + SET merge_tree_min_rows_for_concurrent_read = 1; + SET max_untracked_memory = 0; + SET max_size_to_preallocate_for_aggregation = 1e12; + $query" +} + +check_preallocated_elements() { + $CLICKHOUSE_CLIENT -q "SYSTEM FLUSH LOGS" + # rows may be distributed in any way including "everything goes to the one particular thread" + min=$1 + if [ -z "$2" ]; then + max=$1 + else + max=$2 + fi + $CLICKHOUSE_CLIENT --param_query_id="$query_id" -q " + SELECT COUNT(*) + FROM system.query_log + WHERE event_date >= yesterday() AND query_id = {query_id:String} AND current_database = currentDatabase() + AND ProfileEvents['AggregationPreallocatedElementsInHashTables'] BETWEEN $min AND $max" +} + +check_convertion_to_two_level() { + $CLICKHOUSE_CLIENT -q "SYSTEM FLUSH LOGS" + # rows may be distributed in any way including "everything goes to the one particular thread" + $CLICKHOUSE_CLIENT --param_query_id="$query_id" -q " + SELECT SUM(ProfileEvents['AggregationHashTablesInitializedAsTwoLevel']) BETWEEN 1 AND $max_threads + FROM system.query_log + WHERE event_date >= yesterday() AND query_id = {query_id:String} AND current_database = currentDatabase()" +} + +print_border() { + echo "--" +} + + +# shellcheck source=./02151_hash_table_sizes_stats.testcases +source "$CURDIR"/02151_hash_table_sizes_stats.testcases + + +test_one_thread_simple_group_by +test_one_thread_simple_group_by_with_limit +test_one_thread_simple_group_by_with_join_and_subquery +test_several_threads_simple_group_by_with_limit_single_level_ht +test_several_threads_simple_group_by_with_limit_two_level_ht +test_several_threads_simple_group_by_with_limit_and_rollup_single_level_ht +test_several_threads_simple_group_by_with_limit_and_rollup_two_level_ht +test_several_threads_simple_group_by_with_limit_and_cube_single_level_ht +test_several_threads_simple_group_by_with_limit_and_cube_two_level_ht diff --git a/tests/queries/0_stateless/02151_hash_table_sizes_stats.testcases b/tests/queries/0_stateless/02151_hash_table_sizes_stats.testcases new file mode 100644 index 00000000000..00054b89cc7 --- /dev/null +++ b/tests/queries/0_stateless/02151_hash_table_sizes_stats.testcases @@ -0,0 +1,195 @@ +test_one_thread_simple_group_by() { + expected_size_hint=$table_size + prepare_table + + query=" + -- size_hint = $expected_size_hint -- + SELECT number + FROM $table_name + GROUP BY number + SETTINGS max_threads = 1 + FORMAT Null;" + + run_query + run_query + check_preallocated_elements $expected_size_hint + print_border +} + +test_one_thread_simple_group_by_with_limit() { + expected_size_hint=$table_size + prepare_table + + query=" + -- size_hint = $expected_size_hint despite the presence of limit -- + SELECT number + FROM $table_name + GROUP BY number + LIMIT 5 + SETTINGS max_threads = 1 + FORMAT Null;" + + run_query + run_query + check_preallocated_elements $expected_size_hint + print_border +} + +test_one_thread_simple_group_by_with_join_and_subquery() { + expected_size_hint=$((table_size + table_size / 2)) + prepare_table + + query=" + -- expected two size_hints for different keys: for the inner ($table_size) and the outer aggregation ($((table_size / 2))) + SELECT number + FROM $table_name AS t1 + JOIN + ( + SELECT number + FROM $table_name AS t2 + GROUP BY number + LIMIT $((table_size / 2)) + ) AS t3 USING(number) + GROUP BY number + SETTINGS max_threads = 1, + distributed_product_mode = 'local' + FORMAT Null;" + + run_query + run_query + check_preallocated_elements $expected_size_hint + print_border +} + +test_several_threads_simple_group_by_with_limit_single_level_ht() { + expected_size_hint=$table_size + prepare_table + + query=" + -- size_hint = $expected_size_hint despite the presence of limit -- + SELECT number + FROM $table_name + GROUP BY number + LIMIT 5 + SETTINGS max_threads = $max_threads, + group_by_two_level_threshold = $((expected_size_hint + 1)), + group_by_two_level_threshold_bytes = $((table_size * 1000)) + FORMAT Null;" + + run_query + run_query + check_preallocated_elements $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) + print_border +} + +test_several_threads_simple_group_by_with_limit_two_level_ht() { + expected_size_hint=$table_size + prepare_table + + query=" + -- size_hint = $expected_size_hint despite the presence of limit -- + SELECT number + FROM $table_name + GROUP BY number + LIMIT 5 + SETTINGS max_threads = $max_threads, + group_by_two_level_threshold = $expected_size_hint, + group_by_two_level_threshold_bytes = $((table_size * 1000)) + FORMAT Null;" + + run_query + run_query + check_convertion_to_two_level + check_preallocated_elements $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) + print_border +} + +test_several_threads_simple_group_by_with_limit_and_rollup_single_level_ht() { + expected_size_hint=$table_size + prepare_table + + query=" + -- size_hint = $expected_size_hint despite the presence of limit -- + SELECT number + FROM $table_name + GROUP BY number + WITH ROLLUP + LIMIT 5 + SETTINGS max_threads = $max_threads, + group_by_two_level_threshold = $((expected_size_hint + 1)), + group_by_two_level_threshold_bytes = $((table_size * 1000)) + FORMAT Null;" + + run_query + run_query + check_preallocated_elements $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) + print_border +} + +test_several_threads_simple_group_by_with_limit_and_rollup_two_level_ht() { + expected_size_hint=$table_size + prepare_table + + query=" + -- size_hint = $expected_size_hint despite the presence of limit -- + SELECT number + FROM $table_name + GROUP BY number + WITH ROLLUP + LIMIT 5 + SETTINGS max_threads = $max_threads, + group_by_two_level_threshold = $expected_size_hint, + group_by_two_level_threshold_bytes = $((table_size * 1000)) + FORMAT Null;" + + run_query + run_query + check_convertion_to_two_level + check_preallocated_elements $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) + print_border +} + +test_several_threads_simple_group_by_with_limit_and_cube_single_level_ht() { + expected_size_hint=$table_size + prepare_table + + query=" + -- size_hint = $expected_size_hint despite the presence of limit -- + SELECT number + FROM $table_name + GROUP BY number + WITH CUBE + LIMIT 5 + SETTINGS max_threads = $max_threads, + group_by_two_level_threshold = $((expected_size_hint + 1)), + group_by_two_level_threshold_bytes = $((table_size * 1000)) + FORMAT Null;" + + run_query + run_query + check_preallocated_elements $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) + print_border +} + +test_several_threads_simple_group_by_with_limit_and_cube_two_level_ht() { + expected_size_hint=$table_size + prepare_table + + query=" + -- size_hint = $expected_size_hint despite the presence of limit -- + SELECT number + FROM $table_name + GROUP BY number + WITH CUBE + LIMIT 5 + SETTINGS max_threads = $max_threads, + group_by_two_level_threshold = $expected_size_hint, + group_by_two_level_threshold_bytes = $((table_size * 1000)) + FORMAT Null;" + + run_query + run_query + check_convertion_to_two_level + check_preallocated_elements $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) + print_border +} From b7f4fbbccd36d9403256a89c3e2c407288d848e2 Mon Sep 17 00:00:00 2001 From: Nikita Taranov Date: Tue, 28 May 2024 19:39:59 +0100 Subject: [PATCH 150/211] reduce amount of 'FLUSH LOG'-s and disable sanitizers --- .../02151_hash_table_sizes_stats.sh | 34 ++++++++++++------- .../02151_hash_table_sizes_stats.testcases | 30 +++++----------- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/tests/queries/0_stateless/02151_hash_table_sizes_stats.sh b/tests/queries/0_stateless/02151_hash_table_sizes_stats.sh index bf79e5f769d..488e33ff8c4 100755 --- a/tests/queries/0_stateless/02151_hash_table_sizes_stats.sh +++ b/tests/queries/0_stateless/02151_hash_table_sizes_stats.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Tags: long, no-tsan +# Tags: long, no-debug, no-tsan, no-msan, no-ubsan, no-asan, no-random-settings, no-random-merge-tree-settings # shellcheck disable=SC2154 @@ -44,25 +44,17 @@ run_query() { } check_preallocated_elements() { - $CLICKHOUSE_CLIENT -q "SYSTEM FLUSH LOGS" # rows may be distributed in any way including "everything goes to the one particular thread" - min=$1 - if [ -z "$2" ]; then - max=$1 - else - max=$2 - fi - $CLICKHOUSE_CLIENT --param_query_id="$query_id" -q " + $CLICKHOUSE_CLIENT --param_query_id="$1" -q " SELECT COUNT(*) FROM system.query_log WHERE event_date >= yesterday() AND query_id = {query_id:String} AND current_database = currentDatabase() - AND ProfileEvents['AggregationPreallocatedElementsInHashTables'] BETWEEN $min AND $max" + AND ProfileEvents['AggregationPreallocatedElementsInHashTables'] BETWEEN $2 AND $3" } check_convertion_to_two_level() { - $CLICKHOUSE_CLIENT -q "SYSTEM FLUSH LOGS" # rows may be distributed in any way including "everything goes to the one particular thread" - $CLICKHOUSE_CLIENT --param_query_id="$query_id" -q " + $CLICKHOUSE_CLIENT --param_query_id="$1" -q " SELECT SUM(ProfileEvents['AggregationHashTablesInitializedAsTwoLevel']) BETWEEN 1 AND $max_threads FROM system.query_log WHERE event_date >= yesterday() AND query_id = {query_id:String} AND current_database = currentDatabase()" @@ -72,11 +64,25 @@ print_border() { echo "--" } +# each test case appends to this array +expected_results=() + +check_expectations() { + $CLICKHOUSE_CLIENT -q "SYSTEM FLUSH LOGS" + + for i in "${!expected_results[@]}"; do + read -a args <<< "${expected_results[$i]}" + if [ ${#args[@]} -eq 4 ]; then + check_convertion_to_two_level "${args[0]}" + fi + check_preallocated_elements "${args[@]}" + print_border + done +} # shellcheck source=./02151_hash_table_sizes_stats.testcases source "$CURDIR"/02151_hash_table_sizes_stats.testcases - test_one_thread_simple_group_by test_one_thread_simple_group_by_with_limit test_one_thread_simple_group_by_with_join_and_subquery @@ -86,3 +92,5 @@ test_several_threads_simple_group_by_with_limit_and_rollup_single_level_ht test_several_threads_simple_group_by_with_limit_and_rollup_two_level_ht test_several_threads_simple_group_by_with_limit_and_cube_single_level_ht test_several_threads_simple_group_by_with_limit_and_cube_two_level_ht + +check_expectations diff --git a/tests/queries/0_stateless/02151_hash_table_sizes_stats.testcases b/tests/queries/0_stateless/02151_hash_table_sizes_stats.testcases index 00054b89cc7..7612108a700 100644 --- a/tests/queries/0_stateless/02151_hash_table_sizes_stats.testcases +++ b/tests/queries/0_stateless/02151_hash_table_sizes_stats.testcases @@ -12,8 +12,7 @@ test_one_thread_simple_group_by() { run_query run_query - check_preallocated_elements $expected_size_hint - print_border + expected_results+=("$query_id $expected_size_hint $expected_size_hint") } test_one_thread_simple_group_by_with_limit() { @@ -31,8 +30,7 @@ test_one_thread_simple_group_by_with_limit() { run_query run_query - check_preallocated_elements $expected_size_hint - print_border + expected_results+=("$query_id $expected_size_hint $expected_size_hint") } test_one_thread_simple_group_by_with_join_and_subquery() { @@ -57,8 +55,7 @@ test_one_thread_simple_group_by_with_join_and_subquery() { run_query run_query - check_preallocated_elements $expected_size_hint - print_border + expected_results+=("$query_id $expected_size_hint $expected_size_hint") } test_several_threads_simple_group_by_with_limit_single_level_ht() { @@ -78,8 +75,7 @@ test_several_threads_simple_group_by_with_limit_single_level_ht() { run_query run_query - check_preallocated_elements $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) - print_border + expected_results+=("$query_id $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads))") } test_several_threads_simple_group_by_with_limit_two_level_ht() { @@ -99,9 +95,7 @@ test_several_threads_simple_group_by_with_limit_two_level_ht() { run_query run_query - check_convertion_to_two_level - check_preallocated_elements $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) - print_border + expected_results+=("$query_id $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) check_two_level") } test_several_threads_simple_group_by_with_limit_and_rollup_single_level_ht() { @@ -122,8 +116,7 @@ test_several_threads_simple_group_by_with_limit_and_rollup_single_level_ht() { run_query run_query - check_preallocated_elements $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) - print_border + expected_results+=("$query_id $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads))") } test_several_threads_simple_group_by_with_limit_and_rollup_two_level_ht() { @@ -144,9 +137,7 @@ test_several_threads_simple_group_by_with_limit_and_rollup_two_level_ht() { run_query run_query - check_convertion_to_two_level - check_preallocated_elements $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) - print_border + expected_results+=("$query_id $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) check_two_level") } test_several_threads_simple_group_by_with_limit_and_cube_single_level_ht() { @@ -167,8 +158,7 @@ test_several_threads_simple_group_by_with_limit_and_cube_single_level_ht() { run_query run_query - check_preallocated_elements $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) - print_border + expected_results+=("$query_id $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads))") } test_several_threads_simple_group_by_with_limit_and_cube_two_level_ht() { @@ -189,7 +179,5 @@ test_several_threads_simple_group_by_with_limit_and_cube_two_level_ht() { run_query run_query - check_convertion_to_two_level - check_preallocated_elements $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) - print_border + expected_results+=("$query_id $((expected_size_hint / max_threads)) $((expected_size_hint * max_threads)) check_two_level") } From 016d6653285225575fa692e915f3bf6dd07e5f16 Mon Sep 17 00:00:00 2001 From: Nikita Taranov Date: Tue, 28 May 2024 19:40:59 +0100 Subject: [PATCH 151/211] Revert "Remove 02151_hash_table_sizes_stats_distributed (fixes broken CI) (#54969)" This reverts commit aa5c02c1be5e84c502b1b44c1164853d1f662199. --- ...sh_table_sizes_stats_distributed.reference | 33 +++++++ ...2151_hash_table_sizes_stats_distributed.sh | 95 +++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.reference create mode 100755 tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.sh diff --git a/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.reference b/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.reference new file mode 100644 index 00000000000..0d10114f4ff --- /dev/null +++ b/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.reference @@ -0,0 +1,33 @@ +1 +1 +-- +1 +1 +-- +1 +1 +-- +1 +1 +-- +1 +1 +1 +1 +-- +1 +1 +-- +1 +1 +1 +1 +-- +1 +1 +-- +1 +1 +1 +1 +-- diff --git a/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.sh b/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.sh new file mode 100755 index 00000000000..77b9b2942c5 --- /dev/null +++ b/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash +# Tags: long, distributed, no-tsan, no-debug + +# These tests don't use `current_database = currentDatabase()` condition, because database name isn't propagated during remote queries. + +# shellcheck disable=SC2154 + +CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +# shellcheck source=../shell_config.sh +. "$CURDIR"/../shell_config.sh + + +# tests rely on that all the rows are unique and max_threads divides table_size +table_size=1000005 +max_threads=5 + + +prepare_table() { + table_name="t_hash_table_sizes_stats_$RANDOM$RANDOM" + $CLICKHOUSE_CLIENT -q "DROP TABLE IF EXISTS $table_name;" + if [ -z "$1" ]; then + $CLICKHOUSE_CLIENT -q "CREATE TABLE $table_name(number UInt64) Engine=MergeTree() ORDER BY tuple() SETTINGS index_granularity = 8192, index_granularity_bytes = '10Mi';" + else + $CLICKHOUSE_CLIENT -q "CREATE TABLE $table_name(number UInt64) Engine=MergeTree() ORDER BY $1 SETTINGS index_granularity = 8192, index_granularity_bytes = '10Mi';" + fi + $CLICKHOUSE_CLIENT -q "SYSTEM STOP MERGES $table_name;" + for ((i = 1; i <= max_threads; i++)); do + cnt=$((table_size / max_threads)) + from=$(((i - 1) * cnt)) + $CLICKHOUSE_CLIENT -q "INSERT INTO $table_name SELECT * FROM numbers($from, $cnt);" + done + $CLICKHOUSE_CLIENT -q "DROP TABLE IF EXISTS ${table_name}_d;" + $CLICKHOUSE_CLIENT -q "CREATE TABLE ${table_name}_d AS $table_name ENGINE = Distributed(test_cluster_two_shards, currentDatabase(), $table_name);" + table_name="${table_name}_d" +} + +prepare_table_with_sorting_key() { + prepare_table "$1" +} + +run_query() { + query_id="${CLICKHOUSE_DATABASE}_hash_table_sizes_stats_$RANDOM$RANDOM" + $CLICKHOUSE_CLIENT --query_id="$query_id" --multiquery -q " + SET max_block_size = $((table_size / 10)); + SET merge_tree_min_rows_for_concurrent_read = 1; + SET max_untracked_memory = 0; + SET prefer_localhost_replica = 1; + $query" +} + +check_preallocated_elements() { + $CLICKHOUSE_CLIENT -q "SYSTEM FLUSH LOGS" + # rows may be distributed in any way including "everything goes to the one particular thread" + min=$1 + if [ -z "$2" ]; then + max=$1 + else + max=$2 + fi + $CLICKHOUSE_CLIENT --param_query_id="$query_id" -q " + SELECT COUNT(*) + FROM system.query_log + WHERE event_date >= yesterday() AND (query_id = {query_id:String} OR initial_query_id = {query_id:String}) + AND ProfileEvents['AggregationPreallocatedElementsInHashTables'] BETWEEN $min AND $max + GROUP BY query_id" +} + +check_convertion_to_two_level() { + $CLICKHOUSE_CLIENT -q "SYSTEM FLUSH LOGS" + # rows may be distributed in any way including "everything goes to the one particular thread" + $CLICKHOUSE_CLIENT --param_query_id="$query_id" -q " + SELECT SUM(ProfileEvents['AggregationHashTablesInitializedAsTwoLevel']) BETWEEN 1 AND $max_threads + FROM system.query_log + WHERE event_date >= yesterday() AND (query_id = {query_id:String} OR initial_query_id = {query_id:String}) + GROUP BY query_id" +} + +print_border() { + echo "--" +} + + +# shellcheck source=./02151_hash_table_sizes_stats.testcases +source "$CURDIR"/02151_hash_table_sizes_stats.testcases + + +test_one_thread_simple_group_by +test_one_thread_simple_group_by_with_limit +test_one_thread_simple_group_by_with_join_and_subquery +test_several_threads_simple_group_by_with_limit_single_level_ht +test_several_threads_simple_group_by_with_limit_two_level_ht +test_several_threads_simple_group_by_with_limit_and_rollup_single_level_ht +test_several_threads_simple_group_by_with_limit_and_rollup_two_level_ht +test_several_threads_simple_group_by_with_limit_and_cube_single_level_ht +test_several_threads_simple_group_by_with_limit_and_cube_two_level_ht From 512fa6afbbb1053f0d58fbb446f52f789bdfad04 Mon Sep 17 00:00:00 2001 From: Nikita Taranov Date: Tue, 28 May 2024 20:18:36 +0100 Subject: [PATCH 152/211] fix --- ...2151_hash_table_sizes_stats_distributed.sh | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.sh b/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.sh index 77b9b2942c5..73ba615ce04 100755 --- a/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.sh +++ b/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Tags: long, distributed, no-tsan, no-debug +# Tags: long, distributed, no-debug, no-tsan, no-msan, no-ubsan, no-asan, no-random-settings, no-random-merge-tree-settings # These tests don't use `current_database = currentDatabase()` condition, because database name isn't propagated during remote queries. @@ -49,26 +49,18 @@ run_query() { } check_preallocated_elements() { - $CLICKHOUSE_CLIENT -q "SYSTEM FLUSH LOGS" # rows may be distributed in any way including "everything goes to the one particular thread" - min=$1 - if [ -z "$2" ]; then - max=$1 - else - max=$2 - fi - $CLICKHOUSE_CLIENT --param_query_id="$query_id" -q " + $CLICKHOUSE_CLIENT --param_query_id="$1" -q " SELECT COUNT(*) FROM system.query_log WHERE event_date >= yesterday() AND (query_id = {query_id:String} OR initial_query_id = {query_id:String}) - AND ProfileEvents['AggregationPreallocatedElementsInHashTables'] BETWEEN $min AND $max + AND ProfileEvents['AggregationPreallocatedElementsInHashTables'] BETWEEN $2 AND $3 GROUP BY query_id" } check_convertion_to_two_level() { - $CLICKHOUSE_CLIENT -q "SYSTEM FLUSH LOGS" # rows may be distributed in any way including "everything goes to the one particular thread" - $CLICKHOUSE_CLIENT --param_query_id="$query_id" -q " + $CLICKHOUSE_CLIENT --param_query_id="$1" -q " SELECT SUM(ProfileEvents['AggregationHashTablesInitializedAsTwoLevel']) BETWEEN 1 AND $max_threads FROM system.query_log WHERE event_date >= yesterday() AND (query_id = {query_id:String} OR initial_query_id = {query_id:String}) @@ -79,11 +71,25 @@ print_border() { echo "--" } +# each test case appends to this array +expected_results=() + +check_expectations() { + $CLICKHOUSE_CLIENT -q "SYSTEM FLUSH LOGS" + + for i in "${!expected_results[@]}"; do + read -a args <<< "${expected_results[$i]}" + if [ ${#args[@]} -eq 4 ]; then + check_convertion_to_two_level "${args[0]}" + fi + check_preallocated_elements "${args[@]}" + print_border + done +} # shellcheck source=./02151_hash_table_sizes_stats.testcases source "$CURDIR"/02151_hash_table_sizes_stats.testcases - test_one_thread_simple_group_by test_one_thread_simple_group_by_with_limit test_one_thread_simple_group_by_with_join_and_subquery @@ -93,3 +99,5 @@ test_several_threads_simple_group_by_with_limit_and_rollup_single_level_ht test_several_threads_simple_group_by_with_limit_and_rollup_two_level_ht test_several_threads_simple_group_by_with_limit_and_cube_single_level_ht test_several_threads_simple_group_by_with_limit_and_cube_two_level_ht + +check_expectations From 8405e04c1dd17668af10b19568550f34179fcd00 Mon Sep 17 00:00:00 2001 From: Nikita Taranov Date: Tue, 28 May 2024 20:52:58 +0100 Subject: [PATCH 153/211] fix style --- tests/queries/0_stateless/02151_hash_table_sizes_stats.sh | 2 +- .../0_stateless/02151_hash_table_sizes_stats_distributed.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/queries/0_stateless/02151_hash_table_sizes_stats.sh b/tests/queries/0_stateless/02151_hash_table_sizes_stats.sh index 488e33ff8c4..f99dbdacec2 100755 --- a/tests/queries/0_stateless/02151_hash_table_sizes_stats.sh +++ b/tests/queries/0_stateless/02151_hash_table_sizes_stats.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Tags: long, no-debug, no-tsan, no-msan, no-ubsan, no-asan, no-random-settings, no-random-merge-tree-settings -# shellcheck disable=SC2154 +# shellcheck disable=SC2154,SC2162 CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # shellcheck source=../shell_config.sh diff --git a/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.sh b/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.sh index 73ba615ce04..056c176c1ff 100755 --- a/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.sh +++ b/tests/queries/0_stateless/02151_hash_table_sizes_stats_distributed.sh @@ -3,7 +3,7 @@ # These tests don't use `current_database = currentDatabase()` condition, because database name isn't propagated during remote queries. -# shellcheck disable=SC2154 +# shellcheck disable=SC2154,SC2162 CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # shellcheck source=../shell_config.sh From bc60f2419bd0ea0052c93b578d88d52f1be759d9 Mon Sep 17 00:00:00 2001 From: Sema Checherinda Date: Wed, 29 May 2024 02:25:05 +0200 Subject: [PATCH 154/211] add comment --- tests/integration/helpers/s3_mocks/broken_s3.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/integration/helpers/s3_mocks/broken_s3.py b/tests/integration/helpers/s3_mocks/broken_s3.py index 775424d66a7..686abc76bdf 100644 --- a/tests/integration/helpers/s3_mocks/broken_s3.py +++ b/tests/integration/helpers/s3_mocks/broken_s3.py @@ -183,6 +183,9 @@ class _ServerRuntime: ) request_handler.write_error(429, data) + # make sure that Alibaba errors (QpsLimitExceeded, TotalQpsLimitExceededAction) are retriable + # we patched contrib/aws to achive it: https://github.com/ClickHouse/aws-sdk-cpp/pull/22 https://github.com/ClickHouse/aws-sdk-cpp/pull/23 + # https://www.alibabacloud.com/help/en/oss/support/http-status-code-503 class QpsLimitExceededAction: def inject_error(self, request_handler): data = ( From 7f4c68c0b852e1562e5223225b5adf0461e5f77f Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Tue, 28 May 2024 11:04:01 +0000 Subject: [PATCH 155/211] Port internal changes back to public repo --- programs/server/Server.cpp | 54 ++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/programs/server/Server.cpp b/programs/server/Server.cpp index 223bc1f77e7..8fcb9d87a93 100644 --- a/programs/server/Server.cpp +++ b/programs/server/Server.cpp @@ -792,9 +792,32 @@ try LOG_INFO(log, "Background threads finished in {} ms", watch.elapsedMilliseconds()); }); + /// This object will periodically calculate some metrics. + ServerAsynchronousMetrics async_metrics( + global_context, + server_settings.asynchronous_metrics_update_period_s, + server_settings.asynchronous_heavy_metrics_update_period_s, + [&]() -> std::vector + { + std::vector metrics; + + std::lock_guard lock(servers_lock); + metrics.reserve(servers_to_start_before_tables.size() + servers.size()); + + for (const auto & server : servers_to_start_before_tables) + metrics.emplace_back(ProtocolServerMetrics{server.getPortName(), server.currentThreads()}); + + for (const auto & server : servers) + metrics.emplace_back(ProtocolServerMetrics{server.getPortName(), server.currentThreads()}); + return metrics; + } + ); + /// NOTE: global context should be destroyed *before* GlobalThreadPool::shutdown() /// Otherwise GlobalThreadPool::shutdown() will hang, since Context holds some threads. SCOPE_EXIT({ + async_metrics.stop(); + /** Ask to cancel background jobs all table engines, * and also query_log. * It is important to do early, not in destructor of Context, because @@ -921,27 +944,6 @@ try } } - /// This object will periodically calculate some metrics. - ServerAsynchronousMetrics async_metrics( - global_context, - server_settings.asynchronous_metrics_update_period_s, - server_settings.asynchronous_heavy_metrics_update_period_s, - [&]() -> std::vector - { - std::vector metrics; - - std::lock_guard lock(servers_lock); - metrics.reserve(servers_to_start_before_tables.size() + servers.size()); - - for (const auto & server : servers_to_start_before_tables) - metrics.emplace_back(ProtocolServerMetrics{server.getPortName(), server.currentThreads()}); - - for (const auto & server : servers) - metrics.emplace_back(ProtocolServerMetrics{server.getPortName(), server.currentThreads()}); - return metrics; - } - ); - zkutil::validateZooKeeperConfig(config()); bool has_zookeeper = zkutil::hasZooKeeperConfig(config()); @@ -1748,6 +1750,11 @@ try } + if (config().has(DB::PlacementInfo::PLACEMENT_CONFIG_PREFIX)) + { + PlacementInfo::PlacementInfo::instance().initialize(config()); + } + { std::lock_guard lock(servers_lock); /// We should start interserver communications before (and more important shutdown after) tables. @@ -2096,11 +2103,6 @@ try load_metadata_tasks); } - if (config().has(DB::PlacementInfo::PLACEMENT_CONFIG_PREFIX)) - { - PlacementInfo::PlacementInfo::instance().initialize(config()); - } - /// Do not keep tasks in server, they should be kept inside databases. Used here to make dependent tasks only. load_metadata_tasks.clear(); load_metadata_tasks.shrink_to_fit(); From 9bd558bc00c4d4efdf611019e905e79b64d0d65f Mon Sep 17 00:00:00 2001 From: Blargian Date: Wed, 29 May 2024 11:09:41 +0200 Subject: [PATCH 156/211] Incorporate review changes --- .../sql-reference/functions/json-functions.md | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/en/sql-reference/functions/json-functions.md b/docs/en/sql-reference/functions/json-functions.md index c522789a863..1aae1061625 100644 --- a/docs/en/sql-reference/functions/json-functions.md +++ b/docs/en/sql-reference/functions/json-functions.md @@ -385,7 +385,7 @@ Checks that passed string is valid JSON. isValidJSON(json) ``` -Examples: +**Examples** ``` sql SELECT isValidJSON('{"a": "hello", "b": [-100, 200.0, 300]}') = 1 @@ -405,7 +405,7 @@ JSONHas(json [, indices_or_keys]...) **Parameters** - `json` — JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `indices_or_keys` — A list of zero or more arguments, each of which can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -448,7 +448,7 @@ JSONLength(json [, indices_or_keys]...) **Parameters** - `json` — JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `indices_or_keys` — A list of zero or more arguments, each of which can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -479,7 +479,7 @@ JSONType(json [, indices_or_keys]...) **Parameters** - `json` — JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `indices_or_keys` — A list of zero or more arguments, each of which can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -511,7 +511,7 @@ JSONExtractUInt(json [, indices_or_keys]...) **Parameters** - `json` — JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `indices_or_keys` — A list of zero or more arguments, each of which can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -551,7 +551,7 @@ JSONExtractInt(json [, indices_or_keys]...) **Parameters** - `json` — JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `indices_or_keys` — A list of zero or more arguments, each of which can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -560,7 +560,7 @@ JSONExtractInt(json [, indices_or_keys]...) **Returned value** -- Returns an Int value if it exists, otherwise it returns `Null`. [Int64](../data-types/string.md). +- Returns an Int value if it exists, otherwise it returns `Null`. [Int64](../data-types/int-uint.md). **Examples** @@ -591,7 +591,7 @@ JSONExtractFloat(json [, indices_or_keys]...) **Parameters** - `json` — JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `indices_or_keys` — A list of zero or more arguments, each of which can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -600,7 +600,7 @@ JSONExtractFloat(json [, indices_or_keys]...) **Returned value** -- Returns an Float value if it exists, otherwise it returns `Null`. [Float64](../data-types/string.md). +- Returns an Float value if it exists, otherwise it returns `Null`. [Float64](../data-types/float.md). **Examples** @@ -631,7 +631,7 @@ JSONExtractBool(json\[, indices_or_keys\]...) **Parameters** - `json` — JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `indices_or_keys` — A list of zero or more arguments, each of which can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -671,7 +671,7 @@ JSONExtractString(json [, indices_or_keys]...) **Parameters** - `json` — JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `indices_or_keys` — A list of zero or more arguments, each of which can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -708,7 +708,7 @@ JSONExtract(json [, indices_or_keys...], return_type) **Parameters** - `json` — JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `indices_or_keys` — A list of zero or more arguments, each of which can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). - `return_type` — A string specifying the type of the value to extract. [String](../data-types/string.md). `indices_or_keys` type: @@ -746,7 +746,7 @@ JSONExtractKeysAndValues(json [, indices_or_keys...], value_type) **Parameters** - `json` — JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `indices_or_keys` — A list of zero or more arguments, each of which can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). - `value_type` — A string specifying the type of the value to extract. [String](../data-types/string.md). `indices_or_keys` type: @@ -813,7 +813,7 @@ JSONExtractRaw(json [, indices_or_keys]...) **Parameters** - `json` — JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `indices_or_keys` — A list of zero or more arguments, each of which can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. @@ -822,7 +822,7 @@ JSONExtractRaw(json [, indices_or_keys]...) **Returned value** -- Returns part of the JSON as an unparsed string. Otherwise, an empty string is returned if the part does not exist or has the wrong type. [String](../data-types/string.md). +- Returns part of the JSON as an unparsed string. If the part does not exist or has the wrong type, an empty string is returned. [String](../data-types/string.md). **Example** @@ -832,7 +832,7 @@ SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300]}', 'b') = '[-100, ### JSONExtractArrayRaw -Returns an array with elements of JSON array, each represented as unparsed string. If the part does not exist or isn’t array, an empty array will be returned. +Returns an array with elements of JSON array, each represented as unparsed string. If the part does not exist or isn’t an array, then an empty array will be returned. **Syntax** @@ -843,7 +843,7 @@ JSONExtractArrayRaw(json [, indices_or_keys...]) **Parameters** - `json` — JSON string to parse. [String](../data-types/string.md). -- `indices_or_keys` — A list of zero or more arguments each of them can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). +- `indices_or_keys` — A list of zero or more arguments, each of which can be either string or integer. [String](../data-types/string.md), [Int*](../data-types/int-uint.md). `indices_or_keys` type: - String = access object member by key. From f8ac89151ffc82fec4c022d85da8c4eed8f00656 Mon Sep 17 00:00:00 2001 From: Shaun Struwig <41984034+Blargian@users.noreply.github.com> Date: Wed, 29 May 2024 11:13:54 +0200 Subject: [PATCH 157/211] Update aspell-dict.txt --- utils/check-style/aspell-ignore/en/aspell-dict.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/check-style/aspell-ignore/en/aspell-dict.txt b/utils/check-style/aspell-ignore/en/aspell-dict.txt index 8f8d74f39ad..6239b386bda 100644 --- a/utils/check-style/aspell-ignore/en/aspell-dict.txt +++ b/utils/check-style/aspell-ignore/en/aspell-dict.txt @@ -2789,6 +2789,7 @@ urls usearch userspace userver +UTCTimestamp utils uuid uuidv From db1391114587eaf9fb0265aabe5b6bc8721108c4 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Wed, 29 May 2024 11:14:21 +0200 Subject: [PATCH 158/211] Add a temporary known host for git over ssh --- tests/ci/cherry_pick.py | 45 +++++++++++++++++++---------------------- tests/ci/git_helper.py | 19 +++++++++++------ 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/tests/ci/cherry_pick.py b/tests/ci/cherry_pick.py index 7f267d5ed1a..b3a5efaf3e8 100644 --- a/tests/ci/cherry_pick.py +++ b/tests/ci/cherry_pick.py @@ -33,9 +33,10 @@ from subprocess import CalledProcessError from typing import List, Optional import __main__ + from env_helper import TEMP_PATH from get_robot_token import get_best_robot_token -from git_helper import git_runner, is_shallow +from git_helper import GIT_PREFIX, git_runner, is_shallow from github_helper import GitHub, PullRequest, PullRequests, Repository from lambda_shared_package.lambda_shared.pr import Labels from ssh import SSHKey @@ -104,10 +105,6 @@ close it. self.backport_created_label = backport_created_label - self.git_prefix = ( # All commits to cherrypick are done as robot-clickhouse - "git -c user.email=robot-clickhouse@users.noreply.github.com " - "-c user.name=robot-clickhouse -c commit.gpgsign=false" - ) self.pre_check() def pre_check(self): @@ -190,17 +187,17 @@ close it. def create_cherrypick(self): # First, create backport branch: # Checkout release branch with discarding every change - git_runner(f"{self.git_prefix} checkout -f {self.name}") + git_runner(f"{GIT_PREFIX} checkout -f {self.name}") # Create or reset backport branch - git_runner(f"{self.git_prefix} checkout -B {self.backport_branch}") + git_runner(f"{GIT_PREFIX} checkout -B {self.backport_branch}") # Merge all changes from PR's the first parent commit w/o applying anything # It will allow to create a merge commit like it would be a cherry-pick first_parent = git_runner(f"git rev-parse {self.pr.merge_commit_sha}^1") - git_runner(f"{self.git_prefix} merge -s ours --no-edit {first_parent}") + git_runner(f"{GIT_PREFIX} merge -s ours --no-edit {first_parent}") # Second step, create cherrypick branch git_runner( - f"{self.git_prefix} branch -f " + f"{GIT_PREFIX} branch -f " f"{self.cherrypick_branch} {self.pr.merge_commit_sha}" ) @@ -209,7 +206,7 @@ close it. # manually to the release branch already try: output = git_runner( - f"{self.git_prefix} merge --no-commit --no-ff {self.cherrypick_branch}" + f"{GIT_PREFIX} merge --no-commit --no-ff {self.cherrypick_branch}" ) # 'up-to-date', 'up to date', who knows what else (╯°v°)╯ ^┻━┻ if output.startswith("Already up") and output.endswith("date."): @@ -223,14 +220,14 @@ close it. return except CalledProcessError: # There are most probably conflicts, they'll be resolved in PR - git_runner(f"{self.git_prefix} reset --merge") + git_runner(f"{GIT_PREFIX} reset --merge") else: # There are changes to apply, so continue - git_runner(f"{self.git_prefix} reset --merge") + git_runner(f"{GIT_PREFIX} reset --merge") # Push, create the cherrypick PR, lable and assign it for branch in [self.cherrypick_branch, self.backport_branch]: - git_runner(f"{self.git_prefix} push -f {self.REMOTE} {branch}:{branch}") + git_runner(f"{GIT_PREFIX} push -f {self.REMOTE} {branch}:{branch}") self.cherrypick_pr = self.repo.create_pull( title=f"Cherry pick #{self.pr.number} to {self.name}: {self.pr.title}", @@ -254,21 +251,19 @@ close it. # Checkout the backport branch from the remote and make all changes to # apply like they are only one cherry-pick commit on top of release logging.info("Creating backport for PR #%s", self.pr.number) - git_runner(f"{self.git_prefix} checkout -f {self.backport_branch}") - git_runner( - f"{self.git_prefix} pull --ff-only {self.REMOTE} {self.backport_branch}" - ) + git_runner(f"{GIT_PREFIX} checkout -f {self.backport_branch}") + git_runner(f"{GIT_PREFIX} pull --ff-only {self.REMOTE} {self.backport_branch}") merge_base = git_runner( - f"{self.git_prefix} merge-base " + f"{GIT_PREFIX} merge-base " f"{self.REMOTE}/{self.name} {self.backport_branch}" ) - git_runner(f"{self.git_prefix} reset --soft {merge_base}") + git_runner(f"{GIT_PREFIX} reset --soft {merge_base}") title = f"Backport #{self.pr.number} to {self.name}: {self.pr.title}" - git_runner(f"{self.git_prefix} commit --allow-empty -F -", input=title) + git_runner(f"{GIT_PREFIX} commit --allow-empty -F -", input=title) # Push with force, create the backport PR, lable and assign it git_runner( - f"{self.git_prefix} push -f {self.REMOTE} " + f"{GIT_PREFIX} push -f {self.REMOTE} " f"{self.backport_branch}:{self.backport_branch}" ) self.backport_pr = self.repo.create_pull( @@ -660,9 +655,11 @@ def main(): args.repo, args.from_repo, args.dry_run, - args.must_create_backport_label - if isinstance(args.must_create_backport_label, list) - else [args.must_create_backport_label], + ( + args.must_create_backport_label + if isinstance(args.must_create_backport_label, list) + else [args.must_create_backport_label] + ), args.backport_created_label, ) # https://github.com/python/mypy/issues/3004 diff --git a/tests/ci/git_helper.py b/tests/ci/git_helper.py index f15f1273bb9..8ec90dd7b2d 100644 --- a/tests/ci/git_helper.py +++ b/tests/ci/git_helper.py @@ -1,9 +1,12 @@ #!/usr/bin/env python import argparse +import atexit import logging +import os import os.path as p import re import subprocess +import tempfile from typing import Any, List, Optional logger = logging.getLogger(__name__) @@ -19,12 +22,16 @@ SHA_REGEXP = re.compile(r"\A([0-9]|[a-f]){40}\Z") CWD = p.dirname(p.realpath(__file__)) TWEAK = 1 -GIT_PREFIX = ( # All commits to remote are done as robot-clickhouse - "git -c user.email=robot-clickhouse@users.noreply.github.com " - "-c user.name=robot-clickhouse -c commit.gpgsign=false " - "-c core.sshCommand=" - "'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'" -) +with tempfile.NamedTemporaryFile("w", delete=False) as f: + GIT_KNOWN_HOSTS_FILE = f.name + GIT_PREFIX = ( # All commits to remote are done as robot-clickhouse + "git -c user.email=robot-clickhouse@users.noreply.github.com " + "-c user.name=robot-clickhouse -c commit.gpgsign=false " + "-c core.sshCommand=" + f"'ssh -o UserKnownHostsFile={GIT_KNOWN_HOSTS_FILE} " + "-o StrictHostKeyChecking=accept-new'" + ) + atexit.register(os.remove, f.name) # Py 3.8 removeprefix and removesuffix From 305200412683be9a5897b391d435def1ee807847 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Wed, 29 May 2024 11:40:45 +0200 Subject: [PATCH 159/211] Add a description for `A Sync` check status --- tests/ci/ci_config.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/ci/ci_config.py b/tests/ci/ci_config.py index 68fa6f1cf10..3d7ba28bcfe 100644 --- a/tests/ci/ci_config.py +++ b/tests/ci/ci_config.py @@ -1419,6 +1419,11 @@ class CheckDescription: CHECK_DESCRIPTIONS = [ + CheckDescription( + StatusNames.SYNC, + "A status of the workflow running in the cloud repository against the sync PR", + lambda x: x == StatusNames.SYNC, + ), CheckDescription( "AST fuzzer", "Runs randomly generated queries to catch program errors. " From 73ce2ecc93633fd00535118a6887f2498b8d1d1a Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 29 May 2024 10:31:01 +0000 Subject: [PATCH 160/211] Docs: Update third-party library guide --- docs/en/development/contrib.md | 40 ++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/docs/en/development/contrib.md b/docs/en/development/contrib.md index 5f96466bbec..fd3f6545346 100644 --- a/docs/en/development/contrib.md +++ b/docs/en/development/contrib.md @@ -7,21 +7,43 @@ description: A list of third-party libraries used # Third-Party Libraries Used -ClickHouse utilizes third-party libraries for different purposes, e.g., to connect to other databases, to decode (encode) data during load (save) from (to) disk or to implement certain specialized SQL functions. To be independent of the available libraries in the target system, each third-party library is imported as a Git submodule into ClickHouse's source tree and compiled and linked with ClickHouse. A list of third-party libraries and their licenses can be obtained by the following query: +ClickHouse utilizes third-party libraries for different purposes, e.g., to connect to other databases, to decode/encode data during load/save from/to disk, or to implement certain specialized SQL functions. +To be independent of the available libraries in the target system, each third-party library is imported as a Git submodule into ClickHouse's source tree and compiled and linked with ClickHouse. +A list of third-party libraries and their licenses can be obtained by the following query: ``` sql SELECT library_name, license_type, license_path FROM system.licenses ORDER BY library_name COLLATE 'en'; ``` -Note that the listed libraries are the ones located in the `contrib/` directory of the ClickHouse repository. Depending on the build options, some of the libraries may have not been compiled, and as a result, their functionality may not be available at runtime. +Note that the listed libraries are the ones located in the `contrib/` directory of the ClickHouse repository. +Depending on the build options, some of the libraries may have not been compiled, and as a result, their functionality may not be available at runtime. [Example](https://play.clickhouse.com/play?user=play#U0VMRUNUIGxpYnJhcnlfbmFtZSwgbGljZW5zZV90eXBlLCBsaWNlbnNlX3BhdGggRlJPTSBzeXN0ZW0ubGljZW5zZXMgT1JERVIgQlkgbGlicmFyeV9uYW1lIENPTExBVEUgJ2VuJw==) -## Adding new third-party libraries and maintaining patches in third-party libraries {#adding-third-party-libraries} +## Adding and maintaining third-party libraries -1. Each third-party library must reside in a dedicated directory under the `contrib/` directory of the ClickHouse repository. Avoid dumps/copies of external code, instead use Git submodule feature to pull third-party code from an external upstream repository. -2. Submodules are listed in `.gitmodule`. If the external library can be used as-is, you may reference the upstream repository directly. Otherwise, i.e. the external library requires patching/customization, create a fork of the official repository in the [ClickHouse organization in GitHub](https://github.com/ClickHouse). -3. In the latter case, create a branch with `clickhouse/` prefix from the branch you want to integrate, e.g. `clickhouse/master` (for `master`) or `clickhouse/release/vX.Y.Z` (for a `release/vX.Y.Z` tag). The purpose of this branch is to isolate customization of the library from upstream work. For example, pulls from the upstream repository into the fork will leave all `clickhouse/` branches unaffected. Submodules in `contrib/` must only track `clickhouse/` branches of forked third-party repositories. -4. To patch a fork of a third-party library, create a dedicated branch with `clickhouse/` prefix in the fork, e.g. `clickhouse/fix-some-desaster`. Finally, merge the patch branch into the custom tracking branch (e.g. `clickhouse/master` or `clickhouse/release/vX.Y.Z`) using a PR. -5. Always create patches of third-party libraries with the official repository in mind. Once a PR of a patch branch to the `clickhouse/` branch in the fork repository is done and the submodule version in ClickHouse official repository is bumped, consider opening another PR from the patch branch to the upstream library repository. This ensures, that 1) the contribution has more than a single use case and importance, 2) others will also benefit from it, 3) the change will not remain a maintenance burden solely on ClickHouse developers. -9. To update a submodule with changes in the upstream repository, first merge upstream `master` (or a new `versionX.Y.Z` tag) into the `clickhouse`-tracking branch in the fork repository. Conflicts with patches/customization will need to be resolved in this merge (see Step 4.). Once the merge is done, bump the submodule in ClickHouse to point to the new hash in the fork. +Each third-party library must reside in a dedicated directory under the `contrib/` directory of the ClickHouse repository. +Avoid dumping copies of external code into the library directory. +Instead create a Git submodule to pull third-party code from an external upstream repository. + +All submodules used by ClickHouse are listed in `.gitmodule`. +If the library can be used as-is (the default case), you can reference the upstream repository directly. +If the library needs patching, create a fork of the upstream repository in the [ClickHouse organization in GitHub](https://github.com/ClickHouse). + +In the latter case, we aim to isolate custom patches as much as possible from upstream commits. +To that end, create a branch with prefix `clickhouse/` from the branch or tag you want to integrate, e.g. `clickhouse/master` (for branch `master`) or `clickhouse/release/vX.Y.Z` (for tag `release/vX.Y.Z`. +This ensures that pulls from the upstream repository into the fork will leave custom `clickhouse/` branches unaffected. +Submodules in `contrib/` must only track `clickhouse/` branches of forked third-party repositories. + +Patches are only applied against `clickhouse/` branches of external libraries. +For that, push the patch as a branch with `clickhouse/`, e.g. `clickhouse/fix-some-desaster`. +Then create a PR from the new branch against the custom tracking branch with `clickhouse/` prefix, (e.g. `clickhouse/master` or `clickhouse/release/vX.Y.Z`) and merge the patch. + +Create patches of third-party libraries with the official repository in mind and consider contributing the patch back to the upstream repository. +This makes sure, that others will also benefit from it and the patch will not be a maintenance burden on the ClickHouse team. + +To pull upstream changes into the submodule, you can use two methods: +- (less work but less clean): merge upstream `master` into the corresponding `clickhouse/` tracking branch in the forked repository. You will need to resolve merge conflicts with previous custom patches. This method can be used when the `clickhouse/` branch tracks an upstream development branch like `master`, `main`, `dev`, etc. +- (more work but cleaner): create a new branch with `clickhouse/` prefix from the upstream commit or tag you like to integrate. Then re-apply all existing patches using new PRs (or squash them into a single PR). This method can be used when the `clickhouse/` branch tracks a specific upstream version branch or tag. It is cleaner in the sense that custom patches and upstream changes are better isolated from each other. + +Once the submodule has been updated, bump the submodule in ClickHouse to point to the new hash in the fork. From 7d64cb0229d31a29b9be07889ed320bad44a3b69 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Wed, 29 May 2024 12:45:44 +0200 Subject: [PATCH 161/211] Rephrase the spoiler for old DEB distributions --- docs/en/getting-started/install.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/getting-started/install.md b/docs/en/getting-started/install.md index 8980e3ce521..67752f223ce 100644 --- a/docs/en/getting-started/install.md +++ b/docs/en/getting-started/install.md @@ -111,10 +111,10 @@ clickhouse-client # or "clickhouse-client --password" if you've set up a passwor ```
      -Migration Method for installing the deb-packages +Old distributions method for installing the deb-packages ```bash -sudo apt-key del E0C56BD4 +sudo apt-get install apt-transport-https ca-certificates dirmngr sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 8919F6BD2B48D754 echo "deb https://packages.clickhouse.com/deb stable main" | sudo tee \ /etc/apt/sources.list.d/clickhouse.list From 0cb8793ceb8928ec28cfb8e0260d59894d2a5e5d Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 29 May 2024 12:54:29 +0200 Subject: [PATCH 162/211] Update docs/en/development/contrib.md Co-authored-by: Konstantin Bogdanov --- docs/en/development/contrib.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/development/contrib.md b/docs/en/development/contrib.md index fd3f6545346..04b057518d0 100644 --- a/docs/en/development/contrib.md +++ b/docs/en/development/contrib.md @@ -16,7 +16,7 @@ SELECT library_name, license_type, license_path FROM system.licenses ORDER BY li ``` Note that the listed libraries are the ones located in the `contrib/` directory of the ClickHouse repository. -Depending on the build options, some of the libraries may have not been compiled, and as a result, their functionality may not be available at runtime. +Depending on the build options, some of the libraries may have not been compiled, and, as a result, their functionality may not be available at runtime. [Example](https://play.clickhouse.com/play?user=play#U0VMRUNUIGxpYnJhcnlfbmFtZSwgbGljZW5zZV90eXBlLCBsaWNlbnNlX3BhdGggRlJPTSBzeXN0ZW0ubGljZW5zZXMgT1JERVIgQlkgbGlicmFyeV9uYW1lIENPTExBVEUgJ2VuJw==) From 85f4de47fd20ec247729f826bd4f280a40a98d77 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 29 May 2024 12:54:35 +0200 Subject: [PATCH 163/211] Update docs/en/development/contrib.md Co-authored-by: Konstantin Bogdanov --- docs/en/development/contrib.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/development/contrib.md b/docs/en/development/contrib.md index 04b057518d0..b416426140a 100644 --- a/docs/en/development/contrib.md +++ b/docs/en/development/contrib.md @@ -26,7 +26,7 @@ Each third-party library must reside in a dedicated directory under the `contrib Avoid dumping copies of external code into the library directory. Instead create a Git submodule to pull third-party code from an external upstream repository. -All submodules used by ClickHouse are listed in `.gitmodule`. +All submodules used by ClickHouse are listed in the `.gitmodule` file. If the library can be used as-is (the default case), you can reference the upstream repository directly. If the library needs patching, create a fork of the upstream repository in the [ClickHouse organization in GitHub](https://github.com/ClickHouse). From cfdc0cf7e761f6bde53a7b7caebd1efc58f89980 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 29 May 2024 12:54:42 +0200 Subject: [PATCH 164/211] Update docs/en/development/contrib.md Co-authored-by: Konstantin Bogdanov --- docs/en/development/contrib.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/development/contrib.md b/docs/en/development/contrib.md index b416426140a..1c57ba10a9a 100644 --- a/docs/en/development/contrib.md +++ b/docs/en/development/contrib.md @@ -28,7 +28,7 @@ Instead create a Git submodule to pull third-party code from an external upstrea All submodules used by ClickHouse are listed in the `.gitmodule` file. If the library can be used as-is (the default case), you can reference the upstream repository directly. -If the library needs patching, create a fork of the upstream repository in the [ClickHouse organization in GitHub](https://github.com/ClickHouse). +If the library needs patching, create a fork of the upstream repository in the [ClickHouse organization on GitHub](https://github.com/ClickHouse). In the latter case, we aim to isolate custom patches as much as possible from upstream commits. To that end, create a branch with prefix `clickhouse/` from the branch or tag you want to integrate, e.g. `clickhouse/master` (for branch `master`) or `clickhouse/release/vX.Y.Z` (for tag `release/vX.Y.Z`. From c3cd8ea97ead72767b61c16b522ce3fbbd3bde53 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 29 May 2024 12:55:11 +0200 Subject: [PATCH 165/211] Update docs/en/development/contrib.md Co-authored-by: Konstantin Bogdanov --- docs/en/development/contrib.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/development/contrib.md b/docs/en/development/contrib.md index 1c57ba10a9a..dfc1d79ec5c 100644 --- a/docs/en/development/contrib.md +++ b/docs/en/development/contrib.md @@ -31,7 +31,7 @@ If the library can be used as-is (the default case), you can reference the upstr If the library needs patching, create a fork of the upstream repository in the [ClickHouse organization on GitHub](https://github.com/ClickHouse). In the latter case, we aim to isolate custom patches as much as possible from upstream commits. -To that end, create a branch with prefix `clickhouse/` from the branch or tag you want to integrate, e.g. `clickhouse/master` (for branch `master`) or `clickhouse/release/vX.Y.Z` (for tag `release/vX.Y.Z`. +To that end, create a branch with prefix `clickhouse/` from the branch or tag you want to integrate, e.g. `clickhouse/master` (for branch `master`) or `clickhouse/release/vX.Y.Z` (for tag `release/vX.Y.Z`). This ensures that pulls from the upstream repository into the fork will leave custom `clickhouse/` branches unaffected. Submodules in `contrib/` must only track `clickhouse/` branches of forked third-party repositories. From 87138301c4ded3fb583a6a498c42b2cf44fac2c7 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Fri, 3 May 2024 12:14:33 +0200 Subject: [PATCH 166/211] Use copy of os.environ to not affect the global state --- tests/ci/ci.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/ci/ci.py b/tests/ci/ci.py index c4e06ccd79a..95e2de120f5 100644 --- a/tests/ci/ci.py +++ b/tests/ci/ci.py @@ -1867,8 +1867,9 @@ def _run_test(job_name: str, run_command: str) -> int: run_command or CI_CONFIG.get_job_config(job_name).run_command ), "Run command must be provided as input argument or be configured in job config" + env = os.environ.copy() if CI_CONFIG.get_job_config(job_name).timeout: - os.environ["KILL_TIMEOUT"] = str(CI_CONFIG.get_job_config(job_name).timeout) + env["KILL_TIMEOUT"] = str(CI_CONFIG.get_job_config(job_name).timeout) if not run_command: run_command = "/".join( @@ -1879,12 +1880,13 @@ def _run_test(job_name: str, run_command: str) -> int: print("Use run command from a job config") else: print("Use run command from the workflow") - os.environ["CHECK_NAME"] = job_name + env["CHECK_NAME"] = job_name print(f"Going to start run command [{run_command}]") process = subprocess.run( run_command, stdout=sys.stdout, stderr=sys.stderr, + env=env, text=True, check=False, shell=True, From 744284425f3c4c3c2d8261be6951c0b2bde91533 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 29 May 2024 12:58:57 +0200 Subject: [PATCH 167/211] Update docs/en/development/contrib.md Co-authored-by: Konstantin Bogdanov --- docs/en/development/contrib.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/development/contrib.md b/docs/en/development/contrib.md index dfc1d79ec5c..db3eabaecfc 100644 --- a/docs/en/development/contrib.md +++ b/docs/en/development/contrib.md @@ -40,7 +40,7 @@ For that, push the patch as a branch with `clickhouse/`, e.g. `clickhouse/fix-so Then create a PR from the new branch against the custom tracking branch with `clickhouse/` prefix, (e.g. `clickhouse/master` or `clickhouse/release/vX.Y.Z`) and merge the patch. Create patches of third-party libraries with the official repository in mind and consider contributing the patch back to the upstream repository. -This makes sure, that others will also benefit from it and the patch will not be a maintenance burden on the ClickHouse team. +This makes sure that others will also benefit from the patch and it will not be a maintenance burden for the ClickHouse team. To pull upstream changes into the submodule, you can use two methods: - (less work but less clean): merge upstream `master` into the corresponding `clickhouse/` tracking branch in the forked repository. You will need to resolve merge conflicts with previous custom patches. This method can be used when the `clickhouse/` branch tracks an upstream development branch like `master`, `main`, `dev`, etc. From a68ebaafd7fa7a0c581ddc7c334b242b4e366eb5 Mon Sep 17 00:00:00 2001 From: Blargian Date: Wed, 29 May 2024 13:50:45 +0200 Subject: [PATCH 168/211] Solve merge conflict --- .../sql-reference/functions/url-functions.md | 425 ++++++++++++++++-- 1 file changed, 398 insertions(+), 27 deletions(-) diff --git a/docs/en/sql-reference/functions/url-functions.md b/docs/en/sql-reference/functions/url-functions.md index 868f3133b1f..e69e968cd48 100644 --- a/docs/en/sql-reference/functions/url-functions.md +++ b/docs/en/sql-reference/functions/url-functions.md @@ -6,7 +6,9 @@ sidebar_label: URLs # Functions for Working with URLs -All these functions do not follow the RFC. They are maximally simplified for improved performance. +:::note +The functions mentioned in this section for the most part do not follow the RFC convention as they are maximally simplified for improved performance. Functions following a specific RFC convention have `RFC` appended to the function name and are generally less performant. +::: ## Functions that Extract Parts of a URL @@ -22,15 +24,17 @@ Examples of typical returned values: http, https, ftp, mailto, tel, magnet... Extracts the hostname from a URL. +**Syntax** + ``` sql -domain(url) +domain(URL) ``` **Arguments** - `url` — URL. [String](../data-types/string.md). -The URL can be specified with or without a scheme. Examples: +The URL can be specified with or without a protocol. Examples: ``` text svn+ssh://some.svn-hosting.com:80/repo/trunk @@ -62,6 +66,40 @@ SELECT domain('svn+ssh://some.svn-hosting.com:80/repo/trunk'); └────────────────────────────────────────────────────────┘ ``` +### domainRFC + +Extracts the hostname from a URL. Similar to [domain](#domain), but RFC 3986 conformant. + +**Syntax** + +``` sql +domainRFC(URL) +``` + +**Arguments** + +- `URL` — URL. Type: [String](../../sql-reference/data-types/string.md). + +**Returned values** + +- Host name if ClickHouse can parse the input string as a URL, otherwise an empty string. [String](../data-types/string.md). + +Type: `String`. + +**Example** + +``` sql +SELECT + domain('http://user:password@example.com:8080/path?query=value#fragment'), + domainRFC('http://user:password@example.com:8080/path?query=value#fragment'); +``` + +``` text +┌─domain('http://user:password@example.com:8080/path?query=value#fragment')─┬─domainRFC('http://user:password@example.com:8080/path?query=value#fragment')─┐ +│ │ example.com │ +└───────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────┘ +``` + ### domainWithoutWWW Returns the domain and removes no more than one ‘www.’ from the beginning of it, if present. @@ -71,7 +109,7 @@ Returns the domain and removes no more than one ‘www.’ from the beginning of Extracts the the top-level domain from a URL. ``` sql -topLevelDomain(url) +topLevelDomain(URL) ``` **Arguments** @@ -79,7 +117,7 @@ topLevelDomain(url) - `url` — URL. [String](../data-types/string.md). :::note -The URL can be specified with or without a scheme. Examples: +The URL can be specified with or without a protocol. Examples: ``` text svn+ssh://some.svn-hosting.com:80/repo/trunk @@ -113,7 +151,7 @@ Result: Extracts the the top-level domain from a URL. It is similar to [topLevelDomain](#topleveldomain), but conforms to RFC 3986. ``` sql -topLevelDomainRFC(url) +topLevelDomainRFC(URL) ``` **Arguments** @@ -121,7 +159,7 @@ topLevelDomainRFC(url) - `url` — URL. [String](../data-types/string.md). :::note -The URL can be specified with or without a scheme. Examples: +The URL can be specified with or without a protocol. Examples: ``` text svn+ssh://some.svn-hosting.com:80/repo/trunk @@ -139,48 +177,241 @@ https://clickhouse.com/time/ Query: ``` sql -SELECT topLevelDomainRFC('svn+ssh://www.some.svn-hosting.com:80/repo/trunk'); +SELECT topLevelDomain('http://foo:foo%41bar@foo.com'), topLevelDomainRFC('http://foo:foo%41bar@foo.com'); ``` Result: ``` text -┌─topLevelDomainRFC('svn+ssh://www.some.svn-hosting.com:80/repo/trunk')─┐ -│ com │ -└───────────────────────────────────────────────────────────────────────┘ +┌─topLevelDomain('http://foo:foo%41bar@foo.com')─┬─topLevelDomainRFC('http://foo:foo%41bar@foo.com')─┐ +│ │ com │ +└────────────────────────────────────────────────┴───────────────────────────────────────────────────┘ ``` ### firstSignificantSubdomain Returns the “first significant subdomain”. The first significant subdomain is a second-level domain if it is ‘com’, ‘net’, ‘org’, or ‘co’. Otherwise, it is a third-level domain. For example, `firstSignificantSubdomain (‘https://news.clickhouse.com/’) = ‘clickhouse’, firstSignificantSubdomain (‘https://news.clickhouse.com.tr/’) = ‘clickhouse’`. The list of “insignificant” second-level domains and other implementation details may change in the future. +**Syntax** + +```sql +firstSignificantSubdomain(URL) +``` + +**Arguments** + +- `URL` — URL. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- The first signficant subdomain. [String](../data-types/string.md). + +**Example** + +Query: + +```sql +SELECT firstSignificantSubdomain('http://www.example.com/a/b/c?a=b') +``` + +Result: + +```reference +┌─firstSignificantSubdomain('http://www.example.com/a/b/c?a=b')─┐ +│ example │ +└───────────────────────────────────────────────────────────────┘ +``` + +### firstSignificantSubdomainRFC + +Returns the “first significant subdomain”, similar to [firstSignficantSubdomain](#firstsignificantsubdomain) but according to RFC 1034. + +**Syntax** + +```sql +firstSignificantSubdomainRFC(URL) +``` + +**Arguments** + +- `URL` — URL. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- The first signficant subdomain. [String](../data-types/string.md). + +**Example** + +Query: + +```sql +SELECT + firstSignificantSubdomain('http://user:password@example.com:8080/path?query=value#fragment'), + firstSignificantSubdomainRFC('http://user:password@example.com:8080/path?query=value#fragment'); +``` + +Result: + +```reference +┌─firstSignificantSubdomain('http://user:password@example.com:8080/path?query=value#fragment')─┬─firstSignificantSubdomainRFC('http://user:password@example.com:8080/path?query=value#fragment')─┐ +│ │ example │ +└──────────────────────────────────────────────────────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────┘ +``` + ### cutToFirstSignificantSubdomain -Returns the part of the domain that includes top-level subdomains up to the “first significant subdomain” (see the explanation above). +Returns the part of the domain that includes top-level subdomains up to the [“first significant subdomain”](#firstsignificantsubdomain). -For example: +**Syntax** + +```sql +cutToFirstSignificantSubdomain(URL) +``` + +**Arguments** + +- `URL` — URL. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- Part of the domain that includes top-level subdomains up to the first signficant subdomain if possible, otherwise returns an empty string. [String](../data-types/string.md). + +**Example** + +Query: + +```sql +SELECT + cutToFirstSignificantSubdomain('https://news.clickhouse.com.tr/'), + cutToFirstSignificantSubdomain('www.tr'), + cutToFirstSignificantSubdomain('tr'); +``` + +Result: + +```response +┌─cutToFirstSignificantSubdomain('https://news.clickhouse.com.tr/')─┬─cutToFirstSignificantSubdomain('www.tr')─┬─cutToFirstSignificantSubdomain('tr')─┐ +│ clickhouse.com.tr │ tr │ │ +└───────────────────────────────────────────────────────────────────┴──────────────────────────────────────────┴──────────────────────────────────────┘ +``` + +### cutToFirstSignificantSubdomainRFC + +Returns the part of the domain that includes top-level subdomains up to the [“first significant subdomain”](#firstsignificantsubdomain). It is similar to [cutToFirstSignificantSubdomain](#cuttofirstsignificantsubdomain) but follows stricter rules to be compatible with RFC 3986 and is less performant. + +**Syntax** + +```sql +cutToFirstSignificantSubdomainRFC(URL) +``` + +**Arguments** + +- `URL` — URL. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- Part of the domain that includes top-level subdomains up to the first signficant subdomain if possible, otherwise returns an empty string. [String](../data-types/string.md). + +**Example** + +Query: + +```sql +SELECT + cutToFirstSignificantSubdomain('http://user:password@example.com:8080'), + cutToFirstSignificantSubdomainRFC('http://user:password@example.com:8080'); +``` + +Result: + +```response +┌─cutToFirstSignificantSubdomain('http://user:password@example.com:8080')─┬─cutToFirstSignificantSubdomainRFC('http://user:password@example.com:8080')─┐ +│ │ example.com │ +└─────────────────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────┘ +``` -- `cutToFirstSignificantSubdomain('https://news.clickhouse.com.tr/') = 'clickhouse.com.tr'`. -- `cutToFirstSignificantSubdomain('www.tr') = 'tr'`. -- `cutToFirstSignificantSubdomain('tr') = ''`. ### cutToFirstSignificantSubdomainWithWWW Returns the part of the domain that includes top-level subdomains up to the “first significant subdomain”, without stripping "www". -For example: +**Syntax** -- `cutToFirstSignificantSubdomainWithWWW('https://news.clickhouse.com.tr/') = 'clickhouse.com.tr'`. -- `cutToFirstSignificantSubdomainWithWWW('www.tr') = 'www.tr'`. -- `cutToFirstSignificantSubdomainWithWWW('tr') = ''`. +```sql +cutToFirstSignificantSubdomainWithWWW(URL) +``` + +**Arguments** + +- `URL` — URL. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- Part of the domain that includes top-level subdomains up to the first signficant subdomain (with "www") if possible, otherwise returns an empty string. [String](../data-types/string.md). + +**Example** + +Query: + +```sql +SELECT + cutToFirstSignificantSubdomainWithWWW('https://news.clickhouse.com.tr/'), + cutToFirstSignificantSubdomainWithWWW('www.tr'), + cutToFirstSignificantSubdomainWithWWW('tr'); +``` + +Result: + +```response +┌─cutToFirstSignificantSubdomainWithWWW('https://news.clickhouse.com.tr/')─┬─cutToFirstSignificantSubdomainWithWWW('www.tr')─┬─cutToFirstSignificantSubdomainWithWWW('tr')─┐ +│ clickhouse.com.tr │ www.tr │ │ +└──────────────────────────────────────────────────────────────────────────┴─────────────────────────────────────────────────┴─────────────────────────────────────────────┘ +``` + +### cutToFirstSignificantSubdomainWithWWWRFC + +Returns the part of the domain that includes top-level subdomains up to the “first significant subdomain”, without stripping "www". Similar to [cutToFirstSignificantSubdomainWithWWW](#cuttofirstsignificantsubdomaincustomwithwww) but follows stricter rules to be compatible with RFC 3986 and is less performant. + +**Syntax** + +```sql +cutToFirstSignificantSubdomainWithWWW(URL) +``` + +**Arguments** + +- `URL` — URL. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- Part of the domain that includes top-level subdomains up to the first signficant subdomain (with "www") if possible, otherwise returns an empty string. [String](../data-types/string.md). + +**Example** + +Query: + +```sql +SELECT + cutToFirstSignificantSubdomainWithWWW('http:%2F%2Fwwwww.nova@mail.ru/economicheskiy'), + cutToFirstSignificantSubdomainWithWWWRFC('http:%2F%2Fwwwww.nova@mail.ru/economicheskiy'); +``` + +Result: + +```response +┌─cutToFirstSignificantSubdomainWithWWW('http:%2F%2Fwwwww.nova@mail.ru/economicheskiy')─┬─cutToFirstSignificantSubdomainWithWWWRFC('http:%2F%2Fwwwww.nova@mail.ru/economicheskiy')─┐ +│ │ mail.ru │ +└───────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────┘ +``` ### cutToFirstSignificantSubdomainCustom Returns the part of the domain that includes top-level subdomains up to the first significant subdomain. Accepts custom [TLD list](https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains) name. -Can be useful if you need fresh TLD list or you have custom. +This can be useful if you need a fresh TLD list or if you have a custom list. -Configuration example: +**Configuration example** ```xml @@ -226,13 +457,36 @@ Result: - [firstSignificantSubdomain](#firstsignificantsubdomain). +### cutToFirstSignificantSubdomainCustomRFC + +Returns the part of the domain that includes top-level subdomains up to the first significant subdomain. Accepts custom [TLD list](https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains) name. It is similar to [cutToFirstSignificantSubdomainCustom](#cuttofirstsignificantsubdomaincustom) but follows stricter rules according to RFC 3986 and is generally less performant as a result. + +**Syntax** + +``` sql +cutToFirstSignificantSubdomainRFC(URL, TLD) +``` + +**Arguments** + +- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `TLD` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- Part of the domain that includes top-level subdomains up to the first significant subdomain. [String](../../sql-reference/data-types/string.md). + +**See Also** + +- [firstSignificantSubdomain](#firstsignificantsubdomain). + ### cutToFirstSignificantSubdomainCustomWithWWW Returns the part of the domain that includes top-level subdomains up to the first significant subdomain without stripping `www`. Accepts custom TLD list name. -Can be useful if you need fresh TLD list or you have custom. +It can be useful if you need a fresh TLD list or if you have a custom list. -Configuration example: +**Configuration example** ```xml @@ -278,6 +532,29 @@ Result: - [firstSignificantSubdomain](#firstsignificantsubdomain). +### cutToFirstSignificantSubdomainCustomWithWWWRFC + +Returns the part of the domain that includes top-level subdomains up to the first significant subdomain without stripping `www`. Accepts custom TLD list name. It is similar to [cutToFirstSignificantSubdomainCustomWithWWW](#cuttofirstsignificantsubdomaincustomwithwww) but follows stricter rules according to RFC 3986 and is generally less performant as a result. + +**Syntax** + +```sql +cutToFirstSignificantSubdomainCustomWithWWWRFC(URL, TLD) +``` + +**Arguments** + +- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `TLD` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- Part of the domain that includes top-level subdomains up to the first significant subdomain without stripping `www`. [String](../../sql-reference/data-types/string.md). + +**See Also** + +- [firstSignificantSubdomain](#firstsignificantsubdomain). + ### firstSignificantSubdomainCustom Returns the first significant subdomain. Accepts customs TLD list name. @@ -330,9 +607,103 @@ Result: - [firstSignificantSubdomain](#firstsignificantsubdomain). -### port(URL\[, default_port = 0\]) +### firstSignificantSubdomainCustomRFC -Returns the port or `default_port` if there is no port in the URL (or in case of validation error). +Returns the first significant subdomain. Accepts customs TLD list name. Similar to [firstSignificantSubdomainCustom](#firstsignificantsubdomaincustom) but follows stricter rules according to RFC 3986 and is generally less performant as a result. + +**Syntax** + +```sql +firstSignificantSubdomainCustomRFC(URL, TLD) +``` + +**Arguments** + +- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `TLD` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). + +**Returned value** + +- First significant subdomain. + +Type: [String](../../sql-reference/data-types/string.md). + +**See Also** + +- [firstSignificantSubdomain](#firstsignificantsubdomain). + +### port + +Returns the port or `default_port` if there is no port in the `URL` (or in case of validation error). + +**Syntax** + +```sql +port(URL [, default_port = 0]) +``` + +**Arguments** + +- `URL` — URL. [String](../data-types/string.md). +- `default_port` — The default port number to be returned. [UInt16](../data-types/int-uint.md). + +**Returned value** + +- Port or the default port if there is no port in the URL or in case of a validation error. [UInt16](../data-types/int-uint.md). + +**Example** + +Query: + +```sql +SELECT port('http://paul@www.example.com:80/'); +``` + +Result: + +```response +┌─port('http://paul@www.example.com:80/')─┐ +│ 80 │ +└─────────────────────────────────────────┘ +``` + + +### portRFC + +Returns the port or `default_port` if there is no port in the `URL` (or in case of validation error). Similar to [port](#port), but RFC 3986 conformant. + +**Syntax** + +```sql +portRFC(URL [, default_port = 0]) +``` + +**Arguments** + +- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `default_port` — The default port number to be returned. [UInt16](../data-types/int-uint.md). + +**Returned value** + +- Port or the default port if there is no port in the URL or in case of a validation error. [UInt16](../data-types/int-uint.md). + +**Example** + +Query: + +```sql +SELECT + port('http://user:password@example.com:8080'), + portRFC('http://user:password@example.com:8080'); +``` + +Result: + +```resposne +┌─port('http://user:password@example.com:8080')─┬─portRFC('http://user:password@example.com:8080')─┐ +│ 0 │ 8080 │ +└───────────────────────────────────────────────┴──────────────────────────────────────────────────┘ +``` ### path @@ -508,7 +879,7 @@ cutURLParameter(URL, name) **Arguments** -- `url` — URL. [String](../data-types/string.md). +- `URL` — URL. [String](../data-types/string.md). - `name` — name of URL parameter. [String](../data-types/string.md) or [Array](../data-types/array.md) of Strings. **Returned value** From fcb03aadd05ff6e15a294facdf2baee057690a0e Mon Sep 17 00:00:00 2001 From: Shaun Struwig <41984034+Blargian@users.noreply.github.com> Date: Wed, 29 May 2024 13:52:47 +0200 Subject: [PATCH 169/211] Fix typo --- docs/en/sql-reference/functions/json-functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/sql-reference/functions/json-functions.md b/docs/en/sql-reference/functions/json-functions.md index 1aae1061625..5d73c9a83b3 100644 --- a/docs/en/sql-reference/functions/json-functions.md +++ b/docs/en/sql-reference/functions/json-functions.md @@ -680,7 +680,7 @@ JSONExtractString(json [, indices_or_keys]...) **Returned value** -- Returns an unescapated string from `json`. If unescaping failed, if the value does not exist or if it has a wrong type then it returns an empty string. [String](../data-types/string.md). +- Returns an unescaped string from `json`. If unescaping failed, if the value does not exist or if it has a wrong type then it returns an empty string. [String](../data-types/string.md). **Examples** From 33dc8ce4560c138fbe77819a19a24f34954a85b5 Mon Sep 17 00:00:00 2001 From: Blargian Date: Wed, 29 May 2024 15:04:02 +0200 Subject: [PATCH 170/211] Update url-functions.md --- .../sql-reference/functions/url-functions.md | 78 +++++++++++++------ 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/docs/en/sql-reference/functions/url-functions.md b/docs/en/sql-reference/functions/url-functions.md index e69e968cd48..827a80748dc 100644 --- a/docs/en/sql-reference/functions/url-functions.md +++ b/docs/en/sql-reference/functions/url-functions.md @@ -7,9 +7,35 @@ sidebar_label: URLs # Functions for Working with URLs :::note -The functions mentioned in this section for the most part do not follow the RFC convention as they are maximally simplified for improved performance. Functions following a specific RFC convention have `RFC` appended to the function name and are generally less performant. +The functions mentioned in this section for the most part do not follow the RFC-3986 convention as they are maximally simplified for improved performance. Functions following the RFC-3986 convention have `RFC` appended to the function name and are generally less performant. + +- When should I pick the non-`RFC` variant? +— Pick the non-`RFC` variant when working with domains which are allowed to be publically registered and when userinfo and the `@` symbol does not appear in the URL. ::: +The table belows details which symbols are restricted (`✗`) and which are available (`✔`) for use in the whole URL between the two variants. + +|Symbol | non-`RFC`| `RFC` | +|-------|----------|-------| +| ' ' | ✗ |✗ | +| \t | ✗ |✗ | +| < | ✗ |✗ | +| > | ✗ |✗ | +| % | ✗ |✔* | +| { | ✗ |✗ | +| } | ✗ |✗ | +| \| | ✗ |✗ | +| \\\ | ✗ |✗ | +| ^ | ✗ |✗ | +| ~ | ✗ |✔* | +| [ | ✗ |✗ | +| ] | ✗ |✔ | +| ; | ✗ |✔* | +| = | ✗ |✔* | +| & | ✗ |✔* | + +The symbols above marked `*` are sub-delimiters in the RFC 3986 convention and are allowed for userinfo following the `@` symbol. + ## Functions that Extract Parts of a URL If the relevant part isn’t present in a URL, an empty string is returned. @@ -18,7 +44,7 @@ If the relevant part isn’t present in a URL, an empty string is returned. Extracts the protocol from a URL. -Examples of typical returned values: http, https, ftp, mailto, tel, magnet... +Examples of typical returned values: http, https, ftp, mailto, tel, magnet… ### domain @@ -32,7 +58,7 @@ domain(URL) **Arguments** -- `url` — URL. [String](../data-types/string.md). +- `URL` — URL. Type: [String](../../sql-reference/data-types/string.md). The URL can be specified with or without a protocol. Examples: @@ -114,7 +140,7 @@ topLevelDomain(URL) **Arguments** -- `url` — URL. [String](../data-types/string.md). +- `URL` — URL. [String](../../sql-reference/data-types/string.md). :::note The URL can be specified with or without a protocol. Examples: @@ -128,7 +154,7 @@ https://clickhouse.com/time/ **Returned values** -- Domain name if ClickHouse can parse the input string as a URL. Otherwise, an empty string. [String](../data-types/string.md). +- Domain name if ClickHouse can parse the input string as a URL. Otherwise, an empty string. [String](../../sql-reference/data-types/string.md). **Example** @@ -156,7 +182,7 @@ topLevelDomainRFC(URL) **Arguments** -- `url` — URL. [String](../data-types/string.md). +- `URL` — URL. [String](../../sql-reference/data-types/string.md). :::note The URL can be specified with or without a protocol. Examples: @@ -170,7 +196,7 @@ https://clickhouse.com/time/ **Returned values** -- Domain name if ClickHouse can parse the input string as a URL. Otherwise, an empty string. [String](../data-types/string.md). +- Domain name if ClickHouse can parse the input string as a URL. Otherwise, an empty string. [String](../../sql-reference/data-types/string.md). **Example** @@ -425,17 +451,17 @@ This can be useful if you need a fresh TLD list or if you have a custom list. **Syntax** ``` sql -cutToFirstSignificantSubdomainCustom(URL, TLD) +cutToFirstSignificantSubdomain(URL, TLD) ``` **Arguments** -- `URL` — URL. [String](../data-types/string.md). -- `TLD` — Custom TLD list name. [String](../data-types/string.md). +- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `TLD` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). **Returned value** -- Part of the domain that includes top-level subdomains up to the first significant subdomain. [String](../data-types/string.md). +- Part of the domain that includes top-level subdomains up to the first significant subdomain. [String](../../sql-reference/data-types/string.md). **Example** @@ -505,12 +531,14 @@ cutToFirstSignificantSubdomainCustomWithWWW(URL, TLD) **Arguments** -- `URL` — URL. [String](../data-types/string.md). -- `TLD` — Custom TLD list name. [String](../data-types/string.md). +- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `TLD` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). **Returned value** -- Part of the domain that includes top-level subdomains up to the first significant subdomain without stripping `www`. [String](../data-types/string.md). +- Part of the domain that includes top-level subdomains up to the first significant subdomain without stripping `www`. + +Type: [String](../../sql-reference/data-types/string.md). **Example** @@ -580,12 +608,14 @@ firstSignificantSubdomainCustom(URL, TLD) **Arguments** -- `URL` — URL. [String](../data-types/string.md). -- `TLD` — Custom TLD list name. [String](../data-types/string.md). +- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `TLD` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). **Returned value** -- First significant subdomain. [String](../data-types/string.md). +- First significant subdomain. + +Type: [String](../../sql-reference/data-types/string.md). **Example** @@ -825,11 +855,13 @@ netloc(URL) **Arguments** -- `url` — URL. [String](../data-types/string.md). +- `URL` — URL. [String](../../sql-reference/data-types/string.md). **Returned value** -- `username:password@host:port`. [String](../data-types/string.md). +- `username:password@host:port`. + +Type: `String`. **Example** @@ -879,12 +911,14 @@ cutURLParameter(URL, name) **Arguments** -- `URL` — URL. [String](../data-types/string.md). -- `name` — name of URL parameter. [String](../data-types/string.md) or [Array](../data-types/array.md) of Strings. +- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `name` — name of URL parameter. [String](../../sql-reference/data-types/string.md) or [Array](../../sql-reference/data-types/array.md) of Strings. **Returned value** -- URL with `name` URL parameter removed. [String](../data-types/string.md). +- URL with `name` URL parameter removed. + +Type: `String`. **Example** From fc4bf97ffef6dbe6dffc346903b4263e3aee7e54 Mon Sep 17 00:00:00 2001 From: Blargian Date: Wed, 29 May 2024 15:10:57 +0200 Subject: [PATCH 171/211] Fix typo --- docs/en/sql-reference/functions/url-functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/sql-reference/functions/url-functions.md b/docs/en/sql-reference/functions/url-functions.md index 827a80748dc..e07f5c7574f 100644 --- a/docs/en/sql-reference/functions/url-functions.md +++ b/docs/en/sql-reference/functions/url-functions.md @@ -13,7 +13,7 @@ The functions mentioned in this section for the most part do not follow the RFC- — Pick the non-`RFC` variant when working with domains which are allowed to be publically registered and when userinfo and the `@` symbol does not appear in the URL. ::: -The table belows details which symbols are restricted (`✗`) and which are available (`✔`) for use in the whole URL between the two variants. +The table below details which symbols are restricted (`✗`) and which are available (`✔`) for use in the whole URL between the two variants. |Symbol | non-`RFC`| `RFC` | |-------|----------|-------| From 16c237141b1d56f6133b329cd2f79b755cb68f08 Mon Sep 17 00:00:00 2001 From: Blargian Date: Wed, 29 May 2024 15:12:19 +0200 Subject: [PATCH 172/211] Fix mroe typos --- docs/en/sql-reference/functions/url-functions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/sql-reference/functions/url-functions.md b/docs/en/sql-reference/functions/url-functions.md index e07f5c7574f..a26eaee2013 100644 --- a/docs/en/sql-reference/functions/url-functions.md +++ b/docs/en/sql-reference/functions/url-functions.md @@ -10,7 +10,7 @@ sidebar_label: URLs The functions mentioned in this section for the most part do not follow the RFC-3986 convention as they are maximally simplified for improved performance. Functions following the RFC-3986 convention have `RFC` appended to the function name and are generally less performant. - When should I pick the non-`RFC` variant? -— Pick the non-`RFC` variant when working with domains which are allowed to be publically registered and when userinfo and the `@` symbol does not appear in the URL. +— Pick the non-`RFC` variant when working with domains which are allowed to be publicly registered and when user info and the `@` symbol does not appear in the URL. ::: The table below details which symbols are restricted (`✗`) and which are available (`✔`) for use in the whole URL between the two variants. @@ -34,7 +34,7 @@ The table below details which symbols are restricted (`✗`) and which are avail | = | ✗ |✔* | | & | ✗ |✔* | -The symbols above marked `*` are sub-delimiters in the RFC 3986 convention and are allowed for userinfo following the `@` symbol. +The symbols above marked `*` are sub-delimiters in the RFC 3986 convention and are allowed for user info following the `@` symbol. ## Functions that Extract Parts of a URL From 3495d92803b3026627ecf2348d8705cc241fff1a Mon Sep 17 00:00:00 2001 From: Blargian Date: Wed, 29 May 2024 15:26:10 +0200 Subject: [PATCH 173/211] Fix style check --- docs/en/sql-reference/functions/url-functions.md | 12 ++++++------ utils/check-style/aspell-ignore/en/aspell-dict.txt | 11 +++++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/en/sql-reference/functions/url-functions.md b/docs/en/sql-reference/functions/url-functions.md index a26eaee2013..e22dabe494b 100644 --- a/docs/en/sql-reference/functions/url-functions.md +++ b/docs/en/sql-reference/functions/url-functions.md @@ -230,7 +230,7 @@ firstSignificantSubdomain(URL) **Returned value** -- The first signficant subdomain. [String](../data-types/string.md). +- The first significant subdomain. [String](../data-types/string.md). **Example** @@ -264,7 +264,7 @@ firstSignificantSubdomainRFC(URL) **Returned value** -- The first signficant subdomain. [String](../data-types/string.md). +- The first significant subdomain. [String](../data-types/string.md). **Example** @@ -300,7 +300,7 @@ cutToFirstSignificantSubdomain(URL) **Returned value** -- Part of the domain that includes top-level subdomains up to the first signficant subdomain if possible, otherwise returns an empty string. [String](../data-types/string.md). +- Part of the domain that includes top-level subdomains up to the first significant subdomain if possible, otherwise returns an empty string. [String](../data-types/string.md). **Example** @@ -337,7 +337,7 @@ cutToFirstSignificantSubdomainRFC(URL) **Returned value** -- Part of the domain that includes top-level subdomains up to the first signficant subdomain if possible, otherwise returns an empty string. [String](../data-types/string.md). +- Part of the domain that includes top-level subdomains up to the first significant subdomain if possible, otherwise returns an empty string. [String](../data-types/string.md). **Example** @@ -374,7 +374,7 @@ cutToFirstSignificantSubdomainWithWWW(URL) **Returned value** -- Part of the domain that includes top-level subdomains up to the first signficant subdomain (with "www") if possible, otherwise returns an empty string. [String](../data-types/string.md). +- Part of the domain that includes top-level subdomains up to the first significant subdomain (with "www") if possible, otherwise returns an empty string. [String](../data-types/string.md). **Example** @@ -411,7 +411,7 @@ cutToFirstSignificantSubdomainWithWWW(URL) **Returned value** -- Part of the domain that includes top-level subdomains up to the first signficant subdomain (with "www") if possible, otherwise returns an empty string. [String](../data-types/string.md). +- Part of the domain that includes top-level subdomains up to the first significant subdomain (with "www") if possible, otherwise returns an empty string. [String](../data-types/string.md). **Example** diff --git a/utils/check-style/aspell-ignore/en/aspell-dict.txt b/utils/check-style/aspell-ignore/en/aspell-dict.txt index 8f8d74f39ad..d85a42ef115 100644 --- a/utils/check-style/aspell-ignore/en/aspell-dict.txt +++ b/utils/check-style/aspell-ignore/en/aspell-dict.txt @@ -1357,6 +1357,7 @@ concatWithSeparatorAssumeInjective cond conf config +conformant configs congruential conjuction @@ -1416,6 +1417,10 @@ cutToFirstSignificantSubdomain cutToFirstSignificantSubdomainCustom cutToFirstSignificantSubdomainCustomWithWWW cutToFirstSignificantSubdomainWithWWW +cutToFirstSignificantSubdomainRFC +cutToFirstSignificantSubdomainCustomRFC +cutToFirstSignificantSubdomainCustomWithWWWRFC +cutToFirstSignificantSubdomainWithWWWRFC cutURLParameter cutWWW cyrus @@ -1503,6 +1508,8 @@ distro divideDecimal dmesg domainWithoutWWW +domainWithoutWWWRFC +domainRFC dont dotProduct downsampling @@ -1577,6 +1584,8 @@ fips firstLine firstSignificantSubdomain firstSignificantSubdomainCustom +firstSignificantSubdomainRFC +firstSignificantSubdomainCustomRFC fixedstring flamegraph flatbuffers @@ -2158,6 +2167,7 @@ polygonsWithinCartesian polygonsWithinSpherical popcnt porthttps +portRFC positionCaseInsensitive positionCaseInsensitiveUTF positionUTF @@ -2691,6 +2701,7 @@ toolset topK topKWeighted topLevelDomain +topLevelDomainRFC topk topkweighted transactional From 18d432f44c26d1c46e4e012a6bbc766b7938359e Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Mon, 27 May 2024 10:22:03 +0000 Subject: [PATCH 174/211] Reapply "Remove some unnecessary `UNREACHABLE`s" This reverts commit 5a868304c04755bb62b30c45e408b65a3e78dcd0. --- programs/keeper-client/Commands.cpp | 3 ++- programs/main.cpp | 2 +- src/Access/AccessEntityIO.cpp | 3 +-- src/Access/AccessRights.cpp | 2 +- src/Access/IAccessStorage.cpp | 9 +++------ .../AggregateFunctionGroupArray.cpp | 13 ++++++------- .../AggregateFunctionSequenceNextNode.cpp | 1 - src/AggregateFunctions/AggregateFunctionSum.h | 1 - src/Common/DateLUTImpl.cpp | 1 - src/Common/IntervalKind.cpp | 10 ---------- src/Common/TargetSpecific.cpp | 2 -- src/Common/ThreadProfileEvents.cpp | 1 - src/Common/ZooKeeper/IKeeper.cpp | 2 -- src/Compression/CompressionCodecDeflateQpl.cpp | 1 - src/Compression/CompressionCodecDoubleDelta.cpp | 10 +++++++--- src/Coordination/KeeperReconfiguration.cpp | 8 +++++++- src/Coordination/KeeperServer.cpp | 2 +- src/Core/Field.h | 2 -- src/DataTypes/Serializations/ISerialization.cpp | 1 - .../MetadataStorageTransactionState.cpp | 1 - src/Disks/VolumeJBOD.cpp | 2 -- src/Formats/EscapingRuleUtils.cpp | 1 - src/Functions/FunctionsRound.h | 8 -------- src/Functions/FunctionsTimeWindow.cpp | 2 -- src/Functions/PolygonUtils.h | 2 -- .../UserDefinedSQLObjectsZooKeeperStorage.cpp | 1 - src/IO/CompressionMethod.cpp | 1 - src/IO/HadoopSnappyReadBuffer.h | 1 - src/Interpreters/AggregatedDataVariants.cpp | 8 -------- src/Interpreters/Cache/FileSegment.cpp | 1 - src/Interpreters/ComparisonGraph.cpp | 1 - src/Interpreters/HashJoin.cpp | 3 --- src/Interpreters/HashJoin.h | 6 ------ .../InterpreterTransactionControlQuery.cpp | 1 - src/Interpreters/SetVariants.cpp | 4 ---- src/Parsers/ASTExplainQuery.h | 2 -- src/Parsers/Lexer.cpp | 4 +--- .../Formats/Impl/MsgPackRowInputFormat.cpp | 1 - src/Processors/IProcessor.cpp | 2 -- src/Processors/QueryPlan/ReadFromMergeTree.cpp | 6 ------ src/Processors/QueryPlan/TotalsHavingStep.cpp | 2 -- src/Processors/Transforms/FillingTransform.cpp | 1 - .../Transforms/buildPushingToViewsChain.cpp | 2 -- src/Storages/MergeTree/BackgroundJobsAssignee.cpp | 1 - src/Storages/MergeTree/KeyCondition.cpp | 2 -- src/Storages/MergeTree/MergeTreeData.cpp | 2 -- src/Storages/MergeTree/MergeTreeDataWriter.cpp | 2 -- .../PartMovesBetweenShardsOrchestrator.cpp | 2 -- src/Storages/WindowView/StorageWindowView.cpp | 3 --- 49 files changed, 30 insertions(+), 119 deletions(-) diff --git a/programs/keeper-client/Commands.cpp b/programs/keeper-client/Commands.cpp index a109912e6e0..860840a2d06 100644 --- a/programs/keeper-client/Commands.cpp +++ b/programs/keeper-client/Commands.cpp @@ -10,6 +10,7 @@ namespace DB namespace ErrorCodes { + extern const int LOGICAL_ERROR; extern const int KEEPER_EXCEPTION; } @@ -441,7 +442,7 @@ void ReconfigCommand::execute(const DB::ASTKeeperQuery * query, DB::KeeperClient new_members = query->args[1].safeGet(); break; default: - UNREACHABLE(); + throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected operation: {}", operation); } auto response = client->zookeeper->reconfig(joining, leaving, new_members); diff --git a/programs/main.cpp b/programs/main.cpp index bc8476e4ce4..c270388f17f 100644 --- a/programs/main.cpp +++ b/programs/main.cpp @@ -155,8 +155,8 @@ auto instructionFailToString(InstructionFail fail) ret("AVX2"); case InstructionFail::AVX512: ret("AVX512"); +#undef ret } - UNREACHABLE(); } diff --git a/src/Access/AccessEntityIO.cpp b/src/Access/AccessEntityIO.cpp index b0dfd74c53b..1b073329296 100644 --- a/src/Access/AccessEntityIO.cpp +++ b/src/Access/AccessEntityIO.cpp @@ -144,8 +144,7 @@ AccessEntityPtr deserializeAccessEntity(const String & definition, const String catch (Exception & e) { e.addMessage("Could not parse " + file_path); - e.rethrow(); - UNREACHABLE(); + throw; } } diff --git a/src/Access/AccessRights.cpp b/src/Access/AccessRights.cpp index c10931f554c..2127f4ada70 100644 --- a/src/Access/AccessRights.cpp +++ b/src/Access/AccessRights.cpp @@ -258,7 +258,7 @@ namespace case TABLE_LEVEL: return AccessFlags::allFlagsGrantableOnTableLevel(); case COLUMN_LEVEL: return AccessFlags::allFlagsGrantableOnColumnLevel(); } - UNREACHABLE(); + chassert(false); } } diff --git a/src/Access/IAccessStorage.cpp b/src/Access/IAccessStorage.cpp index 8e51481e415..8d4e7d3073e 100644 --- a/src/Access/IAccessStorage.cpp +++ b/src/Access/IAccessStorage.cpp @@ -257,8 +257,7 @@ std::vector IAccessStorage::insert(const std::vector & mu } e.addMessage("After successfully inserting {}/{}: {}", successfully_inserted.size(), multiple_entities.size(), successfully_inserted_str); } - e.rethrow(); - UNREACHABLE(); + throw; } } @@ -361,8 +360,7 @@ std::vector IAccessStorage::remove(const std::vector & ids, bool thr } e.addMessage("After successfully removing {}/{}: {}", removed_names.size(), ids.size(), removed_names_str); } - e.rethrow(); - UNREACHABLE(); + throw; } } @@ -458,8 +456,7 @@ std::vector IAccessStorage::update(const std::vector & ids, const Up } e.addMessage("After successfully updating {}/{}: {}", names_of_updated.size(), ids.size(), names_of_updated_str); } - e.rethrow(); - UNREACHABLE(); + throw; } } diff --git a/src/AggregateFunctions/AggregateFunctionGroupArray.cpp b/src/AggregateFunctions/AggregateFunctionGroupArray.cpp index c21b1d376d9..16907e0f24f 100644 --- a/src/AggregateFunctions/AggregateFunctionGroupArray.cpp +++ b/src/AggregateFunctions/AggregateFunctionGroupArray.cpp @@ -60,14 +60,13 @@ struct GroupArrayTrait template constexpr const char * getNameByTrait() { - if (Trait::last) + if constexpr (Trait::last) return "groupArrayLast"; - if (Trait::sampler == Sampler::NONE) - return "groupArray"; - else if (Trait::sampler == Sampler::RNG) - return "groupArraySample"; - - UNREACHABLE(); + switch (Trait::sampler) + { + case Sampler::NONE: return "groupArray"; + case Sampler::RNG: return "groupArraySample"; + } } template diff --git a/src/AggregateFunctions/AggregateFunctionSequenceNextNode.cpp b/src/AggregateFunctions/AggregateFunctionSequenceNextNode.cpp index b3824720b04..b0240225138 100644 --- a/src/AggregateFunctions/AggregateFunctionSequenceNextNode.cpp +++ b/src/AggregateFunctions/AggregateFunctionSequenceNextNode.cpp @@ -414,7 +414,6 @@ public: break; return (i == events_size) ? base - i : unmatched_idx; } - UNREACHABLE(); } void insertResultInto(AggregateDataPtr __restrict place, IColumn & to, Arena *) const override diff --git a/src/AggregateFunctions/AggregateFunctionSum.h b/src/AggregateFunctions/AggregateFunctionSum.h index 58aaddf357a..2ce03c530c2 100644 --- a/src/AggregateFunctions/AggregateFunctionSum.h +++ b/src/AggregateFunctions/AggregateFunctionSum.h @@ -463,7 +463,6 @@ public: return "sumWithOverflow"; else if constexpr (Type == AggregateFunctionTypeSumKahan) return "sumKahan"; - UNREACHABLE(); } explicit AggregateFunctionSum(const DataTypes & argument_types_) diff --git a/src/Common/DateLUTImpl.cpp b/src/Common/DateLUTImpl.cpp index 392ee64dcbf..c87d44a4b95 100644 --- a/src/Common/DateLUTImpl.cpp +++ b/src/Common/DateLUTImpl.cpp @@ -41,7 +41,6 @@ UInt8 getDayOfWeek(const cctz::civil_day & date) case cctz::weekday::saturday: return 6; case cctz::weekday::sunday: return 7; } - UNREACHABLE(); } inline cctz::time_point lookupTz(const cctz::time_zone & cctz_time_zone, const cctz::civil_day & date) diff --git a/src/Common/IntervalKind.cpp b/src/Common/IntervalKind.cpp index 22c7db504c3..1548d5cf9a5 100644 --- a/src/Common/IntervalKind.cpp +++ b/src/Common/IntervalKind.cpp @@ -34,8 +34,6 @@ Int64 IntervalKind::toAvgNanoseconds() const default: return toAvgSeconds() * NANOSECONDS_PER_SECOND; } - - UNREACHABLE(); } Int32 IntervalKind::toAvgSeconds() const @@ -54,7 +52,6 @@ Int32 IntervalKind::toAvgSeconds() const case IntervalKind::Kind::Quarter: return 7889238; /// Exactly 1/4 of a year. case IntervalKind::Kind::Year: return 31556952; /// The average length of a Gregorian year is equal to 365.2425 days } - UNREACHABLE(); } Float64 IntervalKind::toSeconds() const @@ -80,7 +77,6 @@ Float64 IntervalKind::toSeconds() const default: throw Exception(ErrorCodes::BAD_ARGUMENTS, "Not possible to get precise number of seconds in non-precise interval"); } - UNREACHABLE(); } bool IntervalKind::isFixedLength() const @@ -99,7 +95,6 @@ bool IntervalKind::isFixedLength() const case IntervalKind::Kind::Quarter: case IntervalKind::Kind::Year: return false; } - UNREACHABLE(); } IntervalKind IntervalKind::fromAvgSeconds(Int64 num_seconds) @@ -141,7 +136,6 @@ const char * IntervalKind::toKeyword() const case IntervalKind::Kind::Quarter: return "QUARTER"; case IntervalKind::Kind::Year: return "YEAR"; } - UNREACHABLE(); } @@ -161,7 +155,6 @@ const char * IntervalKind::toLowercasedKeyword() const case IntervalKind::Kind::Quarter: return "quarter"; case IntervalKind::Kind::Year: return "year"; } - UNREACHABLE(); } @@ -192,7 +185,6 @@ const char * IntervalKind::toDateDiffUnit() const case IntervalKind::Kind::Year: return "year"; } - UNREACHABLE(); } @@ -223,7 +215,6 @@ const char * IntervalKind::toNameOfFunctionToIntervalDataType() const case IntervalKind::Kind::Year: return "toIntervalYear"; } - UNREACHABLE(); } @@ -257,7 +248,6 @@ const char * IntervalKind::toNameOfFunctionExtractTimePart() const case IntervalKind::Kind::Year: return "toYear"; } - UNREACHABLE(); } diff --git a/src/Common/TargetSpecific.cpp b/src/Common/TargetSpecific.cpp index 49f396c0926..8540c9a9986 100644 --- a/src/Common/TargetSpecific.cpp +++ b/src/Common/TargetSpecific.cpp @@ -54,8 +54,6 @@ String toString(TargetArch arch) case TargetArch::AMXTILE: return "amxtile"; case TargetArch::AMXINT8: return "amxint8"; } - - UNREACHABLE(); } } diff --git a/src/Common/ThreadProfileEvents.cpp b/src/Common/ThreadProfileEvents.cpp index 6a63d484cd9..23b41f23bde 100644 --- a/src/Common/ThreadProfileEvents.cpp +++ b/src/Common/ThreadProfileEvents.cpp @@ -75,7 +75,6 @@ const char * TasksStatsCounters::metricsProviderString(MetricsProvider provider) case MetricsProvider::Netlink: return "netlink"; } - UNREACHABLE(); } bool TasksStatsCounters::checkIfAvailable() diff --git a/src/Common/ZooKeeper/IKeeper.cpp b/src/Common/ZooKeeper/IKeeper.cpp index 7d2602bde1e..7cca262baca 100644 --- a/src/Common/ZooKeeper/IKeeper.cpp +++ b/src/Common/ZooKeeper/IKeeper.cpp @@ -146,8 +146,6 @@ const char * errorMessage(Error code) case Error::ZSESSIONMOVED: return "Session moved to another server, so operation is ignored"; case Error::ZNOTREADONLY: return "State-changing request is passed to read-only server"; } - - UNREACHABLE(); } bool isHardwareError(Error zk_return_code) diff --git a/src/Compression/CompressionCodecDeflateQpl.cpp b/src/Compression/CompressionCodecDeflateQpl.cpp index 7e0653c69f8..f1b5b24e866 100644 --- a/src/Compression/CompressionCodecDeflateQpl.cpp +++ b/src/Compression/CompressionCodecDeflateQpl.cpp @@ -466,7 +466,6 @@ void CompressionCodecDeflateQpl::doDecompressData(const char * source, UInt32 so sw_codec->doDecompressData(source, source_size, dest, uncompressed_size); return; } - UNREACHABLE(); } void CompressionCodecDeflateQpl::flushAsynchronousDecompressRequests() diff --git a/src/Compression/CompressionCodecDoubleDelta.cpp b/src/Compression/CompressionCodecDoubleDelta.cpp index e6e8db4c699..cbd8cd57a62 100644 --- a/src/Compression/CompressionCodecDoubleDelta.cpp +++ b/src/Compression/CompressionCodecDoubleDelta.cpp @@ -21,6 +21,11 @@ namespace DB { +namespace ErrorCodes +{ + extern const int BAD_ARGUMENTS; +} + /** NOTE DoubleDelta is surprisingly bad name. The only excuse is that it comes from an academic paper. * Most people will think that "double delta" is just applying delta transform twice. * But in fact it is something more than applying delta transform twice. @@ -142,9 +147,9 @@ namespace ErrorCodes { extern const int CANNOT_COMPRESS; extern const int CANNOT_DECOMPRESS; - extern const int BAD_ARGUMENTS; extern const int ILLEGAL_SYNTAX_FOR_CODEC_TYPE; extern const int ILLEGAL_CODEC_PARAMETER; + extern const int LOGICAL_ERROR; } namespace @@ -163,9 +168,8 @@ inline Int64 getMaxValueForByteSize(Int8 byte_size) case sizeof(UInt64): return std::numeric_limits::max(); default: - assert(false && "only 1, 2, 4 and 8 data sizes are supported"); + throw Exception(ErrorCodes::LOGICAL_ERROR, "only 1, 2, 4 and 8 data sizes are supported"); } - UNREACHABLE(); } struct WriteSpec diff --git a/src/Coordination/KeeperReconfiguration.cpp b/src/Coordination/KeeperReconfiguration.cpp index e3642913a7a..05211af6704 100644 --- a/src/Coordination/KeeperReconfiguration.cpp +++ b/src/Coordination/KeeperReconfiguration.cpp @@ -5,6 +5,12 @@ namespace DB { + +namespace ErrorCodes +{ + extern const int LOGICAL_ERROR; +} + ClusterUpdateActions joiningToClusterUpdates(const ClusterConfigPtr & cfg, std::string_view joining) { ClusterUpdateActions out; @@ -79,7 +85,7 @@ String serializeClusterConfig(const ClusterConfigPtr & cfg, const ClusterUpdateA new_config.emplace_back(RaftServerConfig{*cfg->get_server(priority->id)}); } else - UNREACHABLE(); + throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected update"); } for (const auto & item : cfg->get_servers()) diff --git a/src/Coordination/KeeperServer.cpp b/src/Coordination/KeeperServer.cpp index 8d21ce2ab01..736a01443ce 100644 --- a/src/Coordination/KeeperServer.cpp +++ b/src/Coordination/KeeperServer.cpp @@ -990,7 +990,7 @@ KeeperServer::ConfigUpdateState KeeperServer::applyConfigUpdate( raft_instance->set_priority(update->id, update->priority, /*broadcast on live leader*/true); return Accepted; } - UNREACHABLE(); + std::unreachable(); } ClusterUpdateActions KeeperServer::getRaftConfigurationDiff(const Poco::Util::AbstractConfiguration & config) diff --git a/src/Core/Field.h b/src/Core/Field.h index 73d3f4ec44e..a78b589c883 100644 --- a/src/Core/Field.h +++ b/src/Core/Field.h @@ -667,8 +667,6 @@ public: case Types::AggregateFunctionState: return f(field.template get()); case Types::CustomType: return f(field.template get()); } - - UNREACHABLE(); } String dump() const; diff --git a/src/DataTypes/Serializations/ISerialization.cpp b/src/DataTypes/Serializations/ISerialization.cpp index dbe27a5f3f6..bbb1d1a6cd1 100644 --- a/src/DataTypes/Serializations/ISerialization.cpp +++ b/src/DataTypes/Serializations/ISerialization.cpp @@ -36,7 +36,6 @@ String ISerialization::kindToString(Kind kind) case Kind::SPARSE: return "Sparse"; } - UNREACHABLE(); } ISerialization::Kind ISerialization::stringToKind(const String & str) diff --git a/src/Disks/ObjectStorages/MetadataStorageTransactionState.cpp b/src/Disks/ObjectStorages/MetadataStorageTransactionState.cpp index 245578b5d9e..a37f4ce7e65 100644 --- a/src/Disks/ObjectStorages/MetadataStorageTransactionState.cpp +++ b/src/Disks/ObjectStorages/MetadataStorageTransactionState.cpp @@ -17,7 +17,6 @@ std::string toString(MetadataStorageTransactionState state) case MetadataStorageTransactionState::PARTIALLY_ROLLED_BACK: return "PARTIALLY_ROLLED_BACK"; } - UNREACHABLE(); } } diff --git a/src/Disks/VolumeJBOD.cpp b/src/Disks/VolumeJBOD.cpp index d0e9d32ff5e..f8b9a57affe 100644 --- a/src/Disks/VolumeJBOD.cpp +++ b/src/Disks/VolumeJBOD.cpp @@ -112,7 +112,6 @@ DiskPtr VolumeJBOD::getDisk(size_t /* index */) const return disks_by_size.top().disk; } } - UNREACHABLE(); } ReservationPtr VolumeJBOD::reserve(UInt64 bytes) @@ -164,7 +163,6 @@ ReservationPtr VolumeJBOD::reserve(UInt64 bytes) return reservation; } } - UNREACHABLE(); } bool VolumeJBOD::areMergesAvoided() const diff --git a/src/Formats/EscapingRuleUtils.cpp b/src/Formats/EscapingRuleUtils.cpp index 89a7a31d033..9577ca2a8df 100644 --- a/src/Formats/EscapingRuleUtils.cpp +++ b/src/Formats/EscapingRuleUtils.cpp @@ -62,7 +62,6 @@ String escapingRuleToString(FormatSettings::EscapingRule escaping_rule) case FormatSettings::EscapingRule::Raw: return "Raw"; } - UNREACHABLE(); } void skipFieldByEscapingRule(ReadBuffer & buf, FormatSettings::EscapingRule escaping_rule, const FormatSettings & format_settings) diff --git a/src/Functions/FunctionsRound.h b/src/Functions/FunctionsRound.h index 1f20fbff24e..d2dac467bff 100644 --- a/src/Functions/FunctionsRound.h +++ b/src/Functions/FunctionsRound.h @@ -149,8 +149,6 @@ struct IntegerRoundingComputation return x; } } - - UNREACHABLE(); } static ALWAYS_INLINE T compute(T x, T scale) @@ -163,8 +161,6 @@ struct IntegerRoundingComputation case ScaleMode::Negative: return computeImpl(x, scale); } - - UNREACHABLE(); } static ALWAYS_INLINE void compute(const T * __restrict in, size_t scale, T * __restrict out) requires std::integral @@ -247,8 +243,6 @@ inline float roundWithMode(float x, RoundingMode mode) case RoundingMode::Ceil: return ceilf(x); case RoundingMode::Trunc: return truncf(x); } - - UNREACHABLE(); } inline double roundWithMode(double x, RoundingMode mode) @@ -260,8 +254,6 @@ inline double roundWithMode(double x, RoundingMode mode) case RoundingMode::Ceil: return ceil(x); case RoundingMode::Trunc: return trunc(x); } - - UNREACHABLE(); } template diff --git a/src/Functions/FunctionsTimeWindow.cpp b/src/Functions/FunctionsTimeWindow.cpp index 1c9f28c9724..f93a885ee65 100644 --- a/src/Functions/FunctionsTimeWindow.cpp +++ b/src/Functions/FunctionsTimeWindow.cpp @@ -232,7 +232,6 @@ struct TimeWindowImpl default: throw Exception(ErrorCodes::SYNTAX_ERROR, "Fraction seconds are unsupported by windows yet"); } - UNREACHABLE(); } template @@ -422,7 +421,6 @@ struct TimeWindowImpl default: throw Exception(ErrorCodes::SYNTAX_ERROR, "Fraction seconds are unsupported by windows yet"); } - UNREACHABLE(); } template diff --git a/src/Functions/PolygonUtils.h b/src/Functions/PolygonUtils.h index c4851718da6..57f1243537d 100644 --- a/src/Functions/PolygonUtils.h +++ b/src/Functions/PolygonUtils.h @@ -381,8 +381,6 @@ bool PointInPolygonWithGrid::contains(CoordinateType x, Coordina case CellType::complexPolygon: return boost::geometry::within(Point(x, y), polygons[cell.index_of_inner_polygon]); } - - UNREACHABLE(); } diff --git a/src/Functions/UserDefined/UserDefinedSQLObjectsZooKeeperStorage.cpp b/src/Functions/UserDefined/UserDefinedSQLObjectsZooKeeperStorage.cpp index 568e0b9b5d2..766d63eafb0 100644 --- a/src/Functions/UserDefined/UserDefinedSQLObjectsZooKeeperStorage.cpp +++ b/src/Functions/UserDefined/UserDefinedSQLObjectsZooKeeperStorage.cpp @@ -35,7 +35,6 @@ namespace case UserDefinedSQLObjectType::Function: return "function_"; } - UNREACHABLE(); } constexpr std::string_view sql_extension = ".sql"; diff --git a/src/IO/CompressionMethod.cpp b/src/IO/CompressionMethod.cpp index b8e1134d422..22913125e99 100644 --- a/src/IO/CompressionMethod.cpp +++ b/src/IO/CompressionMethod.cpp @@ -52,7 +52,6 @@ std::string toContentEncodingName(CompressionMethod method) case CompressionMethod::None: return ""; } - UNREACHABLE(); } CompressionMethod chooseHTTPCompressionMethod(const std::string & list) diff --git a/src/IO/HadoopSnappyReadBuffer.h b/src/IO/HadoopSnappyReadBuffer.h index eba614d9d0a..7d6e6db2fa7 100644 --- a/src/IO/HadoopSnappyReadBuffer.h +++ b/src/IO/HadoopSnappyReadBuffer.h @@ -88,7 +88,6 @@ public: case Status::TOO_LARGE_COMPRESSED_BLOCK: return "TOO_LARGE_COMPRESSED_BLOCK"; } - UNREACHABLE(); } explicit HadoopSnappyReadBuffer( diff --git a/src/Interpreters/AggregatedDataVariants.cpp b/src/Interpreters/AggregatedDataVariants.cpp index 87cfdda5948..8f82f15248f 100644 --- a/src/Interpreters/AggregatedDataVariants.cpp +++ b/src/Interpreters/AggregatedDataVariants.cpp @@ -117,8 +117,6 @@ size_t AggregatedDataVariants::size() const APPLY_FOR_AGGREGATED_VARIANTS(M) #undef M } - - UNREACHABLE(); } size_t AggregatedDataVariants::sizeWithoutOverflowRow() const @@ -136,8 +134,6 @@ size_t AggregatedDataVariants::sizeWithoutOverflowRow() const APPLY_FOR_AGGREGATED_VARIANTS(M) #undef M } - - UNREACHABLE(); } const char * AggregatedDataVariants::getMethodName() const @@ -155,8 +151,6 @@ const char * AggregatedDataVariants::getMethodName() const APPLY_FOR_AGGREGATED_VARIANTS(M) #undef M } - - UNREACHABLE(); } bool AggregatedDataVariants::isTwoLevel() const @@ -174,8 +168,6 @@ bool AggregatedDataVariants::isTwoLevel() const APPLY_FOR_AGGREGATED_VARIANTS(M) #undef M } - - UNREACHABLE(); } bool AggregatedDataVariants::isConvertibleToTwoLevel() const diff --git a/src/Interpreters/Cache/FileSegment.cpp b/src/Interpreters/Cache/FileSegment.cpp index 9459029dc4c..61a356fa3c3 100644 --- a/src/Interpreters/Cache/FileSegment.cpp +++ b/src/Interpreters/Cache/FileSegment.cpp @@ -799,7 +799,6 @@ String FileSegment::stateToString(FileSegment::State state) case FileSegment::State::DETACHED: return "DETACHED"; } - UNREACHABLE(); } bool FileSegment::assertCorrectness() const diff --git a/src/Interpreters/ComparisonGraph.cpp b/src/Interpreters/ComparisonGraph.cpp index 4eacbae7a30..d53ff4b0227 100644 --- a/src/Interpreters/ComparisonGraph.cpp +++ b/src/Interpreters/ComparisonGraph.cpp @@ -309,7 +309,6 @@ ComparisonGraphCompareResult ComparisonGraph::pathToCompareResult(Path pat case Path::GREATER: return inverse ? ComparisonGraphCompareResult::LESS : ComparisonGraphCompareResult::GREATER; case Path::GREATER_OR_EQUAL: return inverse ? ComparisonGraphCompareResult::LESS_OR_EQUAL : ComparisonGraphCompareResult::GREATER_OR_EQUAL; } - UNREACHABLE(); } template diff --git a/src/Interpreters/HashJoin.cpp b/src/Interpreters/HashJoin.cpp index 3a21c13db5e..75da8bbc3e7 100644 --- a/src/Interpreters/HashJoin.cpp +++ b/src/Interpreters/HashJoin.cpp @@ -705,7 +705,6 @@ namespace APPLY_FOR_JOIN_VARIANTS(M) #undef M } - UNREACHABLE(); } } @@ -2641,8 +2640,6 @@ private: default: throw Exception(ErrorCodes::UNSUPPORTED_JOIN_KEYS, "Unsupported JOIN keys (type: {})", parent.data->type); } - - UNREACHABLE(); } template diff --git a/src/Interpreters/HashJoin.h b/src/Interpreters/HashJoin.h index 86db8943926..a0996556f9a 100644 --- a/src/Interpreters/HashJoin.h +++ b/src/Interpreters/HashJoin.h @@ -322,8 +322,6 @@ public: APPLY_FOR_JOIN_VARIANTS(M) #undef M } - - UNREACHABLE(); } size_t getTotalByteCountImpl(Type which) const @@ -338,8 +336,6 @@ public: APPLY_FOR_JOIN_VARIANTS(M) #undef M } - - UNREACHABLE(); } size_t getBufferSizeInCells(Type which) const @@ -354,8 +350,6 @@ public: APPLY_FOR_JOIN_VARIANTS(M) #undef M } - - UNREACHABLE(); } /// NOLINTEND(bugprone-macro-parentheses) }; diff --git a/src/Interpreters/InterpreterTransactionControlQuery.cpp b/src/Interpreters/InterpreterTransactionControlQuery.cpp index d31ace758c4..13872fbe3f5 100644 --- a/src/Interpreters/InterpreterTransactionControlQuery.cpp +++ b/src/Interpreters/InterpreterTransactionControlQuery.cpp @@ -33,7 +33,6 @@ BlockIO InterpreterTransactionControlQuery::execute() case ASTTransactionControl::SET_SNAPSHOT: return executeSetSnapshot(session_context, tcl.snapshot); } - UNREACHABLE(); } BlockIO InterpreterTransactionControlQuery::executeBegin(ContextMutablePtr session_context) diff --git a/src/Interpreters/SetVariants.cpp b/src/Interpreters/SetVariants.cpp index 64796a013f1..c600d096160 100644 --- a/src/Interpreters/SetVariants.cpp +++ b/src/Interpreters/SetVariants.cpp @@ -41,8 +41,6 @@ size_t SetVariantsTemplate::getTotalRowCount() const APPLY_FOR_SET_VARIANTS(M) #undef M } - - UNREACHABLE(); } template @@ -57,8 +55,6 @@ size_t SetVariantsTemplate::getTotalByteCount() const APPLY_FOR_SET_VARIANTS(M) #undef M } - - UNREACHABLE(); } template diff --git a/src/Parsers/ASTExplainQuery.h b/src/Parsers/ASTExplainQuery.h index 701bde8cebd..eb095b5dbbc 100644 --- a/src/Parsers/ASTExplainQuery.h +++ b/src/Parsers/ASTExplainQuery.h @@ -40,8 +40,6 @@ public: case TableOverride: return "EXPLAIN TABLE OVERRIDE"; case CurrentTransaction: return "EXPLAIN CURRENT TRANSACTION"; } - - UNREACHABLE(); } static ExplainKind fromString(const String & str) diff --git a/src/Parsers/Lexer.cpp b/src/Parsers/Lexer.cpp index 34855a7ce20..5f2bd50524c 100644 --- a/src/Parsers/Lexer.cpp +++ b/src/Parsers/Lexer.cpp @@ -42,7 +42,7 @@ Token quotedString(const char *& pos, const char * const token_begin, const char continue; } - UNREACHABLE(); + chassert(false); } } @@ -538,8 +538,6 @@ const char * getTokenName(TokenType type) APPLY_FOR_TOKENS(M) #undef M } - - UNREACHABLE(); } diff --git a/src/Processors/Formats/Impl/MsgPackRowInputFormat.cpp b/src/Processors/Formats/Impl/MsgPackRowInputFormat.cpp index 98cbdeaaa4b..6b7f1f5206c 100644 --- a/src/Processors/Formats/Impl/MsgPackRowInputFormat.cpp +++ b/src/Processors/Formats/Impl/MsgPackRowInputFormat.cpp @@ -657,7 +657,6 @@ DataTypePtr MsgPackSchemaReader::getDataType(const msgpack::object & object) throw Exception(ErrorCodes::BAD_ARGUMENTS, "Msgpack extension type {:x} is not supported", object_ext.type()); } } - UNREACHABLE(); } std::optional MsgPackSchemaReader::readRowAndGetDataTypes() diff --git a/src/Processors/IProcessor.cpp b/src/Processors/IProcessor.cpp index 8b160153733..5ab5e5277aa 100644 --- a/src/Processors/IProcessor.cpp +++ b/src/Processors/IProcessor.cpp @@ -36,8 +36,6 @@ std::string IProcessor::statusToName(Status status) case Status::ExpandPipeline: return "ExpandPipeline"; } - - UNREACHABLE(); } } diff --git a/src/Processors/QueryPlan/ReadFromMergeTree.cpp b/src/Processors/QueryPlan/ReadFromMergeTree.cpp index 503031eb04b..caba1d32988 100644 --- a/src/Processors/QueryPlan/ReadFromMergeTree.cpp +++ b/src/Processors/QueryPlan/ReadFromMergeTree.cpp @@ -1136,8 +1136,6 @@ static void addMergingFinal( return std::make_shared(header, num_outputs, sort_description, max_block_size_rows, /*max_block_size_bytes=*/0, merging_params.graphite_params, now); } - - UNREACHABLE(); }; pipe.addTransform(get_merging_processor()); @@ -2125,8 +2123,6 @@ static const char * indexTypeToString(ReadFromMergeTree::IndexType type) case ReadFromMergeTree::IndexType::Skip: return "Skip"; } - - UNREACHABLE(); } static const char * readTypeToString(ReadFromMergeTree::ReadType type) @@ -2142,8 +2138,6 @@ static const char * readTypeToString(ReadFromMergeTree::ReadType type) case ReadFromMergeTree::ReadType::ParallelReplicas: return "Parallel"; } - - UNREACHABLE(); } void ReadFromMergeTree::describeActions(FormatSettings & format_settings) const diff --git a/src/Processors/QueryPlan/TotalsHavingStep.cpp b/src/Processors/QueryPlan/TotalsHavingStep.cpp index d1bd70fd0b2..ac5e144bf4a 100644 --- a/src/Processors/QueryPlan/TotalsHavingStep.cpp +++ b/src/Processors/QueryPlan/TotalsHavingStep.cpp @@ -86,8 +86,6 @@ static String totalsModeToString(TotalsMode totals_mode, double auto_include_thr case TotalsMode::AFTER_HAVING_AUTO: return "after_having_auto threshold " + std::to_string(auto_include_threshold); } - - UNREACHABLE(); } void TotalsHavingStep::describeActions(FormatSettings & settings) const diff --git a/src/Processors/Transforms/FillingTransform.cpp b/src/Processors/Transforms/FillingTransform.cpp index 05fd2a7254f..bb38c3e1dc5 100644 --- a/src/Processors/Transforms/FillingTransform.cpp +++ b/src/Processors/Transforms/FillingTransform.cpp @@ -67,7 +67,6 @@ static FillColumnDescription::StepFunction getStepFunction( FOR_EACH_INTERVAL_KIND(DECLARE_CASE) #undef DECLARE_CASE } - UNREACHABLE(); } static bool tryConvertFields(FillColumnDescription & descr, const DataTypePtr & type) diff --git a/src/Processors/Transforms/buildPushingToViewsChain.cpp b/src/Processors/Transforms/buildPushingToViewsChain.cpp index cdcfad4442c..a1a886fb4f7 100644 --- a/src/Processors/Transforms/buildPushingToViewsChain.cpp +++ b/src/Processors/Transforms/buildPushingToViewsChain.cpp @@ -898,8 +898,6 @@ static std::exception_ptr addStorageToException(std::exception_ptr ptr, const St { return std::current_exception(); } - - UNREACHABLE(); } void FinalizingViewsTransform::work() diff --git a/src/Storages/MergeTree/BackgroundJobsAssignee.cpp b/src/Storages/MergeTree/BackgroundJobsAssignee.cpp index 56a4378cf9a..0a69bf1109f 100644 --- a/src/Storages/MergeTree/BackgroundJobsAssignee.cpp +++ b/src/Storages/MergeTree/BackgroundJobsAssignee.cpp @@ -93,7 +93,6 @@ String BackgroundJobsAssignee::toString(Type type) case Type::Moving: return "Moving"; } - UNREACHABLE(); } void BackgroundJobsAssignee::start() diff --git a/src/Storages/MergeTree/KeyCondition.cpp b/src/Storages/MergeTree/KeyCondition.cpp index bd8642b9f66..9666da574fb 100644 --- a/src/Storages/MergeTree/KeyCondition.cpp +++ b/src/Storages/MergeTree/KeyCondition.cpp @@ -2964,8 +2964,6 @@ String KeyCondition::RPNElement::toString(std::string_view column_name, bool pri case ALWAYS_TRUE: return "true"; } - - UNREACHABLE(); } diff --git a/src/Storages/MergeTree/MergeTreeData.cpp b/src/Storages/MergeTree/MergeTreeData.cpp index 4b3093eeaac..b6373a22d9c 100644 --- a/src/Storages/MergeTree/MergeTreeData.cpp +++ b/src/Storages/MergeTree/MergeTreeData.cpp @@ -1177,8 +1177,6 @@ String MergeTreeData::MergingParams::getModeName() const case Graphite: return "Graphite"; case VersionedCollapsing: return "VersionedCollapsing"; } - - UNREACHABLE(); } Int64 MergeTreeData::getMaxBlockNumber() const diff --git a/src/Storages/MergeTree/MergeTreeDataWriter.cpp b/src/Storages/MergeTree/MergeTreeDataWriter.cpp index 426e36ce9a9..df4087b8546 100644 --- a/src/Storages/MergeTree/MergeTreeDataWriter.cpp +++ b/src/Storages/MergeTree/MergeTreeDataWriter.cpp @@ -360,8 +360,6 @@ Block MergeTreeDataWriter::mergeBlock( return std::make_shared( block, 1, sort_description, block_size + 1, /*block_size_bytes=*/0, merging_params.graphite_params, time(nullptr)); } - - UNREACHABLE(); }; auto merging_algorithm = get_merging_algorithm(); diff --git a/src/Storages/MergeTree/PartMovesBetweenShardsOrchestrator.cpp b/src/Storages/MergeTree/PartMovesBetweenShardsOrchestrator.cpp index 78fcfabb704..4228d7b70b6 100644 --- a/src/Storages/MergeTree/PartMovesBetweenShardsOrchestrator.cpp +++ b/src/Storages/MergeTree/PartMovesBetweenShardsOrchestrator.cpp @@ -616,8 +616,6 @@ PartMovesBetweenShardsOrchestrator::Entry PartMovesBetweenShardsOrchestrator::st } } } - - UNREACHABLE(); } void PartMovesBetweenShardsOrchestrator::removePins(const Entry & entry, zkutil::ZooKeeperPtr zk) diff --git a/src/Storages/WindowView/StorageWindowView.cpp b/src/Storages/WindowView/StorageWindowView.cpp index a9ec1f6c694..8bca1c97aad 100644 --- a/src/Storages/WindowView/StorageWindowView.cpp +++ b/src/Storages/WindowView/StorageWindowView.cpp @@ -297,7 +297,6 @@ namespace CASE_WINDOW_KIND(Year) #undef CASE_WINDOW_KIND } - UNREACHABLE(); } class AddingAggregatedChunkInfoTransform : public ISimpleTransform @@ -920,7 +919,6 @@ UInt32 StorageWindowView::getWindowLowerBound(UInt32 time_sec) CASE_WINDOW_KIND(Year) #undef CASE_WINDOW_KIND } - UNREACHABLE(); } UInt32 StorageWindowView::getWindowUpperBound(UInt32 time_sec) @@ -948,7 +946,6 @@ UInt32 StorageWindowView::getWindowUpperBound(UInt32 time_sec) CASE_WINDOW_KIND(Year) #undef CASE_WINDOW_KIND } - UNREACHABLE(); } void StorageWindowView::addFireSignal(std::set & signals) From a3eec1fc78da4b23ebdea862883aeced1a061d8e Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 29 May 2024 13:40:39 +0000 Subject: [PATCH 175/211] Fix spelling --- .../aspell-ignore/en/aspell-dict.txt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/utils/check-style/aspell-ignore/en/aspell-dict.txt b/utils/check-style/aspell-ignore/en/aspell-dict.txt index d85a42ef115..da805274375 100644 --- a/utils/check-style/aspell-ignore/en/aspell-dict.txt +++ b/utils/check-style/aspell-ignore/en/aspell-dict.txt @@ -246,7 +246,6 @@ DockerHub DoubleDelta Doxygen Durre -doesnt ECMA Ecto EdgeAngle @@ -1357,8 +1356,8 @@ concatWithSeparatorAssumeInjective cond conf config -conformant configs +conformant congruential conjuction conjuctive @@ -1415,11 +1414,11 @@ cutQueryString cutQueryStringAndFragment cutToFirstSignificantSubdomain cutToFirstSignificantSubdomainCustom -cutToFirstSignificantSubdomainCustomWithWWW -cutToFirstSignificantSubdomainWithWWW -cutToFirstSignificantSubdomainRFC cutToFirstSignificantSubdomainCustomRFC +cutToFirstSignificantSubdomainCustomWithWWW cutToFirstSignificantSubdomainCustomWithWWWRFC +cutToFirstSignificantSubdomainRFC +cutToFirstSignificantSubdomainWithWWW cutToFirstSignificantSubdomainWithWWWRFC cutURLParameter cutWWW @@ -1507,9 +1506,10 @@ displaySecretsInShowAndSelect distro divideDecimal dmesg +doesnt +domainRFC domainWithoutWWW domainWithoutWWWRFC -domainRFC dont dotProduct downsampling @@ -1582,10 +1582,11 @@ filesystems finalizeAggregation fips firstLine +firstSignficantSubdomain firstSignificantSubdomain firstSignificantSubdomainCustom -firstSignificantSubdomainRFC firstSignificantSubdomainCustomRFC +firstSignificantSubdomainRFC fixedstring flamegraph flatbuffers @@ -2166,8 +2167,8 @@ polygonsUnionSpherical polygonsWithinCartesian polygonsWithinSpherical popcnt -porthttps portRFC +porthttps positionCaseInsensitive positionCaseInsensitiveUTF positionUTF From a6140ac8b0386a107376ca673164efaa643433bb Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 29 May 2024 13:43:15 +0000 Subject: [PATCH 176/211] Strip trailing whitespace --- .../sql-reference/functions/url-functions.md | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/en/sql-reference/functions/url-functions.md b/docs/en/sql-reference/functions/url-functions.md index e22dabe494b..500b0ad65fc 100644 --- a/docs/en/sql-reference/functions/url-functions.md +++ b/docs/en/sql-reference/functions/url-functions.md @@ -7,31 +7,31 @@ sidebar_label: URLs # Functions for Working with URLs :::note -The functions mentioned in this section for the most part do not follow the RFC-3986 convention as they are maximally simplified for improved performance. Functions following the RFC-3986 convention have `RFC` appended to the function name and are generally less performant. +The functions mentioned in this section for the most part do not follow the RFC-3986 convention as they are maximally simplified for improved performance. Functions following the RFC-3986 convention have `RFC` appended to the function name and are generally less performant. -- When should I pick the non-`RFC` variant? +- When should I pick the non-`RFC` variant? — Pick the non-`RFC` variant when working with domains which are allowed to be publicly registered and when user info and the `@` symbol does not appear in the URL. ::: -The table below details which symbols are restricted (`✗`) and which are available (`✔`) for use in the whole URL between the two variants. +The table below details which symbols are restricted (`✗`) and which are available (`✔`) for use in the whole URL between the two variants. |Symbol | non-`RFC`| `RFC` | |-------|----------|-------| -| ' ' | ✗ |✗ | -| \t | ✗ |✗ | -| < | ✗ |✗ | -| > | ✗ |✗ | -| % | ✗ |✔* | -| { | ✗ |✗ | -| } | ✗ |✗ | -| \| | ✗ |✗ | -| \\\ | ✗ |✗ | -| ^ | ✗ |✗ | -| ~ | ✗ |✔* | -| [ | ✗ |✗ | -| ] | ✗ |✔ | -| ; | ✗ |✔* | -| = | ✗ |✔* | +| ' ' | ✗ |✗ | +| \t | ✗ |✗ | +| < | ✗ |✗ | +| > | ✗ |✗ | +| % | ✗ |✔* | +| { | ✗ |✗ | +| } | ✗ |✗ | +| \| | ✗ |✗ | +| \\\ | ✗ |✗ | +| ^ | ✗ |✗ | +| ~ | ✗ |✔* | +| [ | ✗ |✗ | +| ] | ✗ |✔ | +| ; | ✗ |✔* | +| = | ✗ |✔* | | & | ✗ |✔* | The symbols above marked `*` are sub-delimiters in the RFC 3986 convention and are allowed for user info following the `@` symbol. From c40a5647c2dbbab8a3cbae8ee736ffb6aa1a0203 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 29 May 2024 13:49:46 +0000 Subject: [PATCH 177/211] Rephrase intro a bit --- docs/en/sql-reference/functions/url-functions.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/en/sql-reference/functions/url-functions.md b/docs/en/sql-reference/functions/url-functions.md index 500b0ad65fc..fceaaf5cd38 100644 --- a/docs/en/sql-reference/functions/url-functions.md +++ b/docs/en/sql-reference/functions/url-functions.md @@ -7,13 +7,11 @@ sidebar_label: URLs # Functions for Working with URLs :::note -The functions mentioned in this section for the most part do not follow the RFC-3986 convention as they are maximally simplified for improved performance. Functions following the RFC-3986 convention have `RFC` appended to the function name and are generally less performant. - -- When should I pick the non-`RFC` variant? -— Pick the non-`RFC` variant when working with domains which are allowed to be publicly registered and when user info and the `@` symbol does not appear in the URL. +The functions mentioned in this section are optimized for maximum performance and for the most part do not follow the RFC-3986 standard. Functions which implement RFC-3986 have `RFC` appended to their function name and are generally slower. ::: -The table below details which symbols are restricted (`✗`) and which are available (`✔`) for use in the whole URL between the two variants. +You can generally use the non-`RFC` function variants when working with publicly registered domains that contain neither user strings nor `@` symbols. +Below table below details which symbols in an URL can (`✔`) or cannot (`✗`) be parsed by the respective `RFC` and non-`RFC` variants: |Symbol | non-`RFC`| `RFC` | |-------|----------|-------| @@ -34,7 +32,7 @@ The table below details which symbols are restricted (`✗`) and which are avail | = | ✗ |✔* | | & | ✗ |✔* | -The symbols above marked `*` are sub-delimiters in the RFC 3986 convention and are allowed for user info following the `@` symbol. +symbols marked `*` are sub-delimiters in RFC 3986 and allowed for user info following the `@` symbol. ## Functions that Extract Parts of a URL From f3c735cad074a2117bc290d41f376db515f6408f Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Wed, 29 May 2024 13:49:48 +0000 Subject: [PATCH 178/211] fix corner case --- src/Storages/MergeTree/MergeTask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Storages/MergeTree/MergeTask.cpp b/src/Storages/MergeTree/MergeTask.cpp index d026eea10e6..f1f856da3a2 100644 --- a/src/Storages/MergeTree/MergeTask.cpp +++ b/src/Storages/MergeTree/MergeTask.cpp @@ -572,7 +572,7 @@ bool MergeTask::VerticalMergeStage::prepareVerticalMergeForAllColumns() const bool all_parts_on_remote_disks = std::ranges::all_of(global_ctx->future_part->parts, [](const auto & part) { return part->isStoredOnRemoteDisk(); }); ctx->use_prefetch = all_parts_on_remote_disks && global_ctx->data->getSettings()->vertical_merge_remote_filesystem_prefetch; - if (ctx->use_prefetch) + if (ctx->use_prefetch && ctx->it_name_and_type != global_ctx->gathering_columns.end()) ctx->prepared_pipe = createPipeForReadingOneColumn(ctx->it_name_and_type->name); return false; From c2a71e047a45e542a92143425d9759e6e305512b Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 29 May 2024 13:50:24 +0000 Subject: [PATCH 179/211] =?UTF-8?q?No=20=E2=80=A6,=20please.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/sql-reference/functions/url-functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/sql-reference/functions/url-functions.md b/docs/en/sql-reference/functions/url-functions.md index fceaaf5cd38..32d13196dae 100644 --- a/docs/en/sql-reference/functions/url-functions.md +++ b/docs/en/sql-reference/functions/url-functions.md @@ -42,7 +42,7 @@ If the relevant part isn’t present in a URL, an empty string is returned. Extracts the protocol from a URL. -Examples of typical returned values: http, https, ftp, mailto, tel, magnet… +Examples of typical returned values: http, https, ftp, mailto, tel, magnet. ### domain From 811b5e638bb8ace84fe58a73f4181c0fe22b2d0c Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 29 May 2024 13:52:54 +0000 Subject: [PATCH 180/211] Function arguments are by convention lower case --- .../sql-reference/functions/url-functions.md | 116 +++++++++--------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/docs/en/sql-reference/functions/url-functions.md b/docs/en/sql-reference/functions/url-functions.md index 32d13196dae..469c712bb29 100644 --- a/docs/en/sql-reference/functions/url-functions.md +++ b/docs/en/sql-reference/functions/url-functions.md @@ -51,12 +51,12 @@ Extracts the hostname from a URL. **Syntax** ``` sql -domain(URL) +domain(url) ``` **Arguments** -- `URL` — URL. Type: [String](../../sql-reference/data-types/string.md). +- `url` — URL. Type: [String](../../sql-reference/data-types/string.md). The URL can be specified with or without a protocol. Examples: @@ -97,12 +97,12 @@ Extracts the hostname from a URL. Similar to [domain](#domain), but RFC 3986 con **Syntax** ``` sql -domainRFC(URL) +domainRFC(url) ``` **Arguments** -- `URL` — URL. Type: [String](../../sql-reference/data-types/string.md). +- `url` — URL. Type: [String](../../sql-reference/data-types/string.md). **Returned values** @@ -133,12 +133,12 @@ Returns the domain and removes no more than one ‘www.’ from the beginning of Extracts the the top-level domain from a URL. ``` sql -topLevelDomain(URL) +topLevelDomain(url) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). :::note The URL can be specified with or without a protocol. Examples: @@ -175,12 +175,12 @@ Result: Extracts the the top-level domain from a URL. It is similar to [topLevelDomain](#topleveldomain), but conforms to RFC 3986. ``` sql -topLevelDomainRFC(URL) +topLevelDomainRFC(url) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). :::note The URL can be specified with or without a protocol. Examples: @@ -224,7 +224,7 @@ firstSignificantSubdomain(URL) **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). **Returned value** @@ -253,12 +253,12 @@ Returns the “first significant subdomain”, similar to [firstSignficantSubdom **Syntax** ```sql -firstSignificantSubdomainRFC(URL) +firstSignificantSubdomainRFC(url) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). **Returned value** @@ -289,12 +289,12 @@ Returns the part of the domain that includes top-level subdomains up to the [“ **Syntax** ```sql -cutToFirstSignificantSubdomain(URL) +cutToFirstSignificantSubdomain(url) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). **Returned value** @@ -326,12 +326,12 @@ Returns the part of the domain that includes top-level subdomains up to the [“ **Syntax** ```sql -cutToFirstSignificantSubdomainRFC(URL) +cutToFirstSignificantSubdomainRFC(url) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). **Returned value** @@ -363,12 +363,12 @@ Returns the part of the domain that includes top-level subdomains up to the “f **Syntax** ```sql -cutToFirstSignificantSubdomainWithWWW(URL) +cutToFirstSignificantSubdomainWithWWW(url) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). **Returned value** @@ -400,12 +400,12 @@ Returns the part of the domain that includes top-level subdomains up to the “f **Syntax** ```sql -cutToFirstSignificantSubdomainWithWWW(URL) +cutToFirstSignificantSubdomainWithWWW(url) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). **Returned value** @@ -449,13 +449,13 @@ This can be useful if you need a fresh TLD list or if you have a custom list. **Syntax** ``` sql -cutToFirstSignificantSubdomain(URL, TLD) +cutToFirstSignificantSubdomain(url, tld) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). -- `TLD` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). +- `tld` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). **Returned value** @@ -488,13 +488,13 @@ Returns the part of the domain that includes top-level subdomains up to the firs **Syntax** ``` sql -cutToFirstSignificantSubdomainRFC(URL, TLD) +cutToFirstSignificantSubdomainRFC(url, tld) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). -- `TLD` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). +- `tld` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). **Returned value** @@ -524,13 +524,13 @@ It can be useful if you need a fresh TLD list or if you have a custom list. **Syntax** ```sql -cutToFirstSignificantSubdomainCustomWithWWW(URL, TLD) +cutToFirstSignificantSubdomainCustomWithWWW(url, tld) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). -- `TLD` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). +- `tld` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). **Returned value** @@ -565,13 +565,13 @@ Returns the part of the domain that includes top-level subdomains up to the firs **Syntax** ```sql -cutToFirstSignificantSubdomainCustomWithWWWRFC(URL, TLD) +cutToFirstSignificantSubdomainCustomWithWWWRFC(url, tld) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). -- `TLD` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). +- `tld` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). **Returned value** @@ -601,13 +601,13 @@ Configuration example: **Syntax** ```sql -firstSignificantSubdomainCustom(URL, TLD) +firstSignificantSubdomainCustom(url, tld) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). -- `TLD` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). +- `tld` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). **Returned value** @@ -642,13 +642,13 @@ Returns the first significant subdomain. Accepts customs TLD list name. Similar **Syntax** ```sql -firstSignificantSubdomainCustomRFC(URL, TLD) +firstSignificantSubdomainCustomRFC(url, tld) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). -- `TLD` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). +- `tld` — Custom TLD list name. [String](../../sql-reference/data-types/string.md). **Returned value** @@ -662,17 +662,17 @@ Type: [String](../../sql-reference/data-types/string.md). ### port -Returns the port or `default_port` if there is no port in the `URL` (or in case of validation error). +Returns the port or `default_port` if there is no port in the `url` (or in case of validation error). **Syntax** ```sql -port(URL [, default_port = 0]) +port(url [, default_port = 0]) ``` **Arguments** -- `URL` — URL. [String](../data-types/string.md). +- `url` — URL. [String](../data-types/string.md). - `default_port` — The default port number to be returned. [UInt16](../data-types/int-uint.md). **Returned value** @@ -698,17 +698,17 @@ Result: ### portRFC -Returns the port or `default_port` if there is no port in the `URL` (or in case of validation error). Similar to [port](#port), but RFC 3986 conformant. +Returns the port or `default_port` if there is no port in the `url` (or in case of validation error). Similar to [port](#port), but RFC 3986 conformant. **Syntax** ```sql -portRFC(URL [, default_port = 0]) +portRFC(url [, default_port = 0]) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). - `default_port` — The default port number to be returned. [UInt16](../data-types/int-uint.md). **Returned value** @@ -753,23 +753,23 @@ Returns the fragment identifier. fragment does not include the initial hash symb Returns the query string and fragment identifier. Example: page=1#29390. -### extractURLParameter(URL, name) +### extractURLParameter(url, name) Returns the value of the ‘name’ parameter in the URL, if present. Otherwise, an empty string. If there are many parameters with this name, it returns the first occurrence. This function works under the assumption that the parameter name is encoded in the URL exactly the same way as in the passed argument. -### extractURLParameters(URL) +### extractURLParameters(url) Returns an array of name=value strings corresponding to the URL parameters. The values are not decoded in any way. -### extractURLParameterNames(URL) +### extractURLParameterNames(url) Returns an array of name strings corresponding to the names of URL parameters. The values are not decoded in any way. -### URLHierarchy(URL) +### URLHierarchy(url) Returns an array containing the URL, truncated at the end by the symbols /,? in the path and query-string. Consecutive separator characters are counted as one. The cut is made in the position after all the consecutive separator characters. -### URLPathHierarchy(URL) +### URLPathHierarchy(url) The same as above, but without the protocol and host in the result. The / element (root) is not included. @@ -781,7 +781,7 @@ URLPathHierarchy('https://example.com/browse/CONV-6788') = ] ``` -### encodeURLComponent(URL) +### encodeURLComponent(url) Returns the encoded URL. Example: @@ -796,7 +796,7 @@ SELECT encodeURLComponent('http://127.0.0.1:8123/?query=SELECT 1;') AS EncodedUR └──────────────────────────────────────────────────────────┘ ``` -### decodeURLComponent(URL) +### decodeURLComponent(url) Returns the decoded URL. Example: @@ -811,7 +811,7 @@ SELECT decodeURLComponent('http://127.0.0.1:8123/?query=SELECT%201%3B') AS Decod └────────────────────────────────────────┘ ``` -### encodeURLFormComponent(URL) +### encodeURLFormComponent(url) Returns the encoded URL. Follows rfc-1866, space(` `) is encoded as plus(`+`). Example: @@ -826,7 +826,7 @@ SELECT encodeURLFormComponent('http://127.0.0.1:8123/?query=SELECT 1 2+3') AS En └───────────────────────────────────────────────────────────┘ ``` -### decodeURLFormComponent(URL) +### decodeURLFormComponent(url) Returns the decoded URL. Follows rfc-1866, plain plus(`+`) is decoded as space(` `). Example: @@ -848,12 +848,12 @@ Extracts network locality (`username:password@host:port`) from a URL. **Syntax** ``` sql -netloc(URL) +netloc(url) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). **Returned value** @@ -897,24 +897,24 @@ Removes the fragment identifier. The number sign is also removed. Removes the query string and fragment identifier. The question mark and number sign are also removed. -### cutURLParameter(URL, name) +### cutURLParameter(url, name) Removes the `name` parameter from URL, if present. This function does not encode or decode characters in parameter names, e.g. `Client ID` and `Client%20ID` are treated as different parameter names. **Syntax** ``` sql -cutURLParameter(URL, name) +cutURLParameter(url, name) ``` **Arguments** -- `URL` — URL. [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). - `name` — name of URL parameter. [String](../../sql-reference/data-types/string.md) or [Array](../../sql-reference/data-types/array.md) of Strings. **Returned value** -- URL with `name` URL parameter removed. +- url with `name` URL parameter removed. Type: `String`. From ef8707507b6c077e5cc6dd0391a5d4c370d645d5 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 29 May 2024 13:56:16 +0000 Subject: [PATCH 181/211] Minor consistency fix --- docs/en/sql-reference/functions/url-functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/sql-reference/functions/url-functions.md b/docs/en/sql-reference/functions/url-functions.md index 469c712bb29..92e7070b300 100644 --- a/docs/en/sql-reference/functions/url-functions.md +++ b/docs/en/sql-reference/functions/url-functions.md @@ -248,7 +248,7 @@ Result: ### firstSignificantSubdomainRFC -Returns the “first significant subdomain”, similar to [firstSignficantSubdomain](#firstsignificantsubdomain) but according to RFC 1034. +Returns the “first significant subdomain”. Similar to [firstSignficantSubdomain](#firstsignificantsubdomain) but according to RFC 1034. **Syntax** From 62d95eb13f7fa80212242e31242c930a005a3116 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 29 May 2024 14:15:46 +0000 Subject: [PATCH 182/211] Streamline docs --- .../sql-reference/functions/url-functions.md | 120 ++++++++++++------ 1 file changed, 79 insertions(+), 41 deletions(-) diff --git a/docs/en/sql-reference/functions/url-functions.md b/docs/en/sql-reference/functions/url-functions.md index 92e7070b300..22f57d747cd 100644 --- a/docs/en/sql-reference/functions/url-functions.md +++ b/docs/en/sql-reference/functions/url-functions.md @@ -76,7 +76,7 @@ clickhouse.com **Returned values** -- Host name if ClickHouse can parse the input string as a URL, otherwise an empty string. [String](../data-types/string.md). +- Host name if the input string can be parsed as a URL, otherwise an empty string. [String](../data-types/string.md). **Example** @@ -106,7 +106,7 @@ domainRFC(url) **Returned values** -- Host name if ClickHouse can parse the input string as a URL, otherwise an empty string. [String](../data-types/string.md). +- Host name if the input string can be parsed as a URL, otherwise an empty string. [String](../data-types/string.md). Type: `String`. @@ -126,7 +126,7 @@ SELECT ### domainWithoutWWW -Returns the domain and removes no more than one ‘www.’ from the beginning of it, if present. +Returns the domain without leading `www.` if present. ### topLevelDomain @@ -152,7 +152,7 @@ https://clickhouse.com/time/ **Returned values** -- Domain name if ClickHouse can parse the input string as a URL. Otherwise, an empty string. [String](../../sql-reference/data-types/string.md). +- Domain name if the input string can be parsed as a URL. Otherwise, an empty string. [String](../../sql-reference/data-types/string.md). **Example** @@ -172,7 +172,8 @@ Result: ### topLevelDomainRFC -Extracts the the top-level domain from a URL. It is similar to [topLevelDomain](#topleveldomain), but conforms to RFC 3986. +Extracts the the top-level domain from a URL. +Similar to [topLevelDomain](#topleveldomain), but conforms to RFC 3986. ``` sql topLevelDomainRFC(url) @@ -194,7 +195,7 @@ https://clickhouse.com/time/ **Returned values** -- Domain name if ClickHouse can parse the input string as a URL. Otherwise, an empty string. [String](../../sql-reference/data-types/string.md). +- Domain name if the input string can be parsed as a URL. Otherwise, an empty string. [String](../../sql-reference/data-types/string.md). **Example** @@ -214,12 +215,15 @@ Result: ### firstSignificantSubdomain -Returns the “first significant subdomain”. The first significant subdomain is a second-level domain if it is ‘com’, ‘net’, ‘org’, or ‘co’. Otherwise, it is a third-level domain. For example, `firstSignificantSubdomain (‘https://news.clickhouse.com/’) = ‘clickhouse’, firstSignificantSubdomain (‘https://news.clickhouse.com.tr/’) = ‘clickhouse’`. The list of “insignificant” second-level domains and other implementation details may change in the future. +Returns the “first significant subdomain”. +The first significant subdomain is a second-level domain for `com`, `net`, `org`, or `co`, otherwise it is a third-level domain. +For example, `firstSignificantSubdomain (‘https://news.clickhouse.com/’) = ‘clickhouse’, firstSignificantSubdomain (‘https://news.clickhouse.com.tr/’) = ‘clickhouse’`. +The list of "insignificant" second-level domains and other implementation details may change in the future. **Syntax** ```sql -firstSignificantSubdomain(URL) +firstSignificantSubdomain(url) ``` **Arguments** @@ -248,7 +252,11 @@ Result: ### firstSignificantSubdomainRFC -Returns the “first significant subdomain”. Similar to [firstSignficantSubdomain](#firstsignificantsubdomain) but according to RFC 1034. +Returns the “first significant subdomain”. +The first significant subdomain is a second-level domain for `com`, `net`, `org`, or `co`, otherwise it is a third-level domain. +For example, `firstSignificantSubdomain (‘https://news.clickhouse.com/’) = ‘clickhouse’, firstSignificantSubdomain (‘https://news.clickhouse.com.tr/’) = ‘clickhouse’`. +The list of "insignificant" second-level domains and other implementation details may change in the future. +Similar to [firstSignficantSubdomain](#firstsignificantsubdomain) but conforms to RFC 1034. **Syntax** @@ -321,7 +329,8 @@ Result: ### cutToFirstSignificantSubdomainRFC -Returns the part of the domain that includes top-level subdomains up to the [“first significant subdomain”](#firstsignificantsubdomain). It is similar to [cutToFirstSignificantSubdomain](#cuttofirstsignificantsubdomain) but follows stricter rules to be compatible with RFC 3986 and is less performant. +Returns the part of the domain that includes top-level subdomains up to the [“first significant subdomain”](#firstsignificantsubdomain). +Similar to [cutToFirstSignificantSubdomain](#cuttofirstsignificantsubdomain) but conforms to RFC 3986. **Syntax** @@ -358,7 +367,7 @@ Result: ### cutToFirstSignificantSubdomainWithWWW -Returns the part of the domain that includes top-level subdomains up to the “first significant subdomain”, without stripping "www". +Returns the part of the domain that includes top-level subdomains up to the "first significant subdomain", without stripping `www`. **Syntax** @@ -372,7 +381,7 @@ cutToFirstSignificantSubdomainWithWWW(url) **Returned value** -- Part of the domain that includes top-level subdomains up to the first significant subdomain (with "www") if possible, otherwise returns an empty string. [String](../data-types/string.md). +- Part of the domain that includes top-level subdomains up to the first significant subdomain (with `www`) if possible, otherwise returns an empty string. [String](../data-types/string.md). **Example** @@ -395,7 +404,8 @@ Result: ### cutToFirstSignificantSubdomainWithWWWRFC -Returns the part of the domain that includes top-level subdomains up to the “first significant subdomain”, without stripping "www". Similar to [cutToFirstSignificantSubdomainWithWWW](#cuttofirstsignificantsubdomaincustomwithwww) but follows stricter rules to be compatible with RFC 3986 and is less performant. +Returns the part of the domain that includes top-level subdomains up to the "first significant subdomain", without stripping `www`. +Similar to [cutToFirstSignificantSubdomainWithWWW](#cuttofirstsignificantsubdomaincustomwithwww) but conforms to RFC 3986. **Syntax** @@ -431,9 +441,9 @@ Result: ### cutToFirstSignificantSubdomainCustom -Returns the part of the domain that includes top-level subdomains up to the first significant subdomain. Accepts custom [TLD list](https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains) name. - -This can be useful if you need a fresh TLD list or if you have a custom list. +Returns the part of the domain that includes top-level subdomains up to the first significant subdomain. +Accepts custom [TLD list](https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains) name. +This function can be useful if you need a fresh TLD list or if you have a custom list. **Configuration example** @@ -483,7 +493,10 @@ Result: ### cutToFirstSignificantSubdomainCustomRFC -Returns the part of the domain that includes top-level subdomains up to the first significant subdomain. Accepts custom [TLD list](https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains) name. It is similar to [cutToFirstSignificantSubdomainCustom](#cuttofirstsignificantsubdomaincustom) but follows stricter rules according to RFC 3986 and is generally less performant as a result. +Returns the part of the domain that includes top-level subdomains up to the first significant subdomain. +Accepts custom [TLD list](https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains) name. +This function can be useful if you need a fresh TLD list or if you have a custom list. +Similar to [cutToFirstSignificantSubdomainCustom](#cuttofirstsignificantsubdomaincustom) but conforms to RFC 3986. **Syntax** @@ -506,8 +519,8 @@ cutToFirstSignificantSubdomainRFC(url, tld) ### cutToFirstSignificantSubdomainCustomWithWWW -Returns the part of the domain that includes top-level subdomains up to the first significant subdomain without stripping `www`. Accepts custom TLD list name. - +Returns the part of the domain that includes top-level subdomains up to the first significant subdomain without stripping `www`. +Accepts custom TLD list name. It can be useful if you need a fresh TLD list or if you have a custom list. **Configuration example** @@ -560,7 +573,10 @@ Result: ### cutToFirstSignificantSubdomainCustomWithWWWRFC -Returns the part of the domain that includes top-level subdomains up to the first significant subdomain without stripping `www`. Accepts custom TLD list name. It is similar to [cutToFirstSignificantSubdomainCustomWithWWW](#cuttofirstsignificantsubdomaincustomwithwww) but follows stricter rules according to RFC 3986 and is generally less performant as a result. +Returns the part of the domain that includes top-level subdomains up to the first significant subdomain without stripping `www`. +Accepts custom TLD list name. +It can be useful if you need a fresh TLD list or if you have a custom list. +Similar to [cutToFirstSignificantSubdomainCustomWithWWW](#cuttofirstsignificantsubdomaincustomwithwww) but conforms to RFC 3986. **Syntax** @@ -583,8 +599,8 @@ cutToFirstSignificantSubdomainCustomWithWWWRFC(url, tld) ### firstSignificantSubdomainCustom -Returns the first significant subdomain. Accepts customs TLD list name. - +Returns the first significant subdomain. +Accepts customs TLD list name. Can be useful if you need fresh TLD list or you have custom. Configuration example: @@ -637,7 +653,10 @@ Result: ### firstSignificantSubdomainCustomRFC -Returns the first significant subdomain. Accepts customs TLD list name. Similar to [firstSignificantSubdomainCustom](#firstsignificantsubdomaincustom) but follows stricter rules according to RFC 3986 and is generally less performant as a result. +Returns the first significant subdomain. +Accepts customs TLD list name. +Can be useful if you need fresh TLD list or you have custom. +Similar to [firstSignificantSubdomainCustom](#firstsignificantsubdomaincustom) but conforms to RFC 3986. **Syntax** @@ -662,7 +681,7 @@ Type: [String](../../sql-reference/data-types/string.md). ### port -Returns the port or `default_port` if there is no port in the `url` (or in case of validation error). +Returns the port or `default_port` if the URL contains no port or cannot be parsed. **Syntax** @@ -695,10 +714,10 @@ Result: └─────────────────────────────────────────┘ ``` - ### portRFC -Returns the port or `default_port` if there is no port in the `url` (or in case of validation error). Similar to [port](#port), but RFC 3986 conformant. +Returns the port or `default_port` if the URL contains no port or cannot be parsed. +Similar to [port](#port), but RFC 3986 conformant. **Syntax** @@ -735,39 +754,53 @@ Result: ### path -Returns the path. Example: `/top/news.html` The path does not include the query string. +Returns the path without query string. + +Example: `/top/news.html`. ### pathFull -The same as above, but including query string and fragment. Example: /top/news.html?page=2#comments +The same as above, but including query string and fragment. + +Example: `/top/news.html?page=2#comments`. ### queryString -Returns the query string. Example: page=1&lr=213. query-string does not include the initial question mark, as well as # and everything after #. +Returns the query string without the initial question mark, `#` and everything after `#`. + +Example: `page=1&lr=213`. ### fragment -Returns the fragment identifier. fragment does not include the initial hash symbol. +Returns the fragment identifier without the initial hash symbol. ### queryStringAndFragment -Returns the query string and fragment identifier. Example: page=1#29390. +Returns the query string and fragment identifier. + +Example: `page=1#29390`. ### extractURLParameter(url, name) -Returns the value of the ‘name’ parameter in the URL, if present. Otherwise, an empty string. If there are many parameters with this name, it returns the first occurrence. This function works under the assumption that the parameter name is encoded in the URL exactly the same way as in the passed argument. +Returns the value of the `name` parameter in the URL, if present, otherwise an empty string is returned. +If there are multiple parameters with this name, the first occurrence is returned. +The function assumes that the parameter in the `url` parameter is encoded in the same way as in the `name` argument. ### extractURLParameters(url) -Returns an array of name=value strings corresponding to the URL parameters. The values are not decoded in any way. +Returns an array of `name=value` strings corresponding to the URL parameters. +The values are not decoded. ### extractURLParameterNames(url) -Returns an array of name strings corresponding to the names of URL parameters. The values are not decoded in any way. +Returns an array of name strings corresponding to the names of URL parameters. +The values are not decoded. ### URLHierarchy(url) -Returns an array containing the URL, truncated at the end by the symbols /,? in the path and query-string. Consecutive separator characters are counted as one. The cut is made in the position after all the consecutive separator characters. +Returns an array containing the URL, truncated at the end by the symbols /,? in the path and query-string. +Consecutive separator characters are counted as one. +The cut is made in the position after all the consecutive separator characters. ### URLPathHierarchy(url) @@ -784,6 +817,7 @@ URLPathHierarchy('https://example.com/browse/CONV-6788') = ### encodeURLComponent(url) Returns the encoded URL. + Example: ``` sql @@ -799,6 +833,7 @@ SELECT encodeURLComponent('http://127.0.0.1:8123/?query=SELECT 1;') AS EncodedUR ### decodeURLComponent(url) Returns the decoded URL. + Example: ``` sql @@ -814,6 +849,7 @@ SELECT decodeURLComponent('http://127.0.0.1:8123/?query=SELECT%201%3B') AS Decod ### encodeURLFormComponent(url) Returns the encoded URL. Follows rfc-1866, space(` `) is encoded as plus(`+`). + Example: ``` sql @@ -829,6 +865,7 @@ SELECT encodeURLFormComponent('http://127.0.0.1:8123/?query=SELECT 1 2+3') AS En ### decodeURLFormComponent(url) Returns the decoded URL. Follows rfc-1866, plain plus(`+`) is decoded as space(` `). + Example: ``` sql @@ -877,29 +914,30 @@ Result: └───────────────────────────────────────────┘ ``` -## Functions that Remove Part of a URL +## Functions that remove part of a URL If the URL does not have anything similar, the URL remains unchanged. ### cutWWW -Removes no more than one ‘www.’ from the beginning of the URL’s domain, if present. +Removes leading `www.` (if present) from the URL’s domain. ### cutQueryString -Removes query string. The question mark is also removed. +Removes query string, including the question mark. ### cutFragment -Removes the fragment identifier. The number sign is also removed. +Removes the fragment identifier, including the number sign. ### cutQueryStringAndFragment -Removes the query string and fragment identifier. The question mark and number sign are also removed. +Removes the query string and fragment identifier, including the question mark and number sign. ### cutURLParameter(url, name) -Removes the `name` parameter from URL, if present. This function does not encode or decode characters in parameter names, e.g. `Client ID` and `Client%20ID` are treated as different parameter names. +Removes the `name` parameter from a URL, if present. +This function does not encode or decode characters in parameter names, e.g. `Client ID` and `Client%20ID` are treated as different parameter names. **Syntax** From 010c2cad1cac5a5232d85c1332c4c407aa9e1184 Mon Sep 17 00:00:00 2001 From: Jiebin Sun Date: Thu, 23 May 2024 19:52:18 +0800 Subject: [PATCH 183/211] Replace the offsets.size() in Iterator with offsets_size to avoid frequent call of size() The `isDefault()` of Iterator in sparse column will frequently use size() to check the boundary. We can use the offsets_size instead as offsets will not change in the Iterator. Signed-off-by: Jiebin Sun --- src/Columns/ColumnSparse.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Columns/ColumnSparse.h b/src/Columns/ColumnSparse.h index 1999dcc42f3..12b2def7cf1 100644 --- a/src/Columns/ColumnSparse.h +++ b/src/Columns/ColumnSparse.h @@ -181,11 +181,11 @@ public: { public: Iterator(const PaddedPODArray & offsets_, size_t size_, size_t current_offset_, size_t current_row_) - : offsets(offsets_), size(size_), current_offset(current_offset_), current_row(current_row_) + : offsets(offsets_), offsets_size(offsets.size()), size(size_), current_offset(current_offset_), current_row(current_row_) { } - bool ALWAYS_INLINE isDefault() const { return current_offset == offsets.size() || current_row != offsets[current_offset]; } + bool ALWAYS_INLINE isDefault() const { return current_offset == offsets_size || current_row != offsets[current_offset]; } size_t ALWAYS_INLINE getValueIndex() const { return isDefault() ? 0 : current_offset + 1; } size_t ALWAYS_INLINE getCurrentRow() const { return current_row; } size_t ALWAYS_INLINE getCurrentOffset() const { return current_offset; } @@ -211,6 +211,7 @@ public: private: const PaddedPODArray & offsets; + const size_t offsets_size; const size_t size; size_t current_offset; size_t current_row; From 92ee671310b4b0e275748145cf806b246f1ed278 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Thu, 16 May 2024 18:23:35 +0200 Subject: [PATCH 184/211] Implement global timeout check in _test_run --- tests/ci/ci.py | 49 ++++++++++++++++--------------- tests/ci/ci_config.py | 4 +-- tests/ci/ci_utils.py | 16 ++-------- tests/ci/functional_test_check.py | 9 ------ tests/ci/install_check.py | 17 ++++------- tests/ci/sqllogic_test.py | 15 ++-------- 6 files changed, 37 insertions(+), 73 deletions(-) diff --git a/tests/ci/ci.py b/tests/ci/ci.py index 95e2de120f5..c5271a945c0 100644 --- a/tests/ci/ci.py +++ b/tests/ci/ci.py @@ -18,6 +18,7 @@ import docker_images_helper import upload_result_helper from build_check import get_release_or_pr from ci_config import CI_CONFIG, Build, CILabels, CIStages, JobNames, StatusNames +from ci_metadata import CiMetadata from ci_utils import GHActions, is_hex, normalize_string from clickhouse_helper import ( CiLogsCredentials, @@ -39,22 +40,23 @@ from digest_helper import DockerDigester, JobDigester from env_helper import ( CI, GITHUB_JOB_API_URL, + GITHUB_REPOSITORY, + GITHUB_RUN_ID, GITHUB_RUN_URL, REPO_COPY, REPORT_PATH, S3_BUILDS_BUCKET, TEMP_PATH, - GITHUB_RUN_ID, - GITHUB_REPOSITORY, ) from get_robot_token import get_best_robot_token from git_helper import GIT_PREFIX, Git from git_helper import Runner as GitRunner from github_helper import GitHub from pr_info import PRInfo -from report import ERROR, SUCCESS, BuildResult, JobReport, PENDING +from report import ERROR, FAILURE, PENDING, SUCCESS, BuildResult, JobReport, TestResult from s3_helper import S3Helper -from ci_metadata import CiMetadata +from stopwatch import Stopwatch +from tee_popen import TeePopen from version_helper import get_version_from_repo # pylint: disable=too-many-lines @@ -1868,8 +1870,7 @@ def _run_test(job_name: str, run_command: str) -> int: ), "Run command must be provided as input argument or be configured in job config" env = os.environ.copy() - if CI_CONFIG.get_job_config(job_name).timeout: - env["KILL_TIMEOUT"] = str(CI_CONFIG.get_job_config(job_name).timeout) + timeout = CI_CONFIG.get_job_config(job_name).timeout or None if not run_command: run_command = "/".join( @@ -1882,25 +1883,25 @@ def _run_test(job_name: str, run_command: str) -> int: print("Use run command from the workflow") env["CHECK_NAME"] = job_name print(f"Going to start run command [{run_command}]") - process = subprocess.run( - run_command, - stdout=sys.stdout, - stderr=sys.stderr, - env=env, - text=True, - check=False, - shell=True, - ) + stopwatch = Stopwatch() + job_log = Path(TEMP_PATH) / "job_log.txt" + with TeePopen(run_command, job_log, env, timeout) as process: + retcode = process.wait() + if retcode != 0: + print(f"Run action failed for: [{job_name}] with exit code [{retcode}]") + if timeout and process.timeout_exceeded: + print(f"Timeout {timeout} exceeded, dumping the job report") + JobReport( + status=FAILURE, + description=f"Timeout {timeout} exceeded", + test_results=[TestResult.create_check_timeout_expired(timeout)], + start_time=stopwatch.start_time_str, + duration=stopwatch.duration_seconds, + additional_files=[job_log], + ).dump() - if process.returncode == 0: - print(f"Run action done for: [{job_name}]") - exit_code = 0 - else: - print( - f"Run action failed for: [{job_name}] with exit code [{process.returncode}]" - ) - exit_code = process.returncode - return exit_code + print(f"Run action done for: [{job_name}]") + return retcode def _get_ext_check_name(check_name: str) -> str: diff --git a/tests/ci/ci_config.py b/tests/ci/ci_config.py index 68fa6f1cf10..0d8b6d714a9 100644 --- a/tests/ci/ci_config.py +++ b/tests/ci/ci_config.py @@ -472,12 +472,12 @@ compatibility_test_common_params = { } stateless_test_common_params = { "digest": stateless_check_digest, - "run_command": 'functional_test_check.py "$CHECK_NAME" $KILL_TIMEOUT', + "run_command": 'functional_test_check.py "$CHECK_NAME"', "timeout": 10800, } stateful_test_common_params = { "digest": stateful_check_digest, - "run_command": 'functional_test_check.py "$CHECK_NAME" $KILL_TIMEOUT', + "run_command": 'functional_test_check.py "$CHECK_NAME"', "timeout": 3600, } stress_test_common_params = { diff --git a/tests/ci/ci_utils.py b/tests/ci/ci_utils.py index 97d42f9845b..2bc0a4fef14 100644 --- a/tests/ci/ci_utils.py +++ b/tests/ci/ci_utils.py @@ -1,8 +1,7 @@ -from contextlib import contextmanager import os -import signal -from typing import Any, List, Union, Iterator +from contextlib import contextmanager from pathlib import Path +from typing import Any, Iterator, List, Union class WithIter(type): @@ -49,14 +48,3 @@ class GHActions: for line in lines: print(line) print("::endgroup::") - - -def set_job_timeout(): - def timeout_handler(_signum, _frame): - print("Timeout expired") - raise TimeoutError("Job's KILL_TIMEOUT expired") - - kill_timeout = int(os.getenv("KILL_TIMEOUT", "0")) - assert kill_timeout > 0, "kill timeout must be provided in KILL_TIMEOUT env" - signal.signal(signal.SIGALRM, timeout_handler) - signal.alarm(kill_timeout) diff --git a/tests/ci/functional_test_check.py b/tests/ci/functional_test_check.py index e898138fb3a..5bb46d7ec2f 100644 --- a/tests/ci/functional_test_check.py +++ b/tests/ci/functional_test_check.py @@ -68,7 +68,6 @@ def get_run_command( repo_path: Path, result_path: Path, server_log_path: Path, - kill_timeout: int, additional_envs: List[str], ci_logs_args: str, image: DockerImage, @@ -86,7 +85,6 @@ def get_run_command( ) envs = [ - f"-e MAX_RUN_TIME={int(0.9 * kill_timeout)}", # a static link, don't use S3_URL or S3_DOWNLOAD '-e S3_URL="https://s3.amazonaws.com/clickhouse-datasets"', ] @@ -192,7 +190,6 @@ def process_results( def parse_args(): parser = argparse.ArgumentParser() parser.add_argument("check_name") - parser.add_argument("kill_timeout", type=int) parser.add_argument( "--validate-bugfix", action="store_true", @@ -224,12 +221,7 @@ def main(): assert ( check_name ), "Check name must be provided as an input arg or in CHECK_NAME env" - kill_timeout = args.kill_timeout or int(os.getenv("KILL_TIMEOUT", "0")) - assert ( - kill_timeout > 0 - ), "kill timeout must be provided as an input arg or in KILL_TIMEOUT env" validate_bugfix_check = args.validate_bugfix - print(f"Runnin check [{check_name}] with timeout [{kill_timeout}]") flaky_check = "flaky" in check_name.lower() @@ -288,7 +280,6 @@ def main(): repo_path, result_path, server_log_path, - kill_timeout, additional_envs, ci_logs_args, docker_image, diff --git a/tests/ci/install_check.py b/tests/ci/install_check.py index 54a18c7e26c..6c33b1f2066 100644 --- a/tests/ci/install_check.py +++ b/tests/ci/install_check.py @@ -1,25 +1,21 @@ #!/usr/bin/env python3 import argparse - import logging -import sys import subprocess +import sys from pathlib import Path from shutil import copy2 from typing import Dict - from build_download_helper import download_builds_filter - from compress_files import compress_fast -from docker_images_helper import DockerImage, pull_image, get_docker_image -from env_helper import CI, REPORT_PATH, TEMP_PATH as TEMP -from report import JobReport, TestResults, TestResult, FAILURE, FAIL, OK, SUCCESS +from docker_images_helper import DockerImage, get_docker_image, pull_image +from env_helper import REPORT_PATH +from env_helper import TEMP_PATH as TEMP +from report import FAIL, FAILURE, OK, SUCCESS, JobReport, TestResult, TestResults from stopwatch import Stopwatch from tee_popen import TeePopen -from ci_utils import set_job_timeout - RPM_IMAGE = "clickhouse/install-rpm-test" DEB_IMAGE = "clickhouse/install-deb-test" @@ -256,9 +252,6 @@ def main(): args = parse_args() - if CI: - set_job_timeout() - TEMP_PATH.mkdir(parents=True, exist_ok=True) LOGS_PATH.mkdir(parents=True, exist_ok=True) diff --git a/tests/ci/sqllogic_test.py b/tests/ci/sqllogic_test.py index 6ea6fa19d91..63880f07e92 100755 --- a/tests/ci/sqllogic_test.py +++ b/tests/ci/sqllogic_test.py @@ -9,8 +9,8 @@ from pathlib import Path from typing import Tuple from build_download_helper import download_all_deb_packages -from docker_images_helper import DockerImage, pull_image, get_docker_image -from env_helper import REPORT_PATH, TEMP_PATH, REPO_COPY +from docker_images_helper import DockerImage, get_docker_image, pull_image +from env_helper import REPO_COPY, REPORT_PATH, TEMP_PATH from report import ( ERROR, FAIL, @@ -72,11 +72,6 @@ def parse_args() -> argparse.Namespace: required=False, default="", ) - parser.add_argument( - "--kill-timeout", - required=False, - default=0, - ) return parser.parse_args() @@ -96,10 +91,6 @@ def main(): assert ( check_name ), "Check name must be provided as an input arg or in CHECK_NAME env" - kill_timeout = args.kill_timeout or int(os.getenv("KILL_TIMEOUT", "0")) - assert ( - kill_timeout > 0 - ), "kill timeout must be provided as an input arg or in KILL_TIMEOUT env" docker_image = pull_image(get_docker_image(IMAGE_NAME)) @@ -127,7 +118,7 @@ def main(): ) logging.info("Going to run func tests: %s", run_command) - with TeePopen(run_command, run_log_path, timeout=kill_timeout) as process: + with TeePopen(run_command, run_log_path) as process: retcode = process.wait() if retcode == 0: logging.info("Run successfully") From 31355d5e45c99a24ebd748d039af57b147bd7665 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Thu, 16 May 2024 19:17:52 +0200 Subject: [PATCH 185/211] Add a reasonable timeout to bugfix config --- tests/ci/bugfix_validate_check.py | 8 ++++---- tests/ci/ci_config.py | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/ci/bugfix_validate_check.py b/tests/ci/bugfix_validate_check.py index 7aaf18e7765..d41fdaf05ff 100644 --- a/tests/ci/bugfix_validate_check.py +++ b/tests/ci/bugfix_validate_check.py @@ -109,12 +109,12 @@ def main(): test_script = jobs_scripts[test_job] if report_file.exists(): report_file.unlink() - extra_timeout_option = "" - if test_job == JobNames.STATELESS_TEST_RELEASE: - extra_timeout_option = str(3600) # "bugfix" must be present in checkname, as integration test runner checks this check_name = f"Validate bugfix: {test_job}" - command = f"python3 {test_script} '{check_name}' {extra_timeout_option} --validate-bugfix --report-to-file {report_file}" + command = ( + f"python3 {test_script} '{check_name}' " + f"--validate-bugfix --report-to-file {report_file}" + ) print(f"Going to validate job [{test_job}], command [{command}]") _ = subprocess.run( command, diff --git a/tests/ci/ci_config.py b/tests/ci/ci_config.py index 0d8b6d714a9..496366a4acc 100644 --- a/tests/ci/ci_config.py +++ b/tests/ci/ci_config.py @@ -1123,7 +1123,9 @@ CI_CONFIG = CIConfig( "", # we run this check by label - no digest required job_config=JobConfig( - run_by_label="pr-bugfix", run_command="bugfix_validate_check.py" + run_by_label="pr-bugfix", + run_command="bugfix_validate_check.py", + timeout=900, ), ), }, From a2bfcabc99cdeba89e2f8dcad1b91bb7fc4b2c5a Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Thu, 16 May 2024 20:06:03 +0200 Subject: [PATCH 186/211] Use timeout from ci_config in fast tests --- tests/ci/ci_config.py | 1 + tests/ci/fast_test_check.py | 45 +++---------------------------------- 2 files changed, 4 insertions(+), 42 deletions(-) diff --git a/tests/ci/ci_config.py b/tests/ci/ci_config.py index 496366a4acc..bea23f97506 100644 --- a/tests/ci/ci_config.py +++ b/tests/ci/ci_config.py @@ -1111,6 +1111,7 @@ CI_CONFIG = CIConfig( exclude_files=[".md"], docker=["clickhouse/fasttest"], ), + timeout=2400, ), ), JobNames.STYLE_CHECK: TestConfig( diff --git a/tests/ci/fast_test_check.py b/tests/ci/fast_test_check.py index 383f5b340c7..ed727dd3659 100644 --- a/tests/ci/fast_test_check.py +++ b/tests/ci/fast_test_check.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import argparse import csv import logging import os @@ -11,15 +10,7 @@ from typing import Tuple from docker_images_helper import DockerImage, get_docker_image, pull_image from env_helper import REPO_COPY, S3_BUILDS_BUCKET, TEMP_PATH from pr_info import PRInfo -from report import ( - ERROR, - FAILURE, - SUCCESS, - JobReport, - TestResult, - TestResults, - read_test_results, -) +from report import ERROR, FAILURE, SUCCESS, JobReport, TestResults, read_test_results from stopwatch import Stopwatch from tee_popen import TeePopen @@ -80,30 +71,9 @@ def process_results(result_directory: Path) -> Tuple[str, str, TestResults]: return state, description, test_results -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser( - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - description="FastTest script", - ) - - parser.add_argument( - "--timeout", - type=int, - # Fast tests in most cases done within 10 min and 40 min timout should be sufficient, - # though due to cold cache build time can be much longer - # https://pastila.nl/?146195b6/9bb99293535e3817a9ea82c3f0f7538d.link#5xtClOjkaPLEjSuZ92L2/g== - default=40, - help="Timeout in minutes", - ) - args = parser.parse_args() - args.timeout = args.timeout * 60 - return args - - def main(): logging.basicConfig(level=logging.INFO) stopwatch = Stopwatch() - args = parse_args() temp_path = Path(TEMP_PATH) temp_path.mkdir(parents=True, exist_ok=True) @@ -134,14 +104,10 @@ def main(): logs_path.mkdir(parents=True, exist_ok=True) run_log_path = logs_path / "run.log" - timeout_expired = False - with TeePopen(run_cmd, run_log_path, timeout=args.timeout) as process: + with TeePopen(run_cmd, run_log_path) as process: retcode = process.wait() - if process.timeout_exceeded: - logging.info("Timeout expired for command: %s", run_cmd) - timeout_expired = True - elif retcode == 0: + if retcode == 0: logging.info("Run successfully") else: logging.info("Run failed") @@ -175,11 +141,6 @@ def main(): else: state, description, test_results = process_results(output_path) - if timeout_expired: - test_results.append(TestResult.create_check_timeout_expired(args.timeout)) - state = FAILURE - description = test_results[-1].name - JobReport( description=description, test_results=test_results, From 5f7839740d6b62fb95bb68fe8daaebc1caaf0236 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Thu, 16 May 2024 20:13:56 +0200 Subject: [PATCH 187/211] Use timeout from ci_config in stress tests --- tests/ci/ci_config.py | 1 + tests/ci/stress_check.py | 16 +++------------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/tests/ci/ci_config.py b/tests/ci/ci_config.py index bea23f97506..f8627dac84b 100644 --- a/tests/ci/ci_config.py +++ b/tests/ci/ci_config.py @@ -483,6 +483,7 @@ stateful_test_common_params = { stress_test_common_params = { "digest": stress_check_digest, "run_command": "stress_check.py", + "timeout": 9000, } upgrade_test_common_params = { "digest": upgrade_check_digest, diff --git a/tests/ci/stress_check.py b/tests/ci/stress_check.py index 027d7316e23..bf0281cae68 100644 --- a/tests/ci/stress_check.py +++ b/tests/ci/stress_check.py @@ -14,7 +14,7 @@ from docker_images_helper import DockerImage, get_docker_image, pull_image from env_helper import REPO_COPY, REPORT_PATH, TEMP_PATH from get_robot_token import get_parameter_from_ssm from pr_info import PRInfo -from report import ERROR, JobReport, TestResult, TestResults, read_test_results +from report import ERROR, JobReport, TestResults, read_test_results from stopwatch import Stopwatch from tee_popen import TeePopen @@ -161,14 +161,9 @@ def run_stress_test(docker_image_name: str) -> None: ) logging.info("Going to run stress test: %s", run_command) - timeout_expired = False - timeout = 60 * 150 - with TeePopen(run_command, run_log_path, timeout=timeout) as process: + with TeePopen(run_command, run_log_path) as process: retcode = process.wait() - if process.timeout_exceeded: - logging.info("Timeout expired for command: %s", run_command) - timeout_expired = True - elif retcode == 0: + if retcode == 0: logging.info("Run successfully") else: logging.info("Run failed") @@ -180,11 +175,6 @@ def run_stress_test(docker_image_name: str) -> None: result_path, server_log_path, run_log_path ) - if timeout_expired: - test_results.append(TestResult.create_check_timeout_expired(timeout)) - state = "failure" - description = test_results[-1].name - JobReport( description=description, test_results=test_results, From 383147ac4f83f13e4f7b257cbdb8edae40d964a2 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Thu, 16 May 2024 20:15:49 +0200 Subject: [PATCH 188/211] Use timeout from ci_config in libfuzzer --- tests/ci/ci_config.py | 2 +- tests/ci/libfuzzer_test_check.py | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/ci/ci_config.py b/tests/ci/ci_config.py index f8627dac84b..228f29229ca 100644 --- a/tests/ci/ci_config.py +++ b/tests/ci/ci_config.py @@ -1372,7 +1372,7 @@ CI_CONFIG = CIConfig( job_config=JobConfig( run_by_label=CILabels.libFuzzer, timeout=10800, - run_command='libfuzzer_test_check.py "$CHECK_NAME" 10800', + run_command='libfuzzer_test_check.py "$CHECK_NAME"', ), ), # type: ignore }, diff --git a/tests/ci/libfuzzer_test_check.py b/tests/ci/libfuzzer_test_check.py index 4bb39010978..1f5936c3fec 100644 --- a/tests/ci/libfuzzer_test_check.py +++ b/tests/ci/libfuzzer_test_check.py @@ -46,7 +46,6 @@ def get_run_command( fuzzers_path: Path, repo_path: Path, result_path: Path, - kill_timeout: int, additional_envs: List[str], ci_logs_args: str, image: DockerImage, @@ -59,7 +58,6 @@ def get_run_command( ) envs = [ - f"-e MAX_RUN_TIME={int(0.9 * kill_timeout)}", # a static link, don't use S3_URL or S3_DOWNLOAD '-e S3_URL="https://s3.amazonaws.com/clickhouse-datasets"', ] @@ -83,7 +81,6 @@ def get_run_command( def parse_args(): parser = argparse.ArgumentParser() parser.add_argument("check_name") - parser.add_argument("kill_timeout", type=int) return parser.parse_args() @@ -99,7 +96,6 @@ def main(): args = parse_args() check_name = args.check_name - kill_timeout = args.kill_timeout pr_info = PRInfo() @@ -145,7 +141,6 @@ def main(): fuzzers_path, repo_path, result_path, - kill_timeout, additional_envs, ci_logs_args, docker_image, From b1253761e0db1bc87e33d2ffda3d1541cec20933 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Fri, 17 May 2024 15:28:37 +0200 Subject: [PATCH 189/211] Fix all `clcik` typos --- tests/ci/ci_config.py | 8 ++++---- tests/ci/jepsen_check.py | 3 ++- tests/ci/report.py | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/ci/ci_config.py b/tests/ci/ci_config.py index 228f29229ca..dbe268f5910 100644 --- a/tests/ci/ci_config.py +++ b/tests/ci/ci_config.py @@ -175,8 +175,8 @@ class JobNames(metaclass=WithIter): COMPATIBILITY_TEST = "Compatibility check (amd64)" COMPATIBILITY_TEST_ARM = "Compatibility check (aarch64)" - CLCIKBENCH_TEST = "ClickBench (amd64)" - CLCIKBENCH_TEST_ARM = "ClickBench (aarch64)" + CLICKBENCH_TEST = "ClickBench (amd64)" + CLICKBENCH_TEST_ARM = "ClickBench (aarch64)" LIBFUZZER_TEST = "libFuzzer tests" @@ -1361,10 +1361,10 @@ CI_CONFIG = CIConfig( Build.PACKAGE_RELEASE, job_config=sqllogic_test_params ), JobNames.SQLTEST: TestConfig(Build.PACKAGE_RELEASE, job_config=sql_test_params), - JobNames.CLCIKBENCH_TEST: TestConfig( + JobNames.CLICKBENCH_TEST: TestConfig( Build.PACKAGE_RELEASE, job_config=JobConfig(**clickbench_test_params) # type: ignore ), - JobNames.CLCIKBENCH_TEST_ARM: TestConfig( + JobNames.CLICKBENCH_TEST_ARM: TestConfig( Build.PACKAGE_AARCH64, job_config=JobConfig(**clickbench_test_params) # type: ignore ), JobNames.LIBFUZZER_TEST: TestConfig( diff --git a/tests/ci/jepsen_check.py b/tests/ci/jepsen_check.py index 6ed411a11ef..1e61fd9fab7 100644 --- a/tests/ci/jepsen_check.py +++ b/tests/ci/jepsen_check.py @@ -10,6 +10,7 @@ from typing import Any, List import boto3 # type: ignore import requests + from build_download_helper import ( download_build_with_progress, get_build_name_for_check, @@ -201,7 +202,7 @@ def main(): docker_image = KEEPER_IMAGE_NAME if args.program == "keeper" else SERVER_IMAGE_NAME if pr_info.is_scheduled or pr_info.is_dispatched: - # get latest clcikhouse by the static link for latest master buit - get its version and provide permanent url for this version to the jepsen + # get latest clickhouse by the static link for latest master buit - get its version and provide permanent url for this version to the jepsen build_url = f"{S3_URL}/{S3_BUILDS_BUCKET}/master/amd64/clickhouse" download_build_with_progress(build_url, Path(TEMP_PATH) / "clickhouse") git_runner.run(f"chmod +x {TEMP_PATH}/clickhouse") diff --git a/tests/ci/report.py b/tests/ci/report.py index 670a10f4561..fd94e8a57d9 100644 --- a/tests/ci/report.py +++ b/tests/ci/report.py @@ -288,7 +288,7 @@ class JobReport: start_time: str duration: float additional_files: Union[Sequence[str], Sequence[Path]] - # clcikhouse version, build job only + # clickhouse version, build job only version: str = "" # checkname to set in commit status, set if differs from jjob name check_name: str = "" From 08be26a47bbf800fbdd1094ee0ab9686fb319009 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Fri, 17 May 2024 15:29:35 +0200 Subject: [PATCH 190/211] Add timeout 900 for clickbench tests --- tests/ci/ci_config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ci/ci_config.py b/tests/ci/ci_config.py index dbe268f5910..2a914d443cf 100644 --- a/tests/ci/ci_config.py +++ b/tests/ci/ci_config.py @@ -532,6 +532,7 @@ clickbench_test_params = { docker=["clickhouse/clickbench"], ), "run_command": 'clickbench.py "$CHECK_NAME"', + "timeout": 900, } install_test_params = JobConfig( digest=install_check_digest, From d3bdb739eb83c4e532e46d621d0b9513bf703e2f Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Wed, 29 May 2024 16:44:36 +0000 Subject: [PATCH 191/211] Rename a function and add a comment. --- src/Planner/PlannerExpressionAnalysis.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Planner/PlannerExpressionAnalysis.cpp b/src/Planner/PlannerExpressionAnalysis.cpp index 201c4fa25ac..f0a2845c3e8 100644 --- a/src/Planner/PlannerExpressionAnalysis.cpp +++ b/src/Planner/PlannerExpressionAnalysis.cpp @@ -51,7 +51,7 @@ FilterAnalysisResult analyzeFilter(const QueryTreeNodePtr & filter_expression_no return result; } -bool isDeterministicConstant(const ConstantNode & root) +bool canRemoveConstantFromGroupByKey(const ConstantNode & root) { const auto & source_expression = root.getSourceExpression(); if (!source_expression) @@ -65,18 +65,19 @@ bool isDeterministicConstant(const ConstantNode & root) nodes.pop(); if (node->getNodeType() == QueryTreeNodeType::QUERY) - /// Allow scalar subqueries and IN; we send them to all the shards. + /// Allow removing constants from scalar subqueries. We send them to all the shards. continue; const auto * constant_node = node->as(); const auto * function_node = node->as(); if (constant_node) { - if (!isDeterministicConstant(*constant_node)) + if (!canRemoveConstantFromGroupByKey(*constant_node)) return false; } else if (function_node) { + /// Do not allow removing constants like `hostName()` if (!function_node->getFunctionOrThrow()->isDeterministic()) return false; @@ -126,7 +127,7 @@ std::optional analyzeAggregation(const QueryTreeNodeP bool is_secondary_query = planner_context->getQueryContext()->getClientInfo().query_kind == ClientInfo::QueryKind::SECONDARY_QUERY; bool is_distributed_query = planner_context->getQueryContext()->isDistributed(); - bool check_deterministic_constants = is_secondary_query || is_distributed_query; + bool check_constants_for_group_by_key = is_secondary_query || is_distributed_query; if (query_node.hasGroupBy()) { @@ -143,7 +144,7 @@ std::optional analyzeAggregation(const QueryTreeNodeP const auto * constant_key = grouping_set_key_node->as(); group_by_with_constant_keys |= (constant_key != nullptr); - if (constant_key && !aggregates_descriptions.empty() && (!check_deterministic_constants || isDeterministicConstant(*constant_key))) + if (constant_key && !aggregates_descriptions.empty() && (!check_constants_for_group_by_key || canRemoveConstantFromGroupByKey(*constant_key))) continue; auto expression_dag_nodes = actions_visitor.visit(before_aggregation_actions, grouping_set_key_node); @@ -195,7 +196,7 @@ std::optional analyzeAggregation(const QueryTreeNodeP const auto * constant_key = group_by_key_node->as(); group_by_with_constant_keys |= (constant_key != nullptr); - if (constant_key && !aggregates_descriptions.empty() && (!check_deterministic_constants || isDeterministicConstant(*constant_key))) + if (constant_key && !aggregates_descriptions.empty() && (!check_constants_for_group_by_key || canRemoveConstantFromGroupByKey(*constant_key))) continue; auto expression_dag_nodes = actions_visitor.visit(before_aggregation_actions, group_by_key_node); From 481a1f032f3f13267054aac8e6545fa7c6e5db55 Mon Sep 17 00:00:00 2001 From: Blargian Date: Wed, 29 May 2024 20:26:52 +0200 Subject: [PATCH 192/211] Add missing domainWithoutWWWRFC --- .../sql-reference/functions/url-functions.md | 90 ++++++++++++++----- 1 file changed, 70 insertions(+), 20 deletions(-) diff --git a/docs/en/sql-reference/functions/url-functions.md b/docs/en/sql-reference/functions/url-functions.md index 22f57d747cd..8b3e4f44840 100644 --- a/docs/en/sql-reference/functions/url-functions.md +++ b/docs/en/sql-reference/functions/url-functions.md @@ -11,7 +11,7 @@ The functions mentioned in this section are optimized for maximum performance an ::: You can generally use the non-`RFC` function variants when working with publicly registered domains that contain neither user strings nor `@` symbols. -Below table below details which symbols in an URL can (`✔`) or cannot (`✗`) be parsed by the respective `RFC` and non-`RFC` variants: +The table below details which symbols in a URL can (`✔`) or cannot (`✗`) be parsed by the respective `RFC` and non-`RFC` variants: |Symbol | non-`RFC`| `RFC` | |-------|----------|-------| @@ -56,7 +56,7 @@ domain(url) **Arguments** -- `url` — URL. Type: [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../../sql-reference/data-types/string.md). The URL can be specified with or without a protocol. Examples: @@ -102,14 +102,12 @@ domainRFC(url) **Arguments** -- `url` — URL. Type: [String](../../sql-reference/data-types/string.md). +- `url` — URL. [String](../data-types/string.md). **Returned values** - Host name if the input string can be parsed as a URL, otherwise an empty string. [String](../data-types/string.md). -Type: `String`. - **Example** ``` sql @@ -128,6 +126,68 @@ SELECT Returns the domain without leading `www.` if present. +**Syntax** + +```sql +domainWithoutWWW(url) +``` + +**Arguments** + +- `url` — URL. [String](../data-types/string.md). + +**Returned values** + +- Domain name if the input string can be parsed as a URL (without leading `www.`), otherwise an empty string. [String](../data-types/string.md). + +**Example** + +``` sql +SELECT domainWithoutWWW('http://paul@www.example.com:80/'); +``` + +``` text +┌─domainWithoutWWW('http://paul@www.example.com:80/')─┐ +│ example.com │ +└─────────────────────────────────────────────────────┘ +``` + +### domainWithoutWWWRFC + +Returns the domain without leading `www.` if present. Similar to [domainWithoutWWW](#domainwithoutwww) but conforms to RFC 3986. + +**Syntax** + +```sql +domainWithoutWWWRFC(url) +``` + +**Arguments** + +- `url` — URL. [String](../data-types/string.md). + +**Returned values** + +- Domain name if the input string can be parsed as a URL (without leading `www.`), otherwise an empty string. [String](../data-types/string.md). + +**Example** + +Query: + +```sql +SELECT + domainWithoutWWW('http://user:password@www.example.com:8080/path?query=value#fragment'), + domainWithoutWWWRFC('http://user:password@www.example.com:8080/path?query=value#fragment'); +``` + +Result: + +```response +┌─domainWithoutWWW('http://user:password@www.example.com:8080/path?query=value#fragment')─┬─domainWithoutWWWRFC('http://user:password@www.example.com:8080/path?query=value#fragment')─┐ +│ │ example.com │ +└─────────────────────────────────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────┘ +``` + ### topLevelDomain Extracts the the top-level domain from a URL. @@ -547,9 +607,7 @@ cutToFirstSignificantSubdomainCustomWithWWW(url, tld) **Returned value** -- Part of the domain that includes top-level subdomains up to the first significant subdomain without stripping `www`. - -Type: [String](../../sql-reference/data-types/string.md). +- Part of the domain that includes top-level subdomains up to the first significant subdomain without stripping `www`. [String](../data-types/string.md). **Example** @@ -627,9 +685,7 @@ firstSignificantSubdomainCustom(url, tld) **Returned value** -- First significant subdomain. - -Type: [String](../../sql-reference/data-types/string.md). +- First significant subdomain. [String](../../sql-reference/data-types/string.md). **Example** @@ -671,9 +727,7 @@ firstSignificantSubdomainCustomRFC(url, tld) **Returned value** -- First significant subdomain. - -Type: [String](../../sql-reference/data-types/string.md). +- First significant subdomain. [String](../../sql-reference/data-types/string.md). **See Also** @@ -894,9 +948,7 @@ netloc(url) **Returned value** -- `username:password@host:port`. - -Type: `String`. +- `username:password@host:port`. [String](../data-types/string.md). **Example** @@ -952,9 +1004,7 @@ cutURLParameter(url, name) **Returned value** -- url with `name` URL parameter removed. - -Type: `String`. +- url with `name` URL parameter removed. [String](../data-types/string.md). **Example** From 1e3d2973462db32e74ff64352bbc20ac8c1fe7ae Mon Sep 17 00:00:00 2001 From: Max K Date: Wed, 29 May 2024 21:13:00 +0200 Subject: [PATCH 193/211] CI: Change Required Check list, few fixes --- tests/ci/ci_config.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/ci/ci_config.py b/tests/ci/ci_config.py index 68fa6f1cf10..3c681c9afb5 100644 --- a/tests/ci/ci_config.py +++ b/tests/ci/ci_config.py @@ -1067,6 +1067,7 @@ CI_CONFIG = CIConfig( Build.PACKAGE_TSAN, Build.PACKAGE_MSAN, Build.PACKAGE_DEBUG, + Build.BINARY_RELEASE, ] ), JobNames.BUILD_CHECK_SPECIAL: BuildReportConfig( @@ -1084,7 +1085,6 @@ CI_CONFIG = CIConfig( Build.BINARY_AMD64_COMPAT, Build.BINARY_AMD64_MUSL, Build.PACKAGE_RELEASE_COVERAGE, - Build.BINARY_RELEASE, Build.FUZZERS, ] ), @@ -1386,6 +1386,9 @@ REQUIRED_CHECKS = [ JobNames.FAST_TEST, JobNames.STATEFUL_TEST_RELEASE, JobNames.STATELESS_TEST_RELEASE, + JobNames.STATELESS_TEST_ASAN, + JobNames.STATELESS_TEST_FLAKY_ASAN, + JobNames.STATEFUL_TEST_ASAN, JobNames.STYLE_CHECK, JobNames.UNIT_TEST_ASAN, JobNames.UNIT_TEST_MSAN, @@ -1419,6 +1422,11 @@ class CheckDescription: CHECK_DESCRIPTIONS = [ + CheckDescription( + StatusNames.SYNC, + "If it fails, ask a maintainer for help", + lambda x: "Sync" in x, + ), CheckDescription( "AST fuzzer", "Runs randomly generated queries to catch program errors. " From 208912e559abd19778f10e711531cbad743d6122 Mon Sep 17 00:00:00 2001 From: Max K Date: Wed, 29 May 2024 21:40:22 +0200 Subject: [PATCH 194/211] CI: Change Required Check list, few fixes --- tests/ci/ci_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ci/ci_config.py b/tests/ci/ci_config.py index 3c681c9afb5..12899ccdee3 100644 --- a/tests/ci/ci_config.py +++ b/tests/ci/ci_config.py @@ -1425,7 +1425,7 @@ CHECK_DESCRIPTIONS = [ CheckDescription( StatusNames.SYNC, "If it fails, ask a maintainer for help", - lambda x: "Sync" in x, + lambda x: x == StatusNames.SYNC, ), CheckDescription( "AST fuzzer", From 3a8b95591dae3d8eba81e614924d967e51adb135 Mon Sep 17 00:00:00 2001 From: Max K Date: Wed, 29 May 2024 20:55:45 +0200 Subject: [PATCH 195/211] CI: Backports updates --- tests/ci/cherry_pick.py | 84 ++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 56 deletions(-) diff --git a/tests/ci/cherry_pick.py b/tests/ci/cherry_pick.py index 91a03e55d87..f81d84365ac 100644 --- a/tests/ci/cherry_pick.py +++ b/tests/ci/cherry_pick.py @@ -91,7 +91,7 @@ close it. name: str, pr: PullRequest, repo: Repository, - backport_created_label: str = Labels.PR_BACKPORTS_CREATED, + backport_created_label: str, ): self.name = name self.pr = pr @@ -119,8 +119,6 @@ close it. """the method processes all prs and pops the ReleaseBranch related prs""" to_pop = [] # type: List[int] for i, pr in enumerate(prs): - if self.name not in pr.head.ref: - continue if pr.head.ref.startswith(f"cherrypick/{self.name}"): self.cherrypick_pr = pr to_pop.append(i) @@ -128,10 +126,7 @@ close it. self.backport_pr = pr to_pop.append(i) else: - logging.error( - "head ref of PR #%s isn't starting with known suffix", - pr.number, - ) + assert False, "BUG! Invalid branch suffix" for i in reversed(to_pop): # Going from the tail to keep the order and pop greater index first prs.pop(i) @@ -225,7 +220,7 @@ close it. # There are changes to apply, so continue git_runner(f"{GIT_PREFIX} reset --merge") - # Push, create the cherrypick PR, lable and assign it + # Push, create the cherry-pick PR, label and assign it for branch in [self.cherrypick_branch, self.backport_branch]: git_runner(f"{GIT_PREFIX} push -f {self.REMOTE} {branch}:{branch}") @@ -351,16 +346,22 @@ class Backport: repo: str, fetch_from: Optional[str], dry_run: bool, - must_create_backport_labels: List[str], - backport_created_label: str, ): self.gh = gh self._repo_name = repo self._fetch_from = fetch_from self.dry_run = dry_run - self.must_create_backport_labels = must_create_backport_labels - self.backport_created_label = backport_created_label + self.must_create_backport_label = ( + Labels.MUST_BACKPORT + if self._repo_name == self._fetch_from + else Labels.MUST_BACKPORT_CLOUD + ) + self.backport_created_label = ( + Labels.PR_BACKPORTS_CREATED + if self._repo_name == self._fetch_from + else Labels.PR_BACKPORTS_CREATED_CLOUD + ) self._remote = "" self._remote_line = "" @@ -460,7 +461,7 @@ class Backport: query_args = { "query": f"type:pr repo:{self._fetch_from} -label:{self.backport_created_label}", "label": ",".join( - self.labels_to_backport + self.must_create_backport_labels + self.labels_to_backport + [self.must_create_backport_label] ), "merged": [since_date, tomorrow], } @@ -484,16 +485,12 @@ class Backport: def process_pr(self, pr: PullRequest) -> None: pr_labels = [label.name for label in pr.labels] - for label in self.must_create_backport_labels: - # We backport any vXXX-must-backport to all branches of the fetch repo (better than no backport) - if label in pr_labels or self._fetch_from: - branches = [ - ReleaseBranch(br, pr, self.repo, self.backport_created_label) - for br in self.release_branches - ] # type: List[ReleaseBranch] - break - - if not branches: + if self.must_create_backport_label in pr_labels: + branches = [ + ReleaseBranch(br, pr, self.repo, self.backport_created_label) + for br in self.release_branches + ] # type: List[ReleaseBranch] + else: branches = [ ReleaseBranch(br, pr, self.repo, self.backport_created_label) for br in [ @@ -502,20 +499,20 @@ class Backport: if label in self.labels_to_backport ] ] - if not branches: - # This is definitely some error. There must be at least one branch - # It also make the whole program exit code non-zero - self.error = Exception( - f"There are no branches to backport PR #{pr.number}, logical error" - ) - raise self.error + if not branches: + # This is definitely some error. There must be at least one branch + # It also make the whole program exit code non-zero + self.error = Exception( + f"There are no branches to backport PR #{pr.number}, logical error" + ) + raise self.error logging.info( " PR #%s is supposed to be backported to %s", pr.number, ", ".join(map(str, branches)), ) - # All PRs for cherrypick and backport branches as heads + # All PRs for cherry-pick and backport branches as heads query_suffix = " ".join( [ f"head:{branch.backport_branch} head:{branch.cherrypick_branch}" @@ -539,16 +536,10 @@ class Backport: ) raise self.error - if all(br.backported for br in branches): - # Let's check if the PR is already backported - self.mark_pr_backported(pr) - return - for br in branches: br.process(self.dry_run) if all(br.backported for br in branches): - # And check it after the running self.mark_pr_backported(pr) def mark_pr_backported(self, pr: PullRequest) -> None: @@ -586,19 +577,6 @@ def parse_args(): ) parser.add_argument("--dry-run", action="store_true", help="do not create anything") - parser.add_argument( - "--must-create-backport-label", - default=Labels.MUST_BACKPORT, - choices=(Labels.MUST_BACKPORT, Labels.MUST_BACKPORT_CLOUD), - help="label to filter PRs to backport", - nargs="+", - ) - parser.add_argument( - "--backport-created-label", - default=Labels.PR_BACKPORTS_CREATED, - choices=(Labels.PR_BACKPORTS_CREATED, Labels.PR_BACKPORTS_CREATED_CLOUD), - help="label to mark PRs as backported", - ) parser.add_argument( "--reserve-search-days", default=0, @@ -663,12 +641,6 @@ def main(): args.repo, args.from_repo, args.dry_run, - ( - args.must_create_backport_label - if isinstance(args.must_create_backport_label, list) - else [args.must_create_backport_label] - ), - args.backport_created_label, ) # https://github.com/python/mypy/issues/3004 bp.gh.cache_path = temp_path / "gh_cache" From a33fbc219623cacff2e2c44b83a79a7fc1ebd56a Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Thu, 30 May 2024 00:52:49 +0200 Subject: [PATCH 196/211] Changelog for 24.5 --- CHANGELOG.md | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 207b88f7860..382912ae173 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ ### Table of Contents +**[ClickHouse release v24.5, 2024-05-30](#245)**
      **[ClickHouse release v24.4, 2024-04-30](#244)**
      **[ClickHouse release v24.3 LTS, 2024-03-26](#243)**
      **[ClickHouse release v24.2, 2024-02-29](#242)**
      @@ -7,6 +8,181 @@ # 2024 Changelog +###
      ClickHouse release 24.5, 2024-05-30 + +### ClickHouse release master (09d68968703) FIXME as compared to v24.4.1.2088-stable (6d4b31322d1) + +#### Backward Incompatible Change +* Renamed "inverted indexes" to "full-text indexes" which is a less technical / more user-friendly name. This also changes internal table metadata and breaks tables with existing (experimental) inverted indexes. Please make to drop such indexes before upgrade and re-create them after upgrade. [#62884](https://github.com/ClickHouse/ClickHouse/pull/62884) ([Robert Schulze](https://github.com/rschu1ze)). +* Usage of functions `neighbor`, `runningAccumulate`, `runningDifferenceStartingWithFirstValue`, `runningDifference` deprecated (because it is error-prone). Proper window functions should be used instead. To enable them back, set `allow_deprecated_functions = 1` or set `compatibility = '24.4'` or lower. [#63132](https://github.com/ClickHouse/ClickHouse/pull/63132) ([Nikita Taranov](https://github.com/nickitat)). +* Queries from `system.columns` will work faster if there is a large number of columns, but many databases or tables are not granted for `SHOW TABLES`. Note that in previous versions, if you grant `SHOW COLUMNS` to individual columns without granting `SHOW TABLES` to the corresponding tables, the `system.columns` table will show these columns, but in a new version, it will skip the table entirely. Remove trace log messages "Access granted" and "Access denied" that slowed down queries. [#63439](https://github.com/ClickHouse/ClickHouse/pull/63439) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Setting `replace_long_file_name_to_hash` is enabled by default for `MergeTree` tables. [#64457](https://github.com/ClickHouse/ClickHouse/pull/64457) ([Anton Popov](https://github.com/CurtizJ)). The data written with this setting can be read by server versions since 23.9. After you use ClickHouse with this setting enabled, you cannot downgrade to versions 23.8 and earlier. + +#### New Feature +* Adds the `Form` format to read/write a single record in the `application/x-www-form-urlencoded` format. [#60199](https://github.com/ClickHouse/ClickHouse/pull/60199) ([Shaun Struwig](https://github.com/Blargian)). +* Added possibility to compress in CROSS JOIN. [#60459](https://github.com/ClickHouse/ClickHouse/pull/60459) ([p1rattttt](https://github.com/p1rattttt)). +* Added possibility to do `CROSS JOIN` in temporary files if the size exceeds limits. [#63432](https://github.com/ClickHouse/ClickHouse/pull/63432) ([p1rattttt](https://github.com/p1rattttt)). +* Support join with inequal conditions which involve columns from both left and right table. e.g. `t1.y < t2.y`. To enable, `SET allow_experimental_join_condition = 1`. [#60920](https://github.com/ClickHouse/ClickHouse/pull/60920) ([lgbo](https://github.com/lgbo-ustc)). +* Maps can now have `Float32`, `Float64`, `Array(T)`, `Map(K, V)` and `Tuple(T1, T2, ...)` as keys. Closes [#54537](https://github.com/ClickHouse/ClickHouse/issues/54537). [#59318](https://github.com/ClickHouse/ClickHouse/pull/59318) ([李扬](https://github.com/taiyang-li)). +* Introduce bulk loading to `EmbeddedRocksDB` by creating and ingesting SST file instead of relying on rocksdb build-in memtable. This help to increase importing speed, especially for long-running insert query to StorageEmbeddedRocksDB tables. Also, introduce `EmbeddedRocksDB` table settings. [#59163](https://github.com/ClickHouse/ClickHouse/pull/59163) [#63324](https://github.com/ClickHouse/ClickHouse/pull/63324) ([Duc Canh Le](https://github.com/canhld94)). +* User can now parse CRLF with TSV format using a setting `input_format_tsv_crlf_end_of_line`. Closes [#56257](https://github.com/ClickHouse/ClickHouse/issues/56257). [#59747](https://github.com/ClickHouse/ClickHouse/pull/59747) ([Shaun Struwig](https://github.com/Blargian)). +* A new setting `input_format_force_null_for_omitted_fields` that forces NULL values for omitted fields. [#60887](https://github.com/ClickHouse/ClickHouse/pull/60887) ([Constantine Peresypkin](https://github.com/pkit)). +* Earlier our S3 storage and s3 table function didn't support selecting from archive container files, such as tarballs, zip, 7z. Now they allow to iterate over files inside archives in S3. [#62259](https://github.com/ClickHouse/ClickHouse/pull/62259) ([Daniil Ivanik](https://github.com/divanik)). +* Support for conditional function `clamp`. [#62377](https://github.com/ClickHouse/ClickHouse/pull/62377) ([skyoct](https://github.com/skyoct)). +* Add `NPy` output format. [#62430](https://github.com/ClickHouse/ClickHouse/pull/62430) ([豪肥肥](https://github.com/HowePa)). +* `Raw` format as a synonym for `TSVRaw`. [#63394](https://github.com/ClickHouse/ClickHouse/pull/63394) ([Unalian](https://github.com/Unalian)). +* Added new SQL functions `generateSnowflakeID` for generating Twitter-style Snowflake IDs. [#63577](https://github.com/ClickHouse/ClickHouse/pull/63577) ([Danila Puzov](https://github.com/kazalika)). +* On Linux and MacOS, if the program has stdout redirected to a file with a compression extension, use the corresponding compression method instead of nothing (making it behave similarly to `INTO OUTFILE`). [#63662](https://github.com/ClickHouse/ClickHouse/pull/63662) ([v01dXYZ](https://github.com/v01dXYZ)). +* Change warning on high number of attached tables to differentiate tables, views and dictionaries. [#64180](https://github.com/ClickHouse/ClickHouse/pull/64180) ([Francisco J. Jurado Moreno](https://github.com/Beetelbrox)). +* Added SQL functions `fromReadableSize` (along with `OrNull` and `OrZero` variants) and `fromReadableDecimalSize` (also with `orNull` and `orZero` variants). These functions perform the opposite operation of function `formatReadableSize` and `formatReadableDecimalSize`, i.e. the given human-readable byte size, they return the number of bytes. Example: `SELECT fromReadableSize('3.0 MiB')` returns `3145728`. [#64386](https://github.com/ClickHouse/ClickHouse/pull/64386) ([Francisco J. Jurado Moreno](https://github.com/Beetelbrox)). +* Provide support for `azureBlobStorage` function in ClickHouse server to use Azure Workload identity to authenticate against Azure blob storage. If `use_workload_identity` parameter is set in config, [workload identity](https://github.com/Azure/azure-sdk-for-cpp/tree/main/sdk/identity/azure-identity#authenticate-azure-hosted-applications) is used for authentication. [#57881](https://github.com/ClickHouse/ClickHouse/pull/57881) ([Vinay Suryadevara](https://github.com/vinay92-ch)). +* Add TTL information in the `system.parts_columns` table. [#63200](https://github.com/ClickHouse/ClickHouse/pull/63200) ([litlig](https://github.com/litlig)). + +#### Experimental Features +* Implement `Dynamic` data type that allows to store values of any type inside it without knowing all of them in advance. `Dynamic` type is available under a setting `allow_experimental_dynamic_type`. Reference: [#54864](https://github.com/ClickHouse/ClickHouse/issues/54864). [#63058](https://github.com/ClickHouse/ClickHouse/pull/63058) ([Kruglov Pavel](https://github.com/Avogar)). +* Allowed to create `MaterializedMySQL` database without connection to MySQL. [#63397](https://github.com/ClickHouse/ClickHouse/pull/63397) ([Kirill](https://github.com/kirillgarbar)). +* Automatically mark a replica of Replicated database as lost and start recovery if some DDL task fails more than `max_retries_before_automatic_recovery` (100 by default) times in a row with the same error. Also, fixed a bug that could cause skipping DDL entries when an exception is thrown during an early stage of entry execution. [#63549](https://github.com/ClickHouse/ClickHouse/pull/63549) ([Alexander Tokmakov](https://github.com/tavplubix)). +* Account failed files in `s3queue_tracked_file_ttl_sec` and `s3queue_traked_files_limit` for `StorageS3Queue`. [#63638](https://github.com/ClickHouse/ClickHouse/pull/63638) ([Kseniia Sumarokova](https://github.com/kssenii)). + +#### Performance Improvement +* A native parquet reader, which can read parquet binary to ClickHouse columns directly. Now this feature can be activated by setting `input_format_parquet_use_native_reader` to true. [#60361](https://github.com/ClickHouse/ClickHouse/pull/60361) ([ZhiHong Zhang](https://github.com/copperybean)). +* Less contention in filesystem cache (part 4). Allow to keep filesystem cache not filled to the limit by doing additional eviction in the background (controlled by `keep_free_space_size(elements)_ratio`). This allows to release pressure from space reservation for queries (on `tryReserve` method). Also this is done in a lock free way as much as possible, e.g. should not block normal cache usage. [#61250](https://github.com/ClickHouse/ClickHouse/pull/61250) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Skip merging of newly created projection blocks during `INSERT`-s. [#59405](https://github.com/ClickHouse/ClickHouse/pull/59405) ([Nikita Taranov](https://github.com/nickitat)). +* Process string functions `...UTF8` 'asciily' if input strings are all ascii chars. Inspired by https://github.com/apache/doris/pull/29799. Overall speed up by 1.07x~1.62x. Notice that peak memory usage had been decreased in some cases. [#61632](https://github.com/ClickHouse/ClickHouse/pull/61632) ([李扬](https://github.com/taiyang-li)). +* Improved performance of selection (`{}`) globs in StorageS3. [#62120](https://github.com/ClickHouse/ClickHouse/pull/62120) ([Andrey Zvonov](https://github.com/zvonand)). +* HostResolver has each IP address several times. If remote host has several IPs and by some reason (firewall rules for example) access on some IPs allowed and on others forbidden, than only first record of forbidden IPs marked as failed, and in each try these IPs have a chance to be chosen (and failed again). Even if fix this, every 120 seconds DNS cache dropped, and IPs can be chosen again. [#62652](https://github.com/ClickHouse/ClickHouse/pull/62652) ([Anton Ivashkin](https://github.com/ianton-ru)). +* Function `splitByRegexp` is now faster when the regular expression argument is a single-character, trivial regular expression (in this case, it now falls back internally to `splitByChar`). [#62696](https://github.com/ClickHouse/ClickHouse/pull/62696) ([Robert Schulze](https://github.com/rschu1ze)). +* Aggregation with 8-bit and 16-bit keys became faster: added min/max in FixedHashTable to limit the array index and reduce the `isZero()` calls during iteration. [#62746](https://github.com/ClickHouse/ClickHouse/pull/62746) ([Jiebin Sun](https://github.com/jiebinn)). +* Add a new configuration`prefer_merge_sort_block_bytes` to control the memory usage and speed up sorting 2 times when merging when there are many columns. [#62904](https://github.com/ClickHouse/ClickHouse/pull/62904) ([LiuNeng](https://github.com/liuneng1994)). +* `clickhouse-local` will start faster. In previous versions, it was not deleting temporary directories by mistake. Now it will. This closes [#62941](https://github.com/ClickHouse/ClickHouse/issues/62941). [#63074](https://github.com/ClickHouse/ClickHouse/pull/63074) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Micro-optimizations for the new analyzer. [#63429](https://github.com/ClickHouse/ClickHouse/pull/63429) ([Raúl Marín](https://github.com/Algunenano)). +* Index analysis will work if `DateTime` is compared to `DateTime64`. This closes [#63441](https://github.com/ClickHouse/ClickHouse/issues/63441). [#63443](https://github.com/ClickHouse/ClickHouse/pull/63443) [#63532](https://github.com/ClickHouse/ClickHouse/pull/63532) ([Raúl Marín](https://github.com/Algunenano)). +* Speed up indices of type `set` a little (around 1.5 times) by removing garbage. [#64098](https://github.com/ClickHouse/ClickHouse/pull/64098) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Optimized vertical merges in tables with sparse columns. [#64311](https://github.com/ClickHouse/ClickHouse/pull/64311) ([Anton Popov](https://github.com/CurtizJ)). +* Improve filtering of sparse columns: reduce redundant calls of `ColumnSparse::filter` to improve performance. [#64426](https://github.com/ClickHouse/ClickHouse/pull/64426) ([Jiebin Sun](https://github.com/jiebinn)). +* Remove copying data when writing to the filesystem cache. [#63401](https://github.com/ClickHouse/ClickHouse/pull/63401) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Now backups with azure blob storage will use multicopy. [#64116](https://github.com/ClickHouse/ClickHouse/pull/64116) ([alesapin](https://github.com/alesapin)). +* Allow to use native copy for azure even with different containers. [#64154](https://github.com/ClickHouse/ClickHouse/pull/64154) ([alesapin](https://github.com/alesapin)). +* Finally enable native copy for azure. [#64182](https://github.com/ClickHouse/ClickHouse/pull/64182) ([alesapin](https://github.com/alesapin)). +* Improve the iteration over sparse columns to reduce call of `size`. [#64497](https://github.com/ClickHouse/ClickHouse/pull/64497) ([Jiebin Sun](https://github.com/jiebinn)). + +#### Improvement +* Allow using `clickhouse-local` and its shortcuts `clickhouse` and `ch` with a query or queries file as a positional argument. Examples: `ch "SELECT 1"`, `ch --param_test Hello "SELECT {test:String}"`, `ch query.sql`. This closes [#62361](https://github.com/ClickHouse/ClickHouse/issues/62361). [#63081](https://github.com/ClickHouse/ClickHouse/pull/63081) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Enable plain_rewritable metadata for local and Azure (azure_blob_storage) object storages. [#63365](https://github.com/ClickHouse/ClickHouse/pull/63365) ([Julia Kartseva](https://github.com/jkartseva)). +* Support English-style Unicode quotes, e.g. “Hello”, ‘world’. This is questionable in general but helpful when you type your query in a word processor, such as Google Docs. This closes [#58634](https://github.com/ClickHouse/ClickHouse/issues/58634). [#63381](https://github.com/ClickHouse/ClickHouse/pull/63381) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Allow trailing commas in the columns list in the INSERT query. For example, `INSERT INTO test (a, b, c, ) VALUES ...`. [#63803](https://github.com/ClickHouse/ClickHouse/pull/63803) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Better exception messages for the `Regexp` format. [#63804](https://github.com/ClickHouse/ClickHouse/pull/63804) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Allow trailing commas in the `Values` format. For example, this query is allowed: `INSERT INTO test (a, b, c) VALUES (4, 5, 6,);`. [#63810](https://github.com/ClickHouse/ClickHouse/pull/63810) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Make rabbitmq nack broken messages. Closes [#45350](https://github.com/ClickHouse/ClickHouse/issues/45350). [#60312](https://github.com/ClickHouse/ClickHouse/pull/60312) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix a crash in asynchronous stack unwinding (such as when using the sampling query profiler) while interpreting debug info. This closes [#60460](https://github.com/ClickHouse/ClickHouse/issues/60460). [#60468](https://github.com/ClickHouse/ClickHouse/pull/60468) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Distinct messages for s3 error 'no key' for cases disk and storage. [#61108](https://github.com/ClickHouse/ClickHouse/pull/61108) ([Sema Checherinda](https://github.com/CheSema)). +* The progress bar will work for trivial queries with LIMIT from `system.zeros`, `system.zeros_mt` (it already works for `system.numbers` and `system.numbers_mt`), and the `generateRandom` table function. As a bonus, if the total number of records is greater than the `max_rows_to_read` limit, it will throw an exception earlier. This closes [#58183](https://github.com/ClickHouse/ClickHouse/issues/58183). [#61823](https://github.com/ClickHouse/ClickHouse/pull/61823) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Support for "Merge Key" in YAML configurations (this is a weird feature of YAML, please never mind). [#62685](https://github.com/ClickHouse/ClickHouse/pull/62685) ([Azat Khuzhin](https://github.com/azat)). +* Enhance error message when non-deterministic function is used with Replicated source. [#62896](https://github.com/ClickHouse/ClickHouse/pull/62896) ([Grégoire Pineau](https://github.com/lyrixx)). +* Fix interserver secret for Distributed over Distributed from `remote`. [#63013](https://github.com/ClickHouse/ClickHouse/pull/63013) ([Azat Khuzhin](https://github.com/azat)). +* Support `include_from` for YAML files. However, you should better use `config.d` [#63106](https://github.com/ClickHouse/ClickHouse/pull/63106) ([Eduard Karacharov](https://github.com/korowa)). +* Keep previous data in terminal after picking from skim suggestions. [#63261](https://github.com/ClickHouse/ClickHouse/pull/63261) ([FlameFactory](https://github.com/FlameFactory)). +* Width of fields (in Pretty formats or the `visibleWidth` function) now correctly ignores ANSI escape sequences. [#63270](https://github.com/ClickHouse/ClickHouse/pull/63270) ([Shaun Struwig](https://github.com/Blargian)). +* Update the usage of error code `NUMBER_OF_ARGUMENTS_DOESNT_MATCH` by more accurate error codes when appropriate. [#63406](https://github.com/ClickHouse/ClickHouse/pull/63406) ([Yohann Jardin](https://github.com/yohannj)). +* `os_user` and `client_hostname` are now correctly set up for queries for command line suggestions in clickhouse-client. This closes [#63430](https://github.com/ClickHouse/ClickHouse/issues/63430). [#63433](https://github.com/ClickHouse/ClickHouse/pull/63433) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Automatically correct `max_block_size` to the default value if it is zero. [#63587](https://github.com/ClickHouse/ClickHouse/pull/63587) ([Antonio Andelic](https://github.com/antonio2368)). +* Add a build_id ALIAS column to trace_log to facilitate auto renaming upon detecting binary changes. This is to address [#52086](https://github.com/ClickHouse/ClickHouse/issues/52086). [#63656](https://github.com/ClickHouse/ClickHouse/pull/63656) ([Zimu Li](https://github.com/woodlzm)). +* Enable truncate operation for object storage disks. [#63693](https://github.com/ClickHouse/ClickHouse/pull/63693) ([MikhailBurdukov](https://github.com/MikhailBurdukov)). +* The loading of the keywords list is now dependent on the server revision and will be disabled for the old versions of ClickHouse server. CC @azat. [#63786](https://github.com/ClickHouse/ClickHouse/pull/63786) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)). +* Clickhouse disks have to read server setting to obtain actual metadata format version. [#63831](https://github.com/ClickHouse/ClickHouse/pull/63831) ([Sema Checherinda](https://github.com/CheSema)). +* Disable pretty format restrictions (`output_format_pretty_max_rows`/`output_format_pretty_max_value_width`) when stdout is not TTY. [#63942](https://github.com/ClickHouse/ClickHouse/pull/63942) ([Azat Khuzhin](https://github.com/azat)). +* Exception handling now works when ClickHouse is used inside AWS Lambda. Author: [Alexey Coolnev](https://github.com/acoolnev). [#64014](https://github.com/ClickHouse/ClickHouse/pull/64014) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Throw `CANNOT_DECOMPRESS` instread of `CORRUPTED_DATA` on invalid compressed data passed via HTTP. [#64036](https://github.com/ClickHouse/ClickHouse/pull/64036) ([vdimir](https://github.com/vdimir)). +* A tip for a single large number in Pretty formats now works for Nullable and LowCardinality. This closes [#61993](https://github.com/ClickHouse/ClickHouse/issues/61993). [#64084](https://github.com/ClickHouse/ClickHouse/pull/64084) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Added knob `metadata_storage_type` to keep free space on metadata storage disk. [#64128](https://github.com/ClickHouse/ClickHouse/pull/64128) ([MikhailBurdukov](https://github.com/MikhailBurdukov)). +* Add metrics, logs, and thread names around parts filtering with indices. [#64130](https://github.com/ClickHouse/ClickHouse/pull/64130) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Metrics to track the number of directories created and removed by the `plain_rewritable` metadata storage, and the number of entries in the local-to-remote in-memory map. [#64175](https://github.com/ClickHouse/ClickHouse/pull/64175) ([Julia Kartseva](https://github.com/jkartseva)). +* Ignore `allow_suspicious_primary_key` on `ATTACH` and verify on `ALTER`. [#64202](https://github.com/ClickHouse/ClickHouse/pull/64202) ([Azat Khuzhin](https://github.com/azat)). +* The query cache now considers identical queries with different settings as different. This increases robustness in cases where different settings (e.g. `limit` or `additional_table_filters`) would affect the query result. [#64205](https://github.com/ClickHouse/ClickHouse/pull/64205) ([Robert Schulze](https://github.com/rschu1ze)). +* Test that a non standard error code `QPSLimitExceeded` is supported and it is retryable error. [#64225](https://github.com/ClickHouse/ClickHouse/pull/64225) ([Sema Checherinda](https://github.com/CheSema)). +* Settings from the user config doesn't affect merges and mutations for MergeTree on top of object storage. [#64456](https://github.com/ClickHouse/ClickHouse/pull/64456) ([alesapin](https://github.com/alesapin)). +* Test that `totalqpslimitexceeded` is a retriable s3 error. [#64520](https://github.com/ClickHouse/ClickHouse/pull/64520) ([Sema Checherinda](https://github.com/CheSema)). + +#### Build/Testing/Packaging Improvement +* ClickHouse is built with clang-18. A lot of new checks from clang-tidy-18 have been enabled. [#60469](https://github.com/ClickHouse/ClickHouse/pull/60469) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Experimentally support loongarch64 as a new platform for ClickHouse. [#63733](https://github.com/ClickHouse/ClickHouse/pull/63733) ([qiangxuhui](https://github.com/qiangxuhui)). +* The Dockerfile is reviewed by the docker official library in https://github.com/docker-library/official-images/pull/15846. [#63400](https://github.com/ClickHouse/ClickHouse/pull/63400) ([Mikhail f. Shiryaev](https://github.com/Felixoid)). +* Information about every symbol in every translation unit will be collected in the CI database for every build in the CI. This closes [#63494](https://github.com/ClickHouse/ClickHouse/issues/63494). [#63495](https://github.com/ClickHouse/ClickHouse/pull/63495) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Update Apache Datasketches library. It resolves [#63858](https://github.com/ClickHouse/ClickHouse/issues/63858). [#63923](https://github.com/ClickHouse/ClickHouse/pull/63923) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Enable GRPC support for aarch64 linux while cross-compiling binary. [#64072](https://github.com/ClickHouse/ClickHouse/pull/64072) ([alesapin](https://github.com/alesapin)). +* Fix unwind on SIGSEGV on aarch64 (due to small stack for signal) [#64058](https://github.com/ClickHouse/ClickHouse/pull/64058) ([Azat Khuzhin](https://github.com/azat)). + +#### Bug Fix +* Disabled `enable_vertical_final` setting by default. This feature should not be used because it has a bug: [#64543](https://github.com/ClickHouse/ClickHouse/issues/64543). [#64544](https://github.com/ClickHouse/ClickHouse/pull/64544) ([Alexander Tokmakov](https://github.com/tavplubix)). +* Fix making backup when multiple shards are used [#57684](https://github.com/ClickHouse/ClickHouse/pull/57684) ([Vitaly Baranov](https://github.com/vitlibar)). +* Fix passing projections/indexes/primary key from columns list from CREATE query into inner table of MV [#59183](https://github.com/ClickHouse/ClickHouse/pull/59183) ([Azat Khuzhin](https://github.com/azat)). +* Fix boundRatio incorrect merge [#60532](https://github.com/ClickHouse/ClickHouse/pull/60532) ([Tao Wang](https://github.com/wangtZJU)). +* Fix crash when calling some functions on const low-cardinality columns [#61966](https://github.com/ClickHouse/ClickHouse/pull/61966) ([Michael Kolupaev](https://github.com/al13n321)). +* Fix queries with FINAL give wrong result when table does not use adaptive granularity [#62432](https://github.com/ClickHouse/ClickHouse/pull/62432) ([Duc Canh Le](https://github.com/canhld94)). +* Improve detection of cgroups v2 support for memory controllers [#62903](https://github.com/ClickHouse/ClickHouse/pull/62903) ([Robert Schulze](https://github.com/rschu1ze)). +* Fix subsequent use of external tables in client [#62964](https://github.com/ClickHouse/ClickHouse/pull/62964) ([Azat Khuzhin](https://github.com/azat)). +* Fix crash with untuple and unresolved lambda [#63131](https://github.com/ClickHouse/ClickHouse/pull/63131) ([Raúl Marín](https://github.com/Algunenano)). +* Fix premature server listen for connections [#63181](https://github.com/ClickHouse/ClickHouse/pull/63181) ([alesapin](https://github.com/alesapin)). +* Fix intersecting parts when restarting after a DROP PART command [#63202](https://github.com/ClickHouse/ClickHouse/pull/63202) ([Han Fei](https://github.com/hanfei1991)). +* Correctly load SQL security defaults during startup [#63209](https://github.com/ClickHouse/ClickHouse/pull/63209) ([pufit](https://github.com/pufit)). +* JOIN filter push down filter join fix [#63234](https://github.com/ClickHouse/ClickHouse/pull/63234) ([Maksim Kita](https://github.com/kitaisreal)). +* Fix infinite loop in AzureObjectStorage::listObjects [#63257](https://github.com/ClickHouse/ClickHouse/pull/63257) ([Julia Kartseva](https://github.com/jkartseva)). +* CROSS join ignore join_algorithm setting [#63273](https://github.com/ClickHouse/ClickHouse/pull/63273) ([vdimir](https://github.com/vdimir)). +* Fix finalize WriteBufferToFileSegment and StatusFile [#63346](https://github.com/ClickHouse/ClickHouse/pull/63346) ([vdimir](https://github.com/vdimir)). +* Fix logical error during SELECT query after ALTER in rare case [#63353](https://github.com/ClickHouse/ClickHouse/pull/63353) ([alesapin](https://github.com/alesapin)). +* Fix `X-ClickHouse-Timezone` header with `session_timezone` [#63377](https://github.com/ClickHouse/ClickHouse/pull/63377) ([Andrey Zvonov](https://github.com/zvonand)). +* Fix debug assert when using grouping WITH ROLLUP and LowCardinality types [#63398](https://github.com/ClickHouse/ClickHouse/pull/63398) ([Raúl Marín](https://github.com/Algunenano)). +* Small fixes for group_by_use_nulls [#63405](https://github.com/ClickHouse/ClickHouse/pull/63405) ([vdimir](https://github.com/vdimir)). +* Fix backup/restore of projection part in case projection was removed from table metadata, but part still has projection [#63426](https://github.com/ClickHouse/ClickHouse/pull/63426) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix mysql dictionary source [#63481](https://github.com/ClickHouse/ClickHouse/pull/63481) ([vdimir](https://github.com/vdimir)). +* Insert QueryFinish on AsyncInsertFlush with no data [#63483](https://github.com/ClickHouse/ClickHouse/pull/63483) ([Raúl Marín](https://github.com/Algunenano)). +* Fix: empty used_dictionaries in system.query_log [#63487](https://github.com/ClickHouse/ClickHouse/pull/63487) ([Eduard Karacharov](https://github.com/korowa)). +* Make `MergeTreePrefetchedReadPool` safer [#63513](https://github.com/ClickHouse/ClickHouse/pull/63513) ([Antonio Andelic](https://github.com/antonio2368)). +* Fix crash on exit with sentry enabled (due to openssl destroyed before sentry) [#63548](https://github.com/ClickHouse/ClickHouse/pull/63548) ([Azat Khuzhin](https://github.com/azat)). +* Fix Array and Map support with Keyed hashing [#63628](https://github.com/ClickHouse/ClickHouse/pull/63628) ([Salvatore Mesoraca](https://github.com/aiven-sal)). +* Fix filter pushdown for Parquet and maybe StorageMerge [#63642](https://github.com/ClickHouse/ClickHouse/pull/63642) ([Michael Kolupaev](https://github.com/al13n321)). +* Prevent conversion to Replicated if zookeeper path already exists [#63670](https://github.com/ClickHouse/ClickHouse/pull/63670) ([Kirill](https://github.com/kirillgarbar)). +* Analyzer: views read only necessary columns [#63688](https://github.com/ClickHouse/ClickHouse/pull/63688) ([Maksim Kita](https://github.com/kitaisreal)). +* Analyzer: Forbid WINDOW redefinition [#63694](https://github.com/ClickHouse/ClickHouse/pull/63694) ([Dmitry Novik](https://github.com/novikd)). +* flatten_nested was broken with the experimental Replicated database. [#63695](https://github.com/ClickHouse/ClickHouse/pull/63695) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix [#63653](https://github.com/ClickHouse/ClickHouse/issues/63653) [#63722](https://github.com/ClickHouse/ClickHouse/pull/63722) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Allow cast from Array(Nothing) to Map(Nothing, Nothing) [#63753](https://github.com/ClickHouse/ClickHouse/pull/63753) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix ILLEGAL_COLUMN in partial_merge join [#63755](https://github.com/ClickHouse/ClickHouse/pull/63755) ([vdimir](https://github.com/vdimir)). +* Fix: remove redundant distinct with window functions [#63776](https://github.com/ClickHouse/ClickHouse/pull/63776) ([Igor Nikonov](https://github.com/devcrafter)). +* Fix possible crash with SYSTEM UNLOAD PRIMARY KEY [#63778](https://github.com/ClickHouse/ClickHouse/pull/63778) ([Raúl Marín](https://github.com/Algunenano)). +* Fix a query with duplicating cycling alias. [#63791](https://github.com/ClickHouse/ClickHouse/pull/63791) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Make `TokenIterator` lazy as it should be [#63801](https://github.com/ClickHouse/ClickHouse/pull/63801) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Add `endpoint_subpath` S3 URI setting [#63806](https://github.com/ClickHouse/ClickHouse/pull/63806) ([Julia Kartseva](https://github.com/jkartseva)). +* Fix deadlock in `ParallelReadBuffer` [#63814](https://github.com/ClickHouse/ClickHouse/pull/63814) ([Antonio Andelic](https://github.com/antonio2368)). +* JOIN filter push down equivalent columns fix [#63819](https://github.com/ClickHouse/ClickHouse/pull/63819) ([Maksim Kita](https://github.com/kitaisreal)). +* Remove data from all disks after DROP with Lazy database. [#63848](https://github.com/ClickHouse/ClickHouse/pull/63848) ([MikhailBurdukov](https://github.com/MikhailBurdukov)). +* Fix incorrect result when reading from MV with parallel replicas and new analyzer [#63861](https://github.com/ClickHouse/ClickHouse/pull/63861) ([Nikita Taranov](https://github.com/nickitat)). +* Fixes in `find_super_nodes` and `find_big_family` command of keeper-client [#63862](https://github.com/ClickHouse/ClickHouse/pull/63862) ([Alexander Gololobov](https://github.com/davenger)). +* Update lambda execution name [#63864](https://github.com/ClickHouse/ClickHouse/pull/63864) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix SIGSEGV due to CPU/Real profiler [#63865](https://github.com/ClickHouse/ClickHouse/pull/63865) ([Azat Khuzhin](https://github.com/azat)). +* Fix `EXPLAIN CURRENT TRANSACTION` query [#63926](https://github.com/ClickHouse/ClickHouse/pull/63926) ([Anton Popov](https://github.com/CurtizJ)). +* Fix analyzer: there's turtles all the way down... [#63930](https://github.com/ClickHouse/ClickHouse/pull/63930) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). +* Allow certain ALTER TABLE commands for `plain_rewritable` disk [#63933](https://github.com/ClickHouse/ClickHouse/pull/63933) ([Julia Kartseva](https://github.com/jkartseva)). +* Recursive CTE distributed fix [#63939](https://github.com/ClickHouse/ClickHouse/pull/63939) ([Maksim Kita](https://github.com/kitaisreal)). +* Fix reading of columns of type `Tuple(Map(LowCardinality(...)))` [#63956](https://github.com/ClickHouse/ClickHouse/pull/63956) ([Anton Popov](https://github.com/CurtizJ)). +* Analyzer: Fix COLUMNS resolve [#63962](https://github.com/ClickHouse/ClickHouse/pull/63962) ([Dmitry Novik](https://github.com/novikd)). +* LIMIT BY and skip_unused_shards with analyzer [#63983](https://github.com/ClickHouse/ClickHouse/pull/63983) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* A fix for some trash (experimental Kusto) [#63992](https://github.com/ClickHouse/ClickHouse/pull/63992) ([Yong Wang](https://github.com/kashwy)). +* Deserialize untrusted binary inputs in a safer way [#64024](https://github.com/ClickHouse/ClickHouse/pull/64024) ([Robert Schulze](https://github.com/rschu1ze)). +* Fix query analysis for queries with the setting `final` = 1 for Distributed tables over tables from other than the MergeTree family. [#64037](https://github.com/ClickHouse/ClickHouse/pull/64037) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Add missing settings to recoverLostReplica [#64040](https://github.com/ClickHouse/ClickHouse/pull/64040) ([Raúl Marín](https://github.com/Algunenano)). +* Fix SQL security access checks with analyzer [#64079](https://github.com/ClickHouse/ClickHouse/pull/64079) ([pufit](https://github.com/pufit)). +* Fix analyzer: only interpolate expression should be used for DAG [#64096](https://github.com/ClickHouse/ClickHouse/pull/64096) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). +* Fix azure backup writing multipart blocks by 1 MiB (read buffer size) instead of `max_upload_part_size` (in non-native copy case) [#64117](https://github.com/ClickHouse/ClickHouse/pull/64117) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Correctly fallback during backup copy [#64153](https://github.com/ClickHouse/ClickHouse/pull/64153) ([Antonio Andelic](https://github.com/antonio2368)). +* Prevent LOGICAL_ERROR on CREATE TABLE as Materialized View [#64174](https://github.com/ClickHouse/ClickHouse/pull/64174) ([Raúl Marín](https://github.com/Algunenano)). +* Query Cache: Consider identical queries against different databases as different [#64199](https://github.com/ClickHouse/ClickHouse/pull/64199) ([Robert Schulze](https://github.com/rschu1ze)). +* Ignore `text_log` for Keeper [#64218](https://github.com/ClickHouse/ClickHouse/pull/64218) ([Antonio Andelic](https://github.com/antonio2368)). +* Fix ARRAY JOIN with Distributed. [#64226](https://github.com/ClickHouse/ClickHouse/pull/64226) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix: CNF with mutually exclusive atoms reduction [#64256](https://github.com/ClickHouse/ClickHouse/pull/64256) ([Eduard Karacharov](https://github.com/korowa)). +* Fix Logical error: Bad cast for Buffer table with prewhere. [#64388](https://github.com/ClickHouse/ClickHouse/pull/64388) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). + + ### ClickHouse release 24.4, 2024-04-30 #### Upgrade Notes From 179bf6a0cb7d7a79babc89e7d8270eaa519007fa Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Thu, 30 May 2024 00:57:33 +0200 Subject: [PATCH 197/211] Update CHANGELOG.md --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 382912ae173..161b0604d33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,6 @@ ### ClickHouse release 24.5, 2024-05-30 -### ClickHouse release master (09d68968703) FIXME as compared to v24.4.1.2088-stable (6d4b31322d1) - #### Backward Incompatible Change * Renamed "inverted indexes" to "full-text indexes" which is a less technical / more user-friendly name. This also changes internal table metadata and breaks tables with existing (experimental) inverted indexes. Please make to drop such indexes before upgrade and re-create them after upgrade. [#62884](https://github.com/ClickHouse/ClickHouse/pull/62884) ([Robert Schulze](https://github.com/rschu1ze)). * Usage of functions `neighbor`, `runningAccumulate`, `runningDifferenceStartingWithFirstValue`, `runningDifference` deprecated (because it is error-prone). Proper window functions should be used instead. To enable them back, set `allow_deprecated_functions = 1` or set `compatibility = '24.4'` or lower. [#63132](https://github.com/ClickHouse/ClickHouse/pull/63132) ([Nikita Taranov](https://github.com/nickitat)). From 486e54c3397c3a9b7cdf570aa1f9ab2ae4dd7038 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Thu, 30 May 2024 01:12:30 +0200 Subject: [PATCH 198/211] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 161b0604d33..5f60bc60656 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ * Added new SQL functions `generateSnowflakeID` for generating Twitter-style Snowflake IDs. [#63577](https://github.com/ClickHouse/ClickHouse/pull/63577) ([Danila Puzov](https://github.com/kazalika)). * On Linux and MacOS, if the program has stdout redirected to a file with a compression extension, use the corresponding compression method instead of nothing (making it behave similarly to `INTO OUTFILE`). [#63662](https://github.com/ClickHouse/ClickHouse/pull/63662) ([v01dXYZ](https://github.com/v01dXYZ)). * Change warning on high number of attached tables to differentiate tables, views and dictionaries. [#64180](https://github.com/ClickHouse/ClickHouse/pull/64180) ([Francisco J. Jurado Moreno](https://github.com/Beetelbrox)). -* Added SQL functions `fromReadableSize` (along with `OrNull` and `OrZero` variants) and `fromReadableDecimalSize` (also with `orNull` and `orZero` variants). These functions perform the opposite operation of function `formatReadableSize` and `formatReadableDecimalSize`, i.e. the given human-readable byte size, they return the number of bytes. Example: `SELECT fromReadableSize('3.0 MiB')` returns `3145728`. [#64386](https://github.com/ClickHouse/ClickHouse/pull/64386) ([Francisco J. Jurado Moreno](https://github.com/Beetelbrox)). +* Added SQL functions `fromReadableSize` (along with `OrNull` and `OrZero` variants). This function performs the opposite operation of functions `formatReadableSize` and `formatReadableDecimalSize,` i.e., the given human-readable byte size; they return the number of bytes. Example: `SELECT fromReadableSize('3.0 MiB')` returns `3145728`. [#64386](https://github.com/ClickHouse/ClickHouse/pull/64386) ([Francisco J. Jurado Moreno](https://github.com/Beetelbrox)). * Provide support for `azureBlobStorage` function in ClickHouse server to use Azure Workload identity to authenticate against Azure blob storage. If `use_workload_identity` parameter is set in config, [workload identity](https://github.com/Azure/azure-sdk-for-cpp/tree/main/sdk/identity/azure-identity#authenticate-azure-hosted-applications) is used for authentication. [#57881](https://github.com/ClickHouse/ClickHouse/pull/57881) ([Vinay Suryadevara](https://github.com/vinay92-ch)). * Add TTL information in the `system.parts_columns` table. [#63200](https://github.com/ClickHouse/ClickHouse/pull/63200) ([litlig](https://github.com/litlig)). From 29f7e266db8152aa87574dafd44b59f945fc4e91 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Thu, 30 May 2024 01:48:47 +0200 Subject: [PATCH 199/211] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f60bc60656..64ff3b78065 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,7 +54,7 @@ * Add a new configuration`prefer_merge_sort_block_bytes` to control the memory usage and speed up sorting 2 times when merging when there are many columns. [#62904](https://github.com/ClickHouse/ClickHouse/pull/62904) ([LiuNeng](https://github.com/liuneng1994)). * `clickhouse-local` will start faster. In previous versions, it was not deleting temporary directories by mistake. Now it will. This closes [#62941](https://github.com/ClickHouse/ClickHouse/issues/62941). [#63074](https://github.com/ClickHouse/ClickHouse/pull/63074) ([Alexey Milovidov](https://github.com/alexey-milovidov)). * Micro-optimizations for the new analyzer. [#63429](https://github.com/ClickHouse/ClickHouse/pull/63429) ([Raúl Marín](https://github.com/Algunenano)). -* Index analysis will work if `DateTime` is compared to `DateTime64`. This closes [#63441](https://github.com/ClickHouse/ClickHouse/issues/63441). [#63443](https://github.com/ClickHouse/ClickHouse/pull/63443) [#63532](https://github.com/ClickHouse/ClickHouse/pull/63532) ([Raúl Marín](https://github.com/Algunenano)). +* Index analysis will work if `DateTime` is compared to `DateTime64`. This closes [#63441](https://github.com/ClickHouse/ClickHouse/issues/63441). [#63443](https://github.com/ClickHouse/ClickHouse/pull/63443) [#63532](https://github.com/ClickHouse/ClickHouse/pull/63532) ([Alexey Milovidov](https://github.com/alexey-milovidov)). * Speed up indices of type `set` a little (around 1.5 times) by removing garbage. [#64098](https://github.com/ClickHouse/ClickHouse/pull/64098) ([Alexey Milovidov](https://github.com/alexey-milovidov)). * Optimized vertical merges in tables with sparse columns. [#64311](https://github.com/ClickHouse/ClickHouse/pull/64311) ([Anton Popov](https://github.com/CurtizJ)). * Improve filtering of sparse columns: reduce redundant calls of `ColumnSparse::filter` to improve performance. [#64426](https://github.com/ClickHouse/ClickHouse/pull/64426) ([Jiebin Sun](https://github.com/jiebinn)). From 48bd68a93e8c505e519820cf39a5b560f52b15da Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Thu, 30 May 2024 09:55:26 +0200 Subject: [PATCH 200/211] Revert "Add `fromReadableSize` function" --- .../functions/other-functions.md | 236 ------------------ src/Functions/fromReadable.h | 221 ---------------- src/Functions/fromReadableDecimalSize.cpp | 122 --------- src/Functions/fromReadableSize.cpp | 124 --------- .../03166_fromReadableSize.reference | 53 ---- .../0_stateless/03166_fromReadableSize.sql | 118 --------- .../03167_fromReadableDecimalSize.reference | 53 ---- .../03167_fromReadableDecimalSize.sql | 117 --------- .../aspell-ignore/en/aspell-dict.txt | 6 - 9 files changed, 1050 deletions(-) delete mode 100644 src/Functions/fromReadable.h delete mode 100644 src/Functions/fromReadableDecimalSize.cpp delete mode 100644 src/Functions/fromReadableSize.cpp delete mode 100644 tests/queries/0_stateless/03166_fromReadableSize.reference delete mode 100644 tests/queries/0_stateless/03166_fromReadableSize.sql delete mode 100644 tests/queries/0_stateless/03167_fromReadableDecimalSize.reference delete mode 100644 tests/queries/0_stateless/03167_fromReadableDecimalSize.sql diff --git a/docs/en/sql-reference/functions/other-functions.md b/docs/en/sql-reference/functions/other-functions.md index 9ec9f68ada7..dfe1224f7b8 100644 --- a/docs/en/sql-reference/functions/other-functions.md +++ b/docs/en/sql-reference/functions/other-functions.md @@ -735,8 +735,6 @@ LIMIT 10 Given a size (number of bytes), this function returns a readable, rounded size with suffix (KB, MB, etc.) as string. -The opposite operations of this function are [fromReadableDecimalSize](#fromReadableDecimalSize), [fromReadableDecimalSizeOrZero](#fromReadableDecimalSizeOrZero), and [fromReadableDecimalSizeOrNull](#fromReadableDecimalSizeOrNull). - **Syntax** ```sql @@ -768,8 +766,6 @@ Result: Given a size (number of bytes), this function returns a readable, rounded size with suffix (KiB, MiB, etc.) as string. -The opposite operations of this function are [fromReadableSize](#fromReadableSize), [fromReadableSizeOrZero](#fromReadableSizeOrZero), and [fromReadableSizeOrNull](#fromReadableSizeOrNull). - **Syntax** ```sql @@ -894,238 +890,6 @@ SELECT └────────────────────┴────────────────────────────────────────────────┘ ``` -## fromReadableSize - -Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit (i.e. [ISO/IEC 80000-13](https://en.wikipedia.org/wiki/ISO/IEC_80000) unit), this function returns the corresponding number of bytes. -If the function is unable to parse the input value, it throws an exception. - -The opposite operation of this function is [formatReadableSize](#fromReadableSize). - -**Syntax** - -```sql -fromReadableSize(x) -``` - -**Arguments** - -- `x` : Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md)). - -**Returned value** - -- Number of bytes, rounded up to the nearest integer ([UInt64](../../sql-reference/data-types/int-uint.md)). - -**Example** - -```sql -SELECT - arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB']) AS readable_sizes, - fromReadableSize(readable_sizes) AS sizes -``` - -```text -┌─readable_sizes─┬───sizes─┐ -│ 1 B │ 1 │ -│ 1 KiB │ 1024 │ -│ 3 MiB │ 3145728 │ -│ 5.314 KiB │ 5442 │ -└────────────────┴─────────┘ -``` - -## fromReadableSizeOrNull - -Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit (i.e. [ISO/IEC 80000-13](https://en.wikipedia.org/wiki/ISO/IEC_80000) unit), this function returns the corresponding number of bytes. -If the function is unable to parse the input value, it returns `NULL`. - -The opposite operation of this function is [formatReadableSize](#fromReadableSize). - -**Syntax** - -```sql -fromReadableSizeOrNull(x) -``` - -**Arguments** - -- `x` : Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md)). - -**Returned value** - -- Number of bytes, rounded up to the nearest integer, or NULL if unable to parse the input (Nullable([UInt64](../../sql-reference/data-types/int-uint.md))). - -**Example** - -```sql -SELECT - arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, - fromReadableSizeOrNull(readable_sizes) AS sizes -``` - -```text -┌─readable_sizes─┬───sizes─┐ -│ 1 B │ 1 │ -│ 1 KiB │ 1024 │ -│ 3 MiB │ 3145728 │ -│ 5.314 KiB │ 5442 │ -│ invalid │ ᴺᵁᴸᴸ │ -└────────────────┴─────────┘ -``` - -## fromReadableSizeOrZero - -Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit (i.e. [ISO/IEC 80000-13](https://en.wikipedia.org/wiki/ISO/IEC_80000) unit), this function returns the corresponding number of bytes. -If the function is unable to parse the input value, it returns `0`. - -The opposite operation of this function is [formatReadableSize](#fromReadableSize). - -**Syntax** - -```sql -fromReadableSizeOrZero(x) -``` - -**Arguments** - -- `x` : Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md)). - -**Returned value** - -- Number of bytes, rounded up to the nearest integer, or 0 if unable to parse the input ([UInt64](../../sql-reference/data-types/int-uint.md)). - -**Example** - -```sql -SELECT - arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, - fromReadableSizeOrZero(readable_sizes) AS sizes -``` - -```text -┌─readable_sizes─┬───sizes─┐ -│ 1 B │ 1 │ -│ 1 KiB │ 1024 │ -│ 3 MiB │ 3145728 │ -│ 5.314 KiB │ 5442 │ -│ invalid │ 0 │ -└────────────────┴─────────┘ -``` - -## fromReadableDecimalSize - -Given a string containing a byte size and `B`, `KB`, `MB`, etc. as a unit, this function returns the corresponding number of bytes. -If the function is unable to parse the input value, it throws an exception. - -The opposite operation of this function is [formatReadableDecimalSize](#formatReadableDecimalSize). - -**Syntax** - -```sql -fromReadableDecimalSize(x) -``` - -**Arguments** - -- `x` : Readable size with decimal units ([String](../../sql-reference/data-types/string.md)). - -**Returned value** - -- Number of bytes, rounded up to the nearest integer ([UInt64](../../sql-reference/data-types/int-uint.md)). - -**Example** - -```sql -SELECT - arrayJoin(['1 B', '1 KB', '3 MB', '5.314 KB']) AS readable_sizes, - fromReadableDecimalSize(readable_sizes) AS sizes -``` - -```text -┌─readable_sizes─┬───sizes─┐ -│ 1 B │ 1 │ -│ 1 KB │ 1000 │ -│ 3 MB │ 3000000 │ -│ 5.314 KB │ 5314 │ -└────────────────┴─────────┘ -``` - -## fromReadableDecimalSizeOrNull - -Given a string containing a byte size and `B`, `KB`, `MB`, etc. as a unit, this function returns the corresponding number of bytes. -If the function is unable to parse the input value, it returns `NULL`. - -The opposite operation of this function is [formatReadableDecimalSize](#formatReadableDecimalSize). - -**Syntax** - -```sql -fromReadableDecimalSizeOrNull(x) -``` - -**Arguments** - -- `x` : Readable size with decimal units ([String](../../sql-reference/data-types/string.md)). - -**Returned value** - -- Number of bytes, rounded up to the nearest integer, or NULL if unable to parse the input (Nullable([UInt64](../../sql-reference/data-types/int-uint.md))). - -**Example** - -```sql -SELECT - arrayJoin(['1 B', '1 KB', '3 MB', '5.314 KB', 'invalid']) AS readable_sizes, - fromReadableDecimalSizeOrNull(readable_sizes) AS sizes -``` - -```text -┌─readable_sizes─┬───sizes─┐ -│ 1 B │ 1 │ -│ 1 KB │ 1000 │ -│ 3 MB │ 3000000 │ -│ 5.314 KB │ 5314 │ -│ invalid │ ᴺᵁᴸᴸ │ -└────────────────┴─────────┘ -``` - -## fromReadableDecimalSizeOrZero - -Given a string containing a byte size and `B`, `KB`, `MB`, etc. as a unit, this function returns the corresponding number of bytes. -If the function is unable to parse the input value, it returns `0`. - -The opposite operation of this function is [formatReadableDecimalSize](#formatReadableDecimalSize). - -**Syntax** - -```sql -fromReadableDecimalSizeOrZero(x) -``` - -**Arguments** - -- `x` : Readable size with decimal units ([String](../../sql-reference/data-types/string.md)). - -**Returned value** - -- Number of bytes, rounded up to the nearest integer, or 0 if unable to parse the input ([UInt64](../../sql-reference/data-types/int-uint.md)). - -**Example** - -```sql -SELECT - arrayJoin(['1 B', '1 KB', '3 MB', '5.314 KB', 'invalid']) AS readable_sizes, - fromReadableSizeOrZero(readable_sizes) AS sizes -``` - -```text -┌─readable_sizes─┬───sizes─┐ -│ 1 B │ 1 │ -│ 1 KB │ 1000 │ -│ 3 MB │ 3000000 │ -│ 5.314 KB │ 5000 │ -│ invalid │ 0 │ -└────────────────┴─────────┘ -``` - ## parseTimeDelta Parse a sequence of numbers followed by something resembling a time unit. diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h deleted file mode 100644 index 386250a617b..00000000000 --- a/src/Functions/fromReadable.h +++ /dev/null @@ -1,221 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace DB -{ - -namespace ErrorCodes -{ - extern const int BAD_ARGUMENTS; - extern const int CANNOT_PARSE_INPUT_ASSERTION_FAILED; - extern const int CANNOT_PARSE_NUMBER; - extern const int CANNOT_PARSE_TEXT; - extern const int ILLEGAL_COLUMN; - extern const int UNEXPECTED_DATA_AFTER_PARSED_VALUE; -} - -enum class ErrorHandling : uint8_t -{ - Exception, - Zero, - Null -}; - -using ScaleFactors = std::unordered_map; - -/** fromReadble*Size - Returns the number of bytes corresponding to a given readable binary or decimal size. - * Examples: - * - `fromReadableSize('123 MiB')` - * - `fromReadableDecimalSize('123 MB')` - * Meant to be the inverse of `formatReadable*Size` with the following exceptions: - * - Number of bytes is returned as an unsigned integer amount instead of a float. Decimal points are rounded up to the nearest integer. - * - Negative numbers are not allowed as negative sizes don't make sense. - * Flavours: - * - fromReadableSize - * - fromReadableSizeOrNull - * - fromReadableSizeOrZero - * - fromReadableDecimalSize - * - fromReadableDecimalSizeOrNull - * - fromReadableDecimalSizeOrZero - */ -template -class FunctionFromReadable : public IFunction -{ -public: - static constexpr auto name = Name::name; - static FunctionPtr create(ContextPtr) { return std::make_shared>(); } - - String getName() const override { return name; } - bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } - bool useDefaultImplementationForConstants() const override { return true; } - size_t getNumberOfArguments() const override { return 1; } - - DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override - { - FunctionArgumentDescriptors args - { - {"readable_size", static_cast(&isString), nullptr, "String"}, - }; - validateFunctionArgumentTypes(*this, arguments, args); - DataTypePtr return_type = std::make_shared(); - if (error_handling == ErrorHandling::Null) - return std::make_shared(return_type); - else - return return_type; - } - - - ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override - { - const auto * col_str = checkAndGetColumn(arguments[0].column.get()); - if (!col_str) - { - throw Exception( - ErrorCodes::ILLEGAL_COLUMN, - "Illegal column {} of first ('str') argument of function {}. Must be string.", - arguments[0].column->getName(), - getName() - ); - } - - const ScaleFactors & scale_factors = Impl::getScaleFactors(); - - auto col_res = ColumnUInt64::create(input_rows_count); - - ColumnUInt8::MutablePtr col_null_map; - if constexpr (error_handling == ErrorHandling::Null) - col_null_map = ColumnUInt8::create(input_rows_count, 0); - - auto & res_data = col_res->getData(); - - for (size_t i = 0; i < input_rows_count; ++i) - { - std::string_view value = col_str->getDataAt(i).toView(); - try - { - UInt64 num_bytes = parseReadableFormat(scale_factors, value); - res_data[i] = num_bytes; - } - catch (const Exception &) - { - if constexpr (error_handling == ErrorHandling::Exception) - { - throw; - } - else - { - res_data[i] = 0; - if constexpr (error_handling == ErrorHandling::Null) - col_null_map->getData()[i] = 1; - } - } - } - if constexpr (error_handling == ErrorHandling::Null) - return ColumnNullable::create(std::move(col_res), std::move(col_null_map)); - else - return col_res; - } - -private: - - UInt64 parseReadableFormat(const ScaleFactors & scale_factors, const std::string_view & value) const - { - ReadBufferFromString buf(value); - - // tryReadFloatText does seem to not raise any error when there is leading whitespace so we check it explicitly - skipWhitespaceIfAny(buf); - if (buf.getPosition() > 0) - { - throw Exception( - ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED, - "Invalid expression for function {} - Leading whitespace is not allowed (\"{}\")", - getName(), - value - ); - } - - Float64 base = 0; - if (!tryReadFloatTextPrecise(base, buf)) // If we use the default (fast) tryReadFloatText this returns True on garbage input so we use the Precise version - { - throw Exception( - ErrorCodes::CANNOT_PARSE_NUMBER, - "Invalid expression for function {} - Unable to parse readable size numeric component (\"{}\")", - getName(), - value - ); - } - else if (std::isnan(base) || !std::isfinite(base)) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {} - Invalid numeric component: {}", - getName(), - base - ); - } - else if (base < 0) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {} - Negative sizes are not allowed ({})", - getName(), - base - ); - } - - skipWhitespaceIfAny(buf); - - String unit; - readStringUntilWhitespace(unit, buf); - boost::algorithm::to_lower(unit); - auto iter = scale_factors.find(unit); - if (iter == scale_factors.end()) - { - throw Exception( - ErrorCodes::CANNOT_PARSE_TEXT, - "Invalid expression for function {} - Unknown readable size unit (\"{}\")", - getName(), - unit - ); - } - else if (!buf.eof()) - { - throw Exception( - ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, - "Invalid expression for function {} - Found trailing characters after readable size string (\"{}\")", - getName(), - value - ); - } - - Float64 num_bytes_with_decimals = base * iter->second; - if (num_bytes_with_decimals > std::numeric_limits::max()) - { - throw Exception( - ErrorCodes::BAD_ARGUMENTS, - "Invalid expression for function {} - Result is too big for output type (\"{}\")", - getName(), - num_bytes_with_decimals - ); - } - // As the input might be an arbitrary decimal number we might end up with a non-integer amount of bytes when parsing binary (eg MiB) units. - // This doesn't make sense so we round up to indicate the byte size that can fit the passed size. - return static_cast(std::ceil(num_bytes_with_decimals)); - } -}; -} diff --git a/src/Functions/fromReadableDecimalSize.cpp b/src/Functions/fromReadableDecimalSize.cpp deleted file mode 100644 index 6efabe7267d..00000000000 --- a/src/Functions/fromReadableDecimalSize.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include -#include -#include - -namespace DB -{ - -namespace -{ - -struct Impl -{ - static const ScaleFactors & getScaleFactors() - { - static const ScaleFactors scale_factors = - { - {"b", 1ull}, - {"kb", 1000ull}, - {"mb", 1000ull * 1000ull}, - {"gb", 1000ull * 1000ull * 1000ull}, - {"tb", 1000ull * 1000ull * 1000ull * 1000ull}, - {"pb", 1000ull * 1000ull * 1000ull * 1000ull * 1000ull}, - {"eb", 1000ull * 1000ull * 1000ull * 1000ull * 1000ull * 1000ull}, - }; - - return scale_factors; - } -}; - -struct NameFromReadableDecimalSize -{ - static constexpr auto name = "fromReadableDecimalSize"; -}; - -struct NameFromReadableDecimalSizeOrNull -{ - static constexpr auto name = "fromReadableDecimalSizeOrNull"; -}; - -struct NameFromReadableDecimalSizeOrZero -{ - static constexpr auto name = "fromReadableDecimalSizeOrZero"; -}; - -using FunctionFromReadableDecimalSize = FunctionFromReadable; -using FunctionFromReadableDecimalSizeOrNull = FunctionFromReadable; -using FunctionFromReadableDecimalSizeOrZero = FunctionFromReadable; - - -FunctionDocumentation fromReadableDecimalSize_documentation { - .description = "Given a string containing a byte size and `B`, `KB`, `MB`, etc. as a unit, this function returns the corresponding number of bytes. If the function is unable to parse the input value, it throws an exception.", - .syntax = "fromReadableDecimalSize(x)", - .arguments = {{"x", "Readable size with decimal units ([String](../../sql-reference/data-types/string.md))"}}, - .returned_value = "Number of bytes, rounded up to the nearest integer ([UInt64](../../sql-reference/data-types/int-uint.md))", - .examples = { - { - "basic", - "SELECT arrayJoin(['1 B', '1 KB', '3 MB', '5.314 KB']) AS readable_sizes, fromReadableDecimalSize(readable_sizes) AS sizes;", - R"( -┌─readable_sizes─┬───sizes─┐ -│ 1 B │ 1 │ -│ 1 KB │ 1000 │ -│ 3 MB │ 3000000 │ -│ 5.314 KB │ 5314 │ -└────────────────┴─────────┘)" - }, - }, - .categories = {"OtherFunctions"}, -}; - -FunctionDocumentation fromReadableDecimalSizeOrNull_documentation { - .description = "Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit, this function returns the corresponding number of bytes. If the function is unable to parse the input value, it returns `NULL`", - .syntax = "fromReadableDecimalSizeOrNull(x)", - .arguments = {{"x", "Readable size with decimal units ([String](../../sql-reference/data-types/string.md))"}}, - .returned_value = "Number of bytes, rounded up to the nearest integer, or NULL if unable to parse the input (Nullable([UInt64](../../sql-reference/data-types/int-uint.md)))", - .examples = { - { - "basic", - "SELECT arrayJoin(['1 B', '1 KB', '3 MB', '5.314 KB', 'invalid']) AS readable_sizes, fromReadableSizeOrNull(readable_sizes) AS sizes;", - R"( -┌─readable_sizes─┬───sizes─┐ -│ 1 B │ 1 │ -│ 1 KB │ 1000 │ -│ 3 MB │ 3000000 │ -│ 5.314 KB │ 5314 │ -│ invalid │ ᴺᵁᴸᴸ │ -└────────────────┴─────────┘)" - }, - }, - .categories = {"OtherFunctions"}, -}; - -FunctionDocumentation fromReadableDecimalSizeOrZero_documentation { - .description = "Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit, this function returns the corresponding number of bytes. If the function is unable to parse the input value, it returns `0`", - .syntax = "formatReadableSizeOrZero(x)", - .arguments = {{"x", "Readable size with decimal units ([String](../../sql-reference/data-types/string.md))"}}, - .returned_value = "Number of bytes, rounded up to the nearest integer, or 0 if unable to parse the input ([UInt64](../../sql-reference/data-types/int-uint.md))", - .examples = { - { - "basic", - "SELECT arrayJoin(['1 B', '1 KB', '3 MB', '5.314 KB', 'invalid']) AS readable_sizes, fromReadableSizeOrZero(readable_sizes) AS sizes;", - R"( -┌─readable_sizes─┬───sizes─┐ -│ 1 B │ 1 │ -│ 1 KB │ 1000 │ -│ 3 MB │ 3000000 │ -│ 5.314 KB │ 5000 │ -│ invalid │ 0 │ -└────────────────┴─────────┘)" - }, - }, - .categories = {"OtherFunctions"}, -}; -} - -REGISTER_FUNCTION(FromReadableDecimalSize) -{ - factory.registerFunction(fromReadableDecimalSize_documentation); - factory.registerFunction(fromReadableDecimalSizeOrNull_documentation); - factory.registerFunction(fromReadableDecimalSizeOrZero_documentation); -} -} diff --git a/src/Functions/fromReadableSize.cpp b/src/Functions/fromReadableSize.cpp deleted file mode 100644 index 425fb25e0fd..00000000000 --- a/src/Functions/fromReadableSize.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include -#include -#include "Common/FunctionDocumentation.h" - -namespace DB -{ - -namespace -{ - -struct Impl -{ - static const ScaleFactors & getScaleFactors() - { - // ISO/IEC 80000-13 binary units - static const ScaleFactors scale_factors = - { - {"b", 1ull}, - {"kib", 1024ull}, - {"mib", 1024ull * 1024ull}, - {"gib", 1024ull * 1024ull * 1024ull}, - {"tib", 1024ull * 1024ull * 1024ull * 1024ull}, - {"pib", 1024ull * 1024ull * 1024ull * 1024ull * 1024ull}, - {"eib", 1024ull * 1024ull * 1024ull * 1024ull * 1024ull * 1024ull}, - }; - - return scale_factors; - } -}; - - -struct NameFromReadableSize -{ - static constexpr auto name = "fromReadableSize"; -}; - -struct NameFromReadableSizeOrNull -{ - static constexpr auto name = "fromReadableSizeOrNull"; -}; - -struct NameFromReadableSizeOrZero -{ - static constexpr auto name = "fromReadableSizeOrZero"; -}; - -using FunctionFromReadableSize = FunctionFromReadable; -using FunctionFromReadableSizeOrNull = FunctionFromReadable; -using FunctionFromReadableSizeOrZero = FunctionFromReadable; - -FunctionDocumentation fromReadableSize_documentation { - .description = "Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit (i.e. [ISO/IEC 80000-13](https://en.wikipedia.org/wiki/ISO/IEC_80000) unit), this function returns the corresponding number of bytes. If the function is unable to parse the input value, it throws an exception.", - .syntax = "fromReadableSize(x)", - .arguments = {{"x", "Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md))"}}, - .returned_value = "Number of bytes, rounded up to the nearest integer ([UInt64](../../sql-reference/data-types/int-uint.md))", - .examples = { - { - "basic", - "SELECT arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB']) AS readable_sizes, fromReadableSize(readable_sizes) AS sizes;", - R"( -┌─readable_sizes─┬───sizes─┐ -│ 1 B │ 1 │ -│ 1 KiB │ 1024 │ -│ 3 MiB │ 3145728 │ -│ 5.314 KiB │ 5442 │ -└────────────────┴─────────┘)" - }, - }, - .categories = {"OtherFunctions"}, -}; - -FunctionDocumentation fromReadableSizeOrNull_documentation { - .description = "Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit (i.e. [ISO/IEC 80000-13](https://en.wikipedia.org/wiki/ISO/IEC_80000) unit), this function returns the corresponding number of bytes. If the function is unable to parse the input value, it returns `NULL`", - .syntax = "fromReadableSizeOrNull(x)", - .arguments = {{"x", "Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md))"}}, - .returned_value = "Number of bytes, rounded up to the nearest integer, or NULL if unable to parse the input (Nullable([UInt64](../../sql-reference/data-types/int-uint.md)))", - .examples = { - { - "basic", - "SELECT arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, fromReadableSize(readable_sizes) AS sizes;", - R"( -┌─readable_sizes─┬───sizes─┐ -│ 1 B │ 1 │ -│ 1 KiB │ 1024 │ -│ 3 MiB │ 3145728 │ -│ 5.314 KiB │ 5442 │ -│ invalid │ ᴺᵁᴸᴸ │ -└────────────────┴─────────┘)" - }, - }, - .categories = {"OtherFunctions"}, -}; - -FunctionDocumentation fromReadableSizeOrZero_documentation { - .description = "Given a string containing a byte size and `B`, `KiB`, `MiB`, etc. as a unit (i.e. [ISO/IEC 80000-13](https://en.wikipedia.org/wiki/ISO/IEC_80000) unit), this function returns the corresponding number of bytes. If the function is unable to parse the input value, it returns `0`", - .syntax = "fromReadableSizeOrZero(x)", - .arguments = {{"x", "Readable size with ISO/IEC 80000-13 units ([String](../../sql-reference/data-types/string.md))"}}, - .returned_value = "Number of bytes, rounded up to the nearest integer, or 0 if unable to parse the input ([UInt64](../../sql-reference/data-types/int-uint.md))", - .examples = { - { - "basic", - "SELECT arrayJoin(['1 B', '1 KiB', '3 MiB', '5.314 KiB', 'invalid']) AS readable_sizes, fromReadableSize(readable_sizes) AS sizes;", - R"( -┌─readable_sizes─┬───sizes─┐ -│ 1 B │ 1 │ -│ 1 KiB │ 1024 │ -│ 3 MiB │ 3145728 │ -│ 5.314 KiB │ 5442 │ -│ invalid │ 0 │ -└────────────────┴─────────┘)", - }, - }, - .categories = {"OtherFunctions"}, -}; -} - -REGISTER_FUNCTION(FromReadableSize) -{ - factory.registerFunction(fromReadableSize_documentation); - factory.registerFunction(fromReadableSizeOrNull_documentation); - factory.registerFunction(fromReadableSizeOrZero_documentation); -} -} diff --git a/tests/queries/0_stateless/03166_fromReadableSize.reference b/tests/queries/0_stateless/03166_fromReadableSize.reference deleted file mode 100644 index 6fb54d99171..00000000000 --- a/tests/queries/0_stateless/03166_fromReadableSize.reference +++ /dev/null @@ -1,53 +0,0 @@ -1.00 B -1.00 KiB -1.00 MiB -1.00 GiB -1.00 TiB -1.00 PiB -1.00 EiB -1.00 MiB -1024 -3072 -1024 -1024 -1024 -1024 -1024 -\N -3217 -3217 -1000 -5 -2048 -8192 -0 0 0 -1 B 1 -1 KiB 1024 -1 MiB 1048576 -1 GiB 1073741824 -1 TiB 1099511627776 -1 PiB 1125899906842624 -1 EiB 1152921504606846976 -invalid \N -1 Joe \N -1KB \N - 1 GiB \N -1 TiB with fries \N -NaN KiB \N -Inf KiB \N -0xa123 KiB \N -1 B 1 -1 KiB 1024 -1 MiB 1048576 -1 GiB 1073741824 -1 TiB 1099511627776 -1 PiB 1125899906842624 -1 EiB 1152921504606846976 -invalid 0 -1 Joe 0 -1KB 0 - 1 GiB 0 -1 TiB with fries 0 -NaN KiB 0 -Inf KiB 0 -0xa123 KiB 0 diff --git a/tests/queries/0_stateless/03166_fromReadableSize.sql b/tests/queries/0_stateless/03166_fromReadableSize.sql deleted file mode 100644 index 2983280320c..00000000000 --- a/tests/queries/0_stateless/03166_fromReadableSize.sql +++ /dev/null @@ -1,118 +0,0 @@ --- Should be kept in sync with 03167_fromReadableDecimalSize.sql - --- Should be the inverse of formatReadableSize -SELECT formatReadableSize(fromReadableSize('1 B')); -SELECT formatReadableSize(fromReadableSize('1 KiB')); -SELECT formatReadableSize(fromReadableSize('1 MiB')); -SELECT formatReadableSize(fromReadableSize('1 GiB')); -SELECT formatReadableSize(fromReadableSize('1 TiB')); -SELECT formatReadableSize(fromReadableSize('1 PiB')); -SELECT formatReadableSize(fromReadableSize('1 EiB')); - --- Is case-insensitive -SELECT formatReadableSize(fromReadableSize('1 mIb')); - --- Should be able to parse decimals -SELECT fromReadableSize('1.00 KiB'); -- 1024 -SELECT fromReadableSize('3.00 KiB'); -- 3072 - --- Infix whitespace is ignored -SELECT fromReadableSize('1 KiB'); -SELECT fromReadableSize('1KiB'); - --- Can parse LowCardinality -SELECT fromReadableSize(toLowCardinality('1 KiB')); - --- Can parse nullable fields -SELECT fromReadableSize(toNullable('1 KiB')); - --- Can parse non-const columns fields -SELECT fromReadableSize(materialize('1 KiB')); - --- Output is NULL if NULL arg is passed -SELECT fromReadableSize(NULL); - --- Can parse more decimal places than Float64's precision -SELECT fromReadableSize('3.14159265358979323846264338327950288419716939937510 KiB'); - --- Can parse sizes prefixed with a plus sign -SELECT fromReadableSize('+3.1415 KiB'); - --- Can parse amounts in scientific notation -SELECT fromReadableSize('10e2 B'); - --- Can parse floats with no decimal points -SELECT fromReadableSize('5. B'); - --- Can parse numbers with leading zeroes -SELECT fromReadableSize('002 KiB'); - --- Can parse octal-like -SELECT fromReadableSize('08 KiB'); - --- Can parse various flavours of zero -SELECT fromReadableSize('0 KiB'), fromReadableSize('+0 KiB'), fromReadableSize('-0 KiB'); - --- ERRORS --- No arguments -SELECT fromReadableSize(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } --- Too many arguments -SELECT fromReadableSize('1 B', '2 B'); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } --- Wrong Type -SELECT fromReadableSize(12); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT } --- Invalid input - overall garbage -SELECT fromReadableSize('oh no'); -- { serverError CANNOT_PARSE_NUMBER } --- Invalid input - unknown unit -SELECT fromReadableSize('12.3 rb'); -- { serverError CANNOT_PARSE_TEXT } --- Invalid input - Leading whitespace -SELECT fromReadableSize(' 1 B'); -- { serverError CANNOT_PARSE_INPUT_ASSERTION_FAILED } --- Invalid input - Trailing characters -SELECT fromReadableSize('1 B leftovers'); -- { serverError UNEXPECTED_DATA_AFTER_PARSED_VALUE } --- Invalid input - Decimal size unit is not accepted -SELECT fromReadableSize('1 KB'); -- { serverError CANNOT_PARSE_TEXT } --- Invalid input - Negative sizes are not allowed -SELECT fromReadableSize('-1 KiB'); -- { serverError BAD_ARGUMENTS } --- Invalid input - Input too large to fit in UInt64 -SELECT fromReadableSize('1000 EiB'); -- { serverError BAD_ARGUMENTS } --- Invalid input - Hexadecimal is not supported -SELECT fromReadableSize('0xa123 KiB'); -- { serverError CANNOT_PARSE_TEXT } --- Invalid input - NaN is not supported, with or without sign and with different capitalizations -SELECT fromReadableSize('nan KiB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableSize('+nan KiB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableSize('-nan KiB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableSize('NaN KiB'); -- { serverError BAD_ARGUMENTS } --- Invalid input - Infinite is not supported, with or without sign, in all its forms -SELECT fromReadableSize('inf KiB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableSize('+inf KiB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableSize('-inf KiB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableSize('infinite KiB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableSize('+infinite KiB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableSize('-infinite KiB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableSize('Inf KiB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableSize('Infinite KiB'); -- { serverError BAD_ARGUMENTS } - - - --- OR NULL --- Works as the regular version when inputs are correct -SELECT - arrayJoin(['1 B', '1 KiB', '1 MiB', '1 GiB', '1 TiB', '1 PiB', '1 EiB']) AS readable_sizes, - fromReadableSizeOrNull(readable_sizes) AS filesize; - --- Returns NULL on invalid values -SELECT - arrayJoin(['invalid', '1 Joe', '1KB', ' 1 GiB', '1 TiB with fries', 'NaN KiB', 'Inf KiB', '0xa123 KiB']) AS readable_sizes, - fromReadableSizeOrNull(readable_sizes) AS filesize; - - --- OR ZERO --- Works as the regular version when inputs are correct -SELECT - arrayJoin(['1 B', '1 KiB', '1 MiB', '1 GiB', '1 TiB', '1 PiB', '1 EiB']) AS readable_sizes, - fromReadableSizeOrZero(readable_sizes) AS filesize; - --- Returns NULL on invalid values -SELECT - arrayJoin(['invalid', '1 Joe', '1KB', ' 1 GiB', '1 TiB with fries', 'NaN KiB', 'Inf KiB', '0xa123 KiB']) AS readable_sizes, - fromReadableSizeOrZero(readable_sizes) AS filesize; - diff --git a/tests/queries/0_stateless/03167_fromReadableDecimalSize.reference b/tests/queries/0_stateless/03167_fromReadableDecimalSize.reference deleted file mode 100644 index 62620501de0..00000000000 --- a/tests/queries/0_stateless/03167_fromReadableDecimalSize.reference +++ /dev/null @@ -1,53 +0,0 @@ -1.00 B -1.00 KB -1.00 MB -1.00 GB -1.00 TB -1.00 PB -1.00 EB -1.00 MB -1000 -3000 -1000 -1000 -1000 -1000 -1000 -\N -3142 -3142 -1000 -5 -2000 -8000 -0 0 0 -1 B 1 -1 KB 1000 -1 MB 1000000 -1 GB 1000000000 -1 TB 1000000000000 -1 PB 1000000000000000 -1 EB 1000000000000000000 -invalid \N -1 Joe \N -1 KiB \N - 1 GB \N -1 TB with fries \N -NaN KB \N -Inf KB \N -0xa123 KB \N -1 B 1 -1 KB 1000 -1 MB 1000000 -1 GB 1000000000 -1 TB 1000000000000 -1 PB 1000000000000000 -1 EB 1000000000000000000 -invalid 0 -1 Joe 0 -1 KiB 0 - 1 GiB 0 -1 TiB with fries 0 -NaN KB 0 -Inf KB 0 -0xa123 KB 0 diff --git a/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql b/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql deleted file mode 100644 index 618f99b1d28..00000000000 --- a/tests/queries/0_stateless/03167_fromReadableDecimalSize.sql +++ /dev/null @@ -1,117 +0,0 @@ --- Should be kept in sync with 03166_fromReadableSize.sql - --- Should be the inverse of formatReadableDecimalSize -SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 B')); -SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 KB')); -SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 MB')); -SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 GB')); -SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 TB')); -SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 PB')); -SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 EB')); - --- Is case-insensitive -SELECT formatReadableDecimalSize(fromReadableDecimalSize('1 mb')); - --- Should be able to parse decimals -SELECT fromReadableDecimalSize('1.00 KB'); -- 1024 -SELECT fromReadableDecimalSize('3.00 KB'); -- 3072 - --- Infix whitespace is ignored -SELECT fromReadableDecimalSize('1 KB'); -SELECT fromReadableDecimalSize('1KB'); - --- Can parse LowCardinality -SELECT fromReadableDecimalSize(toLowCardinality('1 KB')); - --- Can parse nullable fields -SELECT fromReadableDecimalSize(toNullable('1 KB')); - --- Can parse non-const columns fields -SELECT fromReadableDecimalSize(materialize('1 KB')); - --- Output is NULL if NULL arg is passed -SELECT fromReadableDecimalSize(NULL); - --- Can parse more decimal places than Float64's precision -SELECT fromReadableDecimalSize('3.14159265358979323846264338327950288419716939937510 KB'); - --- Can parse sizes prefixed with a plus sign -SELECT fromReadableDecimalSize('+3.1415 KB'); - --- Can parse amounts in scientific notation -SELECT fromReadableDecimalSize('10e2 B'); - --- Can parse floats with no decimal points -SELECT fromReadableDecimalSize('5. B'); - --- Can parse numbers with leading zeroes -SELECT fromReadableDecimalSize('002 KB'); - --- Can parse octal-like -SELECT fromReadableDecimalSize('08 KB'); - --- Can parse various flavours of zero -SELECT fromReadableDecimalSize('0 KB'), fromReadableDecimalSize('+0 KB'), fromReadableDecimalSize('-0 KB'); - --- ERRORS --- No arguments -SELECT fromReadableDecimalSize(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } --- Too many arguments -SELECT fromReadableDecimalSize('1 B', '2 B'); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } --- Wrong Type -SELECT fromReadableDecimalSize(12); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT } --- Invalid input - overall garbage -SELECT fromReadableDecimalSize('oh no'); -- { serverError CANNOT_PARSE_NUMBER } --- Invalid input - unknown unit -SELECT fromReadableDecimalSize('12.3 rb'); -- { serverError CANNOT_PARSE_TEXT } --- Invalid input - Leading whitespace -SELECT fromReadableDecimalSize(' 1 B'); -- { serverError CANNOT_PARSE_INPUT_ASSERTION_FAILED } --- Invalid input - Trailing characters -SELECT fromReadableDecimalSize('1 B leftovers'); -- { serverError UNEXPECTED_DATA_AFTER_PARSED_VALUE } --- Invalid input - Binary size unit is not accepted -SELECT fromReadableDecimalSize('1 KiB'); -- { serverError CANNOT_PARSE_TEXT } --- Invalid input - Negative sizes are not allowed -SELECT fromReadableDecimalSize('-1 KB'); -- { serverError BAD_ARGUMENTS } --- Invalid input - Input too large to fit in UInt64 -SELECT fromReadableDecimalSize('1000 EB'); -- { serverError BAD_ARGUMENTS } --- Invalid input - Hexadecimal is not supported -SELECT fromReadableDecimalSize('0xa123 KB'); -- { serverError CANNOT_PARSE_TEXT } --- Invalid input - NaN is not supported, with or without sign and with different capitalizations -SELECT fromReadableDecimalSize('nan KB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableDecimalSize('+nan KB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableDecimalSize('-nan KB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableDecimalSize('NaN KB'); -- { serverError BAD_ARGUMENTS } --- Invalid input - Infinite is not supported, with or without sign, in all its forms -SELECT fromReadableDecimalSize('inf KB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableDecimalSize('+inf KB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableDecimalSize('-inf KB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableDecimalSize('infinite KB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableDecimalSize('+infinite KB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableDecimalSize('-infinite KB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableDecimalSize('Inf KB'); -- { serverError BAD_ARGUMENTS } -SELECT fromReadableDecimalSize('Infinite KB'); -- { serverError BAD_ARGUMENTS } - - --- OR NULL --- Works as the regular version when inputs are correct -SELECT - arrayJoin(['1 B', '1 KB', '1 MB', '1 GB', '1 TB', '1 PB', '1 EB']) AS readable_sizes, - fromReadableDecimalSizeOrNull(readable_sizes) AS filesize; - --- Returns NULL on invalid values -SELECT - arrayJoin(['invalid', '1 Joe', '1 KiB', ' 1 GB', '1 TB with fries', 'NaN KB', 'Inf KB', '0xa123 KB']) AS readable_sizes, - fromReadableDecimalSizeOrNull(readable_sizes) AS filesize; - - --- OR ZERO --- Works as the regular version when inputs are correct -SELECT - arrayJoin(['1 B', '1 KB', '1 MB', '1 GB', '1 TB', '1 PB', '1 EB']) AS readable_sizes, - fromReadableDecimalSizeOrZero(readable_sizes) AS filesize; - --- Returns NULL on invalid values -SELECT - arrayJoin(['invalid', '1 Joe', '1 KiB', ' 1 GiB', '1 TiB with fries', 'NaN KB', 'Inf KB', '0xa123 KB']) AS readable_sizes, - fromReadableDecimalSizeOrZero(readable_sizes) AS filesize; - diff --git a/utils/check-style/aspell-ignore/en/aspell-dict.txt b/utils/check-style/aspell-ignore/en/aspell-dict.txt index f3b4605a85d..244f2ad98ff 100644 --- a/utils/check-style/aspell-ignore/en/aspell-dict.txt +++ b/utils/check-style/aspell-ignore/en/aspell-dict.txt @@ -1613,12 +1613,6 @@ freezed fromDaysSinceYearZero fromModifiedJulianDay fromModifiedJulianDayOrNull -fromReadableSize -fromReadableSizeOrNull -fromReadableSizeOrZero -fromReadableDecimalSize -fromReadableDecimalSizeOrNull -fromReadableDecimalSizeOrZero fromUTCTimestamp fromUnixTimestamp fromUnixTimestampInJodaSyntax From 33bbb29d48b9d8c10bf57246555b1defb58b4926 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Thu, 30 May 2024 15:16:04 +0200 Subject: [PATCH 201/211] Fix broken changelogs for bugfix PRs --- utils/changelog/changelog.py | 1 - 1 file changed, 1 deletion(-) diff --git a/utils/changelog/changelog.py b/utils/changelog/changelog.py index acc7293473d..25c3453e2be 100755 --- a/utils/changelog/changelog.py +++ b/utils/changelog/changelog.py @@ -271,7 +271,6 @@ def generate_description(item: PullRequest, repo: Repository) -> Optional[Descri category, ): category = "Bug Fix (user-visible misbehavior in an official stable release)" - return Description(item.number, item.user, item.html_url, item.title, category) # Filter out documentations changelog if re.match( From e432f9068e45f4b13a416313815d1dc8dde112a6 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Thu, 30 May 2024 15:17:42 +0200 Subject: [PATCH 202/211] Sort imports --- utils/changelog/changelog.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/utils/changelog/changelog.py b/utils/changelog/changelog.py index 25c3453e2be..4e7d892bac2 100755 --- a/utils/changelog/changelog.py +++ b/utils/changelog/changelog.py @@ -3,18 +3,20 @@ import argparse import logging -import os.path as p import os +import os.path as p import re from datetime import date, timedelta -from subprocess import CalledProcessError, DEVNULL +from subprocess import DEVNULL, CalledProcessError from typing import Dict, List, Optional, TextIO from fuzzywuzzy.fuzz import ratio # type: ignore -from github_helper import GitHub, PullRequest, PullRequests, Repository from github.GithubException import RateLimitExceededException, UnknownObjectException from github.NamedUser import NamedUser -from git_helper import is_shallow, git_runner as runner + +from git_helper import git_runner as runner +from git_helper import is_shallow +from github_helper import GitHub, PullRequest, PullRequests, Repository # This array gives the preferred category order, and is also used to # normalize category names. From 90d53fe62538ad72e38389f7dfeffce24bd7314f Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Thu, 30 May 2024 16:58:11 +0200 Subject: [PATCH 203/211] Fix wrong links for 123#issuecomment-1 --- utils/changelog/changelog.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/changelog/changelog.py b/utils/changelog/changelog.py index 4e7d892bac2..0da871c074d 100755 --- a/utils/changelog/changelog.py +++ b/utils/changelog/changelog.py @@ -60,9 +60,10 @@ class Description: self.entry, ) # 2) issue URL w/o markdown link + # including #issuecomment-1 or #event-12 entry = re.sub( - r"([^(])https://github.com/ClickHouse/ClickHouse/issues/([0-9]{4,})", - r"\1[#\2](https://github.com/ClickHouse/ClickHouse/issues/\2)", + r"([^(])(https://github.com/ClickHouse/ClickHouse/issues/([0-9]{4,})[-#a-z0-9]*)", + r"\1[#\3](\2)", entry, ) # It's possible that we face a secondary rate limit. From 69c24eb05bcba3b9abe40dcca7bbf7109b728741 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Thu, 30 May 2024 16:58:36 +0200 Subject: [PATCH 204/211] Partially update corrupted changelogs --- docs/changelogs/v24.1.1.2048-stable.md | 100 ++++++++--------- docs/changelogs/v24.1.2.5-stable.md | 4 +- docs/changelogs/v24.1.3.31-stable.md | 14 +-- docs/changelogs/v24.1.4.20-stable.md | 8 +- docs/changelogs/v24.1.5.6-stable.md | 2 +- docs/changelogs/v24.1.7.18-stable.md | 8 +- docs/changelogs/v24.1.8.22-stable.md | 12 +-- docs/changelogs/v24.2.1.2248-stable.md | 110 +++++++++---------- docs/changelogs/v24.2.2.71-stable.md | 30 +++--- docs/changelogs/v24.2.3.70-stable.md | 44 ++++---- docs/changelogs/v24.3.1.2672-lts.md | 142 ++++++++++++------------- docs/changelogs/v24.3.2.23-lts.md | 6 +- docs/changelogs/v24.3.3.102-lts.md | 60 +++++------ docs/changelogs/v24.4.1.2088-stable.md | 138 ++++++++++++------------ 14 files changed, 339 insertions(+), 339 deletions(-) diff --git a/docs/changelogs/v24.1.1.2048-stable.md b/docs/changelogs/v24.1.1.2048-stable.md index 8e4647da86e..c509ce0058e 100644 --- a/docs/changelogs/v24.1.1.2048-stable.md +++ b/docs/changelogs/v24.1.1.2048-stable.md @@ -133,56 +133,56 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Add join keys conversion for nested lowcardinality [#51550](https://github.com/ClickHouse/ClickHouse/pull/51550) ([vdimir](https://github.com/vdimir)). -* Flatten only true Nested type if flatten_nested=1, not all Array(Tuple) [#56132](https://github.com/ClickHouse/ClickHouse/pull/56132) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix a bug with projections and the aggregate_functions_null_for_empty setting during insertion. [#56944](https://github.com/ClickHouse/ClickHouse/pull/56944) ([Amos Bird](https://github.com/amosbird)). -* Fixed potential exception due to stale profile UUID [#57263](https://github.com/ClickHouse/ClickHouse/pull/57263) ([Vasily Nemkov](https://github.com/Enmk)). -* Fix working with read buffers in StreamingFormatExecutor [#57438](https://github.com/ClickHouse/ClickHouse/pull/57438) ([Kruglov Pavel](https://github.com/Avogar)). -* Ignore MVs with dropped target table during pushing to views [#57520](https://github.com/ClickHouse/ClickHouse/pull/57520) ([Kruglov Pavel](https://github.com/Avogar)). -* [RFC] Eliminate possible race between ALTER_METADATA and MERGE_PARTS [#57755](https://github.com/ClickHouse/ClickHouse/pull/57755) ([Azat Khuzhin](https://github.com/azat)). -* Fix the exprs order bug in group by with rollup [#57786](https://github.com/ClickHouse/ClickHouse/pull/57786) ([Chen768959](https://github.com/Chen768959)). -* Fix lost blobs after dropping a replica with broken detached parts [#58333](https://github.com/ClickHouse/ClickHouse/pull/58333) ([Alexander Tokmakov](https://github.com/tavplubix)). -* Allow users to work with symlinks in user_files_path (again) [#58447](https://github.com/ClickHouse/ClickHouse/pull/58447) ([Duc Canh Le](https://github.com/canhld94)). -* Fix segfault when graphite table does not have agg function [#58453](https://github.com/ClickHouse/ClickHouse/pull/58453) ([Duc Canh Le](https://github.com/canhld94)). -* Delay reading from StorageKafka to allow multiple reads in materialized views [#58477](https://github.com/ClickHouse/ClickHouse/pull/58477) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). -* Fix a stupid case of intersecting parts [#58482](https://github.com/ClickHouse/ClickHouse/pull/58482) ([Alexander Tokmakov](https://github.com/tavplubix)). -* MergeTreePrefetchedReadPool disable for LIMIT only queries [#58505](https://github.com/ClickHouse/ClickHouse/pull/58505) ([Maksim Kita](https://github.com/kitaisreal)). -* Enable ordinary databases while restoration [#58520](https://github.com/ClickHouse/ClickHouse/pull/58520) ([Jihyuk Bok](https://github.com/tomahawk28)). -* Fix hive threadpool read ORC/Parquet/... Failed [#58537](https://github.com/ClickHouse/ClickHouse/pull/58537) ([sunny](https://github.com/sunny19930321)). -* Hide credentials in system.backup_log base_backup_name column [#58550](https://github.com/ClickHouse/ClickHouse/pull/58550) ([Daniel Pozo Escalona](https://github.com/danipozo)). -* toStartOfInterval for milli- microsencods values rounding [#58557](https://github.com/ClickHouse/ClickHouse/pull/58557) ([Yarik Briukhovetskyi](https://github.com/yariks5s)). -* Disable max_joined_block_rows in ConcurrentHashJoin [#58595](https://github.com/ClickHouse/ClickHouse/pull/58595) ([vdimir](https://github.com/vdimir)). -* Fix join using nullable in old analyzer [#58596](https://github.com/ClickHouse/ClickHouse/pull/58596) ([vdimir](https://github.com/vdimir)). -* `makeDateTime64()`: Allow non-const fraction argument [#58597](https://github.com/ClickHouse/ClickHouse/pull/58597) ([Robert Schulze](https://github.com/rschu1ze)). -* Fix possible NULL dereference during symbolizing inline frames [#58607](https://github.com/ClickHouse/ClickHouse/pull/58607) ([Azat Khuzhin](https://github.com/azat)). -* Improve isolation of query cache entries under re-created users or role switches [#58611](https://github.com/ClickHouse/ClickHouse/pull/58611) ([Robert Schulze](https://github.com/rschu1ze)). -* Fix broken partition key analysis when doing projection optimization [#58638](https://github.com/ClickHouse/ClickHouse/pull/58638) ([Amos Bird](https://github.com/amosbird)). -* Query cache: Fix per-user quota [#58731](https://github.com/ClickHouse/ClickHouse/pull/58731) ([Robert Schulze](https://github.com/rschu1ze)). -* Fix stream partitioning in parallel window functions [#58739](https://github.com/ClickHouse/ClickHouse/pull/58739) ([Dmitry Novik](https://github.com/novikd)). -* Fix double destroy call on exception throw in addBatchLookupTable8 [#58745](https://github.com/ClickHouse/ClickHouse/pull/58745) ([Raúl Marín](https://github.com/Algunenano)). -* Don't process requests in Keeper during shutdown [#58765](https://github.com/ClickHouse/ClickHouse/pull/58765) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix Segfault in `SlabsPolygonIndex::find` [#58771](https://github.com/ClickHouse/ClickHouse/pull/58771) ([Yarik Briukhovetskyi](https://github.com/yariks5s)). -* Fix JSONExtract function for LowCardinality(Nullable) columns [#58808](https://github.com/ClickHouse/ClickHouse/pull/58808) ([vdimir](https://github.com/vdimir)). -* Table CREATE DROP Poco::Logger memory leak fix [#58831](https://github.com/ClickHouse/ClickHouse/pull/58831) ([Maksim Kita](https://github.com/kitaisreal)). -* Fix HTTP compressors finalization [#58846](https://github.com/ClickHouse/ClickHouse/pull/58846) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). -* Multiple read file log storage in mv [#58877](https://github.com/ClickHouse/ClickHouse/pull/58877) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). -* Restriction for the access key id for s3. [#58900](https://github.com/ClickHouse/ClickHouse/pull/58900) ([MikhailBurdukov](https://github.com/MikhailBurdukov)). -* Fix possible crash in clickhouse-local during loading suggestions [#58907](https://github.com/ClickHouse/ClickHouse/pull/58907) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix crash when indexHint() is used [#58911](https://github.com/ClickHouse/ClickHouse/pull/58911) ([Dmitry Novik](https://github.com/novikd)). -* Fix StorageURL forgetting headers on server restart [#58933](https://github.com/ClickHouse/ClickHouse/pull/58933) ([Michael Kolupaev](https://github.com/al13n321)). -* Analyzer: fix storage replacement with insertion block [#58958](https://github.com/ClickHouse/ClickHouse/pull/58958) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). -* Fix seek in ReadBufferFromZipArchive [#58966](https://github.com/ClickHouse/ClickHouse/pull/58966) ([Michael Kolupaev](https://github.com/al13n321)). -* `DROP INDEX` of inverted index now removes all relevant files from persistence [#59040](https://github.com/ClickHouse/ClickHouse/pull/59040) ([mochi](https://github.com/MochiXu)). -* Fix data race on query_factories_info [#59049](https://github.com/ClickHouse/ClickHouse/pull/59049) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Disable "Too many redirects" error retry [#59099](https://github.com/ClickHouse/ClickHouse/pull/59099) ([skyoct](https://github.com/skyoct)). -* Fix aggregation issue in mixed x86_64 and ARM clusters [#59132](https://github.com/ClickHouse/ClickHouse/pull/59132) ([Harry Lee](https://github.com/HarryLeeIBM)). -* Fix not started database shutdown deadlock [#59137](https://github.com/ClickHouse/ClickHouse/pull/59137) ([Sergei Trifonov](https://github.com/serxa)). -* Fix: LIMIT BY and LIMIT in distributed query [#59153](https://github.com/ClickHouse/ClickHouse/pull/59153) ([Igor Nikonov](https://github.com/devcrafter)). -* Fix crash with nullable timezone for `toString` [#59190](https://github.com/ClickHouse/ClickHouse/pull/59190) ([Yarik Briukhovetskyi](https://github.com/yariks5s)). -* Fix abort in iceberg metadata on bad file paths [#59275](https://github.com/ClickHouse/ClickHouse/pull/59275) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix architecture name in select of Rust target [#59307](https://github.com/ClickHouse/ClickHouse/pull/59307) ([p1rattttt](https://github.com/p1rattttt)). -* Fix not-ready set for system.tables [#59351](https://github.com/ClickHouse/ClickHouse/pull/59351) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fix lazy initialization in RabbitMQ [#59352](https://github.com/ClickHouse/ClickHouse/pull/59352) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix possible errors when joining sub-types with low cardinality (e.g., Array(LowCardinality(T)) with Array(T)). [#51550](https://github.com/ClickHouse/ClickHouse/pull/51550) ([vdimir](https://github.com/vdimir)). +* Flatten only true Nested type if flatten_nested=1, not all Array(Tuple). [#56132](https://github.com/ClickHouse/ClickHouse/pull/56132) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix a bug with projections and the `aggregate_functions_null_for_empty` setting during insertion. This is an addition to [#42198](https://github.com/ClickHouse/ClickHouse/issues/42198) and [#49873](https://github.com/ClickHouse/ClickHouse/issues/49873). The bug was found by fuzzer in [#56666](https://github.com/ClickHouse/ClickHouse/issues/56666). This PR also fix potential issues with projections and the `transform_null_in` setting. [#56944](https://github.com/ClickHouse/ClickHouse/pull/56944) ([Amos Bird](https://github.com/amosbird)). +* Fixed (a rare) exception in case when user's assigned profiles are updated right after user logging in, which could cause a missing entry in `session_log` or problems with logging in. [#57263](https://github.com/ClickHouse/ClickHouse/pull/57263) ([Vasily Nemkov](https://github.com/Enmk)). +* Fix working with read buffers in StreamingFormatExecutor, previously it could lead to segfaults in Kafka and other streaming engines. [#57438](https://github.com/ClickHouse/ClickHouse/pull/57438) ([Kruglov Pavel](https://github.com/Avogar)). +* Ignore MVs with dropped target table during pushing to views in insert to a source table. [#57520](https://github.com/ClickHouse/ClickHouse/pull/57520) ([Kruglov Pavel](https://github.com/Avogar)). +* Eliminate possible race between ALTER_METADATA and MERGE_PARTS (that leads to checksum mismatch - CHECKSUM_DOESNT_MATCH). [#57755](https://github.com/ClickHouse/ClickHouse/pull/57755) ([Azat Khuzhin](https://github.com/azat)). +* Fix the exprs order bug in group by with rollup. [#57786](https://github.com/ClickHouse/ClickHouse/pull/57786) ([Chen768959](https://github.com/Chen768959)). +* Fix a bug in zero-copy-replication (an experimental feature) that could lead to `The specified key does not exist` error and data loss. It could happen when dropping a replica with broken or unexpected/ignored detached parts. Fixes [#57985](https://github.com/ClickHouse/ClickHouse/issues/57985). [#58333](https://github.com/ClickHouse/ClickHouse/pull/58333) ([Alexander Tokmakov](https://github.com/tavplubix)). +* Fix a bug that users cannot work with symlinks in user_files_path. [#58447](https://github.com/ClickHouse/ClickHouse/pull/58447) ([Duc Canh Le](https://github.com/canhld94)). +* Fix segfault when graphite table does not have agg function. [#58453](https://github.com/ClickHouse/ClickHouse/pull/58453) ([Duc Canh Le](https://github.com/canhld94)). +* Fix reading multiple times from KafkaEngine in materialized views. [#58477](https://github.com/ClickHouse/ClickHouse/pull/58477) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* Fix `Part ... intersects part ...` error that might occur in `ReplicatedMergeTree` when the server was restarted just after [automatically] dropping [an empty] part and adjacent parts were merged. The bug was introduced in https://github.com/ClickHouse/ClickHouse/pull/56282. [#58482](https://github.com/ClickHouse/ClickHouse/pull/58482) ([Alexander Tokmakov](https://github.com/tavplubix)). +* MergeTreePrefetchedReadPool disable for LIMIT only queries, because time spend during filling per thread tasks can be greater than whole query execution for big tables with small limit. [#58505](https://github.com/ClickHouse/ClickHouse/pull/58505) ([Maksim Kita](https://github.com/kitaisreal)). +* While `restore` is underway in Clickhouse, restore should allow the database with an `ordinary` engine. [#58520](https://github.com/ClickHouse/ClickHouse/pull/58520) ([Jihyuk Bok](https://github.com/tomahawk28)). +* Fix read buffer creation in Hive engine when thread_pool read method is used. Closes [#57978](https://github.com/ClickHouse/ClickHouse/issues/57978). [#58537](https://github.com/ClickHouse/ClickHouse/pull/58537) ([sunny](https://github.com/sunny19930321)). +* Hide credentials in `base_backup_name` column of `system.backup_log`. [#58550](https://github.com/ClickHouse/ClickHouse/pull/58550) ([Daniel Pozo Escalona](https://github.com/danipozo)). +* While executing queries like `SELECT toStartOfInterval(toDateTime64('2023-10-09 10:11:12.000999', 6), toIntervalMillisecond(1));`, the result was not rounded to 1 millisecond previously. Current PR solves this issue. Also, current PR will solve some problems appearing in https://github.com/ClickHouse/ClickHouse/pull/56738. [#58557](https://github.com/ClickHouse/ClickHouse/pull/58557) ([Yarik Briukhovetskyi](https://github.com/yariks5s)). +* Fix logical error in `parallel_hash` working with `max_joined_block_size_rows`. [#58595](https://github.com/ClickHouse/ClickHouse/pull/58595) ([vdimir](https://github.com/vdimir)). +* Fix error in join with `USING` when one of the table has `Nullable` key. [#58596](https://github.com/ClickHouse/ClickHouse/pull/58596) ([vdimir](https://github.com/vdimir)). +* The (optional) `fraction` argument in function `makeDateTime64()` can now be non-const. This was possible already with ClickHouse <= 23.8. [#58597](https://github.com/ClickHouse/ClickHouse/pull/58597) ([Robert Schulze](https://github.com/rschu1ze)). +* Fix possible server crash during symbolizing inline frames. [#58607](https://github.com/ClickHouse/ClickHouse/pull/58607) ([Azat Khuzhin](https://github.com/azat)). +* The query cache now denies access to entries when the user is re-created or assumes another role. This improves prevents attacks where 1. an user with the same name as a dropped user may access the old user's cache entries or 2. a user with a different role may access cache entries of a role with a different row policy. [#58611](https://github.com/ClickHouse/ClickHouse/pull/58611) ([Robert Schulze](https://github.com/rschu1ze)). +* Fix broken partition key analysis when doing projection optimization with `force_index_by_date = 1`. This fixes [#58620](https://github.com/ClickHouse/ClickHouse/issues/58620). We don't need partition key analysis for projections after https://github.com/ClickHouse/ClickHouse/pull/56502 . [#58638](https://github.com/ClickHouse/ClickHouse/pull/58638) ([Amos Bird](https://github.com/amosbird)). +* The query cache now behaves properly when per-user quotas are defined and `SYSTEM DROP QUERY CACHE` ran. [#58731](https://github.com/ClickHouse/ClickHouse/pull/58731) ([Robert Schulze](https://github.com/rschu1ze)). +* Fix data stream partitioning for window functions when there are different window descriptions with similar prefixes but different partitioning. Fixes [#58714](https://github.com/ClickHouse/ClickHouse/issues/58714). [#58739](https://github.com/ClickHouse/ClickHouse/pull/58739) ([Dmitry Novik](https://github.com/novikd)). +* Fix double destroy call on exception throw in addBatchLookupTable8. [#58745](https://github.com/ClickHouse/ClickHouse/pull/58745) ([Raúl Marín](https://github.com/Algunenano)). +* Keeper fix: don't process requests during shutdown because it will lead to invalid state. [#58765](https://github.com/ClickHouse/ClickHouse/pull/58765) ([Antonio Andelic](https://github.com/antonio2368)). +* Fix a crash in the polygon dictionary. Fixes [#58612](https://github.com/ClickHouse/ClickHouse/issues/58612). [#58771](https://github.com/ClickHouse/ClickHouse/pull/58771) ([Yarik Briukhovetskyi](https://github.com/yariks5s)). +* Fix possible crash in JSONExtract function extracting `LowCardinality(Nullable(T))` type. [#58808](https://github.com/ClickHouse/ClickHouse/pull/58808) ([vdimir](https://github.com/vdimir)). +* Table CREATE DROP `Poco::Logger` memory leak fix. Closes [#57931](https://github.com/ClickHouse/ClickHouse/issues/57931). Closes [#58496](https://github.com/ClickHouse/ClickHouse/issues/58496). [#58831](https://github.com/ClickHouse/ClickHouse/pull/58831) ([Maksim Kita](https://github.com/kitaisreal)). +* Fix HTTP compressors. Follow-up [#58475](https://github.com/ClickHouse/ClickHouse/issues/58475). [#58846](https://github.com/ClickHouse/ClickHouse/pull/58846) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). +* Fix reading multiple times from FileLog engine in materialized views. [#58877](https://github.com/ClickHouse/ClickHouse/pull/58877) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* Prevent specifying an `access_key_id` that does not match the correct [correct pattern]( https://docs.aws.amazon.com/IAM/latest/APIReference/API_AccessKey.html). [#58900](https://github.com/ClickHouse/ClickHouse/pull/58900) ([MikhailBurdukov](https://github.com/MikhailBurdukov)). +* Fix possible crash in clickhouse-local during loading suggestions. Closes [#58825](https://github.com/ClickHouse/ClickHouse/issues/58825). [#58907](https://github.com/ClickHouse/ClickHouse/pull/58907) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix crash when `indexHint` function is used without arguments in the filters. [#58911](https://github.com/ClickHouse/ClickHouse/pull/58911) ([Dmitry Novik](https://github.com/novikd)). +* Fixed URL and S3 engines losing the `headers` argument on server restart. [#58933](https://github.com/ClickHouse/ClickHouse/pull/58933) ([Michael Kolupaev](https://github.com/al13n321)). +* Fix analyzer - insertion from select with subquery referencing insertion table should process only insertion block for all table expressions. Fixes [#58080](https://github.com/ClickHouse/ClickHouse/issues/58080). follow-up [#50857](https://github.com/ClickHouse/ClickHouse/issues/50857). [#58958](https://github.com/ClickHouse/ClickHouse/pull/58958) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). +* Fixed reading parquet files from archives. [#58966](https://github.com/ClickHouse/ClickHouse/pull/58966) ([Michael Kolupaev](https://github.com/al13n321)). +* Experimental feature of inverted indices: `ALTER TABLE DROP INDEX` for an inverted index now removes all inverted index files from the new part (issue [#59039](https://github.com/ClickHouse/ClickHouse/issues/59039)). [#59040](https://github.com/ClickHouse/ClickHouse/pull/59040) ([mochi](https://github.com/MochiXu)). +* Fix data race on collecting factories info for system.query_log. [#59049](https://github.com/ClickHouse/ClickHouse/pull/59049) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fixs: [#58967](https://github.com/ClickHouse/ClickHouse/issues/58967). [#59099](https://github.com/ClickHouse/ClickHouse/pull/59099) ([skyoct](https://github.com/skyoct)). +* Fixed wrong aggregation results in mixed x86_64 and ARM clusters. [#59132](https://github.com/ClickHouse/ClickHouse/pull/59132) ([Harry Lee](https://github.com/HarryLeeIBM)). +* Fix a deadlock that can happen during the shutdown of the server due to metadata loading failure. [#59137](https://github.com/ClickHouse/ClickHouse/pull/59137) ([Sergei Trifonov](https://github.com/serxa)). +* The combination of LIMIT BY and LIMIT could produce an incorrect result in distributed queries (parallel replicas included). [#59153](https://github.com/ClickHouse/ClickHouse/pull/59153) ([Igor Nikonov](https://github.com/devcrafter)). +* Fixes crash with for `toString()` with timezone in nullable format. Fixes [#59126](https://github.com/ClickHouse/ClickHouse/issues/59126). [#59190](https://github.com/ClickHouse/ClickHouse/pull/59190) ([Yarik Briukhovetskyi](https://github.com/yariks5s)). +* Fix abort in iceberg metadata on bad file paths. [#59275](https://github.com/ClickHouse/ClickHouse/pull/59275) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix architecture name in select of Rust target. [#59307](https://github.com/ClickHouse/ClickHouse/pull/59307) ([p1rattttt](https://github.com/p1rattttt)). +* Fix `Not-ready Set` for queries from `system.tables` with `table IN (subquery)` filter expression. Fixes [#59342](https://github.com/ClickHouse/ClickHouse/issues/59342). [#59351](https://github.com/ClickHouse/ClickHouse/pull/59351) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix lazy initialization in RabbitMQ that could lead to logical error and not initialized state. [#59352](https://github.com/ClickHouse/ClickHouse/pull/59352) ([Kruglov Pavel](https://github.com/Avogar)). #### NO CL ENTRY diff --git a/docs/changelogs/v24.1.2.5-stable.md b/docs/changelogs/v24.1.2.5-stable.md index bac25c9b9ed..080e24da6f0 100644 --- a/docs/changelogs/v24.1.2.5-stable.md +++ b/docs/changelogs/v24.1.2.5-stable.md @@ -9,6 +9,6 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix translate() with FixedString input [#59356](https://github.com/ClickHouse/ClickHouse/pull/59356) ([Raúl Marín](https://github.com/Algunenano)). -* Fix stacktraces for binaries without debug symbols [#59444](https://github.com/ClickHouse/ClickHouse/pull/59444) ([Azat Khuzhin](https://github.com/azat)). +* Backported in [#59425](https://github.com/ClickHouse/ClickHouse/issues/59425): Fix translate() with FixedString input. Could lead to crashes as it'd return a String column (vs the expected FixedString). This issue was found through ClickHouse Bug Bounty Program YohannJardin. [#59356](https://github.com/ClickHouse/ClickHouse/pull/59356) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#59478](https://github.com/ClickHouse/ClickHouse/issues/59478): Fix stacktraces for binaries without debug symbols. [#59444](https://github.com/ClickHouse/ClickHouse/pull/59444) ([Azat Khuzhin](https://github.com/azat)). diff --git a/docs/changelogs/v24.1.3.31-stable.md b/docs/changelogs/v24.1.3.31-stable.md index e898fba5c87..ec73672c8d5 100644 --- a/docs/changelogs/v24.1.3.31-stable.md +++ b/docs/changelogs/v24.1.3.31-stable.md @@ -13,13 +13,13 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix `ASTAlterCommand::formatImpl` in case of column specific settings... [#59445](https://github.com/ClickHouse/ClickHouse/pull/59445) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). -* Make MAX use the same rules as permutation for complex types [#59498](https://github.com/ClickHouse/ClickHouse/pull/59498) ([Raúl Marín](https://github.com/Algunenano)). -* Fix corner case when passing `update_insert_deduplication_token_in_dependent_materialized_views` [#59544](https://github.com/ClickHouse/ClickHouse/pull/59544) ([Jordi Villar](https://github.com/jrdi)). -* Fix incorrect result of arrayElement / map[] on empty value [#59594](https://github.com/ClickHouse/ClickHouse/pull/59594) ([Raúl Marín](https://github.com/Algunenano)). -* Fix crash in topK when merging empty states [#59603](https://github.com/ClickHouse/ClickHouse/pull/59603) ([Raúl Marín](https://github.com/Algunenano)). -* Maintain function alias in RewriteSumFunctionWithSumAndCountVisitor [#59658](https://github.com/ClickHouse/ClickHouse/pull/59658) ([Raúl Marín](https://github.com/Algunenano)). -* Fix leftPad / rightPad function with FixedString input [#59739](https://github.com/ClickHouse/ClickHouse/pull/59739) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#59726](https://github.com/ClickHouse/ClickHouse/issues/59726): Fix formatting of alter commands in case of column specific settings. [#59445](https://github.com/ClickHouse/ClickHouse/pull/59445) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* Backported in [#59585](https://github.com/ClickHouse/ClickHouse/issues/59585): Make MAX use the same rules as permutation for complex types. [#59498](https://github.com/ClickHouse/ClickHouse/pull/59498) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#59579](https://github.com/ClickHouse/ClickHouse/issues/59579): Fix a corner case when passing `update_insert_deduplication_token_in_dependent_materialized_views` setting. There is one corner case not covered due to the absence of tables in the path:. [#59544](https://github.com/ClickHouse/ClickHouse/pull/59544) ([Jordi Villar](https://github.com/jrdi)). +* Backported in [#59647](https://github.com/ClickHouse/ClickHouse/issues/59647): Fix incorrect result of arrayElement / map[] on empty value. [#59594](https://github.com/ClickHouse/ClickHouse/pull/59594) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#59639](https://github.com/ClickHouse/ClickHouse/issues/59639): Fix crash in topK when merging empty states. [#59603](https://github.com/ClickHouse/ClickHouse/pull/59603) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#59696](https://github.com/ClickHouse/ClickHouse/issues/59696): Maintain function alias in RewriteSumFunctionWithSumAndCountVisitor. [#59658](https://github.com/ClickHouse/ClickHouse/pull/59658) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#59764](https://github.com/ClickHouse/ClickHouse/issues/59764): Fix leftPad / rightPad function with FixedString input. [#59739](https://github.com/ClickHouse/ClickHouse/pull/59739) ([Raúl Marín](https://github.com/Algunenano)). #### NO CL ENTRY diff --git a/docs/changelogs/v24.1.4.20-stable.md b/docs/changelogs/v24.1.4.20-stable.md index 8612a485f12..1baec2178b1 100644 --- a/docs/changelogs/v24.1.4.20-stable.md +++ b/docs/changelogs/v24.1.4.20-stable.md @@ -15,10 +15,10 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix digest calculation in Keeper [#59439](https://github.com/ClickHouse/ClickHouse/pull/59439) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix distributed table with a constant sharding key [#59606](https://github.com/ClickHouse/ClickHouse/pull/59606) ([Vitaly Baranov](https://github.com/vitlibar)). -* Fix query start time on non initial queries [#59662](https://github.com/ClickHouse/ClickHouse/pull/59662) ([Raúl Marín](https://github.com/Algunenano)). -* Fix parsing of partition expressions surrounded by parens [#59901](https://github.com/ClickHouse/ClickHouse/pull/59901) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* Backported in [#59457](https://github.com/ClickHouse/ClickHouse/issues/59457): Keeper fix: fix digest calculation for nodes. [#59439](https://github.com/ClickHouse/ClickHouse/pull/59439) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#59682](https://github.com/ClickHouse/ClickHouse/issues/59682): Fix distributed table with a constant sharding key. [#59606](https://github.com/ClickHouse/ClickHouse/pull/59606) ([Vitaly Baranov](https://github.com/vitlibar)). +* Backported in [#59842](https://github.com/ClickHouse/ClickHouse/issues/59842): Fix query start time on non initial queries. [#59662](https://github.com/ClickHouse/ClickHouse/pull/59662) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#59937](https://github.com/ClickHouse/ClickHouse/issues/59937): Fix parsing of partition expressions that are surrounded by parentheses, e.g.: `ALTER TABLE test DROP PARTITION ('2023-10-19')`. [#59901](https://github.com/ClickHouse/ClickHouse/pull/59901) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). #### NOT FOR CHANGELOG / INSIGNIFICANT diff --git a/docs/changelogs/v24.1.5.6-stable.md b/docs/changelogs/v24.1.5.6-stable.md index ce46c51e2f4..caf246fcab6 100644 --- a/docs/changelogs/v24.1.5.6-stable.md +++ b/docs/changelogs/v24.1.5.6-stable.md @@ -9,7 +9,7 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* UniqExactSet read crash fix [#59928](https://github.com/ClickHouse/ClickHouse/pull/59928) ([Maksim Kita](https://github.com/kitaisreal)). +* Backported in [#59959](https://github.com/ClickHouse/ClickHouse/issues/59959): Fix crash during deserialization of aggregation function states that internally use `UniqExactSet`. Introduced https://github.com/ClickHouse/ClickHouse/pull/59009. [#59928](https://github.com/ClickHouse/ClickHouse/pull/59928) ([Maksim Kita](https://github.com/kitaisreal)). #### NOT FOR CHANGELOG / INSIGNIFICANT diff --git a/docs/changelogs/v24.1.7.18-stable.md b/docs/changelogs/v24.1.7.18-stable.md index 603a83a67be..3bc94538174 100644 --- a/docs/changelogs/v24.1.7.18-stable.md +++ b/docs/changelogs/v24.1.7.18-stable.md @@ -9,10 +9,10 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix deadlock in parallel parsing when lots of rows are skipped due to errors [#60516](https://github.com/ClickHouse/ClickHouse/pull/60516) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix_max_query_size_for_kql_compound_operator: [#60534](https://github.com/ClickHouse/ClickHouse/pull/60534) ([Yong Wang](https://github.com/kashwy)). -* Fix crash with different allow_experimental_analyzer value in subqueries [#60770](https://github.com/ClickHouse/ClickHouse/pull/60770) ([Dmitry Novik](https://github.com/novikd)). -* Fix Keeper reconfig for standalone binary [#61233](https://github.com/ClickHouse/ClickHouse/pull/61233) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#61330](https://github.com/ClickHouse/ClickHouse/issues/61330): Fix deadlock in parallel parsing when lots of rows are skipped due to errors. [#60516](https://github.com/ClickHouse/ClickHouse/pull/60516) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#61008](https://github.com/ClickHouse/ClickHouse/issues/61008): Fix the issue of `max_query_size` for KQL compound operator like mv-expand. Related to [#59626](https://github.com/ClickHouse/ClickHouse/issues/59626). [#60534](https://github.com/ClickHouse/ClickHouse/pull/60534) ([Yong Wang](https://github.com/kashwy)). +* Backported in [#61019](https://github.com/ClickHouse/ClickHouse/issues/61019): Fix crash when `allow_experimental_analyzer` setting value is changed in the subqueries. [#60770](https://github.com/ClickHouse/ClickHouse/pull/60770) ([Dmitry Novik](https://github.com/novikd)). +* Backported in [#61293](https://github.com/ClickHouse/ClickHouse/issues/61293): Keeper: fix runtime reconfig for standalone binary. [#61233](https://github.com/ClickHouse/ClickHouse/pull/61233) ([Antonio Andelic](https://github.com/antonio2368)). #### CI Fix or Improvement (changelog entry is not required) diff --git a/docs/changelogs/v24.1.8.22-stable.md b/docs/changelogs/v24.1.8.22-stable.md index f780de41c40..e615c60a942 100644 --- a/docs/changelogs/v24.1.8.22-stable.md +++ b/docs/changelogs/v24.1.8.22-stable.md @@ -9,12 +9,12 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix possible incorrect result of aggregate function `uniqExact` [#61257](https://github.com/ClickHouse/ClickHouse/pull/61257) ([Anton Popov](https://github.com/CurtizJ)). -* Fix consecutive keys optimization for nullable keys [#61393](https://github.com/ClickHouse/ClickHouse/pull/61393) ([Anton Popov](https://github.com/CurtizJ)). -* Fix bug when reading system.parts using UUID (issue 61220). [#61479](https://github.com/ClickHouse/ClickHouse/pull/61479) ([Dan Wu](https://github.com/wudanzy)). -* Fix client `-s` argument [#61530](https://github.com/ClickHouse/ClickHouse/pull/61530) ([Mikhail f. Shiryaev](https://github.com/Felixoid)). -* Fix string search with const position [#61547](https://github.com/ClickHouse/ClickHouse/pull/61547) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix crash in `multiSearchAllPositionsCaseInsensitiveUTF8` for incorrect UTF-8 [#61749](https://github.com/ClickHouse/ClickHouse/pull/61749) ([pufit](https://github.com/pufit)). +* Backported in [#61451](https://github.com/ClickHouse/ClickHouse/issues/61451): Fix possible incorrect result of aggregate function `uniqExact`. [#61257](https://github.com/ClickHouse/ClickHouse/pull/61257) ([Anton Popov](https://github.com/CurtizJ)). +* Backported in [#61844](https://github.com/ClickHouse/ClickHouse/issues/61844): Fixed possible wrong result of aggregation with nullable keys. [#61393](https://github.com/ClickHouse/ClickHouse/pull/61393) ([Anton Popov](https://github.com/CurtizJ)). +* Backported in [#61746](https://github.com/ClickHouse/ClickHouse/issues/61746): Fix incorrect results when filtering `system.parts` or `system.parts_columns` using UUID. [#61479](https://github.com/ClickHouse/ClickHouse/pull/61479) ([Dan Wu](https://github.com/wudanzy)). +* Backported in [#61696](https://github.com/ClickHouse/ClickHouse/issues/61696): Fix `clickhouse-client -s` argument, it was broken by defining it two times. [#61530](https://github.com/ClickHouse/ClickHouse/pull/61530) ([Mikhail f. Shiryaev](https://github.com/Felixoid)). +* Backported in [#61576](https://github.com/ClickHouse/ClickHouse/issues/61576): Fix string search with constant start position which previously could lead to memory corruption. [#61547](https://github.com/ClickHouse/ClickHouse/pull/61547) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#61858](https://github.com/ClickHouse/ClickHouse/issues/61858): Fix crash in `multiSearchAllPositionsCaseInsensitiveUTF8` when specifying incorrect UTF-8 sequence. Example: [#61714](https://github.com/ClickHouse/ClickHouse/issues/61714#issuecomment-2012768202). [#61749](https://github.com/ClickHouse/ClickHouse/pull/61749) ([pufit](https://github.com/pufit)). #### CI Fix or Improvement (changelog entry is not required) diff --git a/docs/changelogs/v24.2.1.2248-stable.md b/docs/changelogs/v24.2.1.2248-stable.md index 02affe12c43..edcd3da3852 100644 --- a/docs/changelogs/v24.2.1.2248-stable.md +++ b/docs/changelogs/v24.2.1.2248-stable.md @@ -60,7 +60,7 @@ sidebar_label: 2024 * Support negative positional arguments. Closes [#57736](https://github.com/ClickHouse/ClickHouse/issues/57736). [#58292](https://github.com/ClickHouse/ClickHouse/pull/58292) ([flynn](https://github.com/ucasfl)). * Implement auto-adjustment for asynchronous insert timeouts. The following settings are introduced: async_insert_poll_timeout_ms, async_insert_use_adaptive_busy_timeout, async_insert_busy_timeout_min_ms, async_insert_busy_timeout_max_ms, async_insert_busy_timeout_increase_rate, async_insert_busy_timeout_decrease_rate. [#58486](https://github.com/ClickHouse/ClickHouse/pull/58486) ([Julia Kartseva](https://github.com/jkartseva)). * Allow to define `volume_priority` in `storage_configuration`. [#58533](https://github.com/ClickHouse/ClickHouse/pull/58533) ([Andrey Zvonov](https://github.com/zvonand)). -* Add support for Date32 type in T64 codec. [#58738](https://github.com/ClickHouse/ClickHouse/pull/58738) ([Hongbin Ma](https://github.com/binmahone)). +* Add support for Date32 type in T64 codec. [#58738](https://github.com/ClickHouse/ClickHouse/pull/58738) ([Hongbin Ma (Mahone)](https://github.com/binmahone)). * Support `LEFT JOIN`, `ALL INNER JOIN`, and simple subqueries for parallel replicas (only with analyzer). New setting `parallel_replicas_prefer_local_join` chooses local `JOIN` execution (by default) vs `GLOBAL JOIN`. All tables should exist on every replica from `cluster_for_parallel_replicas`. New settings `min_external_table_block_size_rows` and `min_external_table_block_size_bytes` are used to squash small blocks that are sent for temporary tables (only with analyzer). [#58916](https://github.com/ClickHouse/ClickHouse/pull/58916) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). * Allow trailing commas in types with several items. [#59119](https://github.com/ClickHouse/ClickHouse/pull/59119) ([Aleksandr Musorin](https://github.com/AVMusorin)). * Allow parallel and distributed processing for `S3Queue` table engine. For distributed processing use setting `s3queue_total_shards_num` (by default `1`). Setting `s3queue_processing_threads_num` previously was not allowed for Ordered processing mode, now it is allowed. Warning: settings `s3queue_processing_threads_num`(processing threads per each shard) and `s3queue_total_shards_num` for ordered mode change how metadata is stored (make the number of `max_processed_file` nodes equal to `s3queue_processing_threads_num * s3queue_total_shards_num`), so they must be the same for all shards and cannot be changed once at least one shard is created. [#59167](https://github.com/ClickHouse/ClickHouse/pull/59167) ([Kseniia Sumarokova](https://github.com/kssenii)). @@ -123,60 +123,60 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Non ready set in TTL WHERE. [#57430](https://github.com/ClickHouse/ClickHouse/pull/57430) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fix quantilesGK bug [#58216](https://github.com/ClickHouse/ClickHouse/pull/58216) ([李扬](https://github.com/taiyang-li)). -* Disable parallel replicas JOIN with CTE (not analyzer) [#59239](https://github.com/ClickHouse/ClickHouse/pull/59239) ([Raúl Marín](https://github.com/Algunenano)). -* Fix bug with `intDiv` for decimal arguments [#59243](https://github.com/ClickHouse/ClickHouse/pull/59243) ([Yarik Briukhovetskyi](https://github.com/yariks5s)). -* Fix translate() with FixedString input [#59356](https://github.com/ClickHouse/ClickHouse/pull/59356) ([Raúl Marín](https://github.com/Algunenano)). -* Fix digest calculation in Keeper [#59439](https://github.com/ClickHouse/ClickHouse/pull/59439) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix stacktraces for binaries without debug symbols [#59444](https://github.com/ClickHouse/ClickHouse/pull/59444) ([Azat Khuzhin](https://github.com/azat)). -* Fix `ASTAlterCommand::formatImpl` in case of column specific settings... [#59445](https://github.com/ClickHouse/ClickHouse/pull/59445) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). -* Fix `SELECT * FROM [...] ORDER BY ALL` with Analyzer [#59462](https://github.com/ClickHouse/ClickHouse/pull/59462) ([zhongyuankai](https://github.com/zhongyuankai)). -* Fix possible uncaught exception during distributed query cancellation [#59487](https://github.com/ClickHouse/ClickHouse/pull/59487) ([Azat Khuzhin](https://github.com/azat)). -* Make MAX use the same rules as permutation for complex types [#59498](https://github.com/ClickHouse/ClickHouse/pull/59498) ([Raúl Marín](https://github.com/Algunenano)). -* Fix corner case when passing `update_insert_deduplication_token_in_dependent_materialized_views` [#59544](https://github.com/ClickHouse/ClickHouse/pull/59544) ([Jordi Villar](https://github.com/jrdi)). -* Fix incorrect result of arrayElement / map[] on empty value [#59594](https://github.com/ClickHouse/ClickHouse/pull/59594) ([Raúl Marín](https://github.com/Algunenano)). -* Fix crash in topK when merging empty states [#59603](https://github.com/ClickHouse/ClickHouse/pull/59603) ([Raúl Marín](https://github.com/Algunenano)). -* Fix distributed table with a constant sharding key [#59606](https://github.com/ClickHouse/ClickHouse/pull/59606) ([Vitaly Baranov](https://github.com/vitlibar)). -* Fix_kql_issue_found_by_wingfuzz [#59626](https://github.com/ClickHouse/ClickHouse/pull/59626) ([Yong Wang](https://github.com/kashwy)). -* Fix error "Read beyond last offset" for AsynchronousBoundedReadBuffer [#59630](https://github.com/ClickHouse/ClickHouse/pull/59630) ([Vitaly Baranov](https://github.com/vitlibar)). -* Maintain function alias in RewriteSumFunctionWithSumAndCountVisitor [#59658](https://github.com/ClickHouse/ClickHouse/pull/59658) ([Raúl Marín](https://github.com/Algunenano)). -* Fix query start time on non initial queries [#59662](https://github.com/ClickHouse/ClickHouse/pull/59662) ([Raúl Marín](https://github.com/Algunenano)). -* Validate types of arguments for `minmax` skipping index [#59733](https://github.com/ClickHouse/ClickHouse/pull/59733) ([Anton Popov](https://github.com/CurtizJ)). -* Fix leftPad / rightPad function with FixedString input [#59739](https://github.com/ClickHouse/ClickHouse/pull/59739) ([Raúl Marín](https://github.com/Algunenano)). -* Fix AST fuzzer issue in function `countMatches` [#59752](https://github.com/ClickHouse/ClickHouse/pull/59752) ([Robert Schulze](https://github.com/rschu1ze)). -* rabbitmq: fix having neither acked nor nacked messages [#59775](https://github.com/ClickHouse/ClickHouse/pull/59775) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix StorageURL doing some of the query execution in single thread [#59833](https://github.com/ClickHouse/ClickHouse/pull/59833) ([Michael Kolupaev](https://github.com/al13n321)). -* s3queue: fix uninitialized value [#59897](https://github.com/ClickHouse/ClickHouse/pull/59897) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix parsing of partition expressions surrounded by parens [#59901](https://github.com/ClickHouse/ClickHouse/pull/59901) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). -* Fix crash in JSONColumnsWithMetadata format over http [#59925](https://github.com/ClickHouse/ClickHouse/pull/59925) ([Kruglov Pavel](https://github.com/Avogar)). -* Do not rewrite sum() to count() if return value differs in analyzer [#59926](https://github.com/ClickHouse/ClickHouse/pull/59926) ([Azat Khuzhin](https://github.com/azat)). -* UniqExactSet read crash fix [#59928](https://github.com/ClickHouse/ClickHouse/pull/59928) ([Maksim Kita](https://github.com/kitaisreal)). -* ReplicatedMergeTree invalid metadata_version fix [#59946](https://github.com/ClickHouse/ClickHouse/pull/59946) ([Maksim Kita](https://github.com/kitaisreal)). -* Fix data race in `StorageDistributed` [#59987](https://github.com/ClickHouse/ClickHouse/pull/59987) ([Nikita Taranov](https://github.com/nickitat)). -* Run init scripts when option is enabled rather than disabled [#59991](https://github.com/ClickHouse/ClickHouse/pull/59991) ([jktng](https://github.com/jktng)). -* Fix scale conversion for DateTime64 [#60004](https://github.com/ClickHouse/ClickHouse/pull/60004) ([Yarik Briukhovetskyi](https://github.com/yariks5s)). -* Fix INSERT into SQLite with single quote (by escaping single quotes with a quote instead of backslash) [#60015](https://github.com/ClickHouse/ClickHouse/pull/60015) ([Azat Khuzhin](https://github.com/azat)). -* Fix several logical errors in arrayFold [#60022](https://github.com/ClickHouse/ClickHouse/pull/60022) ([Raúl Marín](https://github.com/Algunenano)). -* Fix optimize_uniq_to_count removing the column alias [#60026](https://github.com/ClickHouse/ClickHouse/pull/60026) ([Raúl Marín](https://github.com/Algunenano)). -* Fix possible exception from s3queue table on drop [#60036](https://github.com/ClickHouse/ClickHouse/pull/60036) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix formatting of NOT with single literals [#60042](https://github.com/ClickHouse/ClickHouse/pull/60042) ([Raúl Marín](https://github.com/Algunenano)). -* Use max_query_size from context in DDLLogEntry instead of hardcoded 4096 [#60083](https://github.com/ClickHouse/ClickHouse/pull/60083) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix inconsistent formatting of queries [#60095](https://github.com/ClickHouse/ClickHouse/pull/60095) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Fix inconsistent formatting of explain in subqueries [#60102](https://github.com/ClickHouse/ClickHouse/pull/60102) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Fix cosineDistance crash with Nullable [#60150](https://github.com/ClickHouse/ClickHouse/pull/60150) ([Raúl Marín](https://github.com/Algunenano)). -* Allow casting of bools in string representation to to true bools [#60160](https://github.com/ClickHouse/ClickHouse/pull/60160) ([Robert Schulze](https://github.com/rschu1ze)). -* Fix system.s3queue_log [#60166](https://github.com/ClickHouse/ClickHouse/pull/60166) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix arrayReduce with nullable aggregate function name [#60188](https://github.com/ClickHouse/ClickHouse/pull/60188) ([Raúl Marín](https://github.com/Algunenano)). -* Fix actions execution during preliminary filtering (PK, partition pruning) [#60196](https://github.com/ClickHouse/ClickHouse/pull/60196) ([Azat Khuzhin](https://github.com/azat)). -* Hide sensitive info for s3queue [#60233](https://github.com/ClickHouse/ClickHouse/pull/60233) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Revert "Replace `ORDER BY ALL` by `ORDER BY *`" [#60248](https://github.com/ClickHouse/ClickHouse/pull/60248) ([Robert Schulze](https://github.com/rschu1ze)). -* Fix http exception codes. [#60252](https://github.com/ClickHouse/ClickHouse/pull/60252) ([Austin Kothig](https://github.com/kothiga)). -* s3queue: fix bug (also fixes flaky test_storage_s3_queue/test.py::test_shards_distributed) [#60282](https://github.com/ClickHouse/ClickHouse/pull/60282) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix use-of-uninitialized-value and invalid result in hashing functions with IPv6 [#60359](https://github.com/ClickHouse/ClickHouse/pull/60359) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix OptimizeDateOrDateTimeConverterWithPreimageVisitor with null arguments [#60453](https://github.com/ClickHouse/ClickHouse/pull/60453) ([Raúl Marín](https://github.com/Algunenano)). -* Merging [#59674](https://github.com/ClickHouse/ClickHouse/issues/59674). [#60470](https://github.com/ClickHouse/ClickHouse/pull/60470) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Correctly check keys in s3Cluster [#60477](https://github.com/ClickHouse/ClickHouse/pull/60477) ([Antonio Andelic](https://github.com/antonio2368)). +* Support `IN (subquery)` in table TTL expression. Initially, it was allowed to create such a TTL expression, but any TTL merge would fail with `Not-ready Set` error in the background. Now, TTL is correctly applied. Subquery is executed for every TTL merge, and its result is not cached or reused by other merges. Use such configuration with special care, because subqueries in TTL may lead to high memory consumption and, possibly, a non-deterministic result of TTL merge on different replicas (which is correctly handled by replication, however). [#57430](https://github.com/ClickHouse/ClickHouse/pull/57430) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix quantilesGK bug, close [#57683](https://github.com/ClickHouse/ClickHouse/issues/57683). [#58216](https://github.com/ClickHouse/ClickHouse/pull/58216) ([李扬](https://github.com/taiyang-li)). +* Disable parallel replicas JOIN with CTE (not analyzer). [#59239](https://github.com/ClickHouse/ClickHouse/pull/59239) ([Raúl Marín](https://github.com/Algunenano)). +* Fixes bug with for function `intDiv` with decimal arguments. Fixes [#56414](https://github.com/ClickHouse/ClickHouse/issues/56414). [#59243](https://github.com/ClickHouse/ClickHouse/pull/59243) ([Yarik Briukhovetskyi](https://github.com/yariks5s)). +* Fix translate() with FixedString input. Could lead to crashes as it'd return a String column (vs the expected FixedString). This issue was found through ClickHouse Bug Bounty Program YohannJardin. [#59356](https://github.com/ClickHouse/ClickHouse/pull/59356) ([Raúl Marín](https://github.com/Algunenano)). +* Keeper fix: fix digest calculation for nodes. [#59439](https://github.com/ClickHouse/ClickHouse/pull/59439) ([Antonio Andelic](https://github.com/antonio2368)). +* Fix stacktraces for binaries without debug symbols. [#59444](https://github.com/ClickHouse/ClickHouse/pull/59444) ([Azat Khuzhin](https://github.com/azat)). +* Fix formatting of alter commands in case of column specific settings. [#59445](https://github.com/ClickHouse/ClickHouse/pull/59445) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* `SELECT * FROM [...] ORDER BY ALL SETTINGS allow_experimental_analyzer = 1` now works. [#59462](https://github.com/ClickHouse/ClickHouse/pull/59462) ([zhongyuankai](https://github.com/zhongyuankai)). +* Fix possible uncaught exception during distributed query cancellation. Closes [#59169](https://github.com/ClickHouse/ClickHouse/issues/59169). [#59487](https://github.com/ClickHouse/ClickHouse/pull/59487) ([Azat Khuzhin](https://github.com/azat)). +* Make MAX use the same rules as permutation for complex types. [#59498](https://github.com/ClickHouse/ClickHouse/pull/59498) ([Raúl Marín](https://github.com/Algunenano)). +* Fix a corner case when passing `update_insert_deduplication_token_in_dependent_materialized_views` setting. There is one corner case not covered due to the absence of tables in the path:. [#59544](https://github.com/ClickHouse/ClickHouse/pull/59544) ([Jordi Villar](https://github.com/jrdi)). +* Fix incorrect result of arrayElement / map[] on empty value. [#59594](https://github.com/ClickHouse/ClickHouse/pull/59594) ([Raúl Marín](https://github.com/Algunenano)). +* Fix crash in topK when merging empty states. [#59603](https://github.com/ClickHouse/ClickHouse/pull/59603) ([Raúl Marín](https://github.com/Algunenano)). +* Fix distributed table with a constant sharding key. [#59606](https://github.com/ClickHouse/ClickHouse/pull/59606) ([Vitaly Baranov](https://github.com/vitlibar)). +* Fix segmentation fault in KQL parser when the input query exceeds the `max_query_size`. Also re-enable the KQL dialect. Fixes [#59036](https://github.com/ClickHouse/ClickHouse/issues/59036) and [#59037](https://github.com/ClickHouse/ClickHouse/issues/59037). [#59626](https://github.com/ClickHouse/ClickHouse/pull/59626) ([Yong Wang](https://github.com/kashwy)). +* Fix error `Read beyond last offset` for `AsynchronousBoundedReadBuffer`. [#59630](https://github.com/ClickHouse/ClickHouse/pull/59630) ([Vitaly Baranov](https://github.com/vitlibar)). +* Maintain function alias in RewriteSumFunctionWithSumAndCountVisitor. [#59658](https://github.com/ClickHouse/ClickHouse/pull/59658) ([Raúl Marín](https://github.com/Algunenano)). +* Fix query start time on non initial queries. [#59662](https://github.com/ClickHouse/ClickHouse/pull/59662) ([Raúl Marín](https://github.com/Algunenano)). +* Validate types of arguments for `minmax` skipping index. [#59733](https://github.com/ClickHouse/ClickHouse/pull/59733) ([Anton Popov](https://github.com/CurtizJ)). +* Fix leftPad / rightPad function with FixedString input. [#59739](https://github.com/ClickHouse/ClickHouse/pull/59739) ([Raúl Marín](https://github.com/Algunenano)). +* Fixed an exception in function `countMatches` with non-const `FixedString` haystack arguments, e.g. `SELECT countMatches(materialize(toFixedString('foobarfoo', 9)), 'foo');`. [#59752](https://github.com/ClickHouse/ClickHouse/pull/59752) ([Robert Schulze](https://github.com/rschu1ze)). +* Fix having neigher acked nor nacked messages. If exception happens during read-write phase, messages will be nacked. [#59775](https://github.com/ClickHouse/ClickHouse/pull/59775) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fixed queries that read a Parquet file over HTTP (url()/URL()) executing in one thread instead of max_threads. [#59833](https://github.com/ClickHouse/ClickHouse/pull/59833) ([Michael Kolupaev](https://github.com/al13n321)). +* Fixed uninitialized value in s3 queue, which happened during upgrade to a new version if table had Ordered mode and resulted in an error "Existing table metadata in ZooKeeper differs in s3queue_processing_threads_num setting". [#59897](https://github.com/ClickHouse/ClickHouse/pull/59897) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix parsing of partition expressions that are surrounded by parentheses, e.g.: `ALTER TABLE test DROP PARTITION ('2023-10-19')`. [#59901](https://github.com/ClickHouse/ClickHouse/pull/59901) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* Fix crash in JSONColumnsWithMetadata format over http. Closes [#59853](https://github.com/ClickHouse/ClickHouse/issues/59853). [#59925](https://github.com/ClickHouse/ClickHouse/pull/59925) ([Kruglov Pavel](https://github.com/Avogar)). +* Do not rewrite sum() to count() if return value differs in analyzer. [#59926](https://github.com/ClickHouse/ClickHouse/pull/59926) ([Azat Khuzhin](https://github.com/azat)). +* Fix crash during deserialization of aggregation function states that internally use `UniqExactSet`. Introduced https://github.com/ClickHouse/ClickHouse/pull/59009. [#59928](https://github.com/ClickHouse/ClickHouse/pull/59928) ([Maksim Kita](https://github.com/kitaisreal)). +* ReplicatedMergeTree fix invalid `metadata_version` node initialization in Zookeeper during creation of non first replica. Closes [#54902](https://github.com/ClickHouse/ClickHouse/issues/54902). [#59946](https://github.com/ClickHouse/ClickHouse/pull/59946) ([Maksim Kita](https://github.com/kitaisreal)). +* Fixed data race on cluster object between `StorageDistributed` and `Context::reloadClusterConfig()`. Former held const reference to its member while the latter destroyed the object (in process of replacing it with a new one). [#59987](https://github.com/ClickHouse/ClickHouse/pull/59987) ([Nikita Taranov](https://github.com/nickitat)). +* Fixes [#59989](https://github.com/ClickHouse/ClickHouse/issues/59989): runs init scripts when force-enabled or when no database exists, rather than the inverse. [#59991](https://github.com/ClickHouse/ClickHouse/pull/59991) ([jktng](https://github.com/jktng)). +* This PR fixes scale conversion for DateTime64 values (for example, DateTime64(6)->DateTime64(3)). ```SQL create table test (result DateTime64(3)) engine=Memory;. [#60004](https://github.com/ClickHouse/ClickHouse/pull/60004) ([Yarik Briukhovetskyi](https://github.com/yariks5s)). +* Fix INSERT into SQLite with single quote (by properly escaping single quotes with a quote instead of backslash). [#60015](https://github.com/ClickHouse/ClickHouse/pull/60015) ([Azat Khuzhin](https://github.com/azat)). +* Fix several logical errors in arrayFold. Fixes support for Nullable and LowCardinality. [#60022](https://github.com/ClickHouse/ClickHouse/pull/60022) ([Raúl Marín](https://github.com/Algunenano)). +* Fix optimize_uniq_to_count removing the column alias. [#60026](https://github.com/ClickHouse/ClickHouse/pull/60026) ([Raúl Marín](https://github.com/Algunenano)). +* Fix possible error while dropping s3queue table, like "no node shard0". [#60036](https://github.com/ClickHouse/ClickHouse/pull/60036) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix formatting of NOT with single literals. [#60042](https://github.com/ClickHouse/ClickHouse/pull/60042) ([Raúl Marín](https://github.com/Algunenano)). +* Use max_query_size from context in parsing changed settings in DDLWorker. Previously with large number of changed settings DDLWorker could fail with `Max query size exceeded` error and don't process log entries. [#60083](https://github.com/ClickHouse/ClickHouse/pull/60083) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix inconsistent formatting of queries containing tables named `table`. Fix wrong formatting of queries with `UNION ALL`, `INTERSECT`, and `EXCEPT` when their structure wasn't linear. This closes [#52349](https://github.com/ClickHouse/ClickHouse/issues/52349). Fix wrong formatting of `SYSTEM` queries, including `SYSTEM ... DROP FILESYSTEM CACHE`, `SYSTEM ... REFRESH/START/STOP/CANCEL/TEST VIEW`, `SYSTEM ENABLE/DISABLE FAILPOINT`. Fix formatting of parameterized DDL queries. Fix the formatting of the `DESCRIBE FILESYSTEM CACHE` query. Fix incorrect formatting of the `SET param_...` (a query setting a parameter). Fix incorrect formatting of `CREATE INDEX` queries. Fix inconsistent formatting of `CREATE USER` and similar queries. Fix inconsistent formatting of `CREATE SETTINGS PROFILE`. Fix incorrect formatting of `ALTER ... MODIFY REFRESH`. Fix inconsistent formatting of window functions if frame offsets were expressions. Fix inconsistent formatting of `RESPECT NULLS` and `IGNORE NULLS` if they were used after a function that implements an operator (such as `plus`). Fix idiotic formatting of `SYSTEM SYNC REPLICA ... LIGHTWEIGHT FROM ...`. Fix inconsistent formatting of invalid queries with `GROUP BY GROUPING SETS ... WITH ROLLUP/CUBE/TOTALS`. Fix inconsistent formatting of `GRANT CURRENT GRANTS`. Fix inconsistent formatting of `CREATE TABLE (... COLLATE)`. Additionally, I fixed the incorrect formatting of `EXPLAIN` in subqueries ([#60102](https://github.com/ClickHouse/ClickHouse/issues/60102)). Fixed incorrect formatting of lambda functions ([#60012](https://github.com/ClickHouse/ClickHouse/issues/60012)). Added a check so there is no way to miss these abominations in the future. [#60095](https://github.com/ClickHouse/ClickHouse/pull/60095) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Queries like `SELECT * FROM (EXPLAIN ...)` were formatted incorrectly. [#60102](https://github.com/ClickHouse/ClickHouse/pull/60102) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Fix cosineDistance crash with Nullable. [#60150](https://github.com/ClickHouse/ClickHouse/pull/60150) ([Raúl Marín](https://github.com/Algunenano)). +* Boolean values in string representation now cast to true bools. E.g. this query previously threw an exception but now works: `SELECT true = 'true'`. [#60160](https://github.com/ClickHouse/ClickHouse/pull/60160) ([Robert Schulze](https://github.com/rschu1ze)). +* Fix non-filled column `table_uuid` in `system.s3queue_log`. Added columns `database` and `table`. Renamed `table_uuid` to `uuid`. [#60166](https://github.com/ClickHouse/ClickHouse/pull/60166) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix arrayReduce with nullable aggregate function name. [#60188](https://github.com/ClickHouse/ClickHouse/pull/60188) ([Raúl Marín](https://github.com/Algunenano)). +* Fix actions execution during preliminary filtering (PK, partition pruning). [#60196](https://github.com/ClickHouse/ClickHouse/pull/60196) ([Azat Khuzhin](https://github.com/azat)). +* Hide sensitive info for `S3Queue` table engine. [#60233](https://github.com/ClickHouse/ClickHouse/pull/60233) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Restore the previous syntax `ORDER BY ALL` which has temporarily (for a few days) been replaced by ORDER BY *. [#60248](https://github.com/ClickHouse/ClickHouse/pull/60248) ([Robert Schulze](https://github.com/rschu1ze)). +* Fixed a minor bug that caused all http return codes to be 200 (success) instead of a relevant code on exception. [#60252](https://github.com/ClickHouse/ClickHouse/pull/60252) ([Austin Kothig](https://github.com/kothiga)). +* Fix bug in `S3Queue` table engine with ordered parallel mode. [#60282](https://github.com/ClickHouse/ClickHouse/pull/60282) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix use-of-uninitialized-value and invalid result in hashing functions with IPv6. [#60359](https://github.com/ClickHouse/ClickHouse/pull/60359) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix OptimizeDateOrDateTimeConverterWithPreimageVisitor with null arguments. [#60453](https://github.com/ClickHouse/ClickHouse/pull/60453) ([Raúl Marín](https://github.com/Algunenano)). +* Fixed a minor bug that prevented distributed table queries sent from either KQL or PRQL dialect clients to be executed on replicas. [#60470](https://github.com/ClickHouse/ClickHouse/pull/60470) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Fix incomplete results with s3Cluster when multiple threads are used. [#60477](https://github.com/ClickHouse/ClickHouse/pull/60477) ([Antonio Andelic](https://github.com/antonio2368)). #### CI Fix or Improvement (changelog entry is not required) diff --git a/docs/changelogs/v24.2.2.71-stable.md b/docs/changelogs/v24.2.2.71-stable.md index b9aa5be626b..e17c22ab176 100644 --- a/docs/changelogs/v24.2.2.71-stable.md +++ b/docs/changelogs/v24.2.2.71-stable.md @@ -12,21 +12,21 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* PartsSplitter invalid ranges for the same part [#60041](https://github.com/ClickHouse/ClickHouse/pull/60041) ([Maksim Kita](https://github.com/kitaisreal)). -* Try to avoid calculation of scalar subqueries for CREATE TABLE. [#60464](https://github.com/ClickHouse/ClickHouse/pull/60464) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fix deadlock in parallel parsing when lots of rows are skipped due to errors [#60516](https://github.com/ClickHouse/ClickHouse/pull/60516) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix_max_query_size_for_kql_compound_operator: [#60534](https://github.com/ClickHouse/ClickHouse/pull/60534) ([Yong Wang](https://github.com/kashwy)). -* Reduce the number of read rows from `system.numbers` [#60546](https://github.com/ClickHouse/ClickHouse/pull/60546) ([JackyWoo](https://github.com/JackyWoo)). -* Don't output number tips for date types [#60577](https://github.com/ClickHouse/ClickHouse/pull/60577) ([Raúl Marín](https://github.com/Algunenano)). -* Fix buffer overflow in CompressionCodecMultiple [#60731](https://github.com/ClickHouse/ClickHouse/pull/60731) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Remove nonsense from SQL/JSON [#60738](https://github.com/ClickHouse/ClickHouse/pull/60738) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Prevent setting custom metadata headers on unsupported multipart upload operations [#60748](https://github.com/ClickHouse/ClickHouse/pull/60748) ([Francisco J. Jurado Moreno](https://github.com/Beetelbrox)). -* Fix crash in arrayEnumerateRanked [#60764](https://github.com/ClickHouse/ClickHouse/pull/60764) ([Raúl Marín](https://github.com/Algunenano)). -* Fix crash when using input() in INSERT SELECT JOIN [#60765](https://github.com/ClickHouse/ClickHouse/pull/60765) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix crash with different allow_experimental_analyzer value in subqueries [#60770](https://github.com/ClickHouse/ClickHouse/pull/60770) ([Dmitry Novik](https://github.com/novikd)). -* Remove recursion when reading from S3 [#60849](https://github.com/ClickHouse/ClickHouse/pull/60849) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix multiple bugs in groupArraySorted [#61203](https://github.com/ClickHouse/ClickHouse/pull/61203) ([Raúl Marín](https://github.com/Algunenano)). -* Fix Keeper reconfig for standalone binary [#61233](https://github.com/ClickHouse/ClickHouse/pull/61233) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#60640](https://github.com/ClickHouse/ClickHouse/issues/60640): Fixed a bug in parallel optimization for queries with `FINAL`, which could give an incorrect result in rare cases. [#60041](https://github.com/ClickHouse/ClickHouse/pull/60041) ([Maksim Kita](https://github.com/kitaisreal)). +* Backported in [#61085](https://github.com/ClickHouse/ClickHouse/issues/61085): Avoid calculation of scalar subqueries for `CREATE TABLE`. Fixes [#59795](https://github.com/ClickHouse/ClickHouse/issues/59795) and [#59930](https://github.com/ClickHouse/ClickHouse/issues/59930). Attempt to re-implement https://github.com/ClickHouse/ClickHouse/pull/57855. [#60464](https://github.com/ClickHouse/ClickHouse/pull/60464) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Backported in [#61332](https://github.com/ClickHouse/ClickHouse/issues/61332): Fix deadlock in parallel parsing when lots of rows are skipped due to errors. [#60516](https://github.com/ClickHouse/ClickHouse/pull/60516) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#61010](https://github.com/ClickHouse/ClickHouse/issues/61010): Fix the issue of `max_query_size` for KQL compound operator like mv-expand. Related to [#59626](https://github.com/ClickHouse/ClickHouse/issues/59626). [#60534](https://github.com/ClickHouse/ClickHouse/pull/60534) ([Yong Wang](https://github.com/kashwy)). +* Backported in [#61002](https://github.com/ClickHouse/ClickHouse/issues/61002): Reduce the number of read rows from `system.numbers`. Fixes [#59418](https://github.com/ClickHouse/ClickHouse/issues/59418). [#60546](https://github.com/ClickHouse/ClickHouse/pull/60546) ([JackyWoo](https://github.com/JackyWoo)). +* Backported in [#60629](https://github.com/ClickHouse/ClickHouse/issues/60629): Don't output number tips for date types. [#60577](https://github.com/ClickHouse/ClickHouse/pull/60577) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#60793](https://github.com/ClickHouse/ClickHouse/issues/60793): Fix buffer overflow that can happen if the attacker asks the HTTP server to decompress data with a composition of codecs and size triggering numeric overflow. Fix buffer overflow that can happen inside codec NONE on wrong input data. This was submitted by TIANGONG research team through our [Bug Bounty program](https://github.com/ClickHouse/ClickHouse/issues/38986). [#60731](https://github.com/ClickHouse/ClickHouse/pull/60731) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Backported in [#60785](https://github.com/ClickHouse/ClickHouse/issues/60785): Functions for SQL/JSON were able to read uninitialized memory. This closes [#60017](https://github.com/ClickHouse/ClickHouse/issues/60017). Found by Fuzzer. [#60738](https://github.com/ClickHouse/ClickHouse/pull/60738) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Backported in [#60805](https://github.com/ClickHouse/ClickHouse/issues/60805): Do not set aws custom metadata `x-amz-meta-*` headers on UploadPart & CompleteMultipartUpload calls. [#60748](https://github.com/ClickHouse/ClickHouse/pull/60748) ([Francisco J. Jurado Moreno](https://github.com/Beetelbrox)). +* Backported in [#60822](https://github.com/ClickHouse/ClickHouse/issues/60822): Fix crash in arrayEnumerateRanked. [#60764](https://github.com/ClickHouse/ClickHouse/pull/60764) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#60843](https://github.com/ClickHouse/ClickHouse/issues/60843): Fix crash when using input() in INSERT SELECT JOIN. Closes [#60035](https://github.com/ClickHouse/ClickHouse/issues/60035). [#60765](https://github.com/ClickHouse/ClickHouse/pull/60765) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#60919](https://github.com/ClickHouse/ClickHouse/issues/60919): Fix crash when `allow_experimental_analyzer` setting value is changed in the subqueries. [#60770](https://github.com/ClickHouse/ClickHouse/pull/60770) ([Dmitry Novik](https://github.com/novikd)). +* Backported in [#60906](https://github.com/ClickHouse/ClickHouse/issues/60906): Avoid segfault if too many keys are skipped when reading from S3. [#60849](https://github.com/ClickHouse/ClickHouse/pull/60849) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#61307](https://github.com/ClickHouse/ClickHouse/issues/61307): Fix multiple bugs in groupArraySorted. [#61203](https://github.com/ClickHouse/ClickHouse/pull/61203) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#61295](https://github.com/ClickHouse/ClickHouse/issues/61295): Keeper: fix runtime reconfig for standalone binary. [#61233](https://github.com/ClickHouse/ClickHouse/pull/61233) ([Antonio Andelic](https://github.com/antonio2368)). #### CI Fix or Improvement (changelog entry is not required) diff --git a/docs/changelogs/v24.2.3.70-stable.md b/docs/changelogs/v24.2.3.70-stable.md index cd88877e254..1a50355e0b9 100644 --- a/docs/changelogs/v24.2.3.70-stable.md +++ b/docs/changelogs/v24.2.3.70-stable.md @@ -15,28 +15,28 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix possible incorrect result of aggregate function `uniqExact` [#61257](https://github.com/ClickHouse/ClickHouse/pull/61257) ([Anton Popov](https://github.com/CurtizJ)). -* Fix ATTACH query with external ON CLUSTER [#61365](https://github.com/ClickHouse/ClickHouse/pull/61365) ([Nikolay Degterinsky](https://github.com/evillique)). -* Fix consecutive keys optimization for nullable keys [#61393](https://github.com/ClickHouse/ClickHouse/pull/61393) ([Anton Popov](https://github.com/CurtizJ)). -* fix issue of actions dag split [#61458](https://github.com/ClickHouse/ClickHouse/pull/61458) ([Raúl Marín](https://github.com/Algunenano)). -* Disable async_insert_use_adaptive_busy_timeout correctly with compatibility settings [#61468](https://github.com/ClickHouse/ClickHouse/pull/61468) ([Raúl Marín](https://github.com/Algunenano)). -* Fix bug when reading system.parts using UUID (issue 61220). [#61479](https://github.com/ClickHouse/ClickHouse/pull/61479) ([Dan Wu](https://github.com/wudanzy)). -* Fix ALTER QUERY MODIFY SQL SECURITY [#61480](https://github.com/ClickHouse/ClickHouse/pull/61480) ([pufit](https://github.com/pufit)). -* Fix client `-s` argument [#61530](https://github.com/ClickHouse/ClickHouse/pull/61530) ([Mikhail f. Shiryaev](https://github.com/Felixoid)). -* Fix string search with const position [#61547](https://github.com/ClickHouse/ClickHouse/pull/61547) ([Antonio Andelic](https://github.com/antonio2368)). -* Cancel merges before removing moved parts [#61610](https://github.com/ClickHouse/ClickHouse/pull/61610) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). -* Fix crash in `multiSearchAllPositionsCaseInsensitiveUTF8` for incorrect UTF-8 [#61749](https://github.com/ClickHouse/ClickHouse/pull/61749) ([pufit](https://github.com/pufit)). -* Mark CANNOT_PARSE_ESCAPE_SEQUENCE error as parse error to be able to skip it in row input formats [#61883](https://github.com/ClickHouse/ClickHouse/pull/61883) ([Kruglov Pavel](https://github.com/Avogar)). -* Crash in Engine Merge if Row Policy does not have expression [#61971](https://github.com/ClickHouse/ClickHouse/pull/61971) ([Ilya Golshtein](https://github.com/ilejn)). -* Fix data race on scalars in Context [#62305](https://github.com/ClickHouse/ClickHouse/pull/62305) ([Kruglov Pavel](https://github.com/Avogar)). -* Try to fix segfault in Hive engine [#62578](https://github.com/ClickHouse/ClickHouse/pull/62578) ([Nikolay Degterinsky](https://github.com/evillique)). -* Fix memory leak in groupArraySorted [#62597](https://github.com/ClickHouse/ClickHouse/pull/62597) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix GCD codec [#62853](https://github.com/ClickHouse/ClickHouse/pull/62853) ([Nikita Taranov](https://github.com/nickitat)). -* Fix temporary data in cache incorrectly processing failure of cache key directory creation [#62925](https://github.com/ClickHouse/ClickHouse/pull/62925) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix incorrect judgement of of monotonicity of function abs [#63097](https://github.com/ClickHouse/ClickHouse/pull/63097) ([Duc Canh Le](https://github.com/canhld94)). -* Make sanity check of settings worse [#63119](https://github.com/ClickHouse/ClickHouse/pull/63119) ([Raúl Marín](https://github.com/Algunenano)). -* Set server name for SSL handshake in MongoDB engine [#63122](https://github.com/ClickHouse/ClickHouse/pull/63122) ([Alexander Gololobov](https://github.com/davenger)). -* Format SQL security option only in `CREATE VIEW` queries. [#63136](https://github.com/ClickHouse/ClickHouse/pull/63136) ([pufit](https://github.com/pufit)). +* Backported in [#61453](https://github.com/ClickHouse/ClickHouse/issues/61453): Fix possible incorrect result of aggregate function `uniqExact`. [#61257](https://github.com/ClickHouse/ClickHouse/pull/61257) ([Anton Popov](https://github.com/CurtizJ)). +* Backported in [#61946](https://github.com/ClickHouse/ClickHouse/issues/61946): Fix the ATTACH query with the ON CLUSTER clause when the database does not exist on the initiator node. Closes [#55009](https://github.com/ClickHouse/ClickHouse/issues/55009). [#61365](https://github.com/ClickHouse/ClickHouse/pull/61365) ([Nikolay Degterinsky](https://github.com/evillique)). +* Backported in [#61846](https://github.com/ClickHouse/ClickHouse/issues/61846): Fixed possible wrong result of aggregation with nullable keys. [#61393](https://github.com/ClickHouse/ClickHouse/pull/61393) ([Anton Popov](https://github.com/CurtizJ)). +* Backported in [#61591](https://github.com/ClickHouse/ClickHouse/issues/61591): ActionsDAG::split can't make sure that "Execution of first then second parts on block is equivalent to execution of initial DAG.". [#61458](https://github.com/ClickHouse/ClickHouse/pull/61458) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#61648](https://github.com/ClickHouse/ClickHouse/issues/61648): Disable async_insert_use_adaptive_busy_timeout correctly with compatibility settings. [#61468](https://github.com/ClickHouse/ClickHouse/pull/61468) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#61748](https://github.com/ClickHouse/ClickHouse/issues/61748): Fix incorrect results when filtering `system.parts` or `system.parts_columns` using UUID. [#61479](https://github.com/ClickHouse/ClickHouse/pull/61479) ([Dan Wu](https://github.com/wudanzy)). +* Backported in [#61963](https://github.com/ClickHouse/ClickHouse/issues/61963): Fix the `ALTER QUERY MODIFY SQL SECURITY` queries to override the table's DDL correctly. [#61480](https://github.com/ClickHouse/ClickHouse/pull/61480) ([pufit](https://github.com/pufit)). +* Backported in [#61699](https://github.com/ClickHouse/ClickHouse/issues/61699): Fix `clickhouse-client -s` argument, it was broken by defining it two times. [#61530](https://github.com/ClickHouse/ClickHouse/pull/61530) ([Mikhail f. Shiryaev](https://github.com/Felixoid)). +* Backported in [#61578](https://github.com/ClickHouse/ClickHouse/issues/61578): Fix string search with constant start position which previously could lead to memory corruption. [#61547](https://github.com/ClickHouse/ClickHouse/pull/61547) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#62531](https://github.com/ClickHouse/ClickHouse/issues/62531): Fix data race between `MOVE PARTITION` query and merges resulting in intersecting parts. [#61610](https://github.com/ClickHouse/ClickHouse/pull/61610) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* Backported in [#61860](https://github.com/ClickHouse/ClickHouse/issues/61860): Fix crash in `multiSearchAllPositionsCaseInsensitiveUTF8` when specifying incorrect UTF-8 sequence. Example: [#61714](https://github.com/ClickHouse/ClickHouse/issues/61714#issuecomment-2012768202). [#61749](https://github.com/ClickHouse/ClickHouse/pull/61749) ([pufit](https://github.com/pufit)). +* Backported in [#62242](https://github.com/ClickHouse/ClickHouse/issues/62242): Fix skipping escape sequcne parsing errors during JSON data parsing while using `input_format_allow_errors_num/ratio` settings. [#61883](https://github.com/ClickHouse/ClickHouse/pull/61883) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#62218](https://github.com/ClickHouse/ClickHouse/issues/62218): Fixes Crash in Engine Merge if Row Policy does not have expression. [#61971](https://github.com/ClickHouse/ClickHouse/pull/61971) ([Ilya Golshtein](https://github.com/ilejn)). +* Backported in [#62342](https://github.com/ClickHouse/ClickHouse/issues/62342): Fix data race on scalars in Context. [#62305](https://github.com/ClickHouse/ClickHouse/pull/62305) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#62677](https://github.com/ClickHouse/ClickHouse/issues/62677): Fix segmentation fault when using Hive table engine. Reference [#62154](https://github.com/ClickHouse/ClickHouse/issues/62154), [#62560](https://github.com/ClickHouse/ClickHouse/issues/62560). [#62578](https://github.com/ClickHouse/ClickHouse/pull/62578) ([Nikolay Degterinsky](https://github.com/evillique)). +* Backported in [#62639](https://github.com/ClickHouse/ClickHouse/issues/62639): Fix memory leak in groupArraySorted. Fix [#62536](https://github.com/ClickHouse/ClickHouse/issues/62536). [#62597](https://github.com/ClickHouse/ClickHouse/pull/62597) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#63054](https://github.com/ClickHouse/ClickHouse/issues/63054): Fixed bug in GCD codec implementation that may lead to server crashes. [#62853](https://github.com/ClickHouse/ClickHouse/pull/62853) ([Nikita Taranov](https://github.com/nickitat)). +* Backported in [#63030](https://github.com/ClickHouse/ClickHouse/issues/63030): Fix temporary data in cache incorrect behaviour in case creation of cache key base directory fails with `no space left on device`. [#62925](https://github.com/ClickHouse/ClickHouse/pull/62925) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Backported in [#63142](https://github.com/ClickHouse/ClickHouse/issues/63142): Fix incorrect judgement of of monotonicity of function `abs`. [#63097](https://github.com/ClickHouse/ClickHouse/pull/63097) ([Duc Canh Le](https://github.com/canhld94)). +* Backported in [#63183](https://github.com/ClickHouse/ClickHouse/issues/63183): Sanity check: Clamp values instead of throwing. [#63119](https://github.com/ClickHouse/ClickHouse/pull/63119) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#63176](https://github.com/ClickHouse/ClickHouse/issues/63176): Setting server_name might help with recently reported SSL handshake error when connecting to MongoDB Atlas: `Poco::Exception. Code: 1000, e.code() = 0, SSL Exception: error:10000438:SSL routines:OPENSSL_internal:TLSV1_ALERT_INTERNAL_ERROR`. [#63122](https://github.com/ClickHouse/ClickHouse/pull/63122) ([Alexander Gololobov](https://github.com/davenger)). +* Backported in [#63191](https://github.com/ClickHouse/ClickHouse/issues/63191): Fix a bug when `SQL SECURITY` statement appears in all `CREATE` queries if the server setting `ignore_empty_sql_security_in_create_view_query=true` https://github.com/ClickHouse/ClickHouse/pull/63134. [#63136](https://github.com/ClickHouse/ClickHouse/pull/63136) ([pufit](https://github.com/pufit)). #### CI Fix or Improvement (changelog entry is not required) diff --git a/docs/changelogs/v24.3.1.2672-lts.md b/docs/changelogs/v24.3.1.2672-lts.md index 006ab941203..a70a33971c2 100644 --- a/docs/changelogs/v24.3.1.2672-lts.md +++ b/docs/changelogs/v24.3.1.2672-lts.md @@ -20,7 +20,7 @@ sidebar_label: 2024 #### New Feature * Topk/topkweighed support mode, which return count of values and it's error. [#54508](https://github.com/ClickHouse/ClickHouse/pull/54508) ([UnamedRus](https://github.com/UnamedRus)). -* Add generate_series as a table function. This function generates table with an arithmetic progression with natural numbers. [#59390](https://github.com/ClickHouse/ClickHouse/pull/59390) ([divanik](https://github.com/divanik)). +* Add generate_series as a table function. This function generates table with an arithmetic progression with natural numbers. [#59390](https://github.com/ClickHouse/ClickHouse/pull/59390) ([Daniil Ivanik](https://github.com/divanik)). * Support reading and writing backups as tar archives. [#59535](https://github.com/ClickHouse/ClickHouse/pull/59535) ([josh-hildred](https://github.com/josh-hildred)). * Implemented support for S3Express buckets. [#59965](https://github.com/ClickHouse/ClickHouse/pull/59965) ([Nikita Taranov](https://github.com/nickitat)). * Allow to attach parts from a different disk * attach partition from the table on other disks using copy instead of hard link (such as instant table) * attach partition using copy when the hard link fails even on the same disk. [#60112](https://github.com/ClickHouse/ClickHouse/pull/60112) ([Unalian](https://github.com/Unalian)). @@ -133,75 +133,75 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix function execution over const and LowCardinality with GROUP BY const for analyzer [#59986](https://github.com/ClickHouse/ClickHouse/pull/59986) ([Azat Khuzhin](https://github.com/azat)). -* Fix finished_mutations_to_keep=0 for MergeTree (as docs says 0 is to keep everything) [#60031](https://github.com/ClickHouse/ClickHouse/pull/60031) ([Azat Khuzhin](https://github.com/azat)). -* PartsSplitter invalid ranges for the same part [#60041](https://github.com/ClickHouse/ClickHouse/pull/60041) ([Maksim Kita](https://github.com/kitaisreal)). -* Azure Blob Storage : Fix issues endpoint and prefix [#60251](https://github.com/ClickHouse/ClickHouse/pull/60251) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)). -* fix LRUResource Cache bug (Hive cache) [#60262](https://github.com/ClickHouse/ClickHouse/pull/60262) ([shanfengp](https://github.com/Aed-p)). -* Force reanalysis if parallel replicas changed [#60362](https://github.com/ClickHouse/ClickHouse/pull/60362) ([Raúl Marín](https://github.com/Algunenano)). -* Fix usage of plain metadata type with new disks configuration option [#60396](https://github.com/ClickHouse/ClickHouse/pull/60396) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Try to fix logical error 'Cannot capture column because it has incompatible type' in mapContainsKeyLike [#60451](https://github.com/ClickHouse/ClickHouse/pull/60451) ([Kruglov Pavel](https://github.com/Avogar)). -* Try to avoid calculation of scalar subqueries for CREATE TABLE. [#60464](https://github.com/ClickHouse/ClickHouse/pull/60464) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fix deadlock in parallel parsing when lots of rows are skipped due to errors [#60516](https://github.com/ClickHouse/ClickHouse/pull/60516) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix_max_query_size_for_kql_compound_operator: [#60534](https://github.com/ClickHouse/ClickHouse/pull/60534) ([Yong Wang](https://github.com/kashwy)). -* Keeper fix: add timeouts when waiting for commit logs [#60544](https://github.com/ClickHouse/ClickHouse/pull/60544) ([Antonio Andelic](https://github.com/antonio2368)). -* Reduce the number of read rows from `system.numbers` [#60546](https://github.com/ClickHouse/ClickHouse/pull/60546) ([JackyWoo](https://github.com/JackyWoo)). -* Don't output number tips for date types [#60577](https://github.com/ClickHouse/ClickHouse/pull/60577) ([Raúl Marín](https://github.com/Algunenano)). -* Fix reading from MergeTree with non-deterministic functions in filter [#60586](https://github.com/ClickHouse/ClickHouse/pull/60586) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix logical error on bad compatibility setting value type [#60596](https://github.com/ClickHouse/ClickHouse/pull/60596) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix inconsistent aggregate function states in mixed x86-64 / ARM clusters [#60610](https://github.com/ClickHouse/ClickHouse/pull/60610) ([Harry Lee](https://github.com/HarryLeeIBM)). -* fix(prql): Robust panic handler [#60615](https://github.com/ClickHouse/ClickHouse/pull/60615) ([Maximilian Roos](https://github.com/max-sixty)). -* Fix `intDiv` for decimal and date arguments [#60672](https://github.com/ClickHouse/ClickHouse/pull/60672) ([Yarik Briukhovetskyi](https://github.com/yariks5s)). -* Fix: expand CTE in alter modify query [#60682](https://github.com/ClickHouse/ClickHouse/pull/60682) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). -* Fix system.parts for non-Atomic/Ordinary database engine (i.e. Memory) [#60689](https://github.com/ClickHouse/ClickHouse/pull/60689) ([Azat Khuzhin](https://github.com/azat)). -* Fix "Invalid storage definition in metadata file" for parameterized views [#60708](https://github.com/ClickHouse/ClickHouse/pull/60708) ([Azat Khuzhin](https://github.com/azat)). -* Fix buffer overflow in CompressionCodecMultiple [#60731](https://github.com/ClickHouse/ClickHouse/pull/60731) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Remove nonsense from SQL/JSON [#60738](https://github.com/ClickHouse/ClickHouse/pull/60738) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Remove wrong sanitize checking in aggregate function quantileGK [#60740](https://github.com/ClickHouse/ClickHouse/pull/60740) ([李扬](https://github.com/taiyang-li)). -* Fix insert-select + insert_deduplication_token bug by setting streams to 1 [#60745](https://github.com/ClickHouse/ClickHouse/pull/60745) ([Jordi Villar](https://github.com/jrdi)). -* Prevent setting custom metadata headers on unsupported multipart upload operations [#60748](https://github.com/ClickHouse/ClickHouse/pull/60748) ([Francisco J. Jurado Moreno](https://github.com/Beetelbrox)). -* Fix toStartOfInterval [#60763](https://github.com/ClickHouse/ClickHouse/pull/60763) ([Andrey Zvonov](https://github.com/zvonand)). -* Fix crash in arrayEnumerateRanked [#60764](https://github.com/ClickHouse/ClickHouse/pull/60764) ([Raúl Marín](https://github.com/Algunenano)). -* Fix crash when using input() in INSERT SELECT JOIN [#60765](https://github.com/ClickHouse/ClickHouse/pull/60765) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix crash with different allow_experimental_analyzer value in subqueries [#60770](https://github.com/ClickHouse/ClickHouse/pull/60770) ([Dmitry Novik](https://github.com/novikd)). -* Remove recursion when reading from S3 [#60849](https://github.com/ClickHouse/ClickHouse/pull/60849) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix possible stuck on error in HashedDictionaryParallelLoader [#60926](https://github.com/ClickHouse/ClickHouse/pull/60926) ([vdimir](https://github.com/vdimir)). -* Fix async RESTORE with Replicated database [#60934](https://github.com/ClickHouse/ClickHouse/pull/60934) ([Antonio Andelic](https://github.com/antonio2368)). -* fix csv format not support tuple [#60994](https://github.com/ClickHouse/ClickHouse/pull/60994) ([shuai.xu](https://github.com/shuai-xu)). -* Fix deadlock in async inserts to `Log` tables via native protocol [#61055](https://github.com/ClickHouse/ClickHouse/pull/61055) ([Anton Popov](https://github.com/CurtizJ)). -* Fix lazy execution of default argument in dictGetOrDefault for RangeHashedDictionary [#61196](https://github.com/ClickHouse/ClickHouse/pull/61196) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix multiple bugs in groupArraySorted [#61203](https://github.com/ClickHouse/ClickHouse/pull/61203) ([Raúl Marín](https://github.com/Algunenano)). -* Fix Keeper reconfig for standalone binary [#61233](https://github.com/ClickHouse/ClickHouse/pull/61233) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix usage of session_token in S3 engine [#61234](https://github.com/ClickHouse/ClickHouse/pull/61234) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix possible incorrect result of aggregate function `uniqExact` [#61257](https://github.com/ClickHouse/ClickHouse/pull/61257) ([Anton Popov](https://github.com/CurtizJ)). -* Fix bugs in show database [#61269](https://github.com/ClickHouse/ClickHouse/pull/61269) ([Raúl Marín](https://github.com/Algunenano)). -* Fix logical error in RabbitMQ storage with MATERIALIZED columns [#61320](https://github.com/ClickHouse/ClickHouse/pull/61320) ([vdimir](https://github.com/vdimir)). -* Fix CREATE OR REPLACE DICTIONARY [#61356](https://github.com/ClickHouse/ClickHouse/pull/61356) ([Vitaly Baranov](https://github.com/vitlibar)). -* Fix crash in ObjectJson parsing array with nulls [#61364](https://github.com/ClickHouse/ClickHouse/pull/61364) ([vdimir](https://github.com/vdimir)). -* Fix ATTACH query with external ON CLUSTER [#61365](https://github.com/ClickHouse/ClickHouse/pull/61365) ([Nikolay Degterinsky](https://github.com/evillique)). -* Fix consecutive keys optimization for nullable keys [#61393](https://github.com/ClickHouse/ClickHouse/pull/61393) ([Anton Popov](https://github.com/CurtizJ)). -* fix issue of actions dag split [#61458](https://github.com/ClickHouse/ClickHouse/pull/61458) ([Raúl Marín](https://github.com/Algunenano)). -* Fix finishing a failed RESTORE [#61466](https://github.com/ClickHouse/ClickHouse/pull/61466) ([Vitaly Baranov](https://github.com/vitlibar)). -* Disable async_insert_use_adaptive_busy_timeout correctly with compatibility settings [#61468](https://github.com/ClickHouse/ClickHouse/pull/61468) ([Raúl Marín](https://github.com/Algunenano)). -* Allow queuing in restore pool [#61475](https://github.com/ClickHouse/ClickHouse/pull/61475) ([Nikita Taranov](https://github.com/nickitat)). -* Fix bug when reading system.parts using UUID (issue 61220). [#61479](https://github.com/ClickHouse/ClickHouse/pull/61479) ([Dan Wu](https://github.com/wudanzy)). -* Fix ALTER QUERY MODIFY SQL SECURITY [#61480](https://github.com/ClickHouse/ClickHouse/pull/61480) ([pufit](https://github.com/pufit)). -* Fix crash in window view [#61526](https://github.com/ClickHouse/ClickHouse/pull/61526) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Fix `repeat` with non native integers [#61527](https://github.com/ClickHouse/ClickHouse/pull/61527) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix client `-s` argument [#61530](https://github.com/ClickHouse/ClickHouse/pull/61530) ([Mikhail f. Shiryaev](https://github.com/Felixoid)). -* Reset part level upon attach from disk on MergeTree [#61536](https://github.com/ClickHouse/ClickHouse/pull/61536) ([Arthur Passos](https://github.com/arthurpassos)). -* Fix crash in arrayPartialReverseSort [#61539](https://github.com/ClickHouse/ClickHouse/pull/61539) ([Raúl Marín](https://github.com/Algunenano)). -* Fix string search with const position [#61547](https://github.com/ClickHouse/ClickHouse/pull/61547) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix addDays cause an error when used datetime64 [#61561](https://github.com/ClickHouse/ClickHouse/pull/61561) ([Shuai li](https://github.com/loneylee)). -* disallow LowCardinality input type for JSONExtract [#61617](https://github.com/ClickHouse/ClickHouse/pull/61617) ([Julia Kartseva](https://github.com/jkartseva)). -* Fix `system.part_log` for async insert with deduplication [#61620](https://github.com/ClickHouse/ClickHouse/pull/61620) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix Non-ready set for system.parts. [#61666](https://github.com/ClickHouse/ClickHouse/pull/61666) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Don't allow the same expression in ORDER BY with and without WITH FILL [#61667](https://github.com/ClickHouse/ClickHouse/pull/61667) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix actual_part_name for REPLACE_RANGE (`Entry actual part isn't empty yet`) [#61675](https://github.com/ClickHouse/ClickHouse/pull/61675) ([Alexander Tokmakov](https://github.com/tavplubix)). -* Fix columns after executing MODIFY QUERY for a materialized view with internal table [#61734](https://github.com/ClickHouse/ClickHouse/pull/61734) ([Vitaly Baranov](https://github.com/vitlibar)). -* Fix crash in `multiSearchAllPositionsCaseInsensitiveUTF8` for incorrect UTF-8 [#61749](https://github.com/ClickHouse/ClickHouse/pull/61749) ([pufit](https://github.com/pufit)). -* Fix RANGE frame is not supported for Nullable columns. [#61766](https://github.com/ClickHouse/ClickHouse/pull/61766) ([YuanLiu](https://github.com/ditgittube)). -* Revert "Revert "Fix bug when reading system.parts using UUID (issue 61220)."" [#61779](https://github.com/ClickHouse/ClickHouse/pull/61779) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* Fix function execution over const and LowCardinality with GROUP BY const for analyzer. [#59986](https://github.com/ClickHouse/ClickHouse/pull/59986) ([Azat Khuzhin](https://github.com/azat)). +* Fix finished_mutations_to_keep=0 for MergeTree (as docs says 0 is to keep everything). [#60031](https://github.com/ClickHouse/ClickHouse/pull/60031) ([Azat Khuzhin](https://github.com/azat)). +* Fixed a bug in parallel optimization for queries with `FINAL`, which could give an incorrect result in rare cases. [#60041](https://github.com/ClickHouse/ClickHouse/pull/60041) ([Maksim Kita](https://github.com/kitaisreal)). +* Updated to not include account_name in endpoint if flag `endpoint_contains_account_name` is set and fixed issue with empty container name. [#60251](https://github.com/ClickHouse/ClickHouse/pull/60251) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)). +* Fix LRUResource Cache implementation that can be triggered by incorrect component usage. Error can't be triggered with current ClickHouse usage. close [#60122](https://github.com/ClickHouse/ClickHouse/issues/60122). [#60262](https://github.com/ClickHouse/ClickHouse/pull/60262) ([shanfengp](https://github.com/Aed-p)). +* Force reanalysis of the query if parallel replicas isn't supported in a subquery. [#60362](https://github.com/ClickHouse/ClickHouse/pull/60362) ([Raúl Marín](https://github.com/Algunenano)). +* Fix usage of plain metadata type for new disks configuration option. [#60396](https://github.com/ClickHouse/ClickHouse/pull/60396) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix logical error 'Cannot capture column because it has incompatible type' in mapContainsKeyLike. [#60451](https://github.com/ClickHouse/ClickHouse/pull/60451) ([Kruglov Pavel](https://github.com/Avogar)). +* Avoid calculation of scalar subqueries for `CREATE TABLE`. Fixes [#59795](https://github.com/ClickHouse/ClickHouse/issues/59795) and [#59930](https://github.com/ClickHouse/ClickHouse/issues/59930). Attempt to re-implement https://github.com/ClickHouse/ClickHouse/pull/57855. [#60464](https://github.com/ClickHouse/ClickHouse/pull/60464) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix deadlock in parallel parsing when lots of rows are skipped due to errors. [#60516](https://github.com/ClickHouse/ClickHouse/pull/60516) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix the issue of `max_query_size` for KQL compound operator like mv-expand. Related to [#59626](https://github.com/ClickHouse/ClickHouse/issues/59626). [#60534](https://github.com/ClickHouse/ClickHouse/pull/60534) ([Yong Wang](https://github.com/kashwy)). +* Keeper fix: add timeouts when waiting for commit logs. Keeper could get stuck if the log successfully gets replicated but never committed. [#60544](https://github.com/ClickHouse/ClickHouse/pull/60544) ([Antonio Andelic](https://github.com/antonio2368)). +* Reduce the number of read rows from `system.numbers`. Fixes [#59418](https://github.com/ClickHouse/ClickHouse/issues/59418). [#60546](https://github.com/ClickHouse/ClickHouse/pull/60546) ([JackyWoo](https://github.com/JackyWoo)). +* Don't output number tips for date types. [#60577](https://github.com/ClickHouse/ClickHouse/pull/60577) ([Raúl Marín](https://github.com/Algunenano)). +* Fix unexpected result during reading from tables with virtual columns when filter contains non-deterministic functions. Closes [#61106](https://github.com/ClickHouse/ClickHouse/issues/61106). [#60586](https://github.com/ClickHouse/ClickHouse/pull/60586) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix logical error on bad compatibility setting value type. Closes [#60590](https://github.com/ClickHouse/ClickHouse/issues/60590). [#60596](https://github.com/ClickHouse/ClickHouse/pull/60596) ([Kruglov Pavel](https://github.com/Avogar)). +* Fixed potentially inconsistent aggregate function states in mixed x86-64 / ARM clusters. [#60610](https://github.com/ClickHouse/ClickHouse/pull/60610) ([Harry Lee](https://github.com/HarryLeeIBM)). +* Isolates the ClickHouse binary from any panics in `prqlc`. [#60615](https://github.com/ClickHouse/ClickHouse/pull/60615) ([Maximilian Roos](https://github.com/max-sixty)). +* Fixing bug where `intDiv` with decimal and date/datetime as arguments leads to crash. Closes [#60653](https://github.com/ClickHouse/ClickHouse/issues/60653). [#60672](https://github.com/ClickHouse/ClickHouse/pull/60672) ([Yarik Briukhovetskyi](https://github.com/yariks5s)). +* Fix bug when attempt to 'ALTER TABLE ... MODIFY QUERY' with CTE ends up with "Table [CTE] does not exist" exception (Code: 60). [#60682](https://github.com/ClickHouse/ClickHouse/pull/60682) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). +* Fix system.parts for non-Atomic/Ordinary database engine (i.e. Memory - major user is `clickhouse-local`). [#60689](https://github.com/ClickHouse/ClickHouse/pull/60689) ([Azat Khuzhin](https://github.com/azat)). +* Fix "Invalid storage definition in metadata file" for parameterized views. [#60708](https://github.com/ClickHouse/ClickHouse/pull/60708) ([Azat Khuzhin](https://github.com/azat)). +* Fix buffer overflow that can happen if the attacker asks the HTTP server to decompress data with a composition of codecs and size triggering numeric overflow. Fix buffer overflow that can happen inside codec NONE on wrong input data. This was submitted by TIANGONG research team through our [Bug Bounty program](https://github.com/ClickHouse/ClickHouse/issues/38986). [#60731](https://github.com/ClickHouse/ClickHouse/pull/60731) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Functions for SQL/JSON were able to read uninitialized memory. This closes [#60017](https://github.com/ClickHouse/ClickHouse/issues/60017). Found by Fuzzer. [#60738](https://github.com/ClickHouse/ClickHouse/pull/60738) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Remove wrong sanitize checking in aggregate function quantileGK: `sampled_len` in `ApproxSampler` is not guaranteed to be less than `default_compress_threshold`. `default_compress_threshold` is a just soft limitation while executing `ApproxSampler::insert`. cc @Algunenano. This issue was reproduced in https://github.com/oap-project/gluten/pull/4829. [#60740](https://github.com/ClickHouse/ClickHouse/pull/60740) ([李扬](https://github.com/taiyang-li)). +* Fix the issue causing undesired deduplication on insert-select queries passing a custom `insert_deduplication_token.` The change sets streams to 1 in those cases to prevent the issue from happening at the expense of ignoring `max_insert_threads > 1`. [#60745](https://github.com/ClickHouse/ClickHouse/pull/60745) ([Jordi Villar](https://github.com/jrdi)). +* Do not set aws custom metadata `x-amz-meta-*` headers on UploadPart & CompleteMultipartUpload calls. [#60748](https://github.com/ClickHouse/ClickHouse/pull/60748) ([Francisco J. Jurado Moreno](https://github.com/Beetelbrox)). +* One more fix for toStartOfInterval returning wrong result for interval smaller than second. [#60763](https://github.com/ClickHouse/ClickHouse/pull/60763) ([Andrey Zvonov](https://github.com/zvonand)). +* Fix crash in arrayEnumerateRanked. [#60764](https://github.com/ClickHouse/ClickHouse/pull/60764) ([Raúl Marín](https://github.com/Algunenano)). +* Fix crash when using input() in INSERT SELECT JOIN. Closes [#60035](https://github.com/ClickHouse/ClickHouse/issues/60035). [#60765](https://github.com/ClickHouse/ClickHouse/pull/60765) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix crash when `allow_experimental_analyzer` setting value is changed in the subqueries. [#60770](https://github.com/ClickHouse/ClickHouse/pull/60770) ([Dmitry Novik](https://github.com/novikd)). +* Avoid segfault if too many keys are skipped when reading from S3. [#60849](https://github.com/ClickHouse/ClickHouse/pull/60849) ([Antonio Andelic](https://github.com/antonio2368)). +* Fix possible stuck on error while reloading dictionary with `SHARDS`. [#60926](https://github.com/ClickHouse/ClickHouse/pull/60926) ([vdimir](https://github.com/vdimir)). +* Fix async RESTORE with Replicated database. [#60934](https://github.com/ClickHouse/ClickHouse/pull/60934) ([Antonio Andelic](https://github.com/antonio2368)). +* Fix csv write tuple in a wrong format and can not read it. [#60994](https://github.com/ClickHouse/ClickHouse/pull/60994) ([shuai.xu](https://github.com/shuai-xu)). +* Fixed deadlock in async inserts to `Log` tables via native protocol. [#61055](https://github.com/ClickHouse/ClickHouse/pull/61055) ([Anton Popov](https://github.com/CurtizJ)). +* Fix lazy execution of default argument in dictGetOrDefault for RangeHashedDictionary that could lead to nullptr dereference on bad column types in FunctionsConversion. Closes [#56661](https://github.com/ClickHouse/ClickHouse/issues/56661). [#61196](https://github.com/ClickHouse/ClickHouse/pull/61196) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix multiple bugs in groupArraySorted. [#61203](https://github.com/ClickHouse/ClickHouse/pull/61203) ([Raúl Marín](https://github.com/Algunenano)). +* Keeper: fix runtime reconfig for standalone binary. [#61233](https://github.com/ClickHouse/ClickHouse/pull/61233) ([Antonio Andelic](https://github.com/antonio2368)). +* Fix usage of session_token in S3 engine. Fixes https://github.com/ClickHouse/ClickHouse/pull/57850#issuecomment-1966404710. [#61234](https://github.com/ClickHouse/ClickHouse/pull/61234) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix possible incorrect result of aggregate function `uniqExact`. [#61257](https://github.com/ClickHouse/ClickHouse/pull/61257) ([Anton Popov](https://github.com/CurtizJ)). +* Fix bugs in show database. [#61269](https://github.com/ClickHouse/ClickHouse/pull/61269) ([Raúl Marín](https://github.com/Algunenano)). +* Fix possible `LOGICAL_ERROR` in case storage with `RabbitMQ` engine has unsupported `MATERIALIZED|ALIAS|DEFAULT` columns. [#61320](https://github.com/ClickHouse/ClickHouse/pull/61320) ([vdimir](https://github.com/vdimir)). +* This PR fixes `CREATE OR REPLACE DICTIONARY` with `lazy_load` turned off. [#61356](https://github.com/ClickHouse/ClickHouse/pull/61356) ([Vitaly Baranov](https://github.com/vitlibar)). +* Fix possible crash in `Object('json')` data type parsing array with `null`s. [#61364](https://github.com/ClickHouse/ClickHouse/pull/61364) ([vdimir](https://github.com/vdimir)). +* Fix the ATTACH query with the ON CLUSTER clause when the database does not exist on the initiator node. Closes [#55009](https://github.com/ClickHouse/ClickHouse/issues/55009). [#61365](https://github.com/ClickHouse/ClickHouse/pull/61365) ([Nikolay Degterinsky](https://github.com/evillique)). +* Fixed possible wrong result of aggregation with nullable keys. [#61393](https://github.com/ClickHouse/ClickHouse/pull/61393) ([Anton Popov](https://github.com/CurtizJ)). +* ActionsDAG::split can't make sure that "Execution of first then second parts on block is equivalent to execution of initial DAG.". [#61458](https://github.com/ClickHouse/ClickHouse/pull/61458) ([Raúl Marín](https://github.com/Algunenano)). +* Fix finishing a failed RESTORE. [#61466](https://github.com/ClickHouse/ClickHouse/pull/61466) ([Vitaly Baranov](https://github.com/vitlibar)). +* Disable async_insert_use_adaptive_busy_timeout correctly with compatibility settings. [#61468](https://github.com/ClickHouse/ClickHouse/pull/61468) ([Raúl Marín](https://github.com/Algunenano)). +* Fix deadlock during `restore database` execution if `restore_threads` was set to 1. [#61475](https://github.com/ClickHouse/ClickHouse/pull/61475) ([Nikita Taranov](https://github.com/nickitat)). +* Fix incorrect results when filtering `system.parts` or `system.parts_columns` using UUID. [#61479](https://github.com/ClickHouse/ClickHouse/pull/61479) ([Dan Wu](https://github.com/wudanzy)). +* Fix the `ALTER QUERY MODIFY SQL SECURITY` queries to override the table's DDL correctly. [#61480](https://github.com/ClickHouse/ClickHouse/pull/61480) ([pufit](https://github.com/pufit)). +* The experimental "window view" feature (it is disabled by default), which should not be used in production, could lead to a crash. Issue was identified by YohannJardin via Bugcrowd program. [#61526](https://github.com/ClickHouse/ClickHouse/pull/61526) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Fix `repeat` with non-native integers (e.g. `UInt256`). [#61527](https://github.com/ClickHouse/ClickHouse/pull/61527) ([Antonio Andelic](https://github.com/antonio2368)). +* Fix `clickhouse-client -s` argument, it was broken by defining it two times. [#61530](https://github.com/ClickHouse/ClickHouse/pull/61530) ([Mikhail f. Shiryaev](https://github.com/Felixoid)). +* Fix too high part level reported in [#58558](https://github.com/ClickHouse/ClickHouse/issues/58558) by resetting MergeTree part levels upon attach from disk just like `ReplicatedMergeTree` [does](https://github.com/ClickHouse/ClickHouse/blob/9cd7e6155c7027baccd6dc5380d0813db94b03cc/src/Storages/MergeTree/ReplicatedMergeTreeSink.cpp#L838). [#61536](https://github.com/ClickHouse/ClickHouse/pull/61536) ([Arthur Passos](https://github.com/arthurpassos)). +* Fix crash in arrayPartialReverseSort. [#61539](https://github.com/ClickHouse/ClickHouse/pull/61539) ([Raúl Marín](https://github.com/Algunenano)). +* Fix string search with constant start position which previously could lead to memory corruption. [#61547](https://github.com/ClickHouse/ClickHouse/pull/61547) ([Antonio Andelic](https://github.com/antonio2368)). +* Fix the issue where the function `addDays` (and similar functions) reports an error when the first parameter is `DateTime64`. [#61561](https://github.com/ClickHouse/ClickHouse/pull/61561) ([Shuai li](https://github.com/loneylee)). +* Disallow LowCardinality type for the column containing JSON input in the JSONExtract function. [#61617](https://github.com/ClickHouse/ClickHouse/pull/61617) ([Julia Kartseva](https://github.com/jkartseva)). +* Add parts to `system.part_log` when created using async insert with deduplication. [#61620](https://github.com/ClickHouse/ClickHouse/pull/61620) ([Antonio Andelic](https://github.com/antonio2368)). +* Fix `Not-ready Set` error while reading from `system.parts` (with `IN subquery`). Was introduced in [#60510](https://github.com/ClickHouse/ClickHouse/issues/60510). [#61666](https://github.com/ClickHouse/ClickHouse/pull/61666) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Don't allow the same expression in ORDER BY with and without WITH FILL. Such invalid expression could lead to logical error `Invalid number of rows in Chunk`. [#61667](https://github.com/ClickHouse/ClickHouse/pull/61667) ([Kruglov Pavel](https://github.com/Avogar)). +* Fixed `Entry actual part isn't empty yet. This is a bug. (LOGICAL_ERROR)` that might happen in rare cases after executing `REPLACE PARTITION`, `MOVE PARTITION TO TABLE` or `ATTACH PARTITION FROM`. [#61675](https://github.com/ClickHouse/ClickHouse/pull/61675) ([Alexander Tokmakov](https://github.com/tavplubix)). +* Fix columns after executing `ALTER TABLE MODIFY QUERY` for a materialized view with internal table. A materialized view must have the same columns as its internal table if any, however `MODIFY QUERY` could break that rule before this PR causing the materialized view to be inconsistent. [#61734](https://github.com/ClickHouse/ClickHouse/pull/61734) ([Vitaly Baranov](https://github.com/vitlibar)). +* Fix crash in `multiSearchAllPositionsCaseInsensitiveUTF8` when specifying incorrect UTF-8 sequence. Example: [#61714](https://github.com/ClickHouse/ClickHouse/issues/61714#issuecomment-2012768202). [#61749](https://github.com/ClickHouse/ClickHouse/pull/61749) ([pufit](https://github.com/pufit)). +* Fix RANGE frame is not supported for Nullable columns. ``` SELECT number, sum(number) OVER (ORDER BY number ASC RANGE BETWEEN CURRENT ROW AND 1 FOLLOWING) AS sum FROM values('number Nullable(Int8)', 1, 1, 2, 3, NULL). [#61766](https://github.com/ClickHouse/ClickHouse/pull/61766) ([YuanLiu](https://github.com/ditgittube)). +* Fix incorrect results when filtering `system.parts` or `system.parts_columns` using UUID. [#61779](https://github.com/ClickHouse/ClickHouse/pull/61779) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). #### CI Fix or Improvement (changelog entry is not required) @@ -526,7 +526,7 @@ sidebar_label: 2024 * No "please" [#61916](https://github.com/ClickHouse/ClickHouse/pull/61916) ([Alexey Milovidov](https://github.com/alexey-milovidov)). * Update version_date.tsv and changelogs after v23.12.6.19-stable [#61917](https://github.com/ClickHouse/ClickHouse/pull/61917) ([robot-clickhouse](https://github.com/robot-clickhouse)). * Update version_date.tsv and changelogs after v24.1.8.22-stable [#61918](https://github.com/ClickHouse/ClickHouse/pull/61918) ([robot-clickhouse](https://github.com/robot-clickhouse)). -* Fix flaky test_broken_projestions/test.py::test_broken_ignored_replic... [#61932](https://github.com/ClickHouse/ClickHouse/pull/61932) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix flaky test_broken_projestions/test.py::test_broken_ignored_replic… [#61932](https://github.com/ClickHouse/ClickHouse/pull/61932) ([Kseniia Sumarokova](https://github.com/kssenii)). * Check is Rust avaiable for build, if not, suggest a way to disable Rust support [#61938](https://github.com/ClickHouse/ClickHouse/pull/61938) ([Azat Khuzhin](https://github.com/azat)). * CI: new ci menu in PR body [#61948](https://github.com/ClickHouse/ClickHouse/pull/61948) ([Max K.](https://github.com/maxknv)). * Remove flaky test `01193_metadata_loading` [#61961](https://github.com/ClickHouse/ClickHouse/pull/61961) ([Nikita Taranov](https://github.com/nickitat)). diff --git a/docs/changelogs/v24.3.2.23-lts.md b/docs/changelogs/v24.3.2.23-lts.md index 4d59a1cedf6..d8adc63c8ac 100644 --- a/docs/changelogs/v24.3.2.23-lts.md +++ b/docs/changelogs/v24.3.2.23-lts.md @@ -9,9 +9,9 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix logical error in group_by_use_nulls + grouping set + analyzer + materialize/constant [#61567](https://github.com/ClickHouse/ClickHouse/pull/61567) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix external table cannot parse data type Bool [#62115](https://github.com/ClickHouse/ClickHouse/pull/62115) ([Duc Canh Le](https://github.com/canhld94)). -* Revert "Merge pull request [#61564](https://github.com/ClickHouse/ClickHouse/issues/61564) from liuneng1994/optimize_in_single_value" [#62135](https://github.com/ClickHouse/ClickHouse/pull/62135) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#62078](https://github.com/ClickHouse/ClickHouse/issues/62078): Fix logical error ''Unexpected return type from materialize. Expected Nullable. Got UInt8' while using group_by_use_nulls with analyzer and materialize/constant in grouping set. Closes [#61531](https://github.com/ClickHouse/ClickHouse/issues/61531). [#61567](https://github.com/ClickHouse/ClickHouse/pull/61567) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#62122](https://github.com/ClickHouse/ClickHouse/issues/62122): Fix external table cannot parse data type Bool. [#62115](https://github.com/ClickHouse/ClickHouse/pull/62115) ([Duc Canh Le](https://github.com/canhld94)). +* Backported in [#62147](https://github.com/ClickHouse/ClickHouse/issues/62147): Revert "Merge pull request [#61564](https://github.com/ClickHouse/ClickHouse/issues/61564) from liuneng1994/optimize_in_single_value". The feature is broken and can't be disabled individually. [#62135](https://github.com/ClickHouse/ClickHouse/pull/62135) ([Raúl Marín](https://github.com/Algunenano)). #### CI Fix or Improvement (changelog entry is not required) diff --git a/docs/changelogs/v24.3.3.102-lts.md b/docs/changelogs/v24.3.3.102-lts.md index dc89ac24208..1cdbde67031 100644 --- a/docs/changelogs/v24.3.3.102-lts.md +++ b/docs/changelogs/v24.3.3.102-lts.md @@ -17,36 +17,36 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Cancel merges before removing moved parts [#61610](https://github.com/ClickHouse/ClickHouse/pull/61610) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). -* Mark CANNOT_PARSE_ESCAPE_SEQUENCE error as parse error to be able to skip it in row input formats [#61883](https://github.com/ClickHouse/ClickHouse/pull/61883) ([Kruglov Pavel](https://github.com/Avogar)). -* Crash in Engine Merge if Row Policy does not have expression [#61971](https://github.com/ClickHouse/ClickHouse/pull/61971) ([Ilya Golshtein](https://github.com/ilejn)). -* ReadWriteBufferFromHTTP set right header host when redirected [#62068](https://github.com/ClickHouse/ClickHouse/pull/62068) ([Sema Checherinda](https://github.com/CheSema)). -* Analyzer: Fix query parameter resolution [#62186](https://github.com/ClickHouse/ClickHouse/pull/62186) ([Dmitry Novik](https://github.com/novikd)). -* Fixing NULL random seed for generateRandom with analyzer. [#62248](https://github.com/ClickHouse/ClickHouse/pull/62248) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fix PartsSplitter [#62268](https://github.com/ClickHouse/ClickHouse/pull/62268) ([Nikita Taranov](https://github.com/nickitat)). -* Analyzer: Fix alias to parametrized view resolution [#62274](https://github.com/ClickHouse/ClickHouse/pull/62274) ([Dmitry Novik](https://github.com/novikd)). -* Analyzer: Fix name resolution from parent scopes [#62281](https://github.com/ClickHouse/ClickHouse/pull/62281) ([Dmitry Novik](https://github.com/novikd)). -* Fix argMax with nullable non native numeric column [#62285](https://github.com/ClickHouse/ClickHouse/pull/62285) ([Raúl Marín](https://github.com/Algunenano)). -* Fix data race on scalars in Context [#62305](https://github.com/ClickHouse/ClickHouse/pull/62305) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix analyzer with positional arguments in distributed query [#62362](https://github.com/ClickHouse/ClickHouse/pull/62362) ([flynn](https://github.com/ucasfl)). -* Fix filter pushdown from additional_table_filters in Merge engine in analyzer [#62398](https://github.com/ClickHouse/ClickHouse/pull/62398) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix GLOBAL IN table queries with analyzer. [#62409](https://github.com/ClickHouse/ClickHouse/pull/62409) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fix scalar subquery in LIMIT [#62567](https://github.com/ClickHouse/ClickHouse/pull/62567) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Try to fix segfault in Hive engine [#62578](https://github.com/ClickHouse/ClickHouse/pull/62578) ([Nikolay Degterinsky](https://github.com/evillique)). -* Fix memory leak in groupArraySorted [#62597](https://github.com/ClickHouse/ClickHouse/pull/62597) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix argMin/argMax combinator state [#62708](https://github.com/ClickHouse/ClickHouse/pull/62708) ([Raúl Marín](https://github.com/Algunenano)). -* Fix temporary data in cache failing because of cache lock contention optimization [#62715](https://github.com/ClickHouse/ClickHouse/pull/62715) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix FINAL modifier is not respected in CTE with analyzer [#62811](https://github.com/ClickHouse/ClickHouse/pull/62811) ([Duc Canh Le](https://github.com/canhld94)). -* Fix crash in function `formatRow` with `JSON` format and HTTP interface [#62840](https://github.com/ClickHouse/ClickHouse/pull/62840) ([Anton Popov](https://github.com/CurtizJ)). -* Fix GCD codec [#62853](https://github.com/ClickHouse/ClickHouse/pull/62853) ([Nikita Taranov](https://github.com/nickitat)). -* Disable optimize_rewrite_aggregate_function_with_if for sum(nullable) [#62912](https://github.com/ClickHouse/ClickHouse/pull/62912) ([Raúl Marín](https://github.com/Algunenano)). -* Fix temporary data in cache incorrectly processing failure of cache key directory creation [#62925](https://github.com/ClickHouse/ClickHouse/pull/62925) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix optimize_rewrite_aggregate_function_with_if implicit cast [#62999](https://github.com/ClickHouse/ClickHouse/pull/62999) ([Raúl Marín](https://github.com/Algunenano)). -* Do not remove server constants from GROUP BY key for secondary query. [#63047](https://github.com/ClickHouse/ClickHouse/pull/63047) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fix incorrect judgement of of monotonicity of function abs [#63097](https://github.com/ClickHouse/ClickHouse/pull/63097) ([Duc Canh Le](https://github.com/canhld94)). -* Set server name for SSL handshake in MongoDB engine [#63122](https://github.com/ClickHouse/ClickHouse/pull/63122) ([Alexander Gololobov](https://github.com/davenger)). -* Use user specified db instead of "config" for MongoDB wire protocol version check [#63126](https://github.com/ClickHouse/ClickHouse/pull/63126) ([Alexander Gololobov](https://github.com/davenger)). -* Format SQL security option only in `CREATE VIEW` queries. [#63136](https://github.com/ClickHouse/ClickHouse/pull/63136) ([pufit](https://github.com/pufit)). +* Backported in [#62533](https://github.com/ClickHouse/ClickHouse/issues/62533): Fix data race between `MOVE PARTITION` query and merges resulting in intersecting parts. [#61610](https://github.com/ClickHouse/ClickHouse/pull/61610) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* Backported in [#62244](https://github.com/ClickHouse/ClickHouse/issues/62244): Fix skipping escape sequcne parsing errors during JSON data parsing while using `input_format_allow_errors_num/ratio` settings. [#61883](https://github.com/ClickHouse/ClickHouse/pull/61883) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#62220](https://github.com/ClickHouse/ClickHouse/issues/62220): Fixes Crash in Engine Merge if Row Policy does not have expression. [#61971](https://github.com/ClickHouse/ClickHouse/pull/61971) ([Ilya Golshtein](https://github.com/ilejn)). +* Backported in [#62234](https://github.com/ClickHouse/ClickHouse/issues/62234): ReadWriteBufferFromHTTP set right header host when redirected. [#62068](https://github.com/ClickHouse/ClickHouse/pull/62068) ([Sema Checherinda](https://github.com/CheSema)). +* Backported in [#62278](https://github.com/ClickHouse/ClickHouse/issues/62278): Fix query parameter resolution with `allow_experimental_analyzer` enabled. Closes [#62113](https://github.com/ClickHouse/ClickHouse/issues/62113). [#62186](https://github.com/ClickHouse/ClickHouse/pull/62186) ([Dmitry Novik](https://github.com/novikd)). +* Backported in [#62354](https://github.com/ClickHouse/ClickHouse/issues/62354): Fix `generateRandom` with `NULL` in the seed argument. Fixes [#62092](https://github.com/ClickHouse/ClickHouse/issues/62092). [#62248](https://github.com/ClickHouse/ClickHouse/pull/62248) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Backported in [#62412](https://github.com/ClickHouse/ClickHouse/issues/62412): When some index columns are not loaded into memory for some parts of a *MergeTree table, queries with `FINAL` might produce wrong results. Now we explicitly choose only the common prefix of index columns for all parts to avoid this issue. [#62268](https://github.com/ClickHouse/ClickHouse/pull/62268) ([Nikita Taranov](https://github.com/nickitat)). +* Backported in [#62733](https://github.com/ClickHouse/ClickHouse/issues/62733): Fix inability to address parametrized view in SELECT queries via aliases. [#62274](https://github.com/ClickHouse/ClickHouse/pull/62274) ([Dmitry Novik](https://github.com/novikd)). +* Backported in [#62407](https://github.com/ClickHouse/ClickHouse/issues/62407): Fix name resolution in case when identifier is resolved to an executed scalar subquery. [#62281](https://github.com/ClickHouse/ClickHouse/pull/62281) ([Dmitry Novik](https://github.com/novikd)). +* Backported in [#62331](https://github.com/ClickHouse/ClickHouse/issues/62331): Fix argMax with nullable non native numeric column. [#62285](https://github.com/ClickHouse/ClickHouse/pull/62285) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#62344](https://github.com/ClickHouse/ClickHouse/issues/62344): Fix data race on scalars in Context. [#62305](https://github.com/ClickHouse/ClickHouse/pull/62305) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#62484](https://github.com/ClickHouse/ClickHouse/issues/62484): Resolve positional arguments only on the initiator node. Closes [#62289](https://github.com/ClickHouse/ClickHouse/issues/62289). [#62362](https://github.com/ClickHouse/ClickHouse/pull/62362) ([flynn](https://github.com/ucasfl)). +* Backported in [#62442](https://github.com/ClickHouse/ClickHouse/issues/62442): Fix filter pushdown from additional_table_filters in Merge engine in analyzer. Closes [#62229](https://github.com/ClickHouse/ClickHouse/issues/62229). [#62398](https://github.com/ClickHouse/ClickHouse/pull/62398) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#62475](https://github.com/ClickHouse/ClickHouse/issues/62475): Fix `Unknown expression or table expression identifier` error for `GLOBAL IN table` queries (with new analyzer). Fixes [#62286](https://github.com/ClickHouse/ClickHouse/issues/62286). [#62409](https://github.com/ClickHouse/ClickHouse/pull/62409) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Backported in [#62612](https://github.com/ClickHouse/ClickHouse/issues/62612): Fix an error `LIMIT expression must be constant` in queries with constant expression in `LIMIT`/`OFFSET` which contains scalar subquery. Fixes [#62294](https://github.com/ClickHouse/ClickHouse/issues/62294). [#62567](https://github.com/ClickHouse/ClickHouse/pull/62567) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Backported in [#62679](https://github.com/ClickHouse/ClickHouse/issues/62679): Fix segmentation fault when using Hive table engine. Reference [#62154](https://github.com/ClickHouse/ClickHouse/issues/62154), [#62560](https://github.com/ClickHouse/ClickHouse/issues/62560). [#62578](https://github.com/ClickHouse/ClickHouse/pull/62578) ([Nikolay Degterinsky](https://github.com/evillique)). +* Backported in [#62641](https://github.com/ClickHouse/ClickHouse/issues/62641): Fix memory leak in groupArraySorted. Fix [#62536](https://github.com/ClickHouse/ClickHouse/issues/62536). [#62597](https://github.com/ClickHouse/ClickHouse/pull/62597) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#62770](https://github.com/ClickHouse/ClickHouse/issues/62770): Fix argMin/argMax combinator state. [#62708](https://github.com/ClickHouse/ClickHouse/pull/62708) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#62750](https://github.com/ClickHouse/ClickHouse/issues/62750): Fix temporary data in cache failing because of a small value of setting `filesystem_cache_reserve_space_wait_lock_timeout_milliseconds`. Introduced a separate setting `temporary_data_in_cache_reserve_space_wait_lock_timeout_milliseconds`. [#62715](https://github.com/ClickHouse/ClickHouse/pull/62715) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Backported in [#62993](https://github.com/ClickHouse/ClickHouse/issues/62993): Fix an error when `FINAL` is not applied when specified in CTE (new analyzer). Fixes [#62779](https://github.com/ClickHouse/ClickHouse/issues/62779). [#62811](https://github.com/ClickHouse/ClickHouse/pull/62811) ([Duc Canh Le](https://github.com/canhld94)). +* Backported in [#62859](https://github.com/ClickHouse/ClickHouse/issues/62859): Fixed crash in function `formatRow` with `JSON` format in queries executed via the HTTP interface. [#62840](https://github.com/ClickHouse/ClickHouse/pull/62840) ([Anton Popov](https://github.com/CurtizJ)). +* Backported in [#63056](https://github.com/ClickHouse/ClickHouse/issues/63056): Fixed bug in GCD codec implementation that may lead to server crashes. [#62853](https://github.com/ClickHouse/ClickHouse/pull/62853) ([Nikita Taranov](https://github.com/nickitat)). +* Backported in [#62960](https://github.com/ClickHouse/ClickHouse/issues/62960): Disable optimize_rewrite_aggregate_function_with_if for sum(nullable). [#62912](https://github.com/ClickHouse/ClickHouse/pull/62912) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#63032](https://github.com/ClickHouse/ClickHouse/issues/63032): Fix temporary data in cache incorrect behaviour in case creation of cache key base directory fails with `no space left on device`. [#62925](https://github.com/ClickHouse/ClickHouse/pull/62925) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Backported in [#63148](https://github.com/ClickHouse/ClickHouse/issues/63148): Fix optimize_rewrite_aggregate_function_with_if implicit cast. [#62999](https://github.com/ClickHouse/ClickHouse/pull/62999) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#63146](https://github.com/ClickHouse/ClickHouse/issues/63146): Fix `Not found column in block` error for distributed queries with server-side constants in `GROUP BY` key. Fixes [#62682](https://github.com/ClickHouse/ClickHouse/issues/62682). [#63047](https://github.com/ClickHouse/ClickHouse/pull/63047) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Backported in [#63144](https://github.com/ClickHouse/ClickHouse/issues/63144): Fix incorrect judgement of of monotonicity of function `abs`. [#63097](https://github.com/ClickHouse/ClickHouse/pull/63097) ([Duc Canh Le](https://github.com/canhld94)). +* Backported in [#63178](https://github.com/ClickHouse/ClickHouse/issues/63178): Setting server_name might help with recently reported SSL handshake error when connecting to MongoDB Atlas: `Poco::Exception. Code: 1000, e.code() = 0, SSL Exception: error:10000438:SSL routines:OPENSSL_internal:TLSV1_ALERT_INTERNAL_ERROR`. [#63122](https://github.com/ClickHouse/ClickHouse/pull/63122) ([Alexander Gololobov](https://github.com/davenger)). +* Backported in [#63170](https://github.com/ClickHouse/ClickHouse/issues/63170): The wire protocol version check for MongoDB used to try accessing "config" database, but this can fail if the user doesn't have permissions for it. The fix is to use the database name provided by user. [#63126](https://github.com/ClickHouse/ClickHouse/pull/63126) ([Alexander Gololobov](https://github.com/davenger)). +* Backported in [#63193](https://github.com/ClickHouse/ClickHouse/issues/63193): Fix a bug when `SQL SECURITY` statement appears in all `CREATE` queries if the server setting `ignore_empty_sql_security_in_create_view_query=true` https://github.com/ClickHouse/ClickHouse/pull/63134. [#63136](https://github.com/ClickHouse/ClickHouse/pull/63136) ([pufit](https://github.com/pufit)). #### CI Fix or Improvement (changelog entry is not required) diff --git a/docs/changelogs/v24.4.1.2088-stable.md b/docs/changelogs/v24.4.1.2088-stable.md index b8d83f1a31f..06e704356d4 100644 --- a/docs/changelogs/v24.4.1.2088-stable.md +++ b/docs/changelogs/v24.4.1.2088-stable.md @@ -106,75 +106,75 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix parser error when using COUNT(*) with FILTER clause [#61357](https://github.com/ClickHouse/ClickHouse/pull/61357) ([Duc Canh Le](https://github.com/canhld94)). -* Fix logical error in group_by_use_nulls + grouping set + analyzer + materialize/constant [#61567](https://github.com/ClickHouse/ClickHouse/pull/61567) ([Kruglov Pavel](https://github.com/Avogar)). -* Cancel merges before removing moved parts [#61610](https://github.com/ClickHouse/ClickHouse/pull/61610) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). -* Try to fix abort in arrow [#61720](https://github.com/ClickHouse/ClickHouse/pull/61720) ([Kruglov Pavel](https://github.com/Avogar)). -* Search for convert_to_replicated flag at the correct path [#61769](https://github.com/ClickHouse/ClickHouse/pull/61769) ([Kirill](https://github.com/kirillgarbar)). -* Fix possible connections data-race for distributed_foreground_insert/distributed_background_insert_batch [#61867](https://github.com/ClickHouse/ClickHouse/pull/61867) ([Azat Khuzhin](https://github.com/azat)). -* Mark CANNOT_PARSE_ESCAPE_SEQUENCE error as parse error to be able to skip it in row input formats [#61883](https://github.com/ClickHouse/ClickHouse/pull/61883) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix writing exception message in output format in HTTP when http_wait_end_of_query is used [#61951](https://github.com/ClickHouse/ClickHouse/pull/61951) ([Kruglov Pavel](https://github.com/Avogar)). -* Proper fix for LowCardinality together with JSONExtact functions [#61957](https://github.com/ClickHouse/ClickHouse/pull/61957) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)). -* Crash in Engine Merge if Row Policy does not have expression [#61971](https://github.com/ClickHouse/ClickHouse/pull/61971) ([Ilya Golshtein](https://github.com/ilejn)). -* Fix WriteBufferAzureBlobStorage destructor uncaught exception [#61988](https://github.com/ClickHouse/ClickHouse/pull/61988) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)). -* Fix CREATE TABLE w/o columns definition for ReplicatedMergeTree [#62040](https://github.com/ClickHouse/ClickHouse/pull/62040) ([Azat Khuzhin](https://github.com/azat)). -* Fix optimize_skip_unused_shards_rewrite_in for composite sharding key [#62047](https://github.com/ClickHouse/ClickHouse/pull/62047) ([Azat Khuzhin](https://github.com/azat)). -* ReadWriteBufferFromHTTP set right header host when redirected [#62068](https://github.com/ClickHouse/ClickHouse/pull/62068) ([Sema Checherinda](https://github.com/CheSema)). -* Fix external table cannot parse data type Bool [#62115](https://github.com/ClickHouse/ClickHouse/pull/62115) ([Duc Canh Le](https://github.com/canhld94)). -* Revert "Merge pull request [#61564](https://github.com/ClickHouse/ClickHouse/issues/61564) from liuneng1994/optimize_in_single_value" [#62135](https://github.com/ClickHouse/ClickHouse/pull/62135) ([Raúl Marín](https://github.com/Algunenano)). -* Add test for [#35215](https://github.com/ClickHouse/ClickHouse/issues/35215) [#62180](https://github.com/ClickHouse/ClickHouse/pull/62180) ([Raúl Marín](https://github.com/Algunenano)). -* Analyzer: Fix query parameter resolution [#62186](https://github.com/ClickHouse/ClickHouse/pull/62186) ([Dmitry Novik](https://github.com/novikd)). -* Fix restoring parts while readonly [#62207](https://github.com/ClickHouse/ClickHouse/pull/62207) ([Vitaly Baranov](https://github.com/vitlibar)). -* Fix crash in index definition containing sql udf [#62225](https://github.com/ClickHouse/ClickHouse/pull/62225) ([vdimir](https://github.com/vdimir)). -* Fixing NULL random seed for generateRandom with analyzer. [#62248](https://github.com/ClickHouse/ClickHouse/pull/62248) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Correctly handle const columns in DistinctTransfom [#62250](https://github.com/ClickHouse/ClickHouse/pull/62250) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix PartsSplitter [#62268](https://github.com/ClickHouse/ClickHouse/pull/62268) ([Nikita Taranov](https://github.com/nickitat)). -* Analyzer: Fix alias to parametrized view resolution [#62274](https://github.com/ClickHouse/ClickHouse/pull/62274) ([Dmitry Novik](https://github.com/novikd)). -* Analyzer: Fix name resolution from parent scopes [#62281](https://github.com/ClickHouse/ClickHouse/pull/62281) ([Dmitry Novik](https://github.com/novikd)). -* Fix argMax with nullable non native numeric column [#62285](https://github.com/ClickHouse/ClickHouse/pull/62285) ([Raúl Marín](https://github.com/Algunenano)). -* Fix BACKUP and RESTORE of a materialized view in Ordinary database [#62295](https://github.com/ClickHouse/ClickHouse/pull/62295) ([Vitaly Baranov](https://github.com/vitlibar)). -* Fix data race on scalars in Context [#62305](https://github.com/ClickHouse/ClickHouse/pull/62305) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix primary key in materialized view [#62319](https://github.com/ClickHouse/ClickHouse/pull/62319) ([Murat Khairulin](https://github.com/mxwell)). -* Do not build multithread insert pipeline for tables without support [#62333](https://github.com/ClickHouse/ClickHouse/pull/62333) ([vdimir](https://github.com/vdimir)). -* Fix analyzer with positional arguments in distributed query [#62362](https://github.com/ClickHouse/ClickHouse/pull/62362) ([flynn](https://github.com/ucasfl)). -* Fix filter pushdown from additional_table_filters in Merge engine in analyzer [#62398](https://github.com/ClickHouse/ClickHouse/pull/62398) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix GLOBAL IN table queries with analyzer. [#62409](https://github.com/ClickHouse/ClickHouse/pull/62409) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Respect settings truncate_on_insert/create_new_file_on_insert in s3/hdfs/azure engines during partitioned write [#62425](https://github.com/ClickHouse/ClickHouse/pull/62425) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix backup restore path for AzureBlobStorage [#62447](https://github.com/ClickHouse/ClickHouse/pull/62447) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)). -* Fix SimpleSquashingChunksTransform [#62451](https://github.com/ClickHouse/ClickHouse/pull/62451) ([Nikita Taranov](https://github.com/nickitat)). -* Fix capture of nested lambda. [#62462](https://github.com/ClickHouse/ClickHouse/pull/62462) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fix validation of special MergeTree columns [#62498](https://github.com/ClickHouse/ClickHouse/pull/62498) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). -* Avoid crash when reading protobuf with recursive types [#62506](https://github.com/ClickHouse/ClickHouse/pull/62506) ([Raúl Marín](https://github.com/Algunenano)). -* Fix a bug moving one partition from one to itself [#62524](https://github.com/ClickHouse/ClickHouse/pull/62524) ([helifu](https://github.com/helifu)). -* Fix scalar subquery in LIMIT [#62567](https://github.com/ClickHouse/ClickHouse/pull/62567) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Try to fix segfault in Hive engine [#62578](https://github.com/ClickHouse/ClickHouse/pull/62578) ([Nikolay Degterinsky](https://github.com/evillique)). -* Fix memory leak in groupArraySorted [#62597](https://github.com/ClickHouse/ClickHouse/pull/62597) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix crash in largestTriangleThreeBuckets [#62646](https://github.com/ClickHouse/ClickHouse/pull/62646) ([Raúl Marín](https://github.com/Algunenano)). -* Fix tumble[Start,End] and hop[Start,End] for bigger resolutions [#62705](https://github.com/ClickHouse/ClickHouse/pull/62705) ([Jordi Villar](https://github.com/jrdi)). -* Fix argMin/argMax combinator state [#62708](https://github.com/ClickHouse/ClickHouse/pull/62708) ([Raúl Marín](https://github.com/Algunenano)). -* Fix temporary data in cache failing because of cache lock contention optimization [#62715](https://github.com/ClickHouse/ClickHouse/pull/62715) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix crash in function `mergeTreeIndex` [#62762](https://github.com/ClickHouse/ClickHouse/pull/62762) ([Anton Popov](https://github.com/CurtizJ)). -* fix: update: nested materialized columns: size check fixes [#62773](https://github.com/ClickHouse/ClickHouse/pull/62773) ([Eliot Hautefeuille](https://github.com/hileef)). -* Fix FINAL modifier is not respected in CTE with analyzer [#62811](https://github.com/ClickHouse/ClickHouse/pull/62811) ([Duc Canh Le](https://github.com/canhld94)). -* Fix crash in function `formatRow` with `JSON` format and HTTP interface [#62840](https://github.com/ClickHouse/ClickHouse/pull/62840) ([Anton Popov](https://github.com/CurtizJ)). -* Azure: fix building final url from endpoint object [#62850](https://github.com/ClickHouse/ClickHouse/pull/62850) ([Daniel Pozo Escalona](https://github.com/danipozo)). -* Fix GCD codec [#62853](https://github.com/ClickHouse/ClickHouse/pull/62853) ([Nikita Taranov](https://github.com/nickitat)). -* Fix LowCardinality(Nullable) key in hyperrectangle [#62866](https://github.com/ClickHouse/ClickHouse/pull/62866) ([Amos Bird](https://github.com/amosbird)). -* Fix fromUnixtimestamp in joda syntax while the input value beyond UInt32 [#62901](https://github.com/ClickHouse/ClickHouse/pull/62901) ([KevinyhZou](https://github.com/KevinyhZou)). -* Disable optimize_rewrite_aggregate_function_with_if for sum(nullable) [#62912](https://github.com/ClickHouse/ClickHouse/pull/62912) ([Raúl Marín](https://github.com/Algunenano)). -* Fix PREWHERE for StorageBuffer with different source table column types. [#62916](https://github.com/ClickHouse/ClickHouse/pull/62916) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fix temporary data in cache incorrectly processing failure of cache key directory creation [#62925](https://github.com/ClickHouse/ClickHouse/pull/62925) ([Kseniia Sumarokova](https://github.com/kssenii)). -* gRPC: fix crash on IPv6 peer connection [#62978](https://github.com/ClickHouse/ClickHouse/pull/62978) ([Konstantin Bogdanov](https://github.com/thevar1able)). -* Fix possible CHECKSUM_DOESNT_MATCH (and others) during replicated fetches [#62987](https://github.com/ClickHouse/ClickHouse/pull/62987) ([Azat Khuzhin](https://github.com/azat)). -* Fix terminate with uncaught exception in temporary data in cache [#62998](https://github.com/ClickHouse/ClickHouse/pull/62998) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix optimize_rewrite_aggregate_function_with_if implicit cast [#62999](https://github.com/ClickHouse/ClickHouse/pull/62999) ([Raúl Marín](https://github.com/Algunenano)). -* Fix unhandled exception in ~RestorerFromBackup [#63040](https://github.com/ClickHouse/ClickHouse/pull/63040) ([Vitaly Baranov](https://github.com/vitlibar)). -* Do not remove server constants from GROUP BY key for secondary query. [#63047](https://github.com/ClickHouse/ClickHouse/pull/63047) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fix incorrect judgement of of monotonicity of function abs [#63097](https://github.com/ClickHouse/ClickHouse/pull/63097) ([Duc Canh Le](https://github.com/canhld94)). -* Make sanity check of settings worse [#63119](https://github.com/ClickHouse/ClickHouse/pull/63119) ([Raúl Marín](https://github.com/Algunenano)). -* Set server name for SSL handshake in MongoDB engine [#63122](https://github.com/ClickHouse/ClickHouse/pull/63122) ([Alexander Gololobov](https://github.com/davenger)). -* Use user specified db instead of "config" for MongoDB wire protocol version check [#63126](https://github.com/ClickHouse/ClickHouse/pull/63126) ([Alexander Gololobov](https://github.com/davenger)). -* Format SQL security option only in `CREATE VIEW` queries. [#63136](https://github.com/ClickHouse/ClickHouse/pull/63136) ([pufit](https://github.com/pufit)). +* Fix parser error when using COUNT(*) with FILTER clause. [#61357](https://github.com/ClickHouse/ClickHouse/pull/61357) ([Duc Canh Le](https://github.com/canhld94)). +* Fix logical error ''Unexpected return type from materialize. Expected Nullable. Got UInt8' while using group_by_use_nulls with analyzer and materialize/constant in grouping set. Closes [#61531](https://github.com/ClickHouse/ClickHouse/issues/61531). [#61567](https://github.com/ClickHouse/ClickHouse/pull/61567) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix data race between `MOVE PARTITION` query and merges resulting in intersecting parts. [#61610](https://github.com/ClickHouse/ClickHouse/pull/61610) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* TBD. [#61720](https://github.com/ClickHouse/ClickHouse/pull/61720) ([Kruglov Pavel](https://github.com/Avogar)). +* Search for MergeTree to ReplicatedMergeTree conversion flag at the correct location for tables with custom storage policy. [#61769](https://github.com/ClickHouse/ClickHouse/pull/61769) ([Kirill](https://github.com/kirillgarbar)). +* Fix possible connections data-race for distributed_foreground_insert/distributed_background_insert_batch that leads to crashes. [#61867](https://github.com/ClickHouse/ClickHouse/pull/61867) ([Azat Khuzhin](https://github.com/azat)). +* Fix skipping escape sequcne parsing errors during JSON data parsing while using `input_format_allow_errors_num/ratio` settings. [#61883](https://github.com/ClickHouse/ClickHouse/pull/61883) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix writing exception message in output format in HTTP when http_wait_end_of_query is used. Closes [#55101](https://github.com/ClickHouse/ClickHouse/issues/55101). [#61951](https://github.com/ClickHouse/ClickHouse/pull/61951) ([Kruglov Pavel](https://github.com/Avogar)). +* This PR reverts https://github.com/ClickHouse/ClickHouse/pull/61617 and fixed the problem with usage of LowCardinality columns together with JSONExtract function. Previously the user may receive either incorrect result of a logical error. [#61957](https://github.com/ClickHouse/ClickHouse/pull/61957) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)). +* Fixes Crash in Engine Merge if Row Policy does not have expression. [#61971](https://github.com/ClickHouse/ClickHouse/pull/61971) ([Ilya Golshtein](https://github.com/ilejn)). +* Implemented preFinalize, updated finalizeImpl & destructor of WriteBufferAzureBlobStorage to avoided having uncaught exception in destructor. [#61988](https://github.com/ClickHouse/ClickHouse/pull/61988) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)). +* Fix CREATE TABLE w/o columns definition for ReplicatedMergeTree (columns will be obtained from replica). [#62040](https://github.com/ClickHouse/ClickHouse/pull/62040) ([Azat Khuzhin](https://github.com/azat)). +* Fix optimize_skip_unused_shards_rewrite_in for composite sharding key (could lead to `NOT_FOUND_COLUMN_IN_BLOCK` and `TYPE_MISMATCH`). [#62047](https://github.com/ClickHouse/ClickHouse/pull/62047) ([Azat Khuzhin](https://github.com/azat)). +* ReadWriteBufferFromHTTP set right header host when redirected. [#62068](https://github.com/ClickHouse/ClickHouse/pull/62068) ([Sema Checherinda](https://github.com/CheSema)). +* Fix external table cannot parse data type Bool. [#62115](https://github.com/ClickHouse/ClickHouse/pull/62115) ([Duc Canh Le](https://github.com/canhld94)). +* Revert "Merge pull request [#61564](https://github.com/ClickHouse/ClickHouse/issues/61564) from liuneng1994/optimize_in_single_value". The feature is broken and can't be disabled individually. [#62135](https://github.com/ClickHouse/ClickHouse/pull/62135) ([Raúl Marín](https://github.com/Algunenano)). +* Fix override of MergeTree virtual columns. [#62180](https://github.com/ClickHouse/ClickHouse/pull/62180) ([Raúl Marín](https://github.com/Algunenano)). +* Fix query parameter resolution with `allow_experimental_analyzer` enabled. Closes [#62113](https://github.com/ClickHouse/ClickHouse/issues/62113). [#62186](https://github.com/ClickHouse/ClickHouse/pull/62186) ([Dmitry Novik](https://github.com/novikd)). +* This PR makes `RESTORE ON CLUSTER` wait for each `ReplicatedMergeTree` table to stop being readonly before attaching any restored parts to it. Earlier it didn't wait and it could try to attach some parts at nearly the same time as checking other replicas during the table's startup. In rare cases some parts could be not attached at all during `RESTORE ON CLUSTER` because of that issue. [#62207](https://github.com/ClickHouse/ClickHouse/pull/62207) ([Vitaly Baranov](https://github.com/vitlibar)). +* Fix crash on `CREATE TABLE` with `INDEX` containing SQL UDF in expression, close [#62134](https://github.com/ClickHouse/ClickHouse/issues/62134). [#62225](https://github.com/ClickHouse/ClickHouse/pull/62225) ([vdimir](https://github.com/vdimir)). +* Fix `generateRandom` with `NULL` in the seed argument. Fixes [#62092](https://github.com/ClickHouse/ClickHouse/issues/62092). [#62248](https://github.com/ClickHouse/ClickHouse/pull/62248) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix buffer overflow when `DISTINCT` is used with constant values. [#62250](https://github.com/ClickHouse/ClickHouse/pull/62250) ([Antonio Andelic](https://github.com/antonio2368)). +* When some index columns are not loaded into memory for some parts of a *MergeTree table, queries with `FINAL` might produce wrong results. Now we explicitly choose only the common prefix of index columns for all parts to avoid this issue. [#62268](https://github.com/ClickHouse/ClickHouse/pull/62268) ([Nikita Taranov](https://github.com/nickitat)). +* Fix inability to address parametrized view in SELECT queries via aliases. [#62274](https://github.com/ClickHouse/ClickHouse/pull/62274) ([Dmitry Novik](https://github.com/novikd)). +* Fix name resolution in case when identifier is resolved to an executed scalar subquery. [#62281](https://github.com/ClickHouse/ClickHouse/pull/62281) ([Dmitry Novik](https://github.com/novikd)). +* Fix argMax with nullable non native numeric column. [#62285](https://github.com/ClickHouse/ClickHouse/pull/62285) ([Raúl Marín](https://github.com/Algunenano)). +* Fix BACKUP and RESTORE of a materialized view in Ordinary database. [#62295](https://github.com/ClickHouse/ClickHouse/pull/62295) ([Vitaly Baranov](https://github.com/vitlibar)). +* Fix data race on scalars in Context. [#62305](https://github.com/ClickHouse/ClickHouse/pull/62305) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix displaying of materialized_view primary_key in system.tables. Previously it was shown empty even when a CREATE query included PRIMARY KEY. [#62319](https://github.com/ClickHouse/ClickHouse/pull/62319) ([Murat Khairulin](https://github.com/mxwell)). +* Do not build multithread insert pipeline for engines without `max_insert_threads` support. Fix insterted rows order in queries like `INSERT INTO FUNCTION file/s3(...) SELECT * FROM ORDER BY col`. [#62333](https://github.com/ClickHouse/ClickHouse/pull/62333) ([vdimir](https://github.com/vdimir)). +* Resolve positional arguments only on the initiator node. Closes [#62289](https://github.com/ClickHouse/ClickHouse/issues/62289). [#62362](https://github.com/ClickHouse/ClickHouse/pull/62362) ([flynn](https://github.com/ucasfl)). +* Fix filter pushdown from additional_table_filters in Merge engine in analyzer. Closes [#62229](https://github.com/ClickHouse/ClickHouse/issues/62229). [#62398](https://github.com/ClickHouse/ClickHouse/pull/62398) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix `Unknown expression or table expression identifier` error for `GLOBAL IN table` queries (with new analyzer). Fixes [#62286](https://github.com/ClickHouse/ClickHouse/issues/62286). [#62409](https://github.com/ClickHouse/ClickHouse/pull/62409) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Respect settings truncate_on_insert/create_new_file_on_insert in s3/hdfs/azure engines during partitioned write. Closes [#61492](https://github.com/ClickHouse/ClickHouse/issues/61492). [#62425](https://github.com/ClickHouse/ClickHouse/pull/62425) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix backup restore path for AzureBlobStorage to include specified blob path. [#62447](https://github.com/ClickHouse/ClickHouse/pull/62447) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)). +* Fixed rare bug in `SimpleSquashingChunksTransform` that may lead to a loss of the last chunk of data in a stream. [#62451](https://github.com/ClickHouse/ClickHouse/pull/62451) ([Nikita Taranov](https://github.com/nickitat)). +* Fix excessive memory usage for queries with nested lambdas. Fixes [#62036](https://github.com/ClickHouse/ClickHouse/issues/62036). [#62462](https://github.com/ClickHouse/ClickHouse/pull/62462) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix validation of special columns (`ver`, `is_deleted`, `sign`) in MergeTree engines on table creation and alter queries. Fixes [#62463](https://github.com/ClickHouse/ClickHouse/issues/62463). [#62498](https://github.com/ClickHouse/ClickHouse/pull/62498) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* Avoid crash when reading protobuf with recursive types. [#62506](https://github.com/ClickHouse/ClickHouse/pull/62506) ([Raúl Marín](https://github.com/Algunenano)). +* Fix [62459](https://github.com/ClickHouse/ClickHouse/issues/62459). [#62524](https://github.com/ClickHouse/ClickHouse/pull/62524) ([helifu](https://github.com/helifu)). +* Fix an error `LIMIT expression must be constant` in queries with constant expression in `LIMIT`/`OFFSET` which contains scalar subquery. Fixes [#62294](https://github.com/ClickHouse/ClickHouse/issues/62294). [#62567](https://github.com/ClickHouse/ClickHouse/pull/62567) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix segmentation fault when using Hive table engine. Reference [#62154](https://github.com/ClickHouse/ClickHouse/issues/62154), [#62560](https://github.com/ClickHouse/ClickHouse/issues/62560). [#62578](https://github.com/ClickHouse/ClickHouse/pull/62578) ([Nikolay Degterinsky](https://github.com/evillique)). +* Fix memory leak in groupArraySorted. Fix [#62536](https://github.com/ClickHouse/ClickHouse/issues/62536). [#62597](https://github.com/ClickHouse/ClickHouse/pull/62597) ([Antonio Andelic](https://github.com/antonio2368)). +* Fix crash in largestTriangleThreeBuckets. [#62646](https://github.com/ClickHouse/ClickHouse/pull/62646) ([Raúl Marín](https://github.com/Algunenano)). +* Fix `tumble[Start,End]` and `hop[Start,End]` functions for resolutions bigger than a day. [#62705](https://github.com/ClickHouse/ClickHouse/pull/62705) ([Jordi Villar](https://github.com/jrdi)). +* Fix argMin/argMax combinator state. [#62708](https://github.com/ClickHouse/ClickHouse/pull/62708) ([Raúl Marín](https://github.com/Algunenano)). +* Fix temporary data in cache failing because of a small value of setting `filesystem_cache_reserve_space_wait_lock_timeout_milliseconds`. Introduced a separate setting `temporary_data_in_cache_reserve_space_wait_lock_timeout_milliseconds`. [#62715](https://github.com/ClickHouse/ClickHouse/pull/62715) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fixed crash in table function `mergeTreeIndex` after offloading some of the columns from suffix of primary key. [#62762](https://github.com/ClickHouse/ClickHouse/pull/62762) ([Anton Popov](https://github.com/CurtizJ)). +* Fix size checks when updating materialized nested columns ( fixes [#62731](https://github.com/ClickHouse/ClickHouse/issues/62731) ). [#62773](https://github.com/ClickHouse/ClickHouse/pull/62773) ([Eliot Hautefeuille](https://github.com/hileef)). +* Fix an error when `FINAL` is not applied when specified in CTE (new analyzer). Fixes [#62779](https://github.com/ClickHouse/ClickHouse/issues/62779). [#62811](https://github.com/ClickHouse/ClickHouse/pull/62811) ([Duc Canh Le](https://github.com/canhld94)). +* Fixed crash in function `formatRow` with `JSON` format in queries executed via the HTTP interface. [#62840](https://github.com/ClickHouse/ClickHouse/pull/62840) ([Anton Popov](https://github.com/CurtizJ)). +* Fix failure to start when storage account URL has trailing slash. [#62850](https://github.com/ClickHouse/ClickHouse/pull/62850) ([Daniel Pozo Escalona](https://github.com/danipozo)). +* Fixed bug in GCD codec implementation that may lead to server crashes. [#62853](https://github.com/ClickHouse/ClickHouse/pull/62853) ([Nikita Taranov](https://github.com/nickitat)). +* Fix incorrect key analysis when LowCardinality(Nullable) keys appear in the middle of a hyperrectangle. This fixes [#62848](https://github.com/ClickHouse/ClickHouse/issues/62848). [#62866](https://github.com/ClickHouse/ClickHouse/pull/62866) ([Amos Bird](https://github.com/amosbird)). +* When we use function `fromUnixTimestampInJodaSyntax` to convert the input `Int64` or `UInt64` value to `DateTime`, sometimes it return the wrong result,because the input value may exceed the maximum value of Uint32 type,and the function will first convert the input value to Uint32, and so would lead to the wrong result. For example we have a table `test_tbl(a Int64, b UInt64)`, and it has a row (`10262736196`, `10262736196`), when use `fromUnixTimestampInJodaSyntax` to convert, the wrong result as below. [#62901](https://github.com/ClickHouse/ClickHouse/pull/62901) ([KevinyhZou](https://github.com/KevinyhZou)). +* Disable optimize_rewrite_aggregate_function_with_if for sum(nullable). [#62912](https://github.com/ClickHouse/ClickHouse/pull/62912) ([Raúl Marín](https://github.com/Algunenano)). +* Fix the `Unexpected return type` error for queries that read from `StorageBuffer` with `PREWHERE` when the source table has different types. Fixes [#62545](https://github.com/ClickHouse/ClickHouse/issues/62545). [#62916](https://github.com/ClickHouse/ClickHouse/pull/62916) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix temporary data in cache incorrect behaviour in case creation of cache key base directory fails with `no space left on device`. [#62925](https://github.com/ClickHouse/ClickHouse/pull/62925) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fixed server crash on IPv6 gRPC client connection. [#62978](https://github.com/ClickHouse/ClickHouse/pull/62978) ([Konstantin Bogdanov](https://github.com/thevar1able)). +* Fix possible CHECKSUM_DOESNT_MATCH (and others) during replicated fetches. [#62987](https://github.com/ClickHouse/ClickHouse/pull/62987) ([Azat Khuzhin](https://github.com/azat)). +* Fix terminate with uncaught exception in temporary data in cache. [#62998](https://github.com/ClickHouse/ClickHouse/pull/62998) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix optimize_rewrite_aggregate_function_with_if implicit cast. [#62999](https://github.com/ClickHouse/ClickHouse/pull/62999) ([Raúl Marín](https://github.com/Algunenano)). +* Fix possible crash after unsuccessful RESTORE. This PR fixes [#62985](https://github.com/ClickHouse/ClickHouse/issues/62985). [#63040](https://github.com/ClickHouse/ClickHouse/pull/63040) ([Vitaly Baranov](https://github.com/vitlibar)). +* Fix `Not found column in block` error for distributed queries with server-side constants in `GROUP BY` key. Fixes [#62682](https://github.com/ClickHouse/ClickHouse/issues/62682). [#63047](https://github.com/ClickHouse/ClickHouse/pull/63047) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix incorrect judgement of of monotonicity of function `abs`. [#63097](https://github.com/ClickHouse/ClickHouse/pull/63097) ([Duc Canh Le](https://github.com/canhld94)). +* Sanity check: Clamp values instead of throwing. [#63119](https://github.com/ClickHouse/ClickHouse/pull/63119) ([Raúl Marín](https://github.com/Algunenano)). +* Setting server_name might help with recently reported SSL handshake error when connecting to MongoDB Atlas: `Poco::Exception. Code: 1000, e.code() = 0, SSL Exception: error:10000438:SSL routines:OPENSSL_internal:TLSV1_ALERT_INTERNAL_ERROR`. [#63122](https://github.com/ClickHouse/ClickHouse/pull/63122) ([Alexander Gololobov](https://github.com/davenger)). +* The wire protocol version check for MongoDB used to try accessing "config" database, but this can fail if the user doesn't have permissions for it. The fix is to use the database name provided by user. [#63126](https://github.com/ClickHouse/ClickHouse/pull/63126) ([Alexander Gololobov](https://github.com/davenger)). +* Fix a bug when `SQL SECURITY` statement appears in all `CREATE` queries if the server setting `ignore_empty_sql_security_in_create_view_query=true` https://github.com/ClickHouse/ClickHouse/pull/63134. [#63136](https://github.com/ClickHouse/ClickHouse/pull/63136) ([pufit](https://github.com/pufit)). #### CI Fix or Improvement (changelog entry is not required) From 4ba89c8b31dc52cb990defa60377ca245eced113 Mon Sep 17 00:00:00 2001 From: Max K Date: Thu, 30 May 2024 17:35:44 +0200 Subject: [PATCH 205/211] fixes --- tests/ci/cherry_pick.py | 92 ++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 52 deletions(-) diff --git a/tests/ci/cherry_pick.py b/tests/ci/cherry_pick.py index f81d84365ac..2bbf0de78aa 100644 --- a/tests/ci/cherry_pick.py +++ b/tests/ci/cherry_pick.py @@ -115,10 +115,13 @@ close it. if branch_updated: self._backported = True - def pop_prs(self, prs: PullRequests) -> None: + def pop_prs(self, prs: PullRequests) -> PullRequests: """the method processes all prs and pops the ReleaseBranch related prs""" to_pop = [] # type: List[int] for i, pr in enumerate(prs): + if self.name not in pr.head.ref: + # this pr is not for the current branch + continue if pr.head.ref.startswith(f"cherrypick/{self.name}"): self.cherrypick_pr = pr to_pop.append(i) @@ -126,16 +129,18 @@ close it. self.backport_pr = pr to_pop.append(i) else: - assert False, "BUG! Invalid branch suffix" + assert False, f"BUG! Invalid PR's branch [{pr.head.ref}]" for i in reversed(to_pop): # Going from the tail to keep the order and pop greater index first prs.pop(i) + return prs def process( # pylint: disable=too-many-return-statements self, dry_run: bool ) -> None: if self.backported: return + if not self.cherrypick_pr: if dry_run: logging.info( @@ -143,41 +148,39 @@ close it. ) return self.create_cherrypick() - if self.backported: - return - if self.cherrypick_pr is not None: - # Try to merge cherrypick instantly - if self.cherrypick_pr.mergeable and self.cherrypick_pr.state != "closed": - if dry_run: - logging.info( - "DRY RUN: Would merge cherry-pick PR for #%s", self.pr.number - ) - return - self.cherrypick_pr.merge() - # The PR needs update, since PR.merge doesn't update the object - self.cherrypick_pr.update() - if self.cherrypick_pr.merged: - if dry_run: - logging.info( - "DRY RUN: Would create backport PR for #%s", self.pr.number - ) - return - self.create_backport() - return - if self.cherrypick_pr.state == "closed": + assert self.cherrypick_pr, "BUG!" + + if self.cherrypick_pr.mergeable and self.cherrypick_pr.state != "closed": + if dry_run: logging.info( - "The cherrypick PR #%s for PR #%s is discarded", - self.cherrypick_pr.number, - self.pr.number, + "DRY RUN: Would merge cherry-pick PR for #%s", self.pr.number ) - self._backported = True return + self.cherrypick_pr.merge() + # The PR needs update, since PR.merge doesn't update the object + self.cherrypick_pr.update() + if self.cherrypick_pr.merged: + if dry_run: + logging.info( + "DRY RUN: Would create backport PR for #%s", self.pr.number + ) + return + self.create_backport() + return + if self.cherrypick_pr.state == "closed": logging.info( - "Cherrypick PR #%s for PR #%s have conflicts and unable to be merged", + "The cherry-pick PR #%s for PR #%s is discarded", self.cherrypick_pr.number, self.pr.number, ) - self.ping_cherry_pick_assignees(dry_run) + self._backported = True + return + logging.info( + "Cherry-pick PR #%s for PR #%s has conflicts and unable to be merged", + self.cherrypick_pr.number, + self.pr.number, + ) + self.ping_cherry_pick_assignees(dry_run) def create_cherrypick(self): # First, create backport branch: @@ -211,7 +214,6 @@ close it. self.name, self.pr.number, ) - self._backported = True return except CalledProcessError: # There are most probably conflicts, they'll be resolved in PR @@ -241,6 +243,7 @@ close it. self.cherrypick_pr.add_to_labels(Labels.PR_CRITICAL_BUGFIX) elif Labels.PR_BUGFIX in [label.name for label in self.pr.labels]: self.cherrypick_pr.add_to_labels(Labels.PR_BUGFIX) + self._backported = True self._assign_new_pr(self.cherrypick_pr) # update cherrypick PR to get the state for PR.mergable self.cherrypick_pr.update() @@ -478,7 +481,7 @@ class Backport: self.process_pr(pr) except Exception as e: logging.error( - "During processing the PR #%s error occured: %s", pr.number, e + "During processing the PR #%s error occurred: %s", pr.number, e ) self.error = e @@ -499,13 +502,7 @@ class Backport: if label in self.labels_to_backport ] ] - if not branches: - # This is definitely some error. There must be at least one branch - # It also make the whole program exit code non-zero - self.error = Exception( - f"There are no branches to backport PR #{pr.number}, logical error" - ) - raise self.error + assert branches, "BUG!" logging.info( " PR #%s is supposed to be backported to %s", @@ -524,23 +521,14 @@ class Backport: label=f"{Labels.PR_BACKPORT},{Labels.PR_CHERRYPICK}", ) for br in branches: - br.pop_prs(bp_cp_prs) - - if bp_cp_prs: - # This is definitely some error. All prs must be consumed by - # branches with ReleaseBranch.pop_prs. It also makes the whole - # program exit code non-zero - self.error = Exception( - "The following PRs are not filtered by release branches:\n" - "\n".join(map(str, bp_cp_prs)) - ) - raise self.error + bp_cp_prs = br.pop_prs(bp_cp_prs) + assert not bp_cp_prs, "BUG!" for br in branches: br.process(self.dry_run) - if all(br.backported for br in branches): - self.mark_pr_backported(pr) + assert all(br.backported for br in branches), "BUG!" + self.mark_pr_backported(pr) def mark_pr_backported(self, pr: PullRequest) -> None: if self.dry_run: From 0910164e830a001b80d4c64a4e646b121246140d Mon Sep 17 00:00:00 2001 From: kssenii Date: Thu, 30 May 2024 17:25:22 +0200 Subject: [PATCH 206/211] Move NamedCollectionsFactory to a separate file --- .../NamedCollections/NamedCollectionUtils.cpp | 1 + .../NamedCollections/NamedCollections.cpp | 157 ---------------- .../NamedCollections/NamedCollections.h | 55 ------ .../NamedCollectionsFactory.cpp | 169 ++++++++++++++++++ .../NamedCollectionsFactory.h | 57 ++++++ src/Common/tests/gtest_named_collections.cpp | 2 +- .../Cached/registerDiskCache.cpp | 2 +- src/Storages/Kafka/StorageKafka.cpp | 1 + src/Storages/NamedCollectionsHelpers.cpp | 1 + .../System/StorageSystemNamedCollections.cpp | 2 +- 10 files changed, 232 insertions(+), 215 deletions(-) create mode 100644 src/Common/NamedCollections/NamedCollectionsFactory.cpp create mode 100644 src/Common/NamedCollections/NamedCollectionsFactory.h diff --git a/src/Common/NamedCollections/NamedCollectionUtils.cpp b/src/Common/NamedCollections/NamedCollectionUtils.cpp index 21fa9b64c22..5dbdeb10795 100644 --- a/src/Common/NamedCollections/NamedCollectionUtils.cpp +++ b/src/Common/NamedCollections/NamedCollectionUtils.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include diff --git a/src/Common/NamedCollections/NamedCollections.cpp b/src/Common/NamedCollections/NamedCollections.cpp index 6ee47fd6523..cc12e78095c 100644 --- a/src/Common/NamedCollections/NamedCollections.cpp +++ b/src/Common/NamedCollections/NamedCollections.cpp @@ -6,7 +6,6 @@ #include #include #include -#include namespace DB @@ -22,162 +21,6 @@ namespace ErrorCodes namespace Configuration = NamedCollectionConfiguration; - -NamedCollectionFactory & NamedCollectionFactory::instance() -{ - static NamedCollectionFactory instance; - return instance; -} - -bool NamedCollectionFactory::exists(const std::string & collection_name) const -{ - std::lock_guard lock(mutex); - return existsUnlocked(collection_name, lock); -} - -bool NamedCollectionFactory::existsUnlocked( - const std::string & collection_name, - std::lock_guard & /* lock */) const -{ - return loaded_named_collections.contains(collection_name); -} - -NamedCollectionPtr NamedCollectionFactory::get(const std::string & collection_name) const -{ - std::lock_guard lock(mutex); - auto collection = tryGetUnlocked(collection_name, lock); - if (!collection) - { - throw Exception( - ErrorCodes::NAMED_COLLECTION_DOESNT_EXIST, - "There is no named collection `{}`", - collection_name); - } - return collection; -} - -NamedCollectionPtr NamedCollectionFactory::tryGet(const std::string & collection_name) const -{ - std::lock_guard lock(mutex); - return tryGetUnlocked(collection_name, lock); -} - -MutableNamedCollectionPtr NamedCollectionFactory::getMutable( - const std::string & collection_name) const -{ - std::lock_guard lock(mutex); - auto collection = tryGetUnlocked(collection_name, lock); - if (!collection) - { - throw Exception( - ErrorCodes::NAMED_COLLECTION_DOESNT_EXIST, - "There is no named collection `{}`", - collection_name); - } - else if (!collection->isMutable()) - { - throw Exception( - ErrorCodes::NAMED_COLLECTION_IS_IMMUTABLE, - "Cannot get collection `{}` for modification, " - "because collection was defined as immutable", - collection_name); - } - return collection; -} - -MutableNamedCollectionPtr NamedCollectionFactory::tryGetUnlocked( - const std::string & collection_name, - std::lock_guard & /* lock */) const -{ - auto it = loaded_named_collections.find(collection_name); - if (it == loaded_named_collections.end()) - return nullptr; - return it->second; -} - -void NamedCollectionFactory::add( - const std::string & collection_name, - MutableNamedCollectionPtr collection) -{ - std::lock_guard lock(mutex); - addUnlocked(collection_name, collection, lock); -} - -void NamedCollectionFactory::add(NamedCollectionsMap collections) -{ - std::lock_guard lock(mutex); - for (const auto & [collection_name, collection] : collections) - addUnlocked(collection_name, collection, lock); -} - -void NamedCollectionFactory::addUnlocked( - const std::string & collection_name, - MutableNamedCollectionPtr collection, - std::lock_guard & /* lock */) -{ - auto [it, inserted] = loaded_named_collections.emplace(collection_name, collection); - if (!inserted) - { - throw Exception( - ErrorCodes::NAMED_COLLECTION_ALREADY_EXISTS, - "A named collection `{}` already exists", - collection_name); - } -} - -void NamedCollectionFactory::remove(const std::string & collection_name) -{ - std::lock_guard lock(mutex); - bool removed = removeIfExistsUnlocked(collection_name, lock); - if (!removed) - { - throw Exception( - ErrorCodes::NAMED_COLLECTION_DOESNT_EXIST, - "There is no named collection `{}`", - collection_name); - } -} - -void NamedCollectionFactory::removeIfExists(const std::string & collection_name) -{ - std::lock_guard lock(mutex); - removeIfExistsUnlocked(collection_name, lock); // NOLINT -} - -bool NamedCollectionFactory::removeIfExistsUnlocked( - const std::string & collection_name, - std::lock_guard & lock) -{ - auto collection = tryGetUnlocked(collection_name, lock); - if (!collection) - return false; - - if (!collection->isMutable()) - { - throw Exception( - ErrorCodes::NAMED_COLLECTION_IS_IMMUTABLE, - "Cannot get collection `{}` for modification, " - "because collection was defined as immutable", - collection_name); - } - loaded_named_collections.erase(collection_name); - return true; -} - -void NamedCollectionFactory::removeById(NamedCollectionUtils::SourceId id) -{ - std::lock_guard lock(mutex); - std::erase_if( - loaded_named_collections, - [&](const auto & value) { return value.second->getSourceId() == id; }); -} - -NamedCollectionsMap NamedCollectionFactory::getAll() const -{ - std::lock_guard lock(mutex); - return loaded_named_collections; -} - class NamedCollection::Impl { private: diff --git a/src/Common/NamedCollections/NamedCollections.h b/src/Common/NamedCollections/NamedCollections.h index de27f4e6083..c253c56594f 100644 --- a/src/Common/NamedCollections/NamedCollections.h +++ b/src/Common/NamedCollections/NamedCollections.h @@ -93,59 +93,4 @@ private: mutable std::mutex mutex; }; -/** - * A factory of immutable named collections. - */ -class NamedCollectionFactory : boost::noncopyable -{ -public: - static NamedCollectionFactory & instance(); - - bool exists(const std::string & collection_name) const; - - NamedCollectionPtr get(const std::string & collection_name) const; - - NamedCollectionPtr tryGet(const std::string & collection_name) const; - - MutableNamedCollectionPtr getMutable(const std::string & collection_name) const; - - void add(const std::string & collection_name, MutableNamedCollectionPtr collection); - - void add(NamedCollectionsMap collections); - - void update(NamedCollectionsMap collections); - - void remove(const std::string & collection_name); - - void removeIfExists(const std::string & collection_name); - - void removeById(NamedCollectionUtils::SourceId id); - - NamedCollectionsMap getAll() const; - -private: - bool existsUnlocked( - const std::string & collection_name, - std::lock_guard & lock) const; - - MutableNamedCollectionPtr tryGetUnlocked( - const std::string & collection_name, - std::lock_guard & lock) const; - - void addUnlocked( - const std::string & collection_name, - MutableNamedCollectionPtr collection, - std::lock_guard & lock); - - bool removeIfExistsUnlocked( - const std::string & collection_name, - std::lock_guard & lock); - - mutable NamedCollectionsMap loaded_named_collections; - - mutable std::mutex mutex; - bool is_initialized = false; -}; - - } diff --git a/src/Common/NamedCollections/NamedCollectionsFactory.cpp b/src/Common/NamedCollections/NamedCollectionsFactory.cpp new file mode 100644 index 00000000000..dd69952429f --- /dev/null +++ b/src/Common/NamedCollections/NamedCollectionsFactory.cpp @@ -0,0 +1,169 @@ +#include +#include + +namespace DB +{ + +namespace ErrorCodes +{ + extern const int NAMED_COLLECTION_DOESNT_EXIST; + extern const int NAMED_COLLECTION_ALREADY_EXISTS; + extern const int NAMED_COLLECTION_IS_IMMUTABLE; +} + +NamedCollectionFactory & NamedCollectionFactory::instance() +{ + static NamedCollectionFactory instance; + return instance; +} + +bool NamedCollectionFactory::exists(const std::string & collection_name) const +{ + std::lock_guard lock(mutex); + return existsUnlocked(collection_name, lock); +} + +bool NamedCollectionFactory::existsUnlocked( + const std::string & collection_name, + std::lock_guard & /* lock */) const +{ + return loaded_named_collections.contains(collection_name); +} + +NamedCollectionPtr NamedCollectionFactory::get(const std::string & collection_name) const +{ + std::lock_guard lock(mutex); + auto collection = tryGetUnlocked(collection_name, lock); + if (!collection) + { + throw Exception( + ErrorCodes::NAMED_COLLECTION_DOESNT_EXIST, + "There is no named collection `{}`", + collection_name); + } + return collection; +} + +NamedCollectionPtr NamedCollectionFactory::tryGet(const std::string & collection_name) const +{ + std::lock_guard lock(mutex); + return tryGetUnlocked(collection_name, lock); +} + +MutableNamedCollectionPtr NamedCollectionFactory::getMutable( + const std::string & collection_name) const +{ + std::lock_guard lock(mutex); + auto collection = tryGetUnlocked(collection_name, lock); + if (!collection) + { + throw Exception( + ErrorCodes::NAMED_COLLECTION_DOESNT_EXIST, + "There is no named collection `{}`", + collection_name); + } + else if (!collection->isMutable()) + { + throw Exception( + ErrorCodes::NAMED_COLLECTION_IS_IMMUTABLE, + "Cannot get collection `{}` for modification, " + "because collection was defined as immutable", + collection_name); + } + return collection; +} + +MutableNamedCollectionPtr NamedCollectionFactory::tryGetUnlocked( + const std::string & collection_name, + std::lock_guard & /* lock */) const +{ + auto it = loaded_named_collections.find(collection_name); + if (it == loaded_named_collections.end()) + return nullptr; + return it->second; +} + +void NamedCollectionFactory::add( + const std::string & collection_name, + MutableNamedCollectionPtr collection) +{ + std::lock_guard lock(mutex); + addUnlocked(collection_name, collection, lock); +} + +void NamedCollectionFactory::add(NamedCollectionsMap collections) +{ + std::lock_guard lock(mutex); + for (const auto & [collection_name, collection] : collections) + addUnlocked(collection_name, collection, lock); +} + +void NamedCollectionFactory::addUnlocked( + const std::string & collection_name, + MutableNamedCollectionPtr collection, + std::lock_guard & /* lock */) +{ + auto [it, inserted] = loaded_named_collections.emplace(collection_name, collection); + if (!inserted) + { + throw Exception( + ErrorCodes::NAMED_COLLECTION_ALREADY_EXISTS, + "A named collection `{}` already exists", + collection_name); + } +} + +void NamedCollectionFactory::remove(const std::string & collection_name) +{ + std::lock_guard lock(mutex); + bool removed = removeIfExistsUnlocked(collection_name, lock); + if (!removed) + { + throw Exception( + ErrorCodes::NAMED_COLLECTION_DOESNT_EXIST, + "There is no named collection `{}`", + collection_name); + } +} + +void NamedCollectionFactory::removeIfExists(const std::string & collection_name) +{ + std::lock_guard lock(mutex); + removeIfExistsUnlocked(collection_name, lock); // NOLINT +} + +bool NamedCollectionFactory::removeIfExistsUnlocked( + const std::string & collection_name, + std::lock_guard & lock) +{ + auto collection = tryGetUnlocked(collection_name, lock); + if (!collection) + return false; + + if (!collection->isMutable()) + { + throw Exception( + ErrorCodes::NAMED_COLLECTION_IS_IMMUTABLE, + "Cannot get collection `{}` for modification, " + "because collection was defined as immutable", + collection_name); + } + loaded_named_collections.erase(collection_name); + return true; +} + +void NamedCollectionFactory::removeById(NamedCollectionUtils::SourceId id) +{ + std::lock_guard lock(mutex); + std::erase_if( + loaded_named_collections, + [&](const auto & value) { return value.second->getSourceId() == id; }); +} + +NamedCollectionsMap NamedCollectionFactory::getAll() const +{ + std::lock_guard lock(mutex); + return loaded_named_collections; +} + +} diff --git a/src/Common/NamedCollections/NamedCollectionsFactory.h b/src/Common/NamedCollections/NamedCollectionsFactory.h new file mode 100644 index 00000000000..17acd99aead --- /dev/null +++ b/src/Common/NamedCollections/NamedCollectionsFactory.h @@ -0,0 +1,57 @@ +#include + +namespace DB +{ + +class NamedCollectionFactory : boost::noncopyable +{ +public: + static NamedCollectionFactory & instance(); + + bool exists(const std::string & collection_name) const; + + NamedCollectionPtr get(const std::string & collection_name) const; + + NamedCollectionPtr tryGet(const std::string & collection_name) const; + + MutableNamedCollectionPtr getMutable(const std::string & collection_name) const; + + void add(const std::string & collection_name, MutableNamedCollectionPtr collection); + + void add(NamedCollectionsMap collections); + + void update(NamedCollectionsMap collections); + + void remove(const std::string & collection_name); + + void removeIfExists(const std::string & collection_name); + + void removeById(NamedCollectionUtils::SourceId id); + + NamedCollectionsMap getAll() const; + +private: + bool existsUnlocked( + const std::string & collection_name, + std::lock_guard & lock) const; + + MutableNamedCollectionPtr tryGetUnlocked( + const std::string & collection_name, + std::lock_guard & lock) const; + + void addUnlocked( + const std::string & collection_name, + MutableNamedCollectionPtr collection, + std::lock_guard & lock); + + bool removeIfExistsUnlocked( + const std::string & collection_name, + std::lock_guard & lock); + + mutable NamedCollectionsMap loaded_named_collections; + + mutable std::mutex mutex; + bool is_initialized = false; +}; + +} diff --git a/src/Common/tests/gtest_named_collections.cpp b/src/Common/tests/gtest_named_collections.cpp index e2482f6ba8b..8a8a364961b 100644 --- a/src/Common/tests/gtest_named_collections.cpp +++ b/src/Common/tests/gtest_named_collections.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/src/Disks/ObjectStorages/Cached/registerDiskCache.cpp b/src/Disks/ObjectStorages/Cached/registerDiskCache.cpp index 6e0453f5f02..917a12eaaaa 100644 --- a/src/Disks/ObjectStorages/Cached/registerDiskCache.cpp +++ b/src/Disks/ObjectStorages/Cached/registerDiskCache.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Storages/Kafka/StorageKafka.cpp b/src/Storages/Kafka/StorageKafka.cpp index 03a30d47d91..f5c5d093ce1 100644 --- a/src/Storages/Kafka/StorageKafka.cpp +++ b/src/Storages/Kafka/StorageKafka.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/src/Storages/NamedCollectionsHelpers.cpp b/src/Storages/NamedCollectionsHelpers.cpp index c1e744e8d79..47b69d79ad8 100644 --- a/src/Storages/NamedCollectionsHelpers.cpp +++ b/src/Storages/NamedCollectionsHelpers.cpp @@ -1,6 +1,7 @@ #include "NamedCollectionsHelpers.h" #include #include +#include #include #include #include diff --git a/src/Storages/System/StorageSystemNamedCollections.cpp b/src/Storages/System/StorageSystemNamedCollections.cpp index 156fa5e5a9b..0836560dff0 100644 --- a/src/Storages/System/StorageSystemNamedCollections.cpp +++ b/src/Storages/System/StorageSystemNamedCollections.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include namespace DB From b93d4b32e2f4d0a7cd2f17679c6f638c087a209e Mon Sep 17 00:00:00 2001 From: Max K Date: Thu, 30 May 2024 17:59:10 +0200 Subject: [PATCH 207/211] fixes 2 --- tests/ci/cherry_pick.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/ci/cherry_pick.py b/tests/ci/cherry_pick.py index 2bbf0de78aa..e470621e2c5 100644 --- a/tests/ci/cherry_pick.py +++ b/tests/ci/cherry_pick.py @@ -130,6 +130,10 @@ close it. to_pop.append(i) else: assert False, f"BUG! Invalid PR's branch [{pr.head.ref}]" + + # Cherry-pick or backport PR found, set @backported flag for current release branch + self._backported = True + for i in reversed(to_pop): # Going from the tail to keep the order and pop greater index first prs.pop(i) @@ -336,7 +340,7 @@ close it. @property def backported(self) -> bool: - return self._backported or self.backport_pr is not None + return self._backported def __repr__(self): return self.name @@ -527,7 +531,8 @@ class Backport: for br in branches: br.process(self.dry_run) - assert all(br.backported for br in branches), "BUG!" + for br in branches: + assert br.backported, f"BUG! backport to branch [{br}] failed" self.mark_pr_backported(pr) def mark_pr_backported(self, pr: PullRequest) -> None: From 116c74341e98afacee8d72fc0dca0f57526a48b8 Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Thu, 30 May 2024 18:09:50 +0200 Subject: [PATCH 208/211] Fix a year for the changelogs by maximum from PRs --- utils/changelog/changelog.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/utils/changelog/changelog.py b/utils/changelog/changelog.py index 0da871c074d..304ab568e3c 100755 --- a/utils/changelog/changelog.py +++ b/utils/changelog/changelog.py @@ -302,8 +302,9 @@ def generate_description(item: PullRequest, repo: Repository) -> Optional[Descri return Description(item.number, item.user, item.html_url, entry, category) -def write_changelog(fd: TextIO, descriptions: Dict[str, List[Description]]): - year = date.today().year +def write_changelog( + fd: TextIO, descriptions: Dict[str, List[Description]], year: int +) -> None: to_commit = runner(f"git rev-parse {TO_REF}^{{}}")[:11] from_commit = runner(f"git rev-parse {FROM_REF}^{{}}")[:11] fd.write( @@ -361,6 +362,12 @@ def set_sha_in_changelog(): ).split("\n") +def get_year(prs: PullRequests) -> int: + if not prs: + return date.today().year + return max(pr.created_at.year for pr in prs) + + def main(): log_levels = [logging.WARN, logging.INFO, logging.DEBUG] args = parse_args() @@ -414,8 +421,9 @@ def main(): prs = gh.get_pulls_from_search(query=query, merged=merged, sort="created") descriptions = get_descriptions(prs) + changelog_year = get_year(prs) - write_changelog(args.output, descriptions) + write_changelog(args.output, descriptions, changelog_year) if __name__ == "__main__": From 36624a03caa2639e7080291edad01d65202c8eee Mon Sep 17 00:00:00 2001 From: "Mikhail f. Shiryaev" Date: Thu, 30 May 2024 18:10:12 +0200 Subject: [PATCH 209/211] Fix the changelogs for 23.8 --- docs/changelogs/v23.8.1.2992-lts.md | 149 ++++++++++++++-------------- docs/changelogs/v23.8.10.43-lts.md | 22 ++-- docs/changelogs/v23.8.11.28-lts.md | 10 +- docs/changelogs/v23.8.12.13-lts.md | 6 +- docs/changelogs/v23.8.13.25-lts.md | 10 +- docs/changelogs/v23.8.14.6-lts.md | 4 +- docs/changelogs/v23.8.2.7-lts.md | 4 +- docs/changelogs/v23.8.3.48-lts.md | 26 ++--- docs/changelogs/v23.8.4.69-lts.md | 36 +++---- docs/changelogs/v23.8.5.16-lts.md | 6 +- docs/changelogs/v23.8.6.16-lts.md | 10 +- docs/changelogs/v23.8.7.24-lts.md | 12 +-- docs/changelogs/v23.8.8.20-lts.md | 6 +- docs/changelogs/v23.8.9.54-lts.md | 34 +++---- 14 files changed, 168 insertions(+), 167 deletions(-) diff --git a/docs/changelogs/v23.8.1.2992-lts.md b/docs/changelogs/v23.8.1.2992-lts.md index 05385d9c52b..62326533a79 100644 --- a/docs/changelogs/v23.8.1.2992-lts.md +++ b/docs/changelogs/v23.8.1.2992-lts.md @@ -33,7 +33,7 @@ sidebar_label: 2023 * Add input format One that doesn't read any data and always returns single row with column `dummy` with type `UInt8` and value `0` like `system.one`. It can be used together with `_file/_path` virtual columns to list files in file/s3/url/hdfs/etc table functions without reading any data. [#53209](https://github.com/ClickHouse/ClickHouse/pull/53209) ([Kruglov Pavel](https://github.com/Avogar)). * Add tupleConcat function. Closes [#52759](https://github.com/ClickHouse/ClickHouse/issues/52759). [#53239](https://github.com/ClickHouse/ClickHouse/pull/53239) ([Nikolay Degterinsky](https://github.com/evillique)). * Support `TRUNCATE DATABASE` operation. [#53261](https://github.com/ClickHouse/ClickHouse/pull/53261) ([Bharat Nallan](https://github.com/bharatnc)). -* Add max_threads_for_indexes setting to limit number of threads used for primary key processing. [#53313](https://github.com/ClickHouse/ClickHouse/pull/53313) ([jorisgio](https://github.com/jorisgio)). +* Add max_threads_for_indexes setting to limit number of threads used for primary key processing. [#53313](https://github.com/ClickHouse/ClickHouse/pull/53313) ([Joris Giovannangeli](https://github.com/jorisgio)). * Add experimental support for HNSW as approximate neighbor search method. [#53447](https://github.com/ClickHouse/ClickHouse/pull/53447) ([Davit Vardanyan](https://github.com/davvard)). * Re-add SipHash keyed functions. [#53525](https://github.com/ClickHouse/ClickHouse/pull/53525) ([Salvatore Mesoraca](https://github.com/aiven-sal)). * ([#52755](https://github.com/ClickHouse/ClickHouse/issues/52755) , [#52895](https://github.com/ClickHouse/ClickHouse/issues/52895)) Added functions `arrayRotateLeft`, `arrayRotateRight`, `arrayShiftLeft`, `arrayShiftRight`. [#53557](https://github.com/ClickHouse/ClickHouse/pull/53557) ([Mikhail Koviazin](https://github.com/mkmkme)). @@ -72,7 +72,7 @@ sidebar_label: 2023 * Add ability to log when max_partitions_per_insert_block is reached ... [#50948](https://github.com/ClickHouse/ClickHouse/pull/50948) ([Sean Haynes](https://github.com/seandhaynes)). * Added a bunch of custom commands (mostly to make ClickHouse debugging easier). [#51117](https://github.com/ClickHouse/ClickHouse/pull/51117) ([pufit](https://github.com/pufit)). * Updated check for connection_string as connection string with sas does not always begin with DefaultEndPoint and updated connection url to include sas token after adding container to url. [#51141](https://github.com/ClickHouse/ClickHouse/pull/51141) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)). -* Fix description for filtering sets in full_sorting_merge join. [#51329](https://github.com/ClickHouse/ClickHouse/pull/51329) ([Tanay Tummalapalli](https://github.com/ttanay)). +* Fix description for filtering sets in full_sorting_merge join. [#51329](https://github.com/ClickHouse/ClickHouse/pull/51329) ([ttanay](https://github.com/ttanay)). * The sizes of the (index) uncompressed/mark, mmap and query caches can now be configured dynamically at runtime. [#51446](https://github.com/ClickHouse/ClickHouse/pull/51446) ([Robert Schulze](https://github.com/rschu1ze)). * Fixed memory consumption in `Aggregator` when `max_block_size` is huge. [#51566](https://github.com/ClickHouse/ClickHouse/pull/51566) ([Nikita Taranov](https://github.com/nickitat)). * Add `SYSTEM SYNC FILESYSTEM CACHE` command. It will compare in-memory state of filesystem cache with what it has on disk and fix in-memory state if needed. [#51622](https://github.com/ClickHouse/ClickHouse/pull/51622) ([Kseniia Sumarokova](https://github.com/kssenii)). @@ -80,10 +80,10 @@ sidebar_label: 2023 * Support reading tuple subcolumns from file/s3/hdfs/url/azureBlobStorage table functions. [#51806](https://github.com/ClickHouse/ClickHouse/pull/51806) ([Kruglov Pavel](https://github.com/Avogar)). * Function `arrayIntersect` now returns the values sorted like the first argument. Closes [#27622](https://github.com/ClickHouse/ClickHouse/issues/27622). [#51850](https://github.com/ClickHouse/ClickHouse/pull/51850) ([Yarik Briukhovetskyi](https://github.com/yariks5s)). * Add new queries, which allow to create/drop of access entities in specified access storage or move access entities from one access storage to another. [#51912](https://github.com/ClickHouse/ClickHouse/pull/51912) ([pufit](https://github.com/pufit)). -* ALTER TABLE FREEZE are not replicated in Replicated engine. [#52064](https://github.com/ClickHouse/ClickHouse/pull/52064) ([Mike Kot](https://github.com/myrrc)). +* ALTER TABLE FREEZE are not replicated in Replicated engine. [#52064](https://github.com/ClickHouse/ClickHouse/pull/52064) ([Mikhail Kot](https://github.com/myrrc)). * Added possibility to flush logs to the disk on crash - Added logs buffer configuration. [#52174](https://github.com/ClickHouse/ClickHouse/pull/52174) ([Alexey Gerasimchuck](https://github.com/Demilivor)). -* Fix S3 table function does not work for pre-signed URL. close [#50846](https://github.com/ClickHouse/ClickHouse/issues/50846). [#52310](https://github.com/ClickHouse/ClickHouse/pull/52310) ([chen](https://github.com/xiedeyantu)). -* System.events and system.metrics tables add column name as an alias to event and metric. close [#51257](https://github.com/ClickHouse/ClickHouse/issues/51257). [#52315](https://github.com/ClickHouse/ClickHouse/pull/52315) ([chen](https://github.com/xiedeyantu)). +* Fix S3 table function does not work for pre-signed URL. close [#50846](https://github.com/ClickHouse/ClickHouse/issues/50846). [#52310](https://github.com/ClickHouse/ClickHouse/pull/52310) ([Jensen](https://github.com/xiedeyantu)). +* System.events and system.metrics tables add column name as an alias to event and metric. close [#51257](https://github.com/ClickHouse/ClickHouse/issues/51257). [#52315](https://github.com/ClickHouse/ClickHouse/pull/52315) ([Jensen](https://github.com/xiedeyantu)). * Added support of syntax `CREATE UNIQUE INDEX` in parser for better SQL compatibility. `UNIQUE` index is not supported. Set `create_index_ignore_unique=1` to ignore UNIQUE keyword in queries. [#52320](https://github.com/ClickHouse/ClickHouse/pull/52320) ([Ilya Yatsishin](https://github.com/qoega)). * Add support of predefined macro (`{database}` and `{table}`) in some kafka engine settings: topic, consumer, client_id, etc. [#52386](https://github.com/ClickHouse/ClickHouse/pull/52386) ([Yury Bogomolov](https://github.com/ybogo)). * Disable updating fs cache during backup/restore. Filesystem cache must not be updated during backup/restore, it seems it just slows down the process without any profit (because the BACKUP command can read a lot of data and it's no use to put all the data to the filesystem cache and immediately evict it). [#52402](https://github.com/ClickHouse/ClickHouse/pull/52402) ([Vitaly Baranov](https://github.com/vitlibar)). @@ -107,7 +107,7 @@ sidebar_label: 2023 * Use the same default paths for `clickhouse_keeper` (symlink) as for `clickhouse_keeper` (executable). [#52861](https://github.com/ClickHouse/ClickHouse/pull/52861) ([Vitaly Baranov](https://github.com/vitlibar)). * CVE-2016-2183: disable 3DES. [#52893](https://github.com/ClickHouse/ClickHouse/pull/52893) ([Kenji Noguchi](https://github.com/knoguchi)). * Load filesystem cache metadata on startup in parallel. Configured by `load_metadata_threads` (default: 1) cache config setting. Related to [#52037](https://github.com/ClickHouse/ClickHouse/issues/52037). [#52943](https://github.com/ClickHouse/ClickHouse/pull/52943) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Improve error message for table function remote. Closes [#40220](https://github.com/ClickHouse/ClickHouse/issues/40220). [#52959](https://github.com/ClickHouse/ClickHouse/pull/52959) ([jiyoungyoooo](https://github.com/jiyoungyoooo)). +* Improve error message for table function remote. Closes [#40220](https://github.com/ClickHouse/ClickHouse/issues/40220). [#52959](https://github.com/ClickHouse/ClickHouse/pull/52959) ([Jiyoung Yoo](https://github.com/jiyoungyoooo)). * Added the possibility to specify custom storage policy in the `SETTINGS` clause of `RESTORE` queries. [#52970](https://github.com/ClickHouse/ClickHouse/pull/52970) ([Victor Krasnov](https://github.com/sirvickr)). * Add the ability to throttle the S3 requests on backup operations (`BACKUP` and `RESTORE` commands now honor `s3_max_[get/put]_[rps/burst]`). [#52974](https://github.com/ClickHouse/ClickHouse/pull/52974) ([Daniel Pozo Escalona](https://github.com/danipozo)). * Add settings to ignore ON CLUSTER clause in queries for management of replicated user-defined functions or access control entities with replicated storage. [#52975](https://github.com/ClickHouse/ClickHouse/pull/52975) ([Aleksei Filatov](https://github.com/aalexfvk)). @@ -127,7 +127,7 @@ sidebar_label: 2023 * Server settings asynchronous_metrics_update_period_s and asynchronous_heavy_metrics_update_period_s configured to 0 now fail gracefully instead of crash the server. [#53428](https://github.com/ClickHouse/ClickHouse/pull/53428) ([Robert Schulze](https://github.com/rschu1ze)). * Previously the caller could register the same watch callback multiple times. In that case each entry was consuming memory and the same callback was called multiple times which didn't make much sense. In order to avoid this the caller could have some logic to not add the same watch multiple times. With this change this deduplication is done internally if the watch callback is passed via shared_ptr. [#53452](https://github.com/ClickHouse/ClickHouse/pull/53452) ([Alexander Gololobov](https://github.com/davenger)). * The ClickHouse server now respects memory limits changed via cgroups when reloading its configuration. [#53455](https://github.com/ClickHouse/ClickHouse/pull/53455) ([Robert Schulze](https://github.com/rschu1ze)). -* Add ability to turn off flush of Distributed tables on `DETACH`/`DROP`/server shutdown. [#53501](https://github.com/ClickHouse/ClickHouse/pull/53501) ([Azat Khuzhin](https://github.com/azat)). +* Add ability to turn off flush of Distributed tables on `DETACH`/`DROP`/server shutdown (`flush_on_detach` setting for `Distributed`). [#53501](https://github.com/ClickHouse/ClickHouse/pull/53501) ([Azat Khuzhin](https://github.com/azat)). * Domainrfc support ipv6(ip literal within square brackets). [#53506](https://github.com/ClickHouse/ClickHouse/pull/53506) ([Chen768959](https://github.com/Chen768959)). * Use filter by file/path before reading in url/file/hdfs table functins. [#53529](https://github.com/ClickHouse/ClickHouse/pull/53529) ([Kruglov Pavel](https://github.com/Avogar)). * Use longer timeout for S3 CopyObject requests. [#53533](https://github.com/ClickHouse/ClickHouse/pull/53533) ([Michael Kolupaev](https://github.com/al13n321)). @@ -186,71 +186,71 @@ sidebar_label: 2023 #### Bug Fix (user-visible misbehavior in an official stable release) -* Do not reset Annoy index during build-up with > 1 mark [#51325](https://github.com/ClickHouse/ClickHouse/pull/51325) ([Tian Xinhui](https://github.com/xinhuitian)). -* Fix usage of temporary directories during RESTORE [#51493](https://github.com/ClickHouse/ClickHouse/pull/51493) ([Azat Khuzhin](https://github.com/azat)). -* Fix binary arithmetic for Nullable(IPv4) [#51642](https://github.com/ClickHouse/ClickHouse/pull/51642) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). -* Support IPv4 and IPv6 as dictionary attributes [#51756](https://github.com/ClickHouse/ClickHouse/pull/51756) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). -* Bug fix for checksum of compress marks [#51777](https://github.com/ClickHouse/ClickHouse/pull/51777) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)). -* Fix mistakenly comma parsing as part of datetime in CSV best effort parsing [#51950](https://github.com/ClickHouse/ClickHouse/pull/51950) ([Kruglov Pavel](https://github.com/Avogar)). -* Don't throw exception when exec udf has parameters [#51961](https://github.com/ClickHouse/ClickHouse/pull/51961) ([Nikita Taranov](https://github.com/nickitat)). -* Fix recalculation of skip indexes and projections in `ALTER DELETE` queries [#52530](https://github.com/ClickHouse/ClickHouse/pull/52530) ([Anton Popov](https://github.com/CurtizJ)). -* MaterializedMySQL: Fix the infinite loop in ReadBuffer::read [#52621](https://github.com/ClickHouse/ClickHouse/pull/52621) ([Val Doroshchuk](https://github.com/valbok)). -* Load suggestion only with `clickhouse` dialect [#52628](https://github.com/ClickHouse/ClickHouse/pull/52628) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). -* init and destroy ares channel on demand.. [#52634](https://github.com/ClickHouse/ClickHouse/pull/52634) ([Arthur Passos](https://github.com/arthurpassos)). -* RFC: Fix filtering by virtual columns with OR expression [#52653](https://github.com/ClickHouse/ClickHouse/pull/52653) ([Azat Khuzhin](https://github.com/azat)). -* Fix crash in function `tuple` with one sparse column argument [#52659](https://github.com/ClickHouse/ClickHouse/pull/52659) ([Anton Popov](https://github.com/CurtizJ)). -* Fix named collections on cluster 23.7 [#52687](https://github.com/ClickHouse/ClickHouse/pull/52687) ([Al Korgun](https://github.com/alkorgun)). -* Fix reading of unnecessary column in case of multistage `PREWHERE` [#52689](https://github.com/ClickHouse/ClickHouse/pull/52689) ([Anton Popov](https://github.com/CurtizJ)). -* Fix unexpected sort result on multi columns with nulls first direction [#52761](https://github.com/ClickHouse/ClickHouse/pull/52761) ([copperybean](https://github.com/copperybean)). -* Fix data race in Keeper reconfiguration [#52804](https://github.com/ClickHouse/ClickHouse/pull/52804) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix sorting of sparse columns with large limit [#52827](https://github.com/ClickHouse/ClickHouse/pull/52827) ([Anton Popov](https://github.com/CurtizJ)). -* clickhouse-keeper: fix implementation of server with poll() [#52833](https://github.com/ClickHouse/ClickHouse/pull/52833) ([Andy Fiddaman](https://github.com/citrus-it)). -* make regexp analyzer recognize named capturing groups [#52840](https://github.com/ClickHouse/ClickHouse/pull/52840) ([Han Fei](https://github.com/hanfei1991)). -* Fix possible assert in ~PushingAsyncPipelineExecutor in clickhouse-local [#52862](https://github.com/ClickHouse/ClickHouse/pull/52862) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix reading of empty `Nested(Array(LowCardinality(...)))` [#52949](https://github.com/ClickHouse/ClickHouse/pull/52949) ([Anton Popov](https://github.com/CurtizJ)). -* Added new tests for session_log and fixed the inconsistency between login and logout. [#52958](https://github.com/ClickHouse/ClickHouse/pull/52958) ([Alexey Gerasimchuck](https://github.com/Demilivor)). -* Fix password leak in show create mysql table [#52962](https://github.com/ClickHouse/ClickHouse/pull/52962) ([Duc Canh Le](https://github.com/canhld94)). -* Convert sparse to full in CreateSetAndFilterOnTheFlyStep [#53000](https://github.com/ClickHouse/ClickHouse/pull/53000) ([vdimir](https://github.com/vdimir)). -* Fix rare race condition with empty key prefix directory deletion in fs cache [#53055](https://github.com/ClickHouse/ClickHouse/pull/53055) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix ZstdDeflatingWriteBuffer truncating the output sometimes [#53064](https://github.com/ClickHouse/ClickHouse/pull/53064) ([Michael Kolupaev](https://github.com/al13n321)). -* Fix query_id in part_log with async flush queries [#53103](https://github.com/ClickHouse/ClickHouse/pull/53103) ([Raúl Marín](https://github.com/Algunenano)). -* Fix possible error from cache "Read unexpected size" [#53121](https://github.com/ClickHouse/ClickHouse/pull/53121) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Disable the new parquet encoder [#53130](https://github.com/ClickHouse/ClickHouse/pull/53130) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Not-ready Set [#53162](https://github.com/ClickHouse/ClickHouse/pull/53162) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fix character escaping in the PostgreSQL engine [#53250](https://github.com/ClickHouse/ClickHouse/pull/53250) ([Nikolay Degterinsky](https://github.com/evillique)). -* #2 Added new tests for session_log and fixed the inconsistency between login and logout. [#53255](https://github.com/ClickHouse/ClickHouse/pull/53255) ([Alexey Gerasimchuck](https://github.com/Demilivor)). -* #3 Fixed inconsistency between login success and logout [#53302](https://github.com/ClickHouse/ClickHouse/pull/53302) ([Alexey Gerasimchuck](https://github.com/Demilivor)). -* Fix adding sub-second intervals to DateTime [#53309](https://github.com/ClickHouse/ClickHouse/pull/53309) ([Michael Kolupaev](https://github.com/al13n321)). -* Fix "Context has expired" error in dictionaries [#53342](https://github.com/ClickHouse/ClickHouse/pull/53342) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Fix incorrect normal projection AST format [#53347](https://github.com/ClickHouse/ClickHouse/pull/53347) ([Amos Bird](https://github.com/amosbird)). -* Forbid use_structure_from_insertion_table_in_table_functions when execute Scalar [#53348](https://github.com/ClickHouse/ClickHouse/pull/53348) ([flynn](https://github.com/ucasfl)). -* Fix loading lazy database during system.table select query [#53372](https://github.com/ClickHouse/ClickHouse/pull/53372) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)). -* Fixed system.data_skipping_indices for MaterializedMySQL [#53381](https://github.com/ClickHouse/ClickHouse/pull/53381) ([Filipp Ozinov](https://github.com/bakwc)). -* Fix processing single carriage return in TSV file segmentation engine [#53407](https://github.com/ClickHouse/ClickHouse/pull/53407) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix 'Context has expired' error properly [#53433](https://github.com/ClickHouse/ClickHouse/pull/53433) ([Michael Kolupaev](https://github.com/al13n321)). -* Fix timeout_overflow_mode when having subquery in the rhs of IN [#53439](https://github.com/ClickHouse/ClickHouse/pull/53439) ([Duc Canh Le](https://github.com/canhld94)). -* Fix an unexpected behavior in [#53152](https://github.com/ClickHouse/ClickHouse/issues/53152) [#53440](https://github.com/ClickHouse/ClickHouse/pull/53440) ([Zhiguo Zhou](https://github.com/ZhiguoZh)). -* Fix JSON_QUERY Function parse error while path is all number [#53470](https://github.com/ClickHouse/ClickHouse/pull/53470) ([KevinyhZou](https://github.com/KevinyhZou)). -* Fix wrong columns order for queries with parallel FINAL. [#53489](https://github.com/ClickHouse/ClickHouse/pull/53489) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fixed SELECTing from ReplacingMergeTree with do_not_merge_across_partitions_select_final [#53511](https://github.com/ClickHouse/ClickHouse/pull/53511) ([Vasily Nemkov](https://github.com/Enmk)). -* bugfix: Flush async insert queue first on shutdown [#53547](https://github.com/ClickHouse/ClickHouse/pull/53547) ([joelynch](https://github.com/joelynch)). -* Fix crash in join on sparse column [#53548](https://github.com/ClickHouse/ClickHouse/pull/53548) ([vdimir](https://github.com/vdimir)). -* Fix possible UB in Set skipping index for functions with incorrect args [#53559](https://github.com/ClickHouse/ClickHouse/pull/53559) ([Azat Khuzhin](https://github.com/azat)). -* Fix possible UB in inverted indexes (experimental feature) [#53560](https://github.com/ClickHouse/ClickHouse/pull/53560) ([Azat Khuzhin](https://github.com/azat)). -* Fix: interpolate expression takes source column instead of same name aliased from select expression. [#53572](https://github.com/ClickHouse/ClickHouse/pull/53572) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). -* Fix number of dropped granules in EXPLAIN PLAN index=1 [#53616](https://github.com/ClickHouse/ClickHouse/pull/53616) ([wangxiaobo](https://github.com/wzb5212)). -* Correctly handle totals and extremes with `DelayedSource` [#53644](https://github.com/ClickHouse/ClickHouse/pull/53644) ([Antonio Andelic](https://github.com/antonio2368)). -* Prepared set cache in mutation pipeline stuck [#53645](https://github.com/ClickHouse/ClickHouse/pull/53645) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fix bug on mutations with subcolumns of type JSON in predicates of UPDATE and DELETE queries. [#53677](https://github.com/ClickHouse/ClickHouse/pull/53677) ([VanDarkholme7](https://github.com/VanDarkholme7)). -* Fix filter pushdown for full_sorting_merge join [#53699](https://github.com/ClickHouse/ClickHouse/pull/53699) ([vdimir](https://github.com/vdimir)). -* Try to fix bug with NULL::LowCardinality(Nullable(...)) NOT IN [#53706](https://github.com/ClickHouse/ClickHouse/pull/53706) ([Andrey Zvonov](https://github.com/zvonand)). -* Fix: sorted distinct with sparse columns [#53711](https://github.com/ClickHouse/ClickHouse/pull/53711) ([Igor Nikonov](https://github.com/devcrafter)). -* transform: correctly handle default column with multiple rows [#53742](https://github.com/ClickHouse/ClickHouse/pull/53742) ([Salvatore Mesoraca](https://github.com/aiven-sal)). -* Fix fuzzer crash in parseDateTime() [#53764](https://github.com/ClickHouse/ClickHouse/pull/53764) ([Robert Schulze](https://github.com/rschu1ze)). -* Materialized postgres: fix uncaught exception in getCreateTableQueryImpl [#53832](https://github.com/ClickHouse/ClickHouse/pull/53832) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix possible segfault while using PostgreSQL engine [#53847](https://github.com/ClickHouse/ClickHouse/pull/53847) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix named_collection_admin alias [#54066](https://github.com/ClickHouse/ClickHouse/pull/54066) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix rows_before_limit_at_least for DelayedSource. [#54122](https://github.com/ClickHouse/ClickHouse/pull/54122) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix results of queries utilizing the Annoy index when the part has more than one mark. [#51325](https://github.com/ClickHouse/ClickHouse/pull/51325) ([Tian Xinhui](https://github.com/xinhuitian)). +* Fix usage of temporary directories during RESTORE. [#51493](https://github.com/ClickHouse/ClickHouse/pull/51493) ([Azat Khuzhin](https://github.com/azat)). +* Fixed binary arithmetic for Nullable(IPv4). [#51642](https://github.com/ClickHouse/ClickHouse/pull/51642) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). +* Support IPv4 and IPv6 as dictionary attributes. [#51756](https://github.com/ClickHouse/ClickHouse/pull/51756) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). +* Updated checkDataPart to read compress marks as compressed file by checking its extension resolves [#51337](https://github.com/ClickHouse/ClickHouse/issues/51337). [#51777](https://github.com/ClickHouse/ClickHouse/pull/51777) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)). +* Fix mistakenly comma parsing as part of datetime in CSV datetime best effort parsing. Closes [#51059](https://github.com/ClickHouse/ClickHouse/issues/51059). [#51950](https://github.com/ClickHouse/ClickHouse/pull/51950) ([Kruglov Pavel](https://github.com/Avogar)). +* Fixed exception when executable udf was provided with a parameter. [#51961](https://github.com/ClickHouse/ClickHouse/pull/51961) ([Nikita Taranov](https://github.com/nickitat)). +* Fixed recalculation of skip indexes and projections in `ALTER DELETE` queries. [#52530](https://github.com/ClickHouse/ClickHouse/pull/52530) ([Anton Popov](https://github.com/CurtizJ)). +* Fixed the infinite loop in ReadBuffer when the pos overflows the end of the buffer in MaterializedMySQL. [#52621](https://github.com/ClickHouse/ClickHouse/pull/52621) ([Val Doroshchuk](https://github.com/valbok)). +* Do not try to load suggestions in `clickhouse-local` when a the dialect is not `clickhouse`. [#52628](https://github.com/ClickHouse/ClickHouse/pull/52628) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* Remove mutex from CaresPTRResolver and create `ares_channel` on demand. Trying to fix: https://github.com/ClickHouse/ClickHouse/pull/52327#issuecomment-1643021543. [#52634](https://github.com/ClickHouse/ClickHouse/pull/52634) ([Arthur Passos](https://github.com/arthurpassos)). +* Fix filtering by virtual columns with OR expression (i.e. by `_table` for `Merge` engine). [#52653](https://github.com/ClickHouse/ClickHouse/pull/52653) ([Azat Khuzhin](https://github.com/azat)). +* Fix crash in function `tuple` with one sparse column argument. [#52659](https://github.com/ClickHouse/ClickHouse/pull/52659) ([Anton Popov](https://github.com/CurtizJ)). +* Fix named collections related statements: `if [not] exists`, `on cluster`. Closes [#51609](https://github.com/ClickHouse/ClickHouse/issues/51609). [#52687](https://github.com/ClickHouse/ClickHouse/pull/52687) ([Al Korgun](https://github.com/alkorgun)). +* Fix reading of unnecessary column in case of multistage `PREWHERE`. [#52689](https://github.com/ClickHouse/ClickHouse/pull/52689) ([Anton Popov](https://github.com/CurtizJ)). +* Fix unexpected sort result on multi columns with nulls first direction. [#52761](https://github.com/ClickHouse/ClickHouse/pull/52761) ([ZhiHong Zhang](https://github.com/copperybean)). +* Keeper fix: fix data race during reconfiguration. [#52804](https://github.com/ClickHouse/ClickHouse/pull/52804) ([Antonio Andelic](https://github.com/antonio2368)). +* Fixed sorting of sparse columns in case of `ORDER BY ... LIMIT n` clause and large values of `n`. [#52827](https://github.com/ClickHouse/ClickHouse/pull/52827) ([Anton Popov](https://github.com/CurtizJ)). +* Keeper fix: platforms that used poll() would delay responding to requests until the client sent a heartbeat. [#52833](https://github.com/ClickHouse/ClickHouse/pull/52833) ([Andy Fiddaman](https://github.com/citrus-it)). +* Make regexp analyzer recognize named capturing groups. [#52840](https://github.com/ClickHouse/ClickHouse/pull/52840) ([Han Fei](https://github.com/hanfei1991)). +* Fix possible assert in ~PushingAsyncPipelineExecutor in clickhouse-local. [#52862](https://github.com/ClickHouse/ClickHouse/pull/52862) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix reading of empty `Nested(Array(LowCardinality(...)))` columns (added by `ALTER TABLE ... ADD COLUMN ...` query and not materialized in parts) from compact parts of `MergeTree` tables. [#52949](https://github.com/ClickHouse/ClickHouse/pull/52949) ([Anton Popov](https://github.com/CurtizJ)). +* Fixed the record inconsistency in session_log between login and logout. [#52958](https://github.com/ClickHouse/ClickHouse/pull/52958) ([Alexey Gerasimchuck](https://github.com/Demilivor)). +* Fix password leak in show create mysql table. [#52962](https://github.com/ClickHouse/ClickHouse/pull/52962) ([Duc Canh Le](https://github.com/canhld94)). +* Fix possible crash in full sorting merge join on sparse columns, close [#52978](https://github.com/ClickHouse/ClickHouse/issues/52978). [#53000](https://github.com/ClickHouse/ClickHouse/pull/53000) ([vdimir](https://github.com/vdimir)). +* Fix very rare race condition with empty key prefix directory deletion in fs cache. [#53055](https://github.com/ClickHouse/ClickHouse/pull/53055) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fixed `output_format_parquet_compression_method='zstd'` producing invalid Parquet files sometimes. In older versions, use setting `output_format_parquet_use_custom_encoder = 0` as a workaround. [#53064](https://github.com/ClickHouse/ClickHouse/pull/53064) ([Michael Kolupaev](https://github.com/al13n321)). +* Fix query_id in part_log with async flush queries. [#53103](https://github.com/ClickHouse/ClickHouse/pull/53103) ([Raúl Marín](https://github.com/Algunenano)). +* Fix possible error from filesystem cache "Read unexpected size". [#53121](https://github.com/ClickHouse/ClickHouse/pull/53121) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Disable the new parquet encoder: it has a bug. [#53130](https://github.com/ClickHouse/ClickHouse/pull/53130) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* `Not-ready Set is passed as the second argument for function 'in'` could happen with limited `max_result_rows` and ` result_overflow_mode = 'break'`. [#53162](https://github.com/ClickHouse/ClickHouse/pull/53162) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fix character escaping in the PostgreSQL engine (`\'` -> `''`, `\\` -> `\`). Closes [#49821](https://github.com/ClickHouse/ClickHouse/issues/49821). [#53250](https://github.com/ClickHouse/ClickHouse/pull/53250) ([Nikolay Degterinsky](https://github.com/evillique)). +* Fixed the record inconsistency in session_log between login and logout. [#53255](https://github.com/ClickHouse/ClickHouse/pull/53255) ([Alexey Gerasimchuck](https://github.com/Demilivor)). +* Fixed the record inconsistency in session_log between login and logout. [#53302](https://github.com/ClickHouse/ClickHouse/pull/53302) ([Alexey Gerasimchuck](https://github.com/Demilivor)). +* Fixed adding intervals of a fraction of a second to DateTime producing incorrect result. [#53309](https://github.com/ClickHouse/ClickHouse/pull/53309) ([Michael Kolupaev](https://github.com/al13n321)). +* Fix the "Context has expired" error in dictionaries when using subqueries. [#53342](https://github.com/ClickHouse/ClickHouse/pull/53342) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Fix incorrect normal projection AST format when single function is used in ORDER BY. This fixes [#52607](https://github.com/ClickHouse/ClickHouse/issues/52607). [#53347](https://github.com/ClickHouse/ClickHouse/pull/53347) ([Amos Bird](https://github.com/amosbird)). +* Forbid `use_structure_from_insertion_table_in_table_functions` when execute Scalar. Closes [#52494](https://github.com/ClickHouse/ClickHouse/issues/52494). [#53348](https://github.com/ClickHouse/ClickHouse/pull/53348) ([flynn](https://github.com/ucasfl)). +* Avoid loading tables from lazy database when not needed Follow up to [#43840](https://github.com/ClickHouse/ClickHouse/issues/43840). [#53372](https://github.com/ClickHouse/ClickHouse/pull/53372) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)). +* Fixed `system.data_skipping_indices` columns `data_compressed_bytes` and `data_uncompressed_bytes` for MaterializedMySQL. [#53381](https://github.com/ClickHouse/ClickHouse/pull/53381) ([Filipp Ozinov](https://github.com/bakwc)). +* Fix processing single carriage return in TSV file segmentation engine that could lead to parsing errors. Closes [#53320](https://github.com/ClickHouse/ClickHouse/issues/53320). [#53407](https://github.com/ClickHouse/ClickHouse/pull/53407) ([Kruglov Pavel](https://github.com/Avogar)). +* Fix the "Context has expired" error when using subqueries with functions `file()` (regular function, not table function), `joinGet()`, `joinGetOrNull()`, `connectionId()`. [#53433](https://github.com/ClickHouse/ClickHouse/pull/53433) ([Michael Kolupaev](https://github.com/al13n321)). +* Fix timeout_overflow_mode when having subquery in the rhs of IN. [#53439](https://github.com/ClickHouse/ClickHouse/pull/53439) ([Duc Canh Le](https://github.com/canhld94)). +* This PR fixes [#53152](https://github.com/ClickHouse/ClickHouse/issues/53152). [#53440](https://github.com/ClickHouse/ClickHouse/pull/53440) ([Zhiguo Zhou](https://github.com/ZhiguoZh)). +* Fix the JSON_QUERY function can not parse the json string while path is numberic. like in the query SELECT JSON_QUERY('{"123":"abcd"}', '$.123'), we would encounter the exceptions ``` DB::Exception: Unable to parse JSONPath: While processing JSON_QUERY('{"123":"acd"}', '$.123'). (BAD_ARGUMENTS) ```. [#53470](https://github.com/ClickHouse/ClickHouse/pull/53470) ([KevinyhZou](https://github.com/KevinyhZou)). +* Fix possible crash for queries with parallel `FINAL` where `ORDER BY` and `PRIMARY KEY` are different in table definition. [#53489](https://github.com/ClickHouse/ClickHouse/pull/53489) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Fixed ReplacingMergeTree to properly process single-partition cases when `do_not_merge_across_partitions_select_final=1`. Previously `SELECT` could return rows that were marked as deleted. [#53511](https://github.com/ClickHouse/ClickHouse/pull/53511) ([Vasily Nemkov](https://github.com/Enmk)). +* Fix bug in flushing of async insert queue on graceful shutdown. [#53547](https://github.com/ClickHouse/ClickHouse/pull/53547) ([joelynch](https://github.com/joelynch)). +* Fix crash in join on sparse column. [#53548](https://github.com/ClickHouse/ClickHouse/pull/53548) ([vdimir](https://github.com/vdimir)). +* Fix possible UB in Set skipping index for functions with incorrect args. [#53559](https://github.com/ClickHouse/ClickHouse/pull/53559) ([Azat Khuzhin](https://github.com/azat)). +* Fix possible UB in inverted indexes (experimental feature). [#53560](https://github.com/ClickHouse/ClickHouse/pull/53560) ([Azat Khuzhin](https://github.com/azat)). +* Fixed bug for interpolate when interpolated column is aliased with the same name as a source column. [#53572](https://github.com/ClickHouse/ClickHouse/pull/53572) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). +* Fixed a bug in EXPLAIN PLAN index=1 where the number of dropped granules was incorrect. [#53616](https://github.com/ClickHouse/ClickHouse/pull/53616) ([wangxiaobo](https://github.com/wzb5212)). +* Correctly handle totals and extremes when `DelayedSource` is used. [#53644](https://github.com/ClickHouse/ClickHouse/pull/53644) ([Antonio Andelic](https://github.com/antonio2368)). +* Fix `Pipeline stuck` error in mutation with `IN (subquery WITH TOTALS)` where ready set was taken from cache. [#53645](https://github.com/ClickHouse/ClickHouse/pull/53645) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Allow to use JSON subcolumns in predicates of UPDATE and DELETE queries. [#53677](https://github.com/ClickHouse/ClickHouse/pull/53677) ([zps](https://github.com/VanDarkholme7)). +* Fix possible logical error exception during filter pushdown for full_sorting_merge join. [#53699](https://github.com/ClickHouse/ClickHouse/pull/53699) ([vdimir](https://github.com/vdimir)). +* Fix NULL::LowCardinality(Nullable(...)) with IN. [#53706](https://github.com/ClickHouse/ClickHouse/pull/53706) ([Andrey Zvonov](https://github.com/zvonand)). +* Fixes possible crashes in `DISTINCT` queries with enabled `optimize_distinct_in_order` and sparse columns. [#53711](https://github.com/ClickHouse/ClickHouse/pull/53711) ([Igor Nikonov](https://github.com/devcrafter)). +* Correctly handle default column with multiple rows in transform. [#53742](https://github.com/ClickHouse/ClickHouse/pull/53742) ([Salvatore Mesoraca](https://github.com/aiven-sal)). +* Fix crash in SQL function parseDateTime() with non-const timezone argument. [#53764](https://github.com/ClickHouse/ClickHouse/pull/53764) ([Robert Schulze](https://github.com/rschu1ze)). +* Fix uncaught exception in `getCreateTableQueryImpl`. [#53832](https://github.com/ClickHouse/ClickHouse/pull/53832) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix possible segfault while using PostgreSQL engine. Closes [#36919](https://github.com/ClickHouse/ClickHouse/issues/36919). [#53847](https://github.com/ClickHouse/ClickHouse/pull/53847) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix `named_collection_admin` alias to `named_collection_control` not working from config. [#54066](https://github.com/ClickHouse/ClickHouse/pull/54066) ([Kseniia Sumarokova](https://github.com/kssenii)). +* A distributed query could miss `rows_before_limit_at_least` in the query result in case it was executed on a replica with a delay more than `max_replica_delay_for_distributed_queries`. [#54122](https://github.com/ClickHouse/ClickHouse/pull/54122) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). #### NO CL ENTRY @@ -272,7 +272,7 @@ sidebar_label: 2023 * Add more checks into ThreadStatus ctor. [#42019](https://github.com/ClickHouse/ClickHouse/pull/42019) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). * Refactor Query Tree visitor [#46740](https://github.com/ClickHouse/ClickHouse/pull/46740) ([Dmitry Novik](https://github.com/novikd)). * Revert "Revert "Randomize JIT settings in tests"" [#48282](https://github.com/ClickHouse/ClickHouse/pull/48282) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Fix outdated cache configuration in s3 tests: s3_storage_policy_by_defau... [#48424](https://github.com/ClickHouse/ClickHouse/pull/48424) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Fix outdated cache configuration in s3 tests: s3_storage_policy_by_defau… [#48424](https://github.com/ClickHouse/ClickHouse/pull/48424) ([Kseniia Sumarokova](https://github.com/kssenii)). * Fix IN with decimal in analyzer [#48754](https://github.com/ClickHouse/ClickHouse/pull/48754) ([vdimir](https://github.com/vdimir)). * Some unclear change in StorageBuffer::reschedule() for something [#49723](https://github.com/ClickHouse/ClickHouse/pull/49723) ([DimasKovas](https://github.com/DimasKovas)). * MergeTree & SipHash checksum big-endian support [#50276](https://github.com/ClickHouse/ClickHouse/pull/50276) ([ltrk2](https://github.com/ltrk2)). @@ -540,7 +540,7 @@ sidebar_label: 2023 * Do not warn about arch_sys_counter clock [#53739](https://github.com/ClickHouse/ClickHouse/pull/53739) ([Artur Malchanau](https://github.com/Hexta)). * Add some profile events [#53741](https://github.com/ClickHouse/ClickHouse/pull/53741) ([Kseniia Sumarokova](https://github.com/kssenii)). * Support clang-18 (Wmissing-field-initializers) [#53751](https://github.com/ClickHouse/ClickHouse/pull/53751) ([Raúl Marín](https://github.com/Algunenano)). -* Upgrade openSSL to v3.0.10 [#53756](https://github.com/ClickHouse/ClickHouse/pull/53756) ([bhavnajindal](https://github.com/bhavnajindal)). +* Upgrade openSSL to v3.0.10 [#53756](https://github.com/ClickHouse/ClickHouse/pull/53756) ([Bhavna Jindal](https://github.com/bhavnajindal)). * Improve JSON-handling on s390x [#53760](https://github.com/ClickHouse/ClickHouse/pull/53760) ([ltrk2](https://github.com/ltrk2)). * Reduce API calls to SSM client [#53762](https://github.com/ClickHouse/ClickHouse/pull/53762) ([Mikhail f. Shiryaev](https://github.com/Felixoid)). * Remove branch references from .gitmodules [#53763](https://github.com/ClickHouse/ClickHouse/pull/53763) ([Robert Schulze](https://github.com/rschu1ze)). @@ -588,3 +588,4 @@ sidebar_label: 2023 * tests: mark 02152_http_external_tables_memory_tracking as no-parallel [#54155](https://github.com/ClickHouse/ClickHouse/pull/54155) ([Azat Khuzhin](https://github.com/azat)). * The external logs have had colliding arguments [#54165](https://github.com/ClickHouse/ClickHouse/pull/54165) ([Mikhail f. Shiryaev](https://github.com/Felixoid)). * Rename macro [#54169](https://github.com/ClickHouse/ClickHouse/pull/54169) ([Kseniia Sumarokova](https://github.com/kssenii)). + diff --git a/docs/changelogs/v23.8.10.43-lts.md b/docs/changelogs/v23.8.10.43-lts.md index 0093467d129..0750901da8a 100644 --- a/docs/changelogs/v23.8.10.43-lts.md +++ b/docs/changelogs/v23.8.10.43-lts.md @@ -16,17 +16,17 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Background merges correctly use temporary data storage in the cache [#57275](https://github.com/ClickHouse/ClickHouse/pull/57275) ([vdimir](https://github.com/vdimir)). -* MergeTree mutations reuse source part index granularity [#57352](https://github.com/ClickHouse/ClickHouse/pull/57352) ([Maksim Kita](https://github.com/kitaisreal)). -* Fix double destroy call on exception throw in addBatchLookupTable8 [#58745](https://github.com/ClickHouse/ClickHouse/pull/58745) ([Raúl Marín](https://github.com/Algunenano)). -* Fix JSONExtract function for LowCardinality(Nullable) columns [#58808](https://github.com/ClickHouse/ClickHouse/pull/58808) ([vdimir](https://github.com/vdimir)). -* Fix: LIMIT BY and LIMIT in distributed query [#59153](https://github.com/ClickHouse/ClickHouse/pull/59153) ([Igor Nikonov](https://github.com/devcrafter)). -* Fix translate() with FixedString input [#59356](https://github.com/ClickHouse/ClickHouse/pull/59356) ([Raúl Marín](https://github.com/Algunenano)). -* Fix error "Read beyond last offset" for AsynchronousBoundedReadBuffer [#59630](https://github.com/ClickHouse/ClickHouse/pull/59630) ([Vitaly Baranov](https://github.com/vitlibar)). -* Fix query start time on non initial queries [#59662](https://github.com/ClickHouse/ClickHouse/pull/59662) ([Raúl Marín](https://github.com/Algunenano)). -* Fix leftPad / rightPad function with FixedString input [#59739](https://github.com/ClickHouse/ClickHouse/pull/59739) ([Raúl Marín](https://github.com/Algunenano)). -* rabbitmq: fix having neither acked nor nacked messages [#59775](https://github.com/ClickHouse/ClickHouse/pull/59775) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix cosineDistance crash with Nullable [#60150](https://github.com/ClickHouse/ClickHouse/pull/60150) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#57565](https://github.com/ClickHouse/ClickHouse/issues/57565): Background merges correctly use temporary data storage in the cache. [#57275](https://github.com/ClickHouse/ClickHouse/pull/57275) ([vdimir](https://github.com/vdimir)). +* Backported in [#57476](https://github.com/ClickHouse/ClickHouse/issues/57476): Fix possible broken skipping indexes after materialization in MergeTree compact parts. [#57352](https://github.com/ClickHouse/ClickHouse/pull/57352) ([Maksim Kita](https://github.com/kitaisreal)). +* Backported in [#58777](https://github.com/ClickHouse/ClickHouse/issues/58777): Fix double destroy call on exception throw in addBatchLookupTable8. [#58745](https://github.com/ClickHouse/ClickHouse/pull/58745) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#58856](https://github.com/ClickHouse/ClickHouse/issues/58856): Fix possible crash in JSONExtract function extracting `LowCardinality(Nullable(T))` type. [#58808](https://github.com/ClickHouse/ClickHouse/pull/58808) ([vdimir](https://github.com/vdimir)). +* Backported in [#59194](https://github.com/ClickHouse/ClickHouse/issues/59194): The combination of LIMIT BY and LIMIT could produce an incorrect result in distributed queries (parallel replicas included). [#59153](https://github.com/ClickHouse/ClickHouse/pull/59153) ([Igor Nikonov](https://github.com/devcrafter)). +* Backported in [#59429](https://github.com/ClickHouse/ClickHouse/issues/59429): Fix translate() with FixedString input. Could lead to crashes as it'd return a String column (vs the expected FixedString). This issue was found through ClickHouse Bug Bounty Program YohannJardin. [#59356](https://github.com/ClickHouse/ClickHouse/pull/59356) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#60128](https://github.com/ClickHouse/ClickHouse/issues/60128): Fix error `Read beyond last offset` for `AsynchronousBoundedReadBuffer`. [#59630](https://github.com/ClickHouse/ClickHouse/pull/59630) ([Vitaly Baranov](https://github.com/vitlibar)). +* Backported in [#59836](https://github.com/ClickHouse/ClickHouse/issues/59836): Fix query start time on non initial queries. [#59662](https://github.com/ClickHouse/ClickHouse/pull/59662) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#59758](https://github.com/ClickHouse/ClickHouse/issues/59758): Fix leftPad / rightPad function with FixedString input. [#59739](https://github.com/ClickHouse/ClickHouse/pull/59739) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#60304](https://github.com/ClickHouse/ClickHouse/issues/60304): Fix having neigher acked nor nacked messages. If exception happens during read-write phase, messages will be nacked. [#59775](https://github.com/ClickHouse/ClickHouse/pull/59775) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Backported in [#60171](https://github.com/ClickHouse/ClickHouse/issues/60171): Fix cosineDistance crash with Nullable. [#60150](https://github.com/ClickHouse/ClickHouse/pull/60150) ([Raúl Marín](https://github.com/Algunenano)). #### NOT FOR CHANGELOG / INSIGNIFICANT diff --git a/docs/changelogs/v23.8.11.28-lts.md b/docs/changelogs/v23.8.11.28-lts.md index acc284caa72..3da3d10cfa5 100644 --- a/docs/changelogs/v23.8.11.28-lts.md +++ b/docs/changelogs/v23.8.11.28-lts.md @@ -12,11 +12,11 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix buffer overflow in CompressionCodecMultiple [#60731](https://github.com/ClickHouse/ClickHouse/pull/60731) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Remove nonsense from SQL/JSON [#60738](https://github.com/ClickHouse/ClickHouse/pull/60738) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Fix crash in arrayEnumerateRanked [#60764](https://github.com/ClickHouse/ClickHouse/pull/60764) ([Raúl Marín](https://github.com/Algunenano)). -* Fix crash when using input() in INSERT SELECT JOIN [#60765](https://github.com/ClickHouse/ClickHouse/pull/60765) ([Kruglov Pavel](https://github.com/Avogar)). -* Remove recursion when reading from S3 [#60849](https://github.com/ClickHouse/ClickHouse/pull/60849) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#60983](https://github.com/ClickHouse/ClickHouse/issues/60983): Fix buffer overflow that can happen if the attacker asks the HTTP server to decompress data with a composition of codecs and size triggering numeric overflow. Fix buffer overflow that can happen inside codec NONE on wrong input data. This was submitted by TIANGONG research team through our [Bug Bounty program](https://github.com/ClickHouse/ClickHouse/issues/38986). [#60731](https://github.com/ClickHouse/ClickHouse/pull/60731) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Backported in [#60986](https://github.com/ClickHouse/ClickHouse/issues/60986): Functions for SQL/JSON were able to read uninitialized memory. This closes [#60017](https://github.com/ClickHouse/ClickHouse/issues/60017). Found by Fuzzer. [#60738](https://github.com/ClickHouse/ClickHouse/pull/60738) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Backported in [#60816](https://github.com/ClickHouse/ClickHouse/issues/60816): Fix crash in arrayEnumerateRanked. [#60764](https://github.com/ClickHouse/ClickHouse/pull/60764) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#60837](https://github.com/ClickHouse/ClickHouse/issues/60837): Fix crash when using input() in INSERT SELECT JOIN. Closes [#60035](https://github.com/ClickHouse/ClickHouse/issues/60035). [#60765](https://github.com/ClickHouse/ClickHouse/pull/60765) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#60911](https://github.com/ClickHouse/ClickHouse/issues/60911): Avoid segfault if too many keys are skipped when reading from S3. [#60849](https://github.com/ClickHouse/ClickHouse/pull/60849) ([Antonio Andelic](https://github.com/antonio2368)). #### NO CL ENTRY diff --git a/docs/changelogs/v23.8.12.13-lts.md b/docs/changelogs/v23.8.12.13-lts.md index dbb36fdc00e..0329d4349f3 100644 --- a/docs/changelogs/v23.8.12.13-lts.md +++ b/docs/changelogs/v23.8.12.13-lts.md @@ -9,9 +9,9 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Improve isolation of query cache entries under re-created users or role switches [#58611](https://github.com/ClickHouse/ClickHouse/pull/58611) ([Robert Schulze](https://github.com/rschu1ze)). -* Fix string search with const position [#61547](https://github.com/ClickHouse/ClickHouse/pull/61547) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix crash in `multiSearchAllPositionsCaseInsensitiveUTF8` for incorrect UTF-8 [#61749](https://github.com/ClickHouse/ClickHouse/pull/61749) ([pufit](https://github.com/pufit)). +* Backported in [#61439](https://github.com/ClickHouse/ClickHouse/issues/61439): The query cache now denies access to entries when the user is re-created or assumes another role. This improves prevents attacks where 1. an user with the same name as a dropped user may access the old user's cache entries or 2. a user with a different role may access cache entries of a role with a different row policy. [#58611](https://github.com/ClickHouse/ClickHouse/pull/58611) ([Robert Schulze](https://github.com/rschu1ze)). +* Backported in [#61572](https://github.com/ClickHouse/ClickHouse/issues/61572): Fix string search with constant start position which previously could lead to memory corruption. [#61547](https://github.com/ClickHouse/ClickHouse/pull/61547) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#61854](https://github.com/ClickHouse/ClickHouse/issues/61854): Fix crash in `multiSearchAllPositionsCaseInsensitiveUTF8` when specifying incorrect UTF-8 sequence. Example: [#61714](https://github.com/ClickHouse/ClickHouse/issues/61714#issuecomment-2012768202). [#61749](https://github.com/ClickHouse/ClickHouse/pull/61749) ([pufit](https://github.com/pufit)). #### CI Fix or Improvement (changelog entry is not required) diff --git a/docs/changelogs/v23.8.13.25-lts.md b/docs/changelogs/v23.8.13.25-lts.md index 3452621556a..e9c6e2e9f28 100644 --- a/docs/changelogs/v23.8.13.25-lts.md +++ b/docs/changelogs/v23.8.13.25-lts.md @@ -15,11 +15,11 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix REPLACE/MOVE PARTITION with zero-copy replication [#54193](https://github.com/ClickHouse/ClickHouse/pull/54193) ([Alexander Tokmakov](https://github.com/tavplubix)). -* Fix ATTACH query with external ON CLUSTER [#61365](https://github.com/ClickHouse/ClickHouse/pull/61365) ([Nikolay Degterinsky](https://github.com/evillique)). -* Cancel merges before removing moved parts [#61610](https://github.com/ClickHouse/ClickHouse/pull/61610) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). -* Mark CANNOT_PARSE_ESCAPE_SEQUENCE error as parse error to be able to skip it in row input formats [#61883](https://github.com/ClickHouse/ClickHouse/pull/61883) ([Kruglov Pavel](https://github.com/Avogar)). -* Try to fix segfault in Hive engine [#62578](https://github.com/ClickHouse/ClickHouse/pull/62578) ([Nikolay Degterinsky](https://github.com/evillique)). +* Backported in [#62898](https://github.com/ClickHouse/ClickHouse/issues/62898): Fixed a bug in zero-copy replication (an experimental feature) that could cause `The specified key does not exist` errors and data loss after REPLACE/MOVE PARTITION. A similar issue might happen with TTL-moves between disks. [#54193](https://github.com/ClickHouse/ClickHouse/pull/54193) ([Alexander Tokmakov](https://github.com/tavplubix)). +* Backported in [#61964](https://github.com/ClickHouse/ClickHouse/issues/61964): Fix the ATTACH query with the ON CLUSTER clause when the database does not exist on the initiator node. Closes [#55009](https://github.com/ClickHouse/ClickHouse/issues/55009). [#61365](https://github.com/ClickHouse/ClickHouse/pull/61365) ([Nikolay Degterinsky](https://github.com/evillique)). +* Backported in [#62527](https://github.com/ClickHouse/ClickHouse/issues/62527): Fix data race between `MOVE PARTITION` query and merges resulting in intersecting parts. [#61610](https://github.com/ClickHouse/ClickHouse/pull/61610) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* Backported in [#62238](https://github.com/ClickHouse/ClickHouse/issues/62238): Fix skipping escape sequcne parsing errors during JSON data parsing while using `input_format_allow_errors_num/ratio` settings. [#61883](https://github.com/ClickHouse/ClickHouse/pull/61883) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#62673](https://github.com/ClickHouse/ClickHouse/issues/62673): Fix segmentation fault when using Hive table engine. Reference [#62154](https://github.com/ClickHouse/ClickHouse/issues/62154), [#62560](https://github.com/ClickHouse/ClickHouse/issues/62560). [#62578](https://github.com/ClickHouse/ClickHouse/pull/62578) ([Nikolay Degterinsky](https://github.com/evillique)). #### CI Fix or Improvement (changelog entry is not required) diff --git a/docs/changelogs/v23.8.14.6-lts.md b/docs/changelogs/v23.8.14.6-lts.md index 0053502a9dc..3236c931e51 100644 --- a/docs/changelogs/v23.8.14.6-lts.md +++ b/docs/changelogs/v23.8.14.6-lts.md @@ -9,6 +9,6 @@ sidebar_label: 2024 #### Bug Fix (user-visible misbehavior in an official stable release) -* Set server name for SSL handshake in MongoDB engine [#63122](https://github.com/ClickHouse/ClickHouse/pull/63122) ([Alexander Gololobov](https://github.com/davenger)). -* Use user specified db instead of "config" for MongoDB wire protocol version check [#63126](https://github.com/ClickHouse/ClickHouse/pull/63126) ([Alexander Gololobov](https://github.com/davenger)). +* Backported in [#63172](https://github.com/ClickHouse/ClickHouse/issues/63172): Setting server_name might help with recently reported SSL handshake error when connecting to MongoDB Atlas: `Poco::Exception. Code: 1000, e.code() = 0, SSL Exception: error:10000438:SSL routines:OPENSSL_internal:TLSV1_ALERT_INTERNAL_ERROR`. [#63122](https://github.com/ClickHouse/ClickHouse/pull/63122) ([Alexander Gololobov](https://github.com/davenger)). +* Backported in [#63164](https://github.com/ClickHouse/ClickHouse/issues/63164): The wire protocol version check for MongoDB used to try accessing "config" database, but this can fail if the user doesn't have permissions for it. The fix is to use the database name provided by user. [#63126](https://github.com/ClickHouse/ClickHouse/pull/63126) ([Alexander Gololobov](https://github.com/davenger)). diff --git a/docs/changelogs/v23.8.2.7-lts.md b/docs/changelogs/v23.8.2.7-lts.md index 317e2c6d56a..a6f74e7998c 100644 --- a/docs/changelogs/v23.8.2.7-lts.md +++ b/docs/changelogs/v23.8.2.7-lts.md @@ -9,8 +9,8 @@ sidebar_label: 2023 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix: parallel replicas over distributed don't read from all replicas [#54199](https://github.com/ClickHouse/ClickHouse/pull/54199) ([Igor Nikonov](https://github.com/devcrafter)). -* Fix: allow IPv6 for bloom filter [#54200](https://github.com/ClickHouse/ClickHouse/pull/54200) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). +* Backported in [#54209](https://github.com/ClickHouse/ClickHouse/issues/54209): Parallel reading from replicas over Distributed table was using only one replica per shard. [#54199](https://github.com/ClickHouse/ClickHouse/pull/54199) ([Igor Nikonov](https://github.com/devcrafter)). +* Backported in [#54233](https://github.com/ClickHouse/ClickHouse/issues/54233): Allow IPv6 for bloom filter, backward compatibility issue. [#54200](https://github.com/ClickHouse/ClickHouse/pull/54200) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). #### NOT FOR CHANGELOG / INSIGNIFICANT diff --git a/docs/changelogs/v23.8.3.48-lts.md b/docs/changelogs/v23.8.3.48-lts.md index af669c5adc8..91514f48a25 100644 --- a/docs/changelogs/v23.8.3.48-lts.md +++ b/docs/changelogs/v23.8.3.48-lts.md @@ -18,19 +18,19 @@ sidebar_label: 2023 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix: moved to prewhere condition actions can lose column [#53492](https://github.com/ClickHouse/ClickHouse/pull/53492) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). -* Fix: parallel replicas over distributed with prefer_localhost_replica=1 [#54334](https://github.com/ClickHouse/ClickHouse/pull/54334) ([Igor Nikonov](https://github.com/devcrafter)). -* Fix possible error 'URI contains invalid characters' in s3 table function [#54373](https://github.com/ClickHouse/ClickHouse/pull/54373) ([Kruglov Pavel](https://github.com/Avogar)). -* Check for overflow before addition in `analysisOfVariance` function [#54385](https://github.com/ClickHouse/ClickHouse/pull/54385) ([Antonio Andelic](https://github.com/antonio2368)). -* reproduce and fix the bug in removeSharedRecursive [#54430](https://github.com/ClickHouse/ClickHouse/pull/54430) ([Sema Checherinda](https://github.com/CheSema)). -* Fix aggregate projections with normalized states [#54480](https://github.com/ClickHouse/ClickHouse/pull/54480) ([Amos Bird](https://github.com/amosbird)). -* Fix possible parsing error in WithNames formats with disabled input_format_with_names_use_header [#54513](https://github.com/ClickHouse/ClickHouse/pull/54513) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix zero copy garbage [#54550](https://github.com/ClickHouse/ClickHouse/pull/54550) ([Alexander Tokmakov](https://github.com/tavplubix)). -* Fix race in `ColumnUnique` [#54575](https://github.com/ClickHouse/ClickHouse/pull/54575) ([Nikita Taranov](https://github.com/nickitat)). -* Fix serialization of `ColumnDecimal` [#54601](https://github.com/ClickHouse/ClickHouse/pull/54601) ([Nikita Taranov](https://github.com/nickitat)). -* Fix virtual columns having incorrect values after ORDER BY [#54811](https://github.com/ClickHouse/ClickHouse/pull/54811) ([Michael Kolupaev](https://github.com/al13n321)). -* Fix Keeper segfault during shutdown [#54841](https://github.com/ClickHouse/ClickHouse/pull/54841) ([Antonio Andelic](https://github.com/antonio2368)). -* Rebuild minmax_count_projection when partition key gets modified [#54943](https://github.com/ClickHouse/ClickHouse/pull/54943) ([Amos Bird](https://github.com/amosbird)). +* Backported in [#54974](https://github.com/ClickHouse/ClickHouse/issues/54974): Fixed issue when during prewhere optimization compound condition actions DAG can lose output column of intermediate step while this column is required as an input column of some next step. [#53492](https://github.com/ClickHouse/ClickHouse/pull/53492) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). +* Backported in [#54996](https://github.com/ClickHouse/ClickHouse/issues/54996): Parallel replicas either executed completely on the local replica or produce an incorrect result when `prefer_localhost_replica=1`. Fixes [#54276](https://github.com/ClickHouse/ClickHouse/issues/54276). [#54334](https://github.com/ClickHouse/ClickHouse/pull/54334) ([Igor Nikonov](https://github.com/devcrafter)). +* Backported in [#54516](https://github.com/ClickHouse/ClickHouse/issues/54516): Fix possible error 'URI contains invalid characters' in s3 table function. Closes [#54345](https://github.com/ClickHouse/ClickHouse/issues/54345). [#54373](https://github.com/ClickHouse/ClickHouse/pull/54373) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#54418](https://github.com/ClickHouse/ClickHouse/issues/54418): Check for overflow when handling group number argument for `analysisOfVariance` to avoid crashes. Crash found using WINGFUZZ. [#54385](https://github.com/ClickHouse/ClickHouse/pull/54385) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#54527](https://github.com/ClickHouse/ClickHouse/issues/54527): Reproduce the bug described here [#54135](https://github.com/ClickHouse/ClickHouse/issues/54135). [#54430](https://github.com/ClickHouse/ClickHouse/pull/54430) ([Sema Checherinda](https://github.com/CheSema)). +* Backported in [#54854](https://github.com/ClickHouse/ClickHouse/issues/54854): Fix incorrect aggregation projection optimization when using variant aggregate states. This optimization is accidentally enabled but not properly implemented, because after https://github.com/ClickHouse/ClickHouse/pull/39420 the comparison of DataTypeAggregateFunction is normalized. This fixes [#54406](https://github.com/ClickHouse/ClickHouse/issues/54406). [#54480](https://github.com/ClickHouse/ClickHouse/pull/54480) ([Amos Bird](https://github.com/amosbird)). +* Backported in [#54599](https://github.com/ClickHouse/ClickHouse/issues/54599): Fix parsing error in WithNames formats while reading subset of columns with disabled input_format_with_names_use_header. Closes [#52591](https://github.com/ClickHouse/ClickHouse/issues/52591). [#54513](https://github.com/ClickHouse/ClickHouse/pull/54513) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#54594](https://github.com/ClickHouse/ClickHouse/issues/54594): Starting from version 23.5, zero-copy replication could leave some garbage in ZooKeeper and on S3. It might happen on removal of Outdated parts that were mutated. The issue is indicated by `Failed to get mutation parent on {} for part {}, refusing to remove blobs` log messages. [#54550](https://github.com/ClickHouse/ClickHouse/pull/54550) ([Alexander Tokmakov](https://github.com/tavplubix)). +* Backported in [#54627](https://github.com/ClickHouse/ClickHouse/issues/54627): Fix unsynchronised write to a shared variable in `ColumnUnique`. [#54575](https://github.com/ClickHouse/ClickHouse/pull/54575) ([Nikita Taranov](https://github.com/nickitat)). +* Backported in [#54625](https://github.com/ClickHouse/ClickHouse/issues/54625): Fix serialization of `ColumnDecimal`. [#54601](https://github.com/ClickHouse/ClickHouse/pull/54601) ([Nikita Taranov](https://github.com/nickitat)). +* Backported in [#54945](https://github.com/ClickHouse/ClickHouse/issues/54945): Fixed virtual columns (e.g. _file) showing incorrect values with ORDER BY. [#54811](https://github.com/ClickHouse/ClickHouse/pull/54811) ([Michael Kolupaev](https://github.com/al13n321)). +* Backported in [#54872](https://github.com/ClickHouse/ClickHouse/issues/54872): Keeper fix: correctly capture a variable in callback to avoid segfaults during shutdown. [#54841](https://github.com/ClickHouse/ClickHouse/pull/54841) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#54950](https://github.com/ClickHouse/ClickHouse/issues/54950): Fix projection optimization error if table's partition key was ALTERed by extending its Enum type. The fix is to rebuild `minmax_count_projection` when partition key gets modified. This fixes [#54941](https://github.com/ClickHouse/ClickHouse/issues/54941). [#54943](https://github.com/ClickHouse/ClickHouse/pull/54943) ([Amos Bird](https://github.com/amosbird)). #### NOT FOR CHANGELOG / INSIGNIFICANT diff --git a/docs/changelogs/v23.8.4.69-lts.md b/docs/changelogs/v23.8.4.69-lts.md index 065a57549be..a6d8d8bb03b 100644 --- a/docs/changelogs/v23.8.4.69-lts.md +++ b/docs/changelogs/v23.8.4.69-lts.md @@ -11,26 +11,26 @@ sidebar_label: 2023 * Backported in [#55673](https://github.com/ClickHouse/ClickHouse/issues/55673): If the database is already initialized, it doesn't need to be initialized again upon subsequent launches. This can potentially fix the issue of infinite container restarts when the database fails to load within 1000 attempts (relevant for very large databases and multi-node setups). [#50724](https://github.com/ClickHouse/ClickHouse/pull/50724) ([Alexander Nikolaev](https://github.com/AlexNik)). * Backported in [#55293](https://github.com/ClickHouse/ClickHouse/issues/55293): Resource with source code including submodules is built in Darwin special build task. It may be used to build ClickHouse without checkouting submodules. [#51435](https://github.com/ClickHouse/ClickHouse/pull/51435) ([Ilya Yatsishin](https://github.com/qoega)). * Backported in [#55366](https://github.com/ClickHouse/ClickHouse/issues/55366): Solve issue with launching standalone clickhouse-keeper from clickhouse-server package. [#55226](https://github.com/ClickHouse/ClickHouse/pull/55226) ([Mikhail f. Shiryaev](https://github.com/Felixoid)). -* Backported in [#55725](https://github.com/ClickHouse/ClickHouse/issues/55725): Fix integration check python script to use gh api url - Add Readme for CI tests. [#55716](https://github.com/ClickHouse/ClickHouse/pull/55716) ([Max K.](https://github.com/mkaynov)). +* Backported in [#55725](https://github.com/ClickHouse/ClickHouse/issues/55725): Fix integration check python script to use gh api url - Add Readme for CI tests. [#55716](https://github.com/ClickHouse/ClickHouse/pull/55716) ([Max K.](https://github.com/maxknv)). #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix "Invalid number of rows in Chunk" in MaterializedPostgreSQL [#54844](https://github.com/ClickHouse/ClickHouse/pull/54844) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Move obsolete format settings to separate section [#54855](https://github.com/ClickHouse/ClickHouse/pull/54855) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix: insert quorum w/o keeper retries [#55026](https://github.com/ClickHouse/ClickHouse/pull/55026) ([Igor Nikonov](https://github.com/devcrafter)). -* Prevent attaching parts from tables with different projections or indices [#55062](https://github.com/ClickHouse/ClickHouse/pull/55062) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). -* Proper cleanup in case of exception in ctor of ShellCommandSource [#55103](https://github.com/ClickHouse/ClickHouse/pull/55103) ([Alexander Gololobov](https://github.com/davenger)). -* Fix deadlock in LDAP assigned role update [#55119](https://github.com/ClickHouse/ClickHouse/pull/55119) ([Julian Maicher](https://github.com/jmaicher)). -* Fix for background download in fs cache [#55252](https://github.com/ClickHouse/ClickHouse/pull/55252) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Fix functions execution over sparse columns [#55275](https://github.com/ClickHouse/ClickHouse/pull/55275) ([Azat Khuzhin](https://github.com/azat)). -* Fix bug with inability to drop detached partition in replicated merge tree on top of S3 without zero copy [#55309](https://github.com/ClickHouse/ClickHouse/pull/55309) ([alesapin](https://github.com/alesapin)). -* Fix trash optimization (up to a certain extent) [#55353](https://github.com/ClickHouse/ClickHouse/pull/55353) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Fix parsing of arrays in cast operator [#55417](https://github.com/ClickHouse/ClickHouse/pull/55417) ([Anton Popov](https://github.com/CurtizJ)). -* Fix filtering by virtual columns with OR filter in query [#55418](https://github.com/ClickHouse/ClickHouse/pull/55418) ([Azat Khuzhin](https://github.com/azat)). -* Fix MongoDB connection issues [#55419](https://github.com/ClickHouse/ClickHouse/pull/55419) ([Nikolay Degterinsky](https://github.com/evillique)). -* Destroy fiber in case of exception in cancelBefore in AsyncTaskExecutor [#55516](https://github.com/ClickHouse/ClickHouse/pull/55516) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix crash in QueryNormalizer with cyclic aliases [#55602](https://github.com/ClickHouse/ClickHouse/pull/55602) ([vdimir](https://github.com/vdimir)). -* Fix filtering by virtual columns with OR filter in query (resubmit) [#55678](https://github.com/ClickHouse/ClickHouse/pull/55678) ([Azat Khuzhin](https://github.com/azat)). +* Backported in [#55304](https://github.com/ClickHouse/ClickHouse/issues/55304): Fix "Invalid number of rows in Chunk" in MaterializedPostgreSQL (which could happen with PostgreSQL version >= 13). [#54844](https://github.com/ClickHouse/ClickHouse/pull/54844) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Backported in [#55018](https://github.com/ClickHouse/ClickHouse/issues/55018): Move obsolete format settings to separate section and use it together with all format settings to avoid exceptions `Unknown setting` during use of obsolete format settings. Closes [#54792](https://github.com/ClickHouse/ClickHouse/issues/54792) ### Documentation entry for user-facing changes. [#54855](https://github.com/ClickHouse/ClickHouse/pull/54855) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#55097](https://github.com/ClickHouse/ClickHouse/issues/55097): Insert quorum could be marked as satisfied incorrectly in case of keeper retries while waiting for the quorum. Fixes [#54543](https://github.com/ClickHouse/ClickHouse/issues/54543). [#55026](https://github.com/ClickHouse/ClickHouse/pull/55026) ([Igor Nikonov](https://github.com/devcrafter)). +* Backported in [#55473](https://github.com/ClickHouse/ClickHouse/issues/55473): Prevent attaching partitions from tables that doesn't have the same indices or projections defined. [#55062](https://github.com/ClickHouse/ClickHouse/pull/55062) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* Backported in [#55461](https://github.com/ClickHouse/ClickHouse/issues/55461): If an exception happens in `ShellCommandSource` constructor after some of the `send_data_threads` are started, they need to be join()-ed, otherwise abort() will be triggered in `ThreadFromGlobalPool` destructor. Fixes [#55091](https://github.com/ClickHouse/ClickHouse/issues/55091). [#55103](https://github.com/ClickHouse/ClickHouse/pull/55103) ([Alexander Gololobov](https://github.com/davenger)). +* Backported in [#55412](https://github.com/ClickHouse/ClickHouse/issues/55412): Fix deadlock in LDAP assigned role update for non-existing ClickHouse roles. [#55119](https://github.com/ClickHouse/ClickHouse/pull/55119) ([Julian Maicher](https://github.com/jmaicher)). +* Backported in [#55323](https://github.com/ClickHouse/ClickHouse/issues/55323): Fix for background download in fs cache. [#55252](https://github.com/ClickHouse/ClickHouse/pull/55252) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Backported in [#55349](https://github.com/ClickHouse/ClickHouse/issues/55349): Fix functions execution over sparse columns (fixes `DB::Exception: isDefaultAt is not implemented for Function: while executing 'FUNCTION Capture` error). [#55275](https://github.com/ClickHouse/ClickHouse/pull/55275) ([Azat Khuzhin](https://github.com/azat)). +* Backported in [#55475](https://github.com/ClickHouse/ClickHouse/issues/55475): Fix an issue with inability to drop detached partition in `ReplicatedMergeTree` engines family on top of S3 (without zero-copy replication). Fixes issue [#55225](https://github.com/ClickHouse/ClickHouse/issues/55225). Fix bug with abandoned blobs on S3 for complex data types like Arrays or Nested columns. Partially fixes [#52393](https://github.com/ClickHouse/ClickHouse/issues/52393). Many kudos to @alifirat for examples. [#55309](https://github.com/ClickHouse/ClickHouse/pull/55309) ([alesapin](https://github.com/alesapin)). +* Backported in [#55399](https://github.com/ClickHouse/ClickHouse/issues/55399): An optimization introduced one year ago was wrong. This closes [#55272](https://github.com/ClickHouse/ClickHouse/issues/55272). [#55353](https://github.com/ClickHouse/ClickHouse/pull/55353) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Backported in [#55437](https://github.com/ClickHouse/ClickHouse/issues/55437): Fix parsing of arrays in cast operator (`::`). [#55417](https://github.com/ClickHouse/ClickHouse/pull/55417) ([Anton Popov](https://github.com/CurtizJ)). +* Backported in [#55635](https://github.com/ClickHouse/ClickHouse/issues/55635): Fix filtering by virtual columns with OR filter in query (`_part*` filtering for `MergeTree`, `_path`/`_file` for various `File`/`HDFS`/... engines, `_table` for `Merge`). [#55418](https://github.com/ClickHouse/ClickHouse/pull/55418) ([Azat Khuzhin](https://github.com/azat)). +* Backported in [#55445](https://github.com/ClickHouse/ClickHouse/issues/55445): Fix connection issues that occurred with some versions of MongoDB. Closes [#55376](https://github.com/ClickHouse/ClickHouse/issues/55376), [#55232](https://github.com/ClickHouse/ClickHouse/issues/55232). [#55419](https://github.com/ClickHouse/ClickHouse/pull/55419) ([Nikolay Degterinsky](https://github.com/evillique)). +* Backported in [#55534](https://github.com/ClickHouse/ClickHouse/issues/55534): Fix possible deadlock caused by not destroyed fiber in case of exception in async task cancellation. Closes [#55185](https://github.com/ClickHouse/ClickHouse/issues/55185). [#55516](https://github.com/ClickHouse/ClickHouse/pull/55516) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#55747](https://github.com/ClickHouse/ClickHouse/issues/55747): Fix crash in QueryNormalizer with cyclic aliases. [#55602](https://github.com/ClickHouse/ClickHouse/pull/55602) ([vdimir](https://github.com/vdimir)). +* Backported in [#55760](https://github.com/ClickHouse/ClickHouse/issues/55760): Fix filtering by virtual columns with OR filter in query (_part* filtering for MergeTree, _path/_file for various File/HDFS/... engines, _table for Merge). [#55678](https://github.com/ClickHouse/ClickHouse/pull/55678) ([Azat Khuzhin](https://github.com/azat)). #### NO CL CATEGORY @@ -46,6 +46,6 @@ sidebar_label: 2023 * Clean data dir and always start an old server version in aggregate functions compatibility test. [#55105](https://github.com/ClickHouse/ClickHouse/pull/55105) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). * check if block is empty after async insert retries [#55143](https://github.com/ClickHouse/ClickHouse/pull/55143) ([Han Fei](https://github.com/hanfei1991)). * MaterializedPostgreSQL: remove back check [#55297](https://github.com/ClickHouse/ClickHouse/pull/55297) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Remove existing moving/ dir if allow_remove_stale_moving_parts is off [#55480](https://github.com/ClickHouse/ClickHouse/pull/55480) ([Mike Kot](https://github.com/myrrc)). +* Remove existing moving/ dir if allow_remove_stale_moving_parts is off [#55480](https://github.com/ClickHouse/ClickHouse/pull/55480) ([Mikhail Kot](https://github.com/myrrc)). * Bump curl to 8.4 [#55492](https://github.com/ClickHouse/ClickHouse/pull/55492) ([Robert Schulze](https://github.com/rschu1ze)). diff --git a/docs/changelogs/v23.8.5.16-lts.md b/docs/changelogs/v23.8.5.16-lts.md index 4a23b8892be..32ddbd6031d 100644 --- a/docs/changelogs/v23.8.5.16-lts.md +++ b/docs/changelogs/v23.8.5.16-lts.md @@ -12,9 +12,9 @@ sidebar_label: 2023 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix storage Iceberg files retrieval [#55144](https://github.com/ClickHouse/ClickHouse/pull/55144) ([Kseniia Sumarokova](https://github.com/kssenii)). -* Try to fix possible segfault in Native ORC input format [#55891](https://github.com/ClickHouse/ClickHouse/pull/55891) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix window functions in case of sparse columns. [#55895](https://github.com/ClickHouse/ClickHouse/pull/55895) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). +* Backported in [#55736](https://github.com/ClickHouse/ClickHouse/issues/55736): Fix iceberg metadata parsing - delete files were not checked. [#55144](https://github.com/ClickHouse/ClickHouse/pull/55144) ([Kseniia Sumarokova](https://github.com/kssenii)). +* Backported in [#55969](https://github.com/ClickHouse/ClickHouse/issues/55969): Try to fix possible segfault in Native ORC input format. Closes [#55873](https://github.com/ClickHouse/ClickHouse/issues/55873). [#55891](https://github.com/ClickHouse/ClickHouse/pull/55891) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#55907](https://github.com/ClickHouse/ClickHouse/issues/55907): Fix window functions in case of sparse columns. Previously some queries with window functions returned invalid results or made ClickHouse crash when the columns were sparse. [#55895](https://github.com/ClickHouse/ClickHouse/pull/55895) ([János Benjamin Antal](https://github.com/antaljanosbenjamin)). #### NOT FOR CHANGELOG / INSIGNIFICANT diff --git a/docs/changelogs/v23.8.6.16-lts.md b/docs/changelogs/v23.8.6.16-lts.md index 6eb752e987c..df6c03cd668 100644 --- a/docs/changelogs/v23.8.6.16-lts.md +++ b/docs/changelogs/v23.8.6.16-lts.md @@ -9,11 +9,11 @@ sidebar_label: 2023 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix rare case of CHECKSUM_DOESNT_MATCH error [#54549](https://github.com/ClickHouse/ClickHouse/pull/54549) ([alesapin](https://github.com/alesapin)). -* Fix: avoid using regex match, possibly containing alternation, as a key condition. [#54696](https://github.com/ClickHouse/ClickHouse/pull/54696) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). -* Fix a crash during table loading on startup [#56232](https://github.com/ClickHouse/ClickHouse/pull/56232) ([Nikolay Degterinsky](https://github.com/evillique)). -* Fix segfault in signal handler for Keeper [#56266](https://github.com/ClickHouse/ClickHouse/pull/56266) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix buffer overflow in T64 [#56434](https://github.com/ClickHouse/ClickHouse/pull/56434) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Backported in [#54583](https://github.com/ClickHouse/ClickHouse/issues/54583): Fix rare bug in replicated merge tree which could lead to self-recovering `CHECKSUM_DOESNT_MATCH` error in logs. [#54549](https://github.com/ClickHouse/ClickHouse/pull/54549) ([alesapin](https://github.com/alesapin)). +* Backported in [#56253](https://github.com/ClickHouse/ClickHouse/issues/56253): Fixed bug of match() function (regex) with pattern containing alternation produces incorrect key condition. [#54696](https://github.com/ClickHouse/ClickHouse/pull/54696) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)). +* Backported in [#56322](https://github.com/ClickHouse/ClickHouse/issues/56322): Fix a crash during table loading on startup. Closes [#55767](https://github.com/ClickHouse/ClickHouse/issues/55767). [#56232](https://github.com/ClickHouse/ClickHouse/pull/56232) ([Nikolay Degterinsky](https://github.com/evillique)). +* Backported in [#56292](https://github.com/ClickHouse/ClickHouse/issues/56292): Fix segfault in signal handler for Keeper. [#56266](https://github.com/ClickHouse/ClickHouse/pull/56266) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#56443](https://github.com/ClickHouse/ClickHouse/issues/56443): Fix crash due to buffer overflow while decompressing malformed data using `T64` codec. This issue was found with [ClickHouse Bug Bounty Program](https://github.com/ClickHouse/ClickHouse/issues/38986) by https://twitter.com/malacupa. [#56434](https://github.com/ClickHouse/ClickHouse/pull/56434) ([Alexey Milovidov](https://github.com/alexey-milovidov)). #### NOT FOR CHANGELOG / INSIGNIFICANT diff --git a/docs/changelogs/v23.8.7.24-lts.md b/docs/changelogs/v23.8.7.24-lts.md index 37862c17315..042484e2404 100644 --- a/docs/changelogs/v23.8.7.24-lts.md +++ b/docs/changelogs/v23.8.7.24-lts.md @@ -12,12 +12,12 @@ sidebar_label: 2023 #### Bug Fix (user-visible misbehavior in an official stable release) -* Select from system tables when table based on table function. [#55540](https://github.com/ClickHouse/ClickHouse/pull/55540) ([MikhailBurdukov](https://github.com/MikhailBurdukov)). -* Fix incomplete query result for UNION in view() function. [#56274](https://github.com/ClickHouse/ClickHouse/pull/56274) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). -* Fix crash in case of adding a column with type Object(JSON) [#56307](https://github.com/ClickHouse/ClickHouse/pull/56307) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)). -* Fix segfault during Kerberos initialization [#56401](https://github.com/ClickHouse/ClickHouse/pull/56401) ([Nikolay Degterinsky](https://github.com/evillique)). -* Fix: RabbitMQ OpenSSL dynamic loading issue [#56703](https://github.com/ClickHouse/ClickHouse/pull/56703) ([Igor Nikonov](https://github.com/devcrafter)). -* Fix crash in FPC codec [#56795](https://github.com/ClickHouse/ClickHouse/pull/56795) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Backported in [#56581](https://github.com/ClickHouse/ClickHouse/issues/56581): Prevent reference to a remote data source for the `data_paths` column in `system.tables` if the table is created with a table function using explicit column description. [#55540](https://github.com/ClickHouse/ClickHouse/pull/55540) ([MikhailBurdukov](https://github.com/MikhailBurdukov)). +* Backported in [#56877](https://github.com/ClickHouse/ClickHouse/issues/56877): Fix incomplete query result for `UNION` in `view()` table function. [#56274](https://github.com/ClickHouse/ClickHouse/pull/56274) ([Nikolai Kochetov](https://github.com/KochetovNicolai)). +* Backported in [#56409](https://github.com/ClickHouse/ClickHouse/issues/56409): Prohibit adding a column with type `Object(JSON)` to an existing table. This closes: [#56095](https://github.com/ClickHouse/ClickHouse/issues/56095) This closes: [#49944](https://github.com/ClickHouse/ClickHouse/issues/49944). [#56307](https://github.com/ClickHouse/ClickHouse/pull/56307) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)). +* Backported in [#56756](https://github.com/ClickHouse/ClickHouse/issues/56756): Fix a segfault caused by a thrown exception in Kerberos initialization during the creation of the Kafka table. Closes [#56073](https://github.com/ClickHouse/ClickHouse/issues/56073). [#56401](https://github.com/ClickHouse/ClickHouse/pull/56401) ([Nikolay Degterinsky](https://github.com/evillique)). +* Backported in [#56748](https://github.com/ClickHouse/ClickHouse/issues/56748): Fixed the issue that the RabbitMQ table engine wasn't able to connect to RabbitMQ over a secure connection. [#56703](https://github.com/ClickHouse/ClickHouse/pull/56703) ([Igor Nikonov](https://github.com/devcrafter)). +* Backported in [#56839](https://github.com/ClickHouse/ClickHouse/issues/56839): The server crashed when decompressing malformed data using the `FPC` codec. This issue was found with [ClickHouse Bug Bounty Program](https://github.com/ClickHouse/ClickHouse/issues/38986) by https://twitter.com/malacupa. [#56795](https://github.com/ClickHouse/ClickHouse/pull/56795) ([Alexey Milovidov](https://github.com/alexey-milovidov)). #### NO CL CATEGORY diff --git a/docs/changelogs/v23.8.8.20-lts.md b/docs/changelogs/v23.8.8.20-lts.md index 345cfcccf17..f45498cb61f 100644 --- a/docs/changelogs/v23.8.8.20-lts.md +++ b/docs/changelogs/v23.8.8.20-lts.md @@ -16,9 +16,9 @@ sidebar_label: 2023 #### Bug Fix (user-visible misbehavior in an official stable release) -* Fix ON CLUSTER queries without database on initial node [#56484](https://github.com/ClickHouse/ClickHouse/pull/56484) ([Nikolay Degterinsky](https://github.com/evillique)). -* Fix buffer overflow in Gorilla codec [#57107](https://github.com/ClickHouse/ClickHouse/pull/57107) ([Nikolay Degterinsky](https://github.com/evillique)). -* Close interserver connection on any exception before authentication [#57142](https://github.com/ClickHouse/ClickHouse/pull/57142) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#57111](https://github.com/ClickHouse/ClickHouse/issues/57111): Fix ON CLUSTER queries without the database being present on an initial node. Closes [#55009](https://github.com/ClickHouse/ClickHouse/issues/55009). [#56484](https://github.com/ClickHouse/ClickHouse/pull/56484) ([Nikolay Degterinsky](https://github.com/evillique)). +* Backported in [#57169](https://github.com/ClickHouse/ClickHouse/issues/57169): Fix crash due to buffer overflow while decompressing malformed data using `Gorilla` codec. This issue was found with [ClickHouse Bug Bounty Program](https://github.com/ClickHouse/ClickHouse/issues/38986) by https://twitter.com/malacupa. [#57107](https://github.com/ClickHouse/ClickHouse/pull/57107) ([Nikolay Degterinsky](https://github.com/evillique)). +* Backported in [#57175](https://github.com/ClickHouse/ClickHouse/issues/57175): Close interserver connection for any exception that happens before the authentication. This issue was found with [ClickHouse Bug Bounty Program](https://github.com/ClickHouse/ClickHouse/issues/38986) by https://twitter.com/malacupa. [#57142](https://github.com/ClickHouse/ClickHouse/pull/57142) ([Antonio Andelic](https://github.com/antonio2368)). #### NOT FOR CHANGELOG / INSIGNIFICANT diff --git a/docs/changelogs/v23.8.9.54-lts.md b/docs/changelogs/v23.8.9.54-lts.md index 00607c60c39..db13238f4ad 100644 --- a/docs/changelogs/v23.8.9.54-lts.md +++ b/docs/changelogs/v23.8.9.54-lts.md @@ -11,29 +11,29 @@ sidebar_label: 2024 * Backported in [#57668](https://github.com/ClickHouse/ClickHouse/issues/57668): Output valid JSON/XML on excetpion during HTTP query execution. Add setting `http_write_exception_in_output_format` to enable/disable this behaviour (enabled by default). [#52853](https://github.com/ClickHouse/ClickHouse/pull/52853) ([Kruglov Pavel](https://github.com/Avogar)). * Backported in [#58491](https://github.com/ClickHouse/ClickHouse/issues/58491): Fix transfer query to MySQL compatible query. Fixes [#57253](https://github.com/ClickHouse/ClickHouse/issues/57253). Fixes [#52654](https://github.com/ClickHouse/ClickHouse/issues/52654). Fixes [#56729](https://github.com/ClickHouse/ClickHouse/issues/56729). [#56456](https://github.com/ClickHouse/ClickHouse/pull/56456) ([flynn](https://github.com/ucasfl)). * Backported in [#57238](https://github.com/ClickHouse/ClickHouse/issues/57238): Fetching a part waits when that part is fully committed on remote replica. It is better not send part in PreActive state. In case of zero copy this is mandatory restriction. [#56808](https://github.com/ClickHouse/ClickHouse/pull/56808) ([Sema Checherinda](https://github.com/CheSema)). -* Backported in [#57655](https://github.com/ClickHouse/ClickHouse/issues/57655): Handle sigabrt case when getting PostgreSQl table structure with empty array. [#57618](https://github.com/ClickHouse/ClickHouse/pull/57618) ([Mike Kot (Михаил Кот)](https://github.com/myrrc)). +* Backported in [#57655](https://github.com/ClickHouse/ClickHouse/issues/57655): Handle sigabrt case when getting PostgreSQl table structure with empty array. [#57618](https://github.com/ClickHouse/ClickHouse/pull/57618) ([Mikhail Kot](https://github.com/myrrc)). #### Build/Testing/Packaging Improvement * Backported in [#57582](https://github.com/ClickHouse/ClickHouse/issues/57582): Fix issue caught in https://github.com/docker-library/official-images/pull/15846. [#57571](https://github.com/ClickHouse/ClickHouse/pull/57571) ([Mikhail f. Shiryaev](https://github.com/Felixoid)). #### Bug Fix (user-visible misbehavior in an official stable release) -* Flatten only true Nested type if flatten_nested=1, not all Array(Tuple) [#56132](https://github.com/ClickHouse/ClickHouse/pull/56132) ([Kruglov Pavel](https://github.com/Avogar)). -* Fix ALTER COLUMN with ALIAS [#56493](https://github.com/ClickHouse/ClickHouse/pull/56493) ([Nikolay Degterinsky](https://github.com/evillique)). -* Prevent incompatible ALTER of projection columns [#56948](https://github.com/ClickHouse/ClickHouse/pull/56948) ([Amos Bird](https://github.com/amosbird)). -* Fix segfault after ALTER UPDATE with Nullable MATERIALIZED column [#57147](https://github.com/ClickHouse/ClickHouse/pull/57147) ([Nikolay Degterinsky](https://github.com/evillique)). -* Fix incorrect JOIN plan optimization with partially materialized normal projection [#57196](https://github.com/ClickHouse/ClickHouse/pull/57196) ([Amos Bird](https://github.com/amosbird)). -* Fix `ReadonlyReplica` metric for all cases [#57267](https://github.com/ClickHouse/ClickHouse/pull/57267) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix working with read buffers in StreamingFormatExecutor [#57438](https://github.com/ClickHouse/ClickHouse/pull/57438) ([Kruglov Pavel](https://github.com/Avogar)). -* bugfix: correctly parse SYSTEM STOP LISTEN TCP SECURE [#57483](https://github.com/ClickHouse/ClickHouse/pull/57483) ([joelynch](https://github.com/joelynch)). -* Ignore ON CLUSTER clause in grant/revoke queries for management of replicated access entities. [#57538](https://github.com/ClickHouse/ClickHouse/pull/57538) ([MikhailBurdukov](https://github.com/MikhailBurdukov)). -* Disable system.kafka_consumers by default (due to possible live memory leak) [#57822](https://github.com/ClickHouse/ClickHouse/pull/57822) ([Azat Khuzhin](https://github.com/azat)). -* Fix invalid memory access in BLAKE3 (Rust) [#57876](https://github.com/ClickHouse/ClickHouse/pull/57876) ([Raúl Marín](https://github.com/Algunenano)). -* Normalize function names in CREATE INDEX [#57906](https://github.com/ClickHouse/ClickHouse/pull/57906) ([Alexander Tokmakov](https://github.com/tavplubix)). -* Fix invalid preprocessing on Keeper [#58069](https://github.com/ClickHouse/ClickHouse/pull/58069) ([Antonio Andelic](https://github.com/antonio2368)). -* Fix Integer overflow in Poco::UTF32Encoding [#58073](https://github.com/ClickHouse/ClickHouse/pull/58073) ([Andrey Fedotov](https://github.com/anfedotoff)). -* Remove parallel parsing for JSONCompactEachRow [#58181](https://github.com/ClickHouse/ClickHouse/pull/58181) ([Alexey Milovidov](https://github.com/alexey-milovidov)). -* Fix parallel parsing for JSONCompactEachRow [#58250](https://github.com/ClickHouse/ClickHouse/pull/58250) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#58324](https://github.com/ClickHouse/ClickHouse/issues/58324): Flatten only true Nested type if flatten_nested=1, not all Array(Tuple). [#56132](https://github.com/ClickHouse/ClickHouse/pull/56132) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#57395](https://github.com/ClickHouse/ClickHouse/issues/57395): Fix ALTER COLUMN with ALIAS that previously threw the `NO_SUCH_COLUMN_IN_TABLE` exception. Closes [#50927](https://github.com/ClickHouse/ClickHouse/issues/50927). [#56493](https://github.com/ClickHouse/ClickHouse/pull/56493) ([Nikolay Degterinsky](https://github.com/evillique)). +* Backported in [#57449](https://github.com/ClickHouse/ClickHouse/issues/57449): Now ALTER columns which are incompatible with columns used in some projections will be forbidden. Previously it could result in incorrect data. This fixes [#56932](https://github.com/ClickHouse/ClickHouse/issues/56932). This PR also allows RENAME of index columns, and improves the exception message by providing clear information on the affected indices or projections causing the prevention. [#56948](https://github.com/ClickHouse/ClickHouse/pull/56948) ([Amos Bird](https://github.com/amosbird)). +* Backported in [#57281](https://github.com/ClickHouse/ClickHouse/issues/57281): Fix segfault after ALTER UPDATE with Nullable MATERIALIZED column. Closes [#42918](https://github.com/ClickHouse/ClickHouse/issues/42918). [#57147](https://github.com/ClickHouse/ClickHouse/pull/57147) ([Nikolay Degterinsky](https://github.com/evillique)). +* Backported in [#57247](https://github.com/ClickHouse/ClickHouse/issues/57247): Fix incorrect JOIN plan optimization with partially materialized normal projection. This fixes [#57194](https://github.com/ClickHouse/ClickHouse/issues/57194). [#57196](https://github.com/ClickHouse/ClickHouse/pull/57196) ([Amos Bird](https://github.com/amosbird)). +* Backported in [#57346](https://github.com/ClickHouse/ClickHouse/issues/57346): Fix `ReadonlyReplica` metric for some cases (e.g. when a table cannot be initialized because of difference in local and Keeper data). [#57267](https://github.com/ClickHouse/ClickHouse/pull/57267) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#58434](https://github.com/ClickHouse/ClickHouse/issues/58434): Fix working with read buffers in StreamingFormatExecutor, previously it could lead to segfaults in Kafka and other streaming engines. [#57438](https://github.com/ClickHouse/ClickHouse/pull/57438) ([Kruglov Pavel](https://github.com/Avogar)). +* Backported in [#57539](https://github.com/ClickHouse/ClickHouse/issues/57539): Fix parsing of `SYSTEM STOP LISTEN TCP SECURE`. [#57483](https://github.com/ClickHouse/ClickHouse/pull/57483) ([joelynch](https://github.com/joelynch)). +* Backported in [#57779](https://github.com/ClickHouse/ClickHouse/issues/57779): Conf ``` /clickhouse/access/ ``` sql ``` show settings like 'ignore_on_cluster_for_replicated_access_entities_queries' ┌─name─────────────────────────────────────────────────────┬─type─┬─value─┐ │ ignore_on_cluster_for_replicated_access_entities_queries │ bool │ 1 │ └──────────────────────────────────────────────────────────┴──────┴───────┘. [#57538](https://github.com/ClickHouse/ClickHouse/pull/57538) ([MikhailBurdukov](https://github.com/MikhailBurdukov)). +* Backported in [#58256](https://github.com/ClickHouse/ClickHouse/issues/58256): Disable system.kafka_consumers by default (due to possible live memory leak). [#57822](https://github.com/ClickHouse/ClickHouse/pull/57822) ([Azat Khuzhin](https://github.com/azat)). +* Backported in [#57923](https://github.com/ClickHouse/ClickHouse/issues/57923): Fix invalid memory access in BLAKE3. [#57876](https://github.com/ClickHouse/ClickHouse/pull/57876) ([Raúl Marín](https://github.com/Algunenano)). +* Backported in [#58084](https://github.com/ClickHouse/ClickHouse/issues/58084): Normilize function names in `CREATE INDEX` query. Avoid `Existing table metadata in ZooKeeper differs in skip indexes` errors if an alias was used insead of canonical function name when creating an index. [#57906](https://github.com/ClickHouse/ClickHouse/pull/57906) ([Alexander Tokmakov](https://github.com/tavplubix)). +* Backported in [#58110](https://github.com/ClickHouse/ClickHouse/issues/58110): Keeper fix: Leader should correctly fail on preprocessing a request if it is not initialized. [#58069](https://github.com/ClickHouse/ClickHouse/pull/58069) ([Antonio Andelic](https://github.com/antonio2368)). +* Backported in [#58155](https://github.com/ClickHouse/ClickHouse/issues/58155): Fix Integer overflow in Poco::UTF32Encoding. [#58073](https://github.com/ClickHouse/ClickHouse/pull/58073) ([Andrey Fedotov](https://github.com/anfedotoff)). +* Backported in [#58188](https://github.com/ClickHouse/ClickHouse/issues/58188): Parallel parsing for `JSONCompactEachRow` could work incorrectly in previous versions. This closes [#58180](https://github.com/ClickHouse/ClickHouse/issues/58180). [#58181](https://github.com/ClickHouse/ClickHouse/pull/58181) ([Alexey Milovidov](https://github.com/alexey-milovidov)). +* Backported in [#58301](https://github.com/ClickHouse/ClickHouse/issues/58301): Fix parallel parsing for JSONCompactEachRow. [#58250](https://github.com/ClickHouse/ClickHouse/pull/58250) ([Kruglov Pavel](https://github.com/Avogar)). #### NO CL ENTRY From ef2b6e7c3f2a05e9cb234c466d2935037ab524f8 Mon Sep 17 00:00:00 2001 From: Kseniia Sumarokova <54203879+kssenii@users.noreply.github.com> Date: Thu, 30 May 2024 18:15:36 +0200 Subject: [PATCH 210/211] Update NamedCollections.cpp --- src/Common/NamedCollections/NamedCollections.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Common/NamedCollections/NamedCollections.cpp b/src/Common/NamedCollections/NamedCollections.cpp index cc12e78095c..04d2099f4df 100644 --- a/src/Common/NamedCollections/NamedCollections.cpp +++ b/src/Common/NamedCollections/NamedCollections.cpp @@ -13,8 +13,6 @@ namespace DB namespace ErrorCodes { - extern const int NAMED_COLLECTION_DOESNT_EXIST; - extern const int NAMED_COLLECTION_ALREADY_EXISTS; extern const int NAMED_COLLECTION_IS_IMMUTABLE; extern const int BAD_ARGUMENTS; } From f38bc4899ebf2c5c002f6b959250c5945538d468 Mon Sep 17 00:00:00 2001 From: Kseniia Sumarokova <54203879+kssenii@users.noreply.github.com> Date: Thu, 30 May 2024 18:15:53 +0200 Subject: [PATCH 211/211] Update NamedCollectionsFactory.h --- src/Common/NamedCollections/NamedCollectionsFactory.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Common/NamedCollections/NamedCollectionsFactory.h b/src/Common/NamedCollections/NamedCollectionsFactory.h index 17acd99aead..2d64a03bde3 100644 --- a/src/Common/NamedCollections/NamedCollectionsFactory.h +++ b/src/Common/NamedCollections/NamedCollectionsFactory.h @@ -1,3 +1,4 @@ +#pragma once #include namespace DB

      rEP2-*hpogRNCQ75z@9A@AYruypfHw<0~>!7 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

      RZwrAqFCDu|YRg^eiCz6e$@NBSxXf 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�O6R6y3#oqnYUKVEUom(B6Mwxq%Wg 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