Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions clickhouse/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,10 @@ Block Client::Impl::BeginInsert(Query query) {
throw ValidationError("cannot execute query while executing another operation");
}

if (query.HasEventCallbacks()) {
throw ValidationError("Query callbacks are not supported in BeginInsert");
}

EnsureNull en(static_cast<QueryEvents*>(&query), &events_);

if (options_.ping_before_query) {
Expand All @@ -546,7 +550,7 @@ Block Client::Impl::BeginInsert(Query query) {
return true;
});

SendQuery(query.GetText());
SendQuery(query);

// Wait for a data packet and return
uint64_t server_packet = 0;
Expand Down Expand Up @@ -1373,8 +1377,8 @@ void Client::Insert(const std::string& table_name, const std::string& query_id,
impl_->Insert(table_name, query_id, block);
}

Block Client::BeginInsert(const std::string& query) {
return impl_->BeginInsert(Query(query));
Block Client::BeginInsert(const Query& query) {
return impl_->BeginInsert(query);
}

Block Client::BeginInsert(const std::string& query, const std::string& query_id) {
Expand Down
5 changes: 4 additions & 1 deletion clickhouse/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,10 @@ class Client {
void Insert(const std::string& table_name, const std::string& query_id, const Block& block);

/// Start an \p INSERT statement, insert batches of data, then finish the insert.
Block BeginInsert(const std::string& query);
/// A bare string converts to a Query implicitly; use BeginInsert(const Query&)
/// to pass per-insert settings, params, and query_id. Event callbacks on the
/// Query are rejected (throws ValidationError): BeginInsert owns the data path.
Block BeginInsert(const Query& query);
Block BeginInsert(const std::string& query, const std::string& query_id);

/// Insert data using a \p block returned by \p BeginInsert.
Expand Down
8 changes: 8 additions & 0 deletions clickhouse/query.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,14 @@ class Query : public QueryEvents {
return *this;
}

/// True if any server-event handler is installed. BeginInsert rejects such
/// a Query: it drives its own block-capture OnData and would otherwise let
/// the caller's handlers fire from the insert handshake's packet loop.
inline bool HasEventCallbacks() const {
return exception_cb_ || progress_cb_ || select_cb_ || select_cancelable_cb_
|| select_server_log_cb_ || profile_events_callback_cb_ || profile_callback_cb_;
}

static const std::string default_query_id;

private:
Expand Down
39 changes: 39 additions & 0 deletions ut/client_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,45 @@ TEST_P(ClientCase, InsertData) {
EXPECT_EQ(exp, row);
}

TEST_P(ClientCase, BeginInsertQuery) {
client_->Execute(
"CREATE TEMPORARY TABLE IF NOT EXISTS test_clickhouse_cpp_begin_insert_query (id UInt64)");

/// A Query carrying any event callback is rejected: BeginInsert drives its
/// own data path and the caller's handlers would otherwise fire from the
/// insert handshake's packet loop.
{
Query q("INSERT INTO test_clickhouse_cpp_begin_insert_query VALUES");
q.OnException([](const Exception&) {});
EXPECT_THROW(client_->BeginInsert(q), ValidationError);
}

/// A Query with per-insert settings and a query_id (no callbacks) streams
/// normally through the overload.
{
Query q("INSERT INTO test_clickhouse_cpp_begin_insert_query VALUES", "begin-insert-query-id");
q.SetSetting("max_block_size", {"100"});

auto block = client_->BeginInsert(q);
ASSERT_EQ(size_t(1), block.GetColumnCount());

auto id = block[0]->As<ColumnUInt64>();
id->Append(42);
block.RefreshRowCount();
client_->SendInsertBlock(block);
client_->EndInsert();
}

size_t row = 0;
client_->Select("SELECT id FROM test_clickhouse_cpp_begin_insert_query",
[&row](const Block& block) {
for (size_t c = 0; c < block.GetRowCount(); ++c, ++row) {
EXPECT_EQ(uint64_t(42), (*block[0]->As<ColumnUInt64>())[c]);
}
});
EXPECT_EQ(size_t(1), row);
}

TEST_P(ClientCase, Nullable) {
/// Create a table.
client_->Execute(
Expand Down
Loading