clickhouse-native 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/ext/clickhouse_native/client.cpp +42 -3
  3. data/ext/clickhouse_native/extconf.rb +30 -3
  4. data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/bazel.yml +120 -0
  5. data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/cross-repo-bug-relay.yml +17 -0
  6. data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/linux.yml +22 -23
  7. data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/macos.yml +22 -21
  8. data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/windows_mingw.yml +29 -36
  9. data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/windows_msvc.yml +29 -36
  10. data/ext/clickhouse_native/vendor/clickhouse-cpp/.gitignore +6 -0
  11. data/ext/clickhouse_native/vendor/clickhouse-cpp/AI_POLICY.md +13 -0
  12. data/ext/clickhouse_native/vendor/clickhouse-cpp/BUILD.bazel +167 -0
  13. data/ext/clickhouse_native/vendor/clickhouse-cpp/CMakeLists.txt +2 -1
  14. data/ext/clickhouse_native/vendor/clickhouse-cpp/MODULE.bazel +17 -0
  15. data/ext/clickhouse_native/vendor/clickhouse-cpp/MODULE.bazel.lock +503 -0
  16. data/ext/clickhouse_native/vendor/clickhouse-cpp/README.md +32 -6
  17. data/ext/clickhouse_native/vendor/clickhouse-cpp/ci/docker-compose/config.xml +53 -0
  18. data/ext/clickhouse_native/vendor/clickhouse-cpp/ci/docker-compose/users.xml +35 -0
  19. data/ext/clickhouse_native/vendor/clickhouse-cpp/ci/docker-compose.yml +22 -0
  20. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/CMakeLists.txt +11 -0
  21. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/base/sslsocket.cpp +24 -0
  22. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/block.cpp +1 -1
  23. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/block.h +2 -1
  24. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/client.cpp +293 -136
  25. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/client.h +31 -2
  26. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/array.cpp +12 -0
  27. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/array.h +17 -7
  28. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/bool.cpp +79 -0
  29. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/bool.h +62 -0
  30. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/factory.cpp +16 -0
  31. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/itemview.cpp +2 -0
  32. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/itemview.h +6 -2
  33. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/json.cpp +102 -0
  34. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/json.h +82 -0
  35. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/lowcardinality.cpp +2 -1
  36. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/string.cpp +7 -2
  37. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/tuple.cpp +48 -5
  38. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/tuple.h +14 -1
  39. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/query.h +2 -2
  40. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/server_exception.h +0 -3
  41. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/types/type_parser.cpp +43 -0
  42. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/types/type_parser.h +9 -0
  43. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/types/types.cpp +61 -11
  44. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/types/types.h +18 -2
  45. data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/version.h +1 -1
  46. data/lib/clickhouse_native/version.rb +1 -1
  47. data/lib/clickhouse_native.rb +1 -0
  48. metadata +14 -1
@@ -8,10 +8,12 @@
8
8
 
9
9
  #include "columns/factory.h"
10
10
 
11
- #include <assert.h>
11
+ #include <cassert>
12
+ #include <optional>
13
+ #include <sstream>
12
14
  #include <system_error>
15
+ #include <variant>
13
16
  #include <vector>
14
- #include <sstream>
15
17
 
16
18
  #if defined(WITH_OPENSSL)
17
19
  #include "base/sslsocket.h"
@@ -125,6 +127,48 @@ ClientOptions& ClientOptions::SetSSLOptions(ClientOptions::SSLOptions options)
125
127
 
