clickhouse-native 0.8.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.
- checksums.yaml +4 -4
- data/ext/clickhouse_native/client.cpp +112 -28
- data/ext/clickhouse_native/extconf.rb +30 -3
- data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/bazel.yml +120 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/cross-repo-bug-relay.yml +17 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/linux.yml +22 -23
- data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/macos.yml +22 -21
- data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/windows_mingw.yml +29 -36
- data/ext/clickhouse_native/vendor/clickhouse-cpp/.github/workflows/windows_msvc.yml +29 -36
- data/ext/clickhouse_native/vendor/clickhouse-cpp/.gitignore +6 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/AI_POLICY.md +13 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/BUILD.bazel +167 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/CMakeLists.txt +2 -1
- data/ext/clickhouse_native/vendor/clickhouse-cpp/MODULE.bazel +17 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/MODULE.bazel.lock +503 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/README.md +32 -6
- data/ext/clickhouse_native/vendor/clickhouse-cpp/ci/docker-compose/config.xml +53 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/ci/docker-compose/users.xml +35 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/ci/docker-compose.yml +22 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/CMakeLists.txt +11 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/base/sslsocket.cpp +24 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/block.cpp +1 -1
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/block.h +2 -1
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/client.cpp +293 -136
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/client.h +31 -2
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/array.cpp +12 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/array.h +17 -7
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/bool.cpp +79 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/bool.h +62 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/factory.cpp +16 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/itemview.cpp +2 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/itemview.h +6 -2
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/json.cpp +102 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/json.h +82 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/lowcardinality.cpp +2 -1
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/string.cpp +7 -2
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/tuple.cpp +48 -5
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/columns/tuple.h +14 -1
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/query.h +2 -2
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/server_exception.h +0 -3
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/types/type_parser.cpp +43 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/types/type_parser.h +9 -0
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/types/types.cpp +61 -11
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/types/types.h +18 -2
- data/ext/clickhouse_native/vendor/clickhouse-cpp/clickhouse/version.h +1 -1
- data/lib/clickhouse_native/logging.rb +4 -4
- data/lib/clickhouse_native/pool.rb +8 -8
- data/lib/clickhouse_native/version.rb +1 -1
- data/lib/clickhouse_native.rb +1 -0
- metadata +15 -2
|
@@ -8,10 +8,12 @@
|
|
|
8
8
|
|
|
9
9
|
#include "columns/factory.h"
|
|
10
10
|
|
|
11
|
-
#include <
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
356
|
+
if (state_ == State::Inserting) {
|
|
357
|
+
EndInsert();
|
|
358
|
+
}
|
|
294
359
|
} catch (...) {
|
|
295
360
|
}
|
|
296
361
|
}
|
|
297
362
|
|
|
298
|
-
void Client::Impl::
|
|
299
|
-
if (
|
|
300
|
-
throw ValidationError("cannot execute query while
|
|
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
|
-
|
|
372
|
+
query_ = query;
|
|
373
|
+
events_ = static_cast<QueryEvents*>(&query_);
|
|
374
|
+
state_ = State::Selecting;
|
|
310
375
|
|
|
311
|
-
|
|
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
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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
|
-
|
|
323
|
-
|
|
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
|
-
|
|
329
|
-
|
|
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
|
-
|
|
333
|
-
|
|
334
|
-
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
424
|
-
throw ValidationError("cannot execute query while
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
457
|
-
throw ValidationError("illegal
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
589
|
+
state_ = State::Idle;
|
|
483
590
|
}
|
|
484
591
|
|
|
485
592
|
void Client::Impl::Ping() {
|
|
486
|
-
if (
|
|
487
|
-
throw ValidationError("cannot execute query while
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
691
|
+
Block ret{};
|
|
692
|
+
if (!ReceiveData(ret)) {
|
|
585
693
|
throw ProtocolError("can't read data packet from input stream");
|
|
586
694
|
}
|
|
587
|
-
return
|
|
695
|
+
return ret;
|
|
588
696
|
}
|
|
589
697
|
|
|
590
698
|
case ServerCodes::Exception: {
|
|
591
|
-
|
|
592
|
-
|
|
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
|
|
707
|
+
Profile ret{};
|
|
597
708
|
|
|
598
|
-
if (!WireFormat::ReadUInt64(*input_, &
|
|
599
|
-
return
|
|
709
|
+
if (!WireFormat::ReadUInt64(*input_, &ret.rows)) {
|
|
710
|
+
return {};
|
|
600
711
|
}
|
|
601
|
-
if (!WireFormat::ReadUInt64(*input_, &
|
|
602
|
-
return
|
|
712
|
+
if (!WireFormat::ReadUInt64(*input_, &ret.blocks)) {
|
|
713
|
+
return {};
|
|
603
714
|
}
|
|
604
|
-
if (!WireFormat::ReadUInt64(*input_, &
|
|
605
|
-
return
|
|
715
|
+
if (!WireFormat::ReadUInt64(*input_, &ret.bytes)) {
|
|
716
|
+
return {};
|
|
606
717
|
}
|
|
607
|
-
if (!WireFormat::ReadFixed(*input_, &
|
|
608
|
-
return
|
|
718
|
+
if (!WireFormat::ReadFixed(*input_, &ret.applied_limit)) {
|
|
719
|
+
return {};
|
|
609
720
|
}
|
|
610
|
-
if (!WireFormat::ReadUInt64(*input_, &
|
|
611
|
-
return
|
|
721
|
+
if (!WireFormat::ReadUInt64(*input_, &ret.rows_before_limit)) {
|
|
722
|
+
return {};
|
|
612
723
|
}
|
|
613
|
-
if (!WireFormat::ReadFixed(*input_, &
|
|
614
|
-
return
|
|
724
|
+
if (!WireFormat::ReadFixed(*input_, &ret.calculated_rows_before_limit)) {
|
|
725
|
+
return {};
|
|
615
726
|
}
|
|
616
727
|
|
|
617
728
|
if (events_) {
|
|
618
|
-
events_->OnProfile(
|
|
729
|
+
events_->OnProfile(ret);
|
|
619
730
|
}
|
|
620
731
|
|
|
621
|
-
return
|
|
732
|
+
return ret;
|
|
622
733
|
}
|
|
623
734
|
|
|
624
735
|
case ServerCodes::Progress: {
|
|
625
|
-
Progress
|
|
736
|
+
Progress ret{};
|
|
626
737
|
|
|
627
|
-
if (!WireFormat::ReadUInt64(*input_, &
|
|
628
|
-
return
|
|
738
|
+
if (!WireFormat::ReadUInt64(*input_, &ret.rows)) {
|
|
739
|
+
return {};
|
|
629
740
|
}
|
|
630
|
-
if (!WireFormat::ReadUInt64(*input_, &
|
|
631
|
-
return
|
|
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_, &
|
|
635
|
-
return
|
|
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_, &
|
|
641
|
-
return
|
|
751
|
+
if (!WireFormat::ReadUInt64(*input_, &ret.written_rows)) {
|
|
752
|
+
return {};
|
|
642
753
|
}
|
|
643
|
-
if (!WireFormat::ReadUInt64(*input_, &
|
|
644
|
-
return
|
|
754
|
+
if (!WireFormat::ReadUInt64(*input_, &ret.written_bytes)) {
|
|
755
|
+
return {};
|
|
645
756
|
}
|
|
646
757
|
}
|
|
647
758
|
|
|
648
759
|
if (events_) {
|
|
649
|
-
events_->OnProgress(
|
|
760
|
+
events_->OnProgress(ret);
|
|
650
761
|
}
|
|
651
762
|
|
|
652
|
-
return
|
|
763
|
+
return ret;
|
|
653
764
|
}
|
|
654
765
|
|
|
655
766
|
case ServerCodes::Pong: {
|
|
656
|
-
return
|
|
767
|
+
return Pong{};
|
|
657
768
|
}
|
|
658
769
|
|
|
659
770
|
case ServerCodes::Hello: {
|
|
660
|
-
return
|
|
771
|
+
return Hello{};
|
|
661
772
|
}
|
|
662
773
|
|
|
663
774
|
case ServerCodes::EndOfStream: {
|
|
664
775
|
if (events_) {
|
|
665
776
|
events_->OnFinish();
|
|
666
777
|
}
|
|
667
|
-
return
|
|
778
|
+
return EndOfStream{};
|
|
668
779
|
}
|
|
669
780
|
|
|
670
781
|
case ServerCodes::Log: {
|
|
671
782
|
// log tag
|
|
672
783
|
if (!WireFormat::SkipString(*input_)) {
|
|
673
|
-
return
|
|
784
|
+
return {};
|
|
674
785
|
}
|
|
675
|
-
|
|
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
|
|
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
|
|
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
|
|
802
|
+
return {};
|
|
692
803
|
}
|
|
693
804
|
|
|
694
805
|
// columns metadata
|
|
695
806
|
if (!WireFormat::SkipString(*input_)) {
|
|
696
|
-
return
|
|
807
|
+
return {};
|
|
697
808
|
}
|
|
698
|
-
return
|
|
809
|
+
return TableColumns{};
|
|
699
810
|
}
|
|
700
811
|
|
|
701
812
|
case ServerCodes::ProfileEvents: {
|
|
702
813
|
if (!WireFormat::SkipString(*input_)) {
|
|
703
|
-
return
|
|
814
|
+
return {};
|
|
704
815
|
}
|
|
705
816
|
|
|
706
|
-
|
|
707
|
-
if (!ReadBlock(*input_, &block)) {
|
|
708
|
-
return
|
|
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
|
|
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
|
-
|
|
829
|
-
|
|
830
|
-
bool exception_received = true;
|
|
831
|
-
do {
|
|
832
|
-
bool has_nested = false;
|
|
833
|
-
|
|
834
|
-
if (!WireFormat::ReadFixed(*input_, ¤t->code)) {
|
|
835
|
-
exception_received = false;
|
|
836
|
-
break;
|
|
837
|
-
}
|
|
838
|
-
if (!WireFormat::ReadString(*input_, ¤t->name)) {
|
|
839
|
-
exception_received = false;
|
|
840
|
-
break;
|
|
841
|
-
}
|
|
842
|
-
if (!WireFormat::ReadString(*input_, ¤t->display_text)) {
|
|
843
|
-
exception_received = false;
|
|
844
|
-
break;
|
|
845
|
-
}
|
|
846
|
-
if (!WireFormat::ReadString(*input_, ¤t->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
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
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
|
}
|