11#include < Storages/IStorageCluster.h>
22
3+ #include < pcg_random.hpp>
4+ #include < Common/randomSeed.h>
5+
36#include < Common/Exception.h>
47#include < Core/Settings.h>
58#include < Core/QueryProcessingStage.h>
1215#include < Interpreters/AddDefaultDatabaseVisitor.h>
1316#include < Interpreters/TranslateQualifiedNamesVisitor.h>
1417#include < Interpreters/InterpreterSelectQueryAnalyzer.h>
18+ #include < Planner/Utils.h>
1519#include < Processors/Sources/NullSource.h>
1620#include < Processors/Sources/RemoteSource.h>
1721#include < QueryPipeline/narrowPipe.h>
2125#include < Storages/IStorage.h>
2226#include < Storages/SelectQueryInfo.h>
2327#include < Storages/StorageDictionary.h>
28+ #include < Storages/StorageDistributed.h>
29+ #include < TableFunctions/TableFunctionFactory.h>
30+ #include < Storages/extractTableFunctionFromSelectQuery.h>
2431
2532#include < algorithm>
2633#include < memory>
@@ -39,6 +46,7 @@ namespace Setting
3946 extern const SettingsString cluster_for_parallel_replicas;
4047 extern const SettingsNonZeroUInt64 max_parallel_replicas;
4148 extern const SettingsUInt64 object_storage_max_nodes;
49+ extern const SettingsBool object_storage_remote_initiator;
4250}
4351
4452namespace ErrorCodes
@@ -96,15 +104,16 @@ void IStorageCluster::read(
96104
97105 storage_snapshot->check (column_names);
98106
99- updateBeforeRead (context);
100- auto cluster = getClusterImpl (context, cluster_name_from_settings, context->getSettingsRef ()[Setting::object_storage_max_nodes]);
107+ const auto & settings = context->getSettingsRef ();
108+
109+ auto cluster = getClusterImpl (context, cluster_name_from_settings, settings[Setting::object_storage_max_nodes]);
101110
102111 // / Calculate the header. This is significant, because some columns could be thrown away in some cases like query with count(*)
103112
104113 Block sample_block;
105114 ASTPtr query_to_send = query_info.query ;
106115
107- if (context-> getSettingsRef () [Setting::allow_experimental_analyzer])
116+ if (settings [Setting::allow_experimental_analyzer])
108117 {
109118 sample_block = InterpreterSelectQueryAnalyzer::getSampleBlock (query_info.query , context, SelectQueryOptions (processed_stage));
110119 }
@@ -117,6 +126,17 @@ void IStorageCluster::read(
117126
118127 updateQueryToSendIfNeeded (query_to_send, storage_snapshot, context);
119128
129+ if (settings[Setting::object_storage_remote_initiator])
130+ {
131+ auto storage_and_context = convertToRemote (cluster, context, cluster_name_from_settings, query_to_send);
132+ auto src_distributed = std::dynamic_pointer_cast<StorageDistributed>(storage_and_context.storage );
133+ auto modified_query_info = query_info;
134+ modified_query_info.cluster = src_distributed->getCluster ();
135+ auto new_storage_snapshot = storage_and_context.storage ->getStorageSnapshot (storage_snapshot->metadata , storage_and_context.context );
136+ storage_and_context.storage ->read (query_plan, column_names, new_storage_snapshot, modified_query_info, storage_and_context.context , processed_stage, max_block_size, num_streams);
137+ return ;
138+ }
139+
120140 RestoreQualifiedNamesVisitor::Data data;
121141 data.distributed_table = DatabaseAndTableWithAlias (*getTableExpression (query_info.query ->as <ASTSelectQuery &>(), 0 ));
122142 data.remote_table .database = context->getCurrentDatabase ();
@@ -144,6 +164,62 @@ void IStorageCluster::read(
144164 query_plan.addStep (std::move (reading));
145165}
146166
167+ IStorageCluster::RemoteCallVariables IStorageCluster::convertToRemote (
168+ ClusterPtr cluster,
169+ ContextPtr context,
170+ const std::string & cluster_name_from_settings,
171+ ASTPtr query_to_send)
172+ {
173+ auto host_addresses = cluster->getShardsAddresses ();
174+ if (host_addresses.empty ())
175+ throw Exception (ErrorCodes::LOGICAL_ERROR, " Empty cluster {}" , cluster_name_from_settings);
176+
177+ static pcg64 rng (randomSeed ());
178+ size_t shard_num = rng () % host_addresses.size ();
179+ auto shard_addresses = host_addresses[shard_num];
180+ // / After getClusterImpl each shard must have exactly 1 replica
181+ if (shard_addresses.size () != 1 )
182+ throw Exception (ErrorCodes::LOGICAL_ERROR, " Size of shard {} in cluster {} is not equal 1" , shard_num, cluster_name_from_settings);
183+ auto host_name = shard_addresses[0 ].toString ();
184+
185+ LOG_INFO (log, " Choose remote initiator '{}'" , host_name);
186+
187+ bool secure = shard_addresses[0 ].secure == Protocol::Secure::Enable;
188+ std::string remote_function_name = secure ? " remoteSecure" : " remote" ;
189+
190+ // / Clean object_storage_remote_initiator setting to avoid infinite remote call
191+ auto new_context = Context::createCopy (context);
192+ new_context->setSetting (" object_storage_remote_initiator" , false );
193+
194+ auto * select_query = query_to_send->as <ASTSelectQuery>();
195+ if (!select_query)
196+ throw Exception (ErrorCodes::LOGICAL_ERROR, " Expected SELECT query" );
197+
198+ auto query_settings = select_query->settings ();
199+ if (query_settings)
200+ {
201+ auto & settings_ast = query_settings->as <ASTSetQuery &>();
202+ if (settings_ast.changes .removeSetting (" object_storage_remote_initiator" ) && settings_ast.changes .empty ())
203+ {
204+ select_query->setExpression (ASTSelectQuery::Expression::SETTINGS, {});
205+ }
206+ }
207+
208+ ASTTableExpression * table_expression = extractTableExpressionASTPtrFromSelectQuery (query_to_send);
209+ if (!table_expression)
210+ throw Exception (ErrorCodes::LOGICAL_ERROR, " Can't find table expression" );
211+
212+ auto remote_query = makeASTFunction (remote_function_name, std::make_shared<ASTLiteral>(host_name), table_expression->table_function );
213+
214+ table_expression->table_function = remote_query;
215+
216+ auto remote_function = TableFunctionFactory::instance ().get (remote_query, new_context);
217+
218+ auto storage = remote_function->execute (query_to_send, new_context, remote_function_name);
219+
220+ return RemoteCallVariables{storage, new_context};
221+ }
222+
147223SinkToStoragePtr IStorageCluster::write (
148224 const ASTPtr & query,
149225 const StorageMetadataPtr & metadata_snapshot,
0 commit comments