126
128
  namespace {
127
129
 
130
+ // Compared to std::visit this is a more convenient way to unpack std::variant values. The
131
+ // `VariantIndex` trait allows to get index of the variant by type. This way, the variant can be
132
+ // unpacked using the old and simple `switch` statement. While the standard way of doing do is
133
+ // std::visit, using it is very inconvenient, it's semantics are often unclear and it lead to
134
+ // bizarre and hard to parse errors.
135
+ template <typename T>
136
+ struct VariantIndexTag {};
137
+ template <typename T, typename V>
138
+ struct VariantIndex;
139
+ template <typename T, typename... Ts>
140
+ struct VariantIndex<T, std::variant<Ts...>>
141
+ : std::integral_constant<size_t, std::variant<VariantIndexTag<Ts>...>{VariantIndexTag<T>{}}.index()>
142
+ {
143
+ };
144
+
145
+ struct Pong {
146
+ };
147
+ struct Hello {
148
+ };
149
+ struct Log {
150
+ Block block;
151
+ };
152
+ struct TableColumns {
153
+ };
154
+ struct ProfileEvents {
155
+ Block block;
156
+ };
157
+ struct EndOfStream {
158
+ };
159
+ using DecodedPacket = std::variant<
160
+ std::monostate,
161
+ Block,
162
+ ServerException,
163
+ Profile,
164
+ Progress,
165
+ Pong,
166
+ Hello,
167
+ Log,
168
+ TableColumns,
169
+ ProfileEvents,
170
+ EndOfStream>;
171
+
128
172
  std::unique_ptr<SocketFactory> GetSocketFactory(const ClientOptions& opts) {
129
173
  (void)opts;
130
174
  #if defined(WITH_OPENSSL)
@@ -144,7 +188,7 @@ std::unique_ptr<EndpointsIteratorBase> GetEndpointsIterator(const ClientOptions&
144
188
  return std::make_unique<RoundRobinEndpointsIterator>(opts.endpoints);
145
189
  }
146
190
 
147
- }
191
+ } // anonymous namespace
148
192
 
149
193
  class Client::Impl {
150
194
  public:
@@ -154,11 +198,19 @@ public:
154
198
  ~Impl();
155
199
 
156
200
  void ExecuteQuery(Query query);
201
+ void BeginExecuteQuery(const Query& query, bool finalize = true);
202
+
203
+ // Note, next block returns the block, but also notifies `query.OnData()` if it is set.
204
+ std::optional<Block> NextBlock();
157
205
 
158
206
  void SelectWithExternalData(Query query, const ExternalTables& external_tables);
159
207
 
160
208
  void SendCancel();
161
209
 
210
+ void Cancel();
211
+
212
+ bool IsSelecting() const { return state_ == State::Selecting; }
213
+
162
214
  void Insert(const std::string& table_name, const std::string& query_id, const Block& block);
163
215
 
164
216
  Block BeginInsert(Query query);
@@ -167,6 +219,8 @@ public:
167
219
 
168
220
  void EndInsert();
169
221
 
222
+ bool IsInserting() const { return state_ == State::Inserting; }
223
+
170
224
  void Ping();
171
225
 
172
226
  void ResetConnection();
@@ -180,7 +234,9 @@ public:
180
234
  private:
181
235
  bool Handshake();
182
236
 
183
- bool ReceivePacket(uint64_t* server_packet = nullptr);
237
+ DecodedPacket ReceivePacket(uint64_t* server_packet = nullptr);
238
+ bool ProcessPacket(uint64_t* server_packet = nullptr);
239
+ void ResetState();
184
240
 
185
241
  void SendQuery(const Query& query, bool finalize = true);
186
242
  void FinalizeQuery();
@@ -197,10 +253,10 @@ private:
197
253
  bool ReceiveHello();
198
254
 
199
255
  /// Reads data packet form input stream.
200
- bool ReceiveData();
256
+ bool ReceiveData(Block & block);
201
257
 
202
258
  /// Reads exception packet form input stream.
203
- bool ReceiveException(bool rethrow = false);
259
+ bool ReceiveException(bool rethrow = false, ServerError * error = nullptr);
204
260
 
205
261
  void WriteBlock(const Block& block, OutputStream& output);
206
262
 
@@ -221,6 +277,12 @@ private:
221
277
  void RetryConnectToTheEndpoint(std::function<void()>& func);
222
278
 
223
279
  private:
280
+ enum class State : uint8_t {
281
+ Idle = 0,
282
+ Selecting = 1,
283
+ Inserting = 2,
284
+ };
285
+
224
286
  class EnsureNull {
225
287
  public:
226
288
  inline EnsureNull(QueryEvents* ev, QueryEvents** ptr)
@@ -244,6 +306,7 @@ private:
244
306
 
245
307
 
246
308
  const ClientOptions options_;
309
+ Query query_;
247
310
  QueryEvents* events_;
248
311
  int compression_ = CompressionState::Disable;
249
312
 
@@ -258,7 +321,7 @@ private:
258
321
 
259
322
  ServerInfo server_info_;
260
323
 
261
- bool inserting_;
324
+ State state_ = State::Idle;
262
325
  };
263
326
 
264
327
  ClientOptions modifyClientOptions(ClientOptions opts)
@@ -290,50 +353,91 @@ Client::Impl::Impl(const ClientOptions& opts,
290
353
 
291
354
  Client::Impl::~Impl() {
292
355
  try {
293
- EndInsert();
356
+ if (state_ == State::Inserting) {
357
+ EndInsert();
358
+ }
294
359
  } catch (...) {
295
360
  }
296
361
  }
297
362
 
298
- void Client::Impl::ExecuteQuery(Query query) {
299
- if (inserting_) {
300
- throw ValidationError("cannot execute query while inserting");
363
+ void Client::Impl::BeginExecuteQuery(const Query& query, bool finalize) {
364
+ if (state_ != State::Idle) {
365
+ throw ValidationError("cannot execute query while executing another operation");
301
366
  }
302
367
 
303
- EnsureNull en(static_cast<QueryEvents*>(&query), &events_);
304
-
305
368
  if (options_.ping_before_query) {
306
369
  RetryGuard([this]() { Ping(); });
307
370
  }
308
371
 
309
- SendQuery(query);
372
+ query_ = query;
373
+ events_ = static_cast<QueryEvents*>(&query_);
374
+ state_ = State::Selecting;
310
375
 
311
- while (ReceivePacket()) {
312
- ;
376
+ try {
377
+ SendQuery(query_, finalize);
378
+ }
379
+ catch (...) {
380
+ ResetState();
381
+ throw;
313
382
  }
314
383
  }
315
384
 
385
+ std::optional<Block> Client::Impl::NextBlock() {
386
+ if (state_ != State::Selecting) {
387
+ throw ValidationError("cannot execute NextBlock while not selecting");
388
+ }
316
389
 
317
- void Client::Impl::SelectWithExternalData(Query query, const ExternalTables& external_tables) {
318
- if (inserting_) {
319
- throw ValidationError("cannot execute query while inserting");
390
+ try {
391
+ while (true) {
392
+ auto packet = ReceivePacket();
393
+ switch (packet.index()) {
394
+ case VariantIndex<Block, decltype(packet)>(): {
395
+ Block & block = std::get<Block>(packet);
396
+ if (block.GetColumnCount() == 0) {
397
+ continue;
398
+ }
399
+ return {std::move(block)};
400
+ }
401
+ case VariantIndex<ServerError, decltype(packet)>():
402
+ case VariantIndex<std::monostate, decltype(packet)>():
403
+ case VariantIndex<EndOfStream, decltype(packet)>():
404
+ ResetState();
405
+ return std::nullopt;
406
+ default:
407
+ continue;
408
+ }
409
+ }
410
+ }
411
+ catch (...) {
412
+ ResetState();
413
+ throw;
320
414
  }
415
+ }
321
416
 
322
- if (server_info_.revision < DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES) {
323
- throw UnimplementedError("This version of ClickHouse server doesn't support temporary tables");
417
+ void Client::Impl::ExecuteQuery(Query query) {
418
+ BeginExecuteQuery(query);
419
+ while (NextBlock().has_value()) {
420
+ ;
324
421
  }
422
+ }
325
423
 
326
- EnsureNull en(static_cast<QueryEvents*>(&query), &events_);
327
424
 
328
- if (options_.ping_before_query) {
329
- RetryGuard([this]() { Ping(); });
425
+ void Client::Impl::SelectWithExternalData(Query query, const ExternalTables& external_tables) {
426
+ if (server_info_.revision < DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES) {
427
+ throw UnimplementedError("This version of ClickHouse server doesn't support temporary tables");
330
428
  }
331
429
 
332
- SendQuery(query, false);
333
- SendExternalData(external_tables);
334
- FinalizeQuery();
430
+ BeginExecuteQuery(query, /*finalize=*/ false);
431
+ try {
432
+ SendExternalData(external_tables);
433
+ FinalizeQuery();
434
+ }
435
+ catch (...) {
436
+ ResetState();
437
+ throw;
438
+ }
335
439
 
336
- while (ReceivePacket()) {
440
+ while (NextBlock().has_value()) {
337
441
  ;
338
442
  }
339
443
  }
@@ -382,15 +486,18 @@ std::string NameToQueryString(const std::string &input)
382
486
  }
383
487
 
384
488
  void Client::Impl::Insert(const std::string& table_name, const std::string& query_id, const Block& block) {
385
- if (inserting_) {
489
+ if (state_ == State::Inserting) {
386
490
  throw ValidationError("cannot execute query while inserting, use SendInsertData instead");
387
491
  }
492
+ if (state_ != State::Idle) {
493
+ throw ValidationError("cannot execute query while executing another operation");
494
+ }
388
495
 
389
496
  if (options_.ping_before_query) {
390
497
  RetryGuard([this]() { Ping(); });
391
498
  }
392
499
 
393
- inserting_ = true;
500
+ state_ = State::Inserting;
394
501
 
395
502
  std::stringstream fields_section;
396
503
  const auto num_columns = block.GetColumnCount();
@@ -408,7 +515,7 @@ void Client::Impl::Insert(const std::string& table_name, const std::string& quer
408
515
 
409
516
  // Wait for a data packet and return
410
517
  uint64_t server_packet = 0;
411
- while (ReceivePacket(&server_packet)) {
518
+ while (ProcessPacket(&server_packet)) {
412
519
  if (server_packet == ServerCodes::Data) {
413
520
  SendData(block);
414
521
  EndInsert();
@@ -420,8 +527,8 @@ void Client::Impl::Insert(const std::string& table_name, const std::string& quer
420
527
  }
421
528
 
422
529
  Block Client::Impl::BeginInsert(Query query) {
423
- if (inserting_) {
424
- throw ValidationError("cannot execute query while inserting");
530
+ if (state_ != State::Idle) {
531
+ throw ValidationError("cannot execute query while executing another operation");
425
532
  }
426
533
 
427
534
  EnsureNull en(static_cast<QueryEvents*>(&query), &events_);
@@ -430,7 +537,7 @@ Block Client::Impl::BeginInsert(Query query) {
430
537
  RetryGuard([this]() { Ping(); });
431
538
  }
432
539
 
433
- inserting_ = true;
540
+ state_ = State::Inserting;
434
541
 
435
542
  // Create a callback to extract the block with the proper query columns.
436
543
  Block block;
@@ -443,7 +550,7 @@ Block Client::Impl::BeginInsert(Query query) {
443
550
 
444
551
  // Wait for a data packet and return
445
552
  uint64_t server_packet = 0;
446
- while (ReceivePacket(&server_packet)) {
553
+ while (ProcessPacket(&server_packet)) {
447
554
  if (server_packet == ServerCodes::Data) {
448
555
  return block;
449
556
  }
@@ -453,15 +560,15 @@ Block Client::Impl::BeginInsert(Query query) {
453
560
  }
454
561
 
455
562
  void Client::Impl::SendInsertBlock(const Block& block) {
456
- if (!inserting_) {
457
- throw ValidationError("illegal call to InsertData without first calling BeginInsert");
563
+ if (state_ != State::Inserting) {
564
+ throw ValidationError("illegal to send insert data without first calling BeginInsert");
458
565
  }
459
566
 
460
567
  SendData(block);
461
568
  }
462
569
 
463
570
  void Client::Impl::EndInsert() {
464
- if (!inserting_) {
571
+ if (state_ != State::Inserting) {
465
572
  return;
466
573
  }
467
574
 
@@ -470,7 +577,7 @@ void Client::Impl::EndInsert() {
470
577
 
471
578
  // Wait for EOS.
472
579
  uint64_t eos_packet{0};
473
- while (ReceivePacket(&eos_packet)) {
580
+ while (ProcessPacket(&eos_packet)) {
474
581
  ;
475
582
  }
476
583
 
@@ -479,19 +586,19 @@ void Client::Impl::EndInsert() {
479
586
  throw ProtocolError(std::string{"unexpected packet from server while receiving end of query, expected (expected Exception, EndOfStream or Log, got: "}
480
587
  + (eos_packet ? std::to_string(eos_packet) : "nothing") + ")");
481
588
  }
482
- inserting_ = false;
589
+ state_ = State::Idle;
483
590
  }
484
591
 
485
592
  void Client::Impl::Ping() {
486
- if (inserting_) {
487
- throw ValidationError("cannot execute query while inserting");
593
+ if (state_ != State::Idle) {
594
+ throw ValidationError("cannot execute query while executing another operation");
488
595
  }
489
596
 
490
597
  WireFormat::WriteUInt64(*output_, ClientCodes::Ping);
491
598
  output_->Flush();
492
599
 
493
600
  uint64_t server_packet;
494
- const bool ret = ReceivePacket(&server_packet);
601
+ const bool ret = ProcessPacket(&server_packet);
495
602
 
496
603
  if (!ret || server_packet != ServerCodes::Pong) {
497
604
  throw ProtocolError("fail to ping server");
@@ -500,7 +607,7 @@ void Client::Impl::Ping() {
500
607
 
501
608
  void Client::Impl::ResetConnection() {
502
609
  InitializeStreams(socket_factory_->connect(options_, current_endpoint_.value()));
503
- inserting_ = false;
610
+ state_ = State::Idle;
504
611
 
505
612
  if (!Handshake()) {
506
613
  throw ProtocolError("fail to connect to " + options_.host);
@@ -569,11 +676,11 @@ bool Client::Impl::Handshake() {
569
676
  return true;
570
677
  }
571
678
 
572
- bool Client::Impl::ReceivePacket(uint64_t* server_packet) {
679
+ DecodedPacket Client::Impl::ReceivePacket(uint64_t* server_packet) {
573
680
  uint64_t packet_type = 0;
574
681
 
575
682
  if (!WireFormat::ReadVarint64(*input_, &packet_type)) {
576
- return false;
683
+ return {};
577
684
  }
578
685
  if (server_packet) {
579
686
  *server_packet = packet_type;
@@ -581,137 +688,141 @@ bool Client::Impl::ReceivePacket(uint64_t* server_packet) {
581
688
 
582
689
  switch (packet_type) {
583
690
  case ServerCodes::Data: {
584
- if (!ReceiveData()) {
691
+ Block ret{};
692
+ if (!ReceiveData(ret)) {
585
693
  throw ProtocolError("can't read data packet from input stream");
586
694
  }
587
- return true;
695
+ return ret;
588
696
  }
589
697
 
590
698
  case ServerCodes::Exception: {
591
- ReceiveException();
592
- return false;
699
+ ServerError ret{std::make_shared<Exception>()};
700
+ if (!ReceiveException(false, &ret)) {
701
+ throw ProtocolError("can't read exception packet from input stream");
702
+ }
703
+ return ret;
593
704
  }
594
705
 
595
706
  case ServerCodes::ProfileInfo: {
596
- Profile profile;
707
+ Profile ret{};
597
708
 
598
- if (!WireFormat::ReadUInt64(*input_, &profile.rows)) {
599
- return false;
709
+ if (!WireFormat::ReadUInt64(*input_, &ret.rows)) {
710
+ return {};
600
711
  }
601
- if (!WireFormat::ReadUInt64(*input_, &profile.blocks)) {
602
- return false;
712
+ if (!WireFormat::ReadUInt64(*input_, &ret.blocks)) {
713
+ return {};
603
714
  }
604
- if (!WireFormat::ReadUInt64(*input_, &profile.bytes)) {
605
- return false;
715
+ if (!WireFormat::ReadUInt64(*input_, &ret.bytes)) {
716
+ return {};
606
717
  }
607
- if (!WireFormat::ReadFixed(*input_, &profile.applied_limit)) {
608
- return false;
718
+ if (!WireFormat::ReadFixed(*input_, &ret.applied_limit)) {
719
+ return {};
609
720
  }
610
- if (!WireFormat::ReadUInt64(*input_, &profile.rows_before_limit)) {
611
- return false;
721
+ if (!WireFormat::ReadUInt64(*input_, &ret.rows_before_limit)) {
722
+ return {};
612
723
  }
613
- if (!WireFormat::ReadFixed(*input_, &profile.calculated_rows_before_limit)) {
614
- return false;
724
+ if (!WireFormat::ReadFixed(*input_, &ret.calculated_rows_before_limit)) {
725
+ return {};
615
726
  }
616
727
 
617
728
  if (events_) {
618
- events_->OnProfile(profile);
729
+ events_->OnProfile(ret);
619
730
  }
620
731
 
621
- return true;
732
+ return ret;
622
733
  }
623
734
 
624
735
  case ServerCodes::Progress: {
625
- Progress info;
736
+ Progress ret{};
626
737
 
627
- if (!WireFormat::ReadUInt64(*input_, &info.rows)) {
628
- return false;
738
+ if (!WireFormat::ReadUInt64(*input_, &ret.rows)) {
739
+ return {};
629
740
  }
630
- if (!WireFormat::ReadUInt64(*input_, &info.bytes)) {
631
- return false;
741
+ if (!WireFormat::ReadUInt64(*input_, &ret.bytes)) {
742
+ return {};
632
743
  }
633
744
  if constexpr(DMBS_PROTOCOL_REVISION >= DBMS_MIN_REVISION_WITH_TOTAL_ROWS_IN_PROGRESS) {
634
- if (!WireFormat::ReadUInt64(*input_, &info.total_rows)) {
635
- return false;
745
+ if (!WireFormat::ReadUInt64(*input_, &ret.total_rows)) {
746
+ return {};
636
747
  }
637
748
  }
638
749
  if (server_info_.revision >= DBMS_MIN_REVISION_WITH_CLIENT_WRITE_INFO)
639
750
  {
640
- if (!WireFormat::ReadUInt64(*input_, &info.written_rows)) {
641
- return false;
751
+ if (!WireFormat::ReadUInt64(*input_, &ret.written_rows)) {
752
+ return {};
642
753
  }
643
- if (!WireFormat::ReadUInt64(*input_, &info.written_bytes)) {
644
- return false;
754
+ if (!WireFormat::ReadUInt64(*input_, &ret.written_bytes)) {
755
+ return {};
645
756
  }
646
757
  }
647
758
 
648
759
  if (events_) {
649
- events_->OnProgress(info);
760
+ events_->OnProgress(ret);
650
761
  }
651
762
 
652
- return true;
763
+ return ret;
653
764
  }
654
765
 
655
766
  case ServerCodes::Pong: {
656
- return true;
767
+ return Pong{};
657
768
  }
658
769
 
659
770
  case ServerCodes::Hello: {
660
- return true;
771
+ return Hello{};
661
772
  }
662
773
 
663
774
  case ServerCodes::EndOfStream: {
664
775
  if (events_) {
665
776
  events_->OnFinish();
666
777
  }
667
- return false;
778
+ return EndOfStream{};
668
779
  }
669
780
 
670
781
  case ServerCodes::Log: {
671
782
  // log tag
672
783
  if (!WireFormat::SkipString(*input_)) {
673
- return false;
784
+ return {};
674
785
  }
675
- Block block;
786
+ Log ret;
676
787
 
677
788
  // Use uncompressed stream since log blocks usually contain only one row
678
- if (!ReadBlock(*input_, &block)) {
679
- return false;
789
+ if (!ReadBlock(*input_, &ret.block)) {
790
+ return {};
680
791
  }
681
792
 
682
793
  if (events_) {
683
- events_->OnServerLog(block);
794
+ events_->OnServerLog(ret.block);
684
795
  }
685
- return true;
796
+ return ret;
686
797
  }
687
798
 
688
799
  case ServerCodes::TableColumns: {
689
800
  // external table name
690
801
  if (!WireFormat::SkipString(*input_)) {
691
- return false;
802
+ return {};
692
803
  }
693
804
 
694
805
  // columns metadata
695
806
  if (!WireFormat::SkipString(*input_)) {
696
- return false;
807
+ return {};
697
808
  }
698
- return true;
809
+ return TableColumns{};
699
810
  }
700
811
 
701
812
  case ServerCodes::ProfileEvents: {
702
813
  if (!WireFormat::SkipString(*input_)) {
703
- return false;
814
+ return {};
704
815
  }
705
816
 
706
- Block block;
707
- if (!ReadBlock(*input_, &block)) {
708
- return false;
817
+ ProfileEvents ret;
818
+ if (!ReadBlock(*input_, &ret.block)) {
819
+ return {};
709
820
  }
710
821
 
711
822
  if (events_) {
712
- events_->OnProfileEvents(block);
823
+ events_->OnProfileEvents(ret.block);
713
824
  }
714
- return true;
825
+ return ret;
715
826
  }
716
827
 
717
828
  default:
@@ -720,6 +831,25 @@ bool Client::Impl::ReceivePacket(uint64_t* server_packet) {
720
831
  }
721
832
  }
722
833
 
834
+ bool Client::Impl::ProcessPacket(uint64_t* server_packet) {
835
+ auto packet = ReceivePacket(server_packet);
836
+ switch (packet.index()) {
837
+ case VariantIndex<ServerError, decltype(packet)>():
838
+ case VariantIndex<std::monostate, decltype(packet)>():
839
+ case VariantIndex<EndOfStream, decltype(packet)>():
840
+ return false;
841
+ default:
842
+ return true;
843
+ }
844
+ }
845
+
846
+ void Client::Impl::ResetState()
847
+ {
848
+ state_ = State::Idle;
849
+ query_ = {};
850
+ events_ = nullptr;
851
+ }
852
+
723
853
  bool Client::Impl::ReadBlock(InputStream& input, Block* block) {
724
854
  // Additional information about block.
725
855
  if (server_info_.revision >= DBMS_MIN_REVISION_WITH_BLOCK_INFO) {
@@ -793,8 +923,7 @@ bool Client::Impl::ReadBlock(InputStream& input, Block* block) {
793
923
  return true;
794
924
  }
795
925
 
796
- bool Client::Impl::ReceiveData() {
797
- Block block;
926
+ bool Client::Impl::ReceiveData(Block & block) {
798
927
 
799
928
  if (server_info_.revision >= DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES) {
800
929
  if (!WireFormat::SkipString(*input_)) {
@@ -823,42 +952,16 @@ bool Client::Impl::ReceiveData() {
823
952
  return true;
824
953
  }
825
954
 
826
- bool Client::Impl::ReceiveException(bool rethrow) {
955
+ bool Client::Impl::ReceiveException(bool rethrow, ServerError * error) {
827
956
  std::shared_ptr<Exception> e(new Exception);
828
- Exception* current = e.get();
829
-
830
- bool exception_received = true;
831
- do {
832
- bool has_nested = false;
833
-
834
- if (!WireFormat::ReadFixed(*input_, &current->code)) {
835
- exception_received = false;
836
- break;
837
- }
838
- if (!WireFormat::ReadString(*input_, &current->name)) {
839
- exception_received = false;
840
- break;
841
- }
842
- if (!WireFormat::ReadString(*input_, &current->display_text)) {
843
- exception_received = false;
844
- break;
845
- }
846
- if (!WireFormat::ReadString(*input_, &current->stack_trace)) {
847
- exception_received = false;
848
- break;
849
- }
850
- if (!WireFormat::ReadFixed(*input_, &has_nested)) {
851
- exception_received = false;
852
- break;
853
- }
957
+ bool has_nested = false; // obsolete: https://github.com/ClickHouse/ClickHouse/blob/ef11941cf5a/src/IO/ReadHelpers.cpp#L2017
854
958
 
855
- if (has_nested) {
856
- current->nested.reset(new Exception);
857
- current = current->nested.get();
858
- } else {
859
- break;
860
- }
861
- } while (true);
959
+ bool exception_received =
960
+ WireFormat::ReadFixed(*input_, &e->code)
961
+ && WireFormat::ReadString(*input_, &e->name)
962
+ && WireFormat::ReadString(*input_, &e->display_text)
963
+ && WireFormat::ReadString(*input_, &e->stack_trace)
964
+ && WireFormat::ReadFixed(*input_, &has_nested);
862
965
 
863
966
  if (events_) {
864
967
  events_->OnServerException(*e);
@@ -868,6 +971,9 @@ bool Client::Impl::ReceiveException(bool rethrow) {
868
971
  throw ServerError(e);
869
972
  }
870
973
 
974
+ if (exception_received && error != nullptr) {
975
+ *error = ServerError(e);
976
+ }
871
977
  return exception_received;
872
978
  }
873
979
 
@@ -876,6 +982,16 @@ void Client::Impl::SendCancel() {
876
982
  output_->Flush();
877
983
  }
878
984
 
985
+ void Client::Impl::Cancel() {
986
+ if (state_ != State::Selecting) {
987
+ throw ValidationError("cannot cancel while not executing a query");
988
+ }
989
+ SendCancel();
990
+ while (NextBlock().has_value()) {
991
+ ;
992
+ }
993
+ }
994
+
879
995
  void Client::Impl::SendQuery(const Query& query, bool finalize) {
880
996
  WireFormat::WriteUInt64(*output_, ClientCodes::Query);
881
997
  WireFormat::WriteString(*output_, query.GetQueryID());
@@ -1176,6 +1292,10 @@ void Client::Execute(const Query& query) {
1176
1292
  impl_->ExecuteQuery(query);
1177
1293
  }
1178
1294
 
1295
+ void Client::Select(const Query& query) {
1296
+ Execute(query);
1297
+ }
1298
+
1179
1299
  void Client::Select(const std::string& query, SelectCallback cb) {
1180
1300
  Execute(Query(query).OnData(std::move(cb)));
1181
1301
  }
@@ -1192,10 +1312,6 @@ void Client::SelectCancelable(const std::string& query, const std::string& query
1192
1312
  Execute(Query(query, query_id).OnDataCancelable(std::move(cb)));
1193
1313
  }
1194
1314
 
1195
- void Client::Select(const Query& query) {
1196
- Execute(query);
1197
- }
1198
-
1199
1315
  void Client::SelectWithExternalData(const std::string& query, const ExternalTables& external_tables, SelectCallback cb) {
1200
1316
  impl_->SelectWithExternalData(Query(query).OnData(std::move(cb)), external_tables);
1201
1317
  }
@@ -1212,6 +1328,43 @@ void Client::SelectWithExternalDataCancelable(const std::string& query, const st
1212
1328
  impl_->SelectWithExternalData(Query(query, query_id).OnDataCancelable(std::move(cb)), external_tables);
1213
1329
  }
1214
1330
 
1331
+ void Client::BeginExecute(const Query& query) {
1332
+ impl_->BeginExecuteQuery(query);
1333
+ }
1334
+
1335
+ void Client::BeginSelect(const Query& query) {
1336
+ impl_->BeginExecuteQuery(query);
1337
+ }
1338
+
1339
+ void Client::BeginSelect(const char* query)
1340
+ {
1341
+ BeginExecute(Query(query));
1342
+ }
1343
+
1344
+ void Client::BeginSelect(const std::string& query)
1345
+ {
1346
+ BeginExecute(Query(query));
1347
+ }
1348
+
1349
+ void Client::BeginSelect(const std::string& query, const std::string& query_id)
1350
+ {
1351
+ BeginExecute(Query(query, query_id));
1352
+ }
1353
+
1354
+ std::optional<Block> Client::NextBlock() {
1355
+ return impl_->NextBlock();
1356
+ }
1357
+
1358
+ void Client::Cancel()
1359
+ {
1360
+ impl_->Cancel();
1361
+ }
1362
+
1363
+ bool Client::IsSelecting() const
1364
+ {
1365
+ return impl_->IsSelecting();
1366
+ }
1367
+
1215
1368
  void Client::Insert(const std::string& table_name, const Block& block) {
1216
1369
  impl_->Insert(table_name, Query::default_query_id, block);
1217
1370
  }
@@ -1236,6 +1389,10 @@ void Client::EndInsert() {
1236
1389
  impl_->EndInsert();
1237
1390
  }
1238
1391
 
1392
+ bool Client::IsInserting() const {
1393
+ return impl_->IsInserting();
1394
+ }
1395
+
1239
1396
  void Client::Ping() {
1240
1397
  impl_->Ping();
1241
1398
  }