@@ -155,6 +155,8 @@ class Client::Impl {
155155
156156 void ExecuteQuery (Query query);
157157
158+ void SelectWithExternalData (Query query, const ExternalTables& external_tables);
159+
158160 void SendCancel ();
159161
160162 void Insert (const std::string& table_name, const std::string& query_id, const Block& block);
@@ -174,10 +176,14 @@ class Client::Impl {
174176
175177 bool ReceivePacket (uint64_t * server_packet = nullptr );
176178
177- void SendQuery (const Query& query);
179+ void SendQuery (const Query& query, bool finalize = true );
180+ void FinalizeQuery ();
178181
179182 void SendData (const Block& block);
180183
184+ void SendBlockData (const Block& block);
185+ void SendExternalData (const ExternalTables& external_tables);
186+
181187 bool SendHello ();
182188
183189 bool ReadBlock (InputStream& input, Block* block);
@@ -291,6 +297,51 @@ void Client::Impl::ExecuteQuery(Query query) {
291297 }
292298}
293299
300+
301+ void Client::Impl::SelectWithExternalData (Query query, const ExternalTables& external_tables) {
302+ if (server_info_.revision < DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES) {
303+ throw UnimplementedError (" This version of ClickHouse server doesn't support temporary tables" );
304+ }
305+
306+ EnsureNull en (static_cast <QueryEvents*>(&query), &events_);
307+
308+ if (options_.ping_before_query ) {
309+ RetryGuard ([this ]() { Ping (); });
310+ }
311+
312+ SendQuery (query, false );
313+ SendExternalData (external_tables);
314+ FinalizeQuery ();
315+
316+ while (ReceivePacket ()) {
317+ ;
318+ }
319+ }
320+
321+ void Client::Impl::SendBlockData (const Block& block) {
322+ if (compression_ == CompressionState::Enable) {
323+ std::unique_ptr<OutputStream> compressed_output = std::make_unique<CompressedOutput>(output_.get (), options_.max_compression_chunk_size , options_.compression_method );
324+ BufferedOutput buffered (std::move (compressed_output), options_.max_compression_chunk_size );
325+
326+ WriteBlock (block, buffered);
327+ } else {
328+ WriteBlock (block, *output_);
329+ }
330+ }
331+
332+ void Client::Impl::SendExternalData (const ExternalTables& external_tables) {
333+ for (const auto & table: external_tables) {
334+ if (!table.data .GetRowCount ()) {
335+ // skip empty blocks to keep the connection in the consistent state as the current request would be marked as finished by such an empty block
336+ continue ;
337+ }
338+ WireFormat::WriteFixed<uint8_t >(*output_, ClientCodes::Data);
339+ WireFormat::WriteString (*output_, table.name );
340+ SendBlockData (table.data );
341+ }
342+ }
343+
344+
294345std::string NameToQueryString (const std::string &input)
295346{
296347 std::string output;
@@ -753,7 +804,7 @@ void Client::Impl::SendCancel() {
753804 output_->Flush ();
754805}
755806
756- void Client::Impl::SendQuery (const Query& query) {
807+ void Client::Impl::SendQuery (const Query& query, bool finalize ) {
757808 WireFormat::WriteUInt64 (*output_, ClientCodes::Query);
758809 WireFormat::WriteString (*output_, query.GetQueryID ());
759810
@@ -858,7 +909,13 @@ void Client::Impl::SendQuery(const Query& query) {
858909 }
859910 WireFormat::WriteString (*output_, std::string ()); // empty string after last param
860911 }
912+
913+ if (finalize) {
914+ FinalizeQuery ();
915+ }
916+ }
861917
918+ void Client::Impl::FinalizeQuery () {
862919 // Send empty block as marker of
863920 // end of data
864921 SendData (Block ());
@@ -905,16 +962,7 @@ void Client::Impl::SendData(const Block& block) {
905962 if (server_info_.revision >= DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES) {
906963 WireFormat::WriteString (*output_, std::string ());
907964 }
908-
909- if (compression_ == CompressionState::Enable) {
910-
911- std::unique_ptr<OutputStream> compressed_output = std::make_unique<CompressedOutput>(output_.get (), options_.max_compression_chunk_size , options_.compression_method );
912- BufferedOutput buffered (std::move (compressed_output), options_.max_compression_chunk_size );
913-
914- WriteBlock (block, buffered);
915- } else {
916- WriteBlock (block, *output_);
917- }
965+ SendBlockData (block);
918966
919967 output_->Flush ();
920968}
@@ -1077,6 +1125,22 @@ void Client::Select(const Query& query) {
10771125 Execute (query);
10781126}
10791127
1128+ void Client::SelectWithExternalData (const std::string& query, const ExternalTables& external_tables, SelectCallback cb) {
1129+ impl_->SelectWithExternalData (Query (query).OnData (std::move (cb)), external_tables);
1130+ }
1131+
1132+ void Client::SelectWithExternalData (const std::string& query, const std::string& query_id, const ExternalTables& external_tables, SelectCallback cb) {
1133+ impl_->SelectWithExternalData (Query (query, query_id).OnData (std::move (cb)), external_tables);
1134+ }
1135+
1136+ void Client::SelectWithExternalDataCancelable (const std::string& query, const ExternalTables& external_tables, SelectCancelableCallback cb) {
1137+ impl_->SelectWithExternalData (Query (query).OnDataCancelable (std::move (cb)), external_tables);
1138+ }
1139+
1140+ void Client::SelectWithExternalDataCancelable (const std::string& query, const std::string& query_id, const ExternalTables& external_tables, SelectCancelableCallback cb) {
1141+ impl_->SelectWithExternalData (Query (query, query_id).OnDataCancelable (std::move (cb)), external_tables);
1142+ }
1143+
10801144void Client::Insert (const std::string& table_name, const Block& block) {
10811145 impl_->Insert (table_name, Query::default_query_id, block);
10821146}
0 commit comments