ClickHouse / clickhouse-cpp

C++ client library for ClickHouse
Apache License 2.0
306 stars 159 forks source link

Select query returns block.GetRowCount() as 0 although there are two rows in the database. #373

Closed neeravbm closed 6 months ago

neeravbm commented 6 months ago

I have the following code:

`

client.Select("SELECT * FROM tasks", [&taskId, &env, &error, &reset, &taskName, &detailsStr](const clickhouse::Block &block) {
    if (block.GetRowCount() == 0) {
        std::cout << error << "Task with id " << taskId << " is not present in the " << env << " database" << reset << std::endl;
        exit (-1);
    }

    taskName = block[1]->As<clickhouse::ColumnString>()->At(0);
    detailsStr = block[2]->As<clickhouse::ColumnString>()->At(0);
});

`

There are two rows in the task table. If I execute the same query via clickhouse client, I get the following result:

`

┌─────────id─┬─name──────────────────┬─details────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐

  1. │ 1714853690 │ collect_strategy_data │ {"asset":"future","end_time":"23:59","params":{"PT":{"type":0,"values":[10.0]},"SL":{"type":0,"values":[5.0]},"closeEOD":{"type":0,"values":[false]},"emaPeriod":{"type":0,"values":[40]},"minGapBars":{"type":0,"values":[55]},"strategyDirection":{"type":0,"values":[0]},"validQuarters":{"type":0,"values":[[]]},"validSetupMinutesInDay":{"type":0,"values":[[]]}},"period":1,"start_time":"00:00","strategy":"EMATouchAfterGapLimitEntryAtEMAFixedSLFixedPT","ticker":"ES"} │
  2. │ 1714860605 │ collect_strategy_data │ {"asset":"future","end_time":"23:59","params":{"PT":{"type":0,"values":[10.0]},"SL":{"type":0,"values":[5.0]},"closeEOD":{"type":0,"values":[false]},"emaPeriod":{"type":0,"values":[40]},"minGapBars":{"type":0,"values":[55]},"strategyDirection":{"type":0,"values":[0]},"validQuarters":{"type":0,"values":[[]]},"validSetupMinutesInDay":{"type":0,"values":[[]]}},"period":1,"start_time":"00:00","strategy":"EMATouchAfterGapLimitEntryAtEMAFixedSLFixedPT","ticker":"NQ"} │ └────────────┴───────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ `

The issue seems to be the following lines in the file client.cpp (line 617):

`

if (!WireFormat::ReadUInt64(input, &num_columns)) {
    return false;
}
if (!WireFormat::ReadUInt64(input, &num_rows)) {
    return false;
}

`

num_columns is set to 3 as expected but num_rows is set to 0.

I put a breakpoint and inspected the memory of input->arrayinput->data_.

Screenshot 2024-05-04 at 11 18 45 PM

The first line shows 03 at position 0x14c00c40a. This corresponds to num_columns. The next address has value 0 and based on the code, it should be equal to num_rows. But it's set to 0 instead of 2. As a result, num_rows is being set as 0 instead of 2. If you look at the values in memory, 2 is present in the next 4 bytes but I believe that corresponds to the length of the first column name and not num_rows.

1261385937 commented 6 months ago

@neeravbm 。 No problem here. The callback may be called more than once. Your code should like this:

client.Select("SELECT * FROM tasks", [&taskId, &env, &error, &reset, &taskName, &detailsStr](const clickhouse::Block &block) {
    if (block.GetRowCount() == 0) {
      return;
    }
    taskName = block[1]->As<clickhouse::ColumnString>()->At(0);
    detailsStr = block[2]->As<clickhouse::ColumnString>()->At(0);
});
neeravbm commented 6 months ago

@1261385937 It worked. Thanks! I think it'll be useful to update the example in README to reflect this.