| 235 | } |
| 236 | |
| 237 | std::optional<Chunk> StreamingExchangeSource::tryGenerate() |
| 238 | { |
| 239 | if (!was_on_start_called) |
| 240 | { |
| 241 | was_on_start_called = true; |
| 242 | onStart(); |
| 243 | return Chunk(); /// Empty chunk means we need to be called again |
| 244 | } |
| 245 | |
| 246 | if (output_finished) |
| 247 | { |
| 248 | LOG_TRACE(log, "NoMoreDataNeeded from exchange stream {}, total rows: {}, bytes: {}", stream_name, rows_read, bytes_read); |
| 249 | |
| 250 | sendNoMoreDataNeeded(); |
| 251 | finished_reading = true; |
| 252 | return {}; |
| 253 | } |
| 254 | |
| 255 | LOG_TEST(log, "Reading from exchange stream {}", stream_name); |
| 256 | |
| 257 | if (packet_receive_state == ReceivingHeader) |
| 258 | tryReadHeader(); |
| 259 | |
| 260 | if (packet_receive_state == ReceivingBody) |
| 261 | tryReadBody(); |
| 262 | |
| 263 | /// If a whole packet has been read, we can parse it. |
| 264 | if (!packet_in) |
| 265 | return Chunk(); /// Empty chunk means that we currently heve no data but we have not finished yet. |
| 266 | |
| 267 | UInt64 flags = 0; |
| 268 | readVarUInt(flags, *packet_in); |
| 269 | const bool final_chunk = (flags & 1); |
| 270 | const bool has_aggregated_chunk_info = (flags & 2); |
| 271 | UInt64 num_rows = 0; |
| 272 | readVarUInt(num_rows, *packet_in); |
| 273 | UInt64 num_columns = 0; |
| 274 | readVarUInt(num_columns, *packet_in); |
| 275 | UInt64 chunk_num = 0; |
| 276 | if (has_aggregated_chunk_info) |
| 277 | readVarUInt(chunk_num, *packet_in); |
| 278 | |
| 279 | /// The final packet is the empty end-of-stream marker. A final packet carrying rows would have |
| 280 | /// them dropped once finished_reading is set, so reject it as a protocol violation. |
| 281 | if (final_chunk && num_rows != 0) |
| 282 | throw Exception(ErrorCodes::UNEXPECTED_PACKET_FROM_CLIENT, |
| 283 | "Final data packet on exchange stream {} carries {} rows; it must be empty", stream_name, num_rows); |
| 284 | |
| 285 | /// A data packet must carry exactly the header's columns, or values would be dropped while the |
| 286 | /// row count is kept. A header-less stream (e.g. SELECT count()) sends rows with zero columns. |
| 287 | const size_t expected_columns = output.getHeader().columns(); |
| 288 | if (num_rows != 0 && num_columns != expected_columns) |
| 289 | throw Exception(ErrorCodes::UNEXPECTED_PACKET_FROM_CLIENT, |
| 290 | "Data packet on exchange stream {} carries {} rows with {} columns, but the stream header has {} columns", |
| 291 | stream_name, num_rows, num_columns, expected_columns); |
| 292 | |
| 293 | std::optional<Chunk> result; |
| 294 | if (num_columns != 0) |
nothing calls this directly
no test coverage detected