@@ -295,4 +295,177 @@ bool ColumnarTable::read_batch(uint64_t start_row, uint32_t batch_size,
295295 return true ;
296296}
297297
298+ bool ColumnarTable::read_batch (uint64_t start_row, uint32_t batch_size,
299+ executor::VectorBatch& out_batch,
300+ const std::vector<size_t >& col_indices) {
301+ if (start_row >= row_count_) return false ;
302+ if (col_indices.empty ()) return false ;
303+
304+ uint32_t actual_rows =
305+ static_cast <uint32_t >(std::min (static_cast <uint64_t >(batch_size), row_count_ - start_row));
306+
307+ // out_batch is pre-initialized with the reduced schema by the caller
308+ // (VectorizedSeqScanOperator via set_required_columns)
309+
310+ for (size_t idx = 0 ; idx < col_indices.size (); ++idx) {
311+ size_t col_idx = col_indices[idx];
312+ const std::string base = name_ + " .col" + std::to_string (col_idx);
313+ std::ifstream n_in (storage_manager_.get_full_path (base + " .nulls.bin" ), std::ios::binary);
314+ std::ifstream d_in (storage_manager_.get_full_path (base + " .data.bin" ), std::ios::binary);
315+ if (!n_in.is_open () || !d_in.is_open ()) return false ;
316+
317+ auto & target_col = out_batch.get_column (idx);
318+ const auto type = schema_.get_column (col_idx).type ();
319+
320+ if (type == common::ValueType::TYPE_INT64 ) {
321+ auto & num_vec = dynamic_cast <executor::NumericVector<int64_t >&>(target_col);
322+
323+ n_in.seekg (static_cast <std::streamoff>(start_row), std::ios::beg);
324+ std::vector<uint8_t > nulls (actual_rows);
325+ n_in.read (reinterpret_cast <char *>(nulls.data ()), actual_rows);
326+
327+ d_in.seekg (static_cast <std::streamoff>(start_row * 8 ), std::ios::beg);
328+ std::vector<int64_t > data (actual_rows);
329+ d_in.read (reinterpret_cast <char *>(data.data ()), actual_rows * 8 );
330+
331+ for (uint32_t r = 0 ; r < actual_rows; ++r) {
332+ if (nulls[r] != 0U ) {
333+ num_vec.append (common::Value::make_null ());
334+ } else {
335+ num_vec.append (common::Value::make_int64 (data[r]));
336+ }
337+ }
338+ } else if (type == common::ValueType::TYPE_INT32 || type == common::ValueType::TYPE_INT16 ||
339+ type == common::ValueType::TYPE_INT8 ) {
340+ auto & num_vec = dynamic_cast <executor::NumericVector<int64_t >&>(target_col);
341+
342+ n_in.seekg (static_cast <std::streamoff>(start_row), std::ios::beg);
343+ std::vector<uint8_t > nulls (actual_rows);
344+ n_in.read (reinterpret_cast <char *>(nulls.data ()), actual_rows);
345+
346+ d_in.seekg (static_cast <std::streamoff>(start_row * 8 ), std::ios::beg);
347+ std::vector<int64_t > data (actual_rows);
348+ d_in.read (reinterpret_cast <char *>(data.data ()), actual_rows * 8 );
349+
350+ for (uint32_t r = 0 ; r < actual_rows; ++r) {
351+ if (nulls[r] != 0U ) {
352+ num_vec.append (common::Value::make_null ());
353+ } else if (type == common::ValueType::TYPE_INT32 ) {
354+ num_vec.append (common::Value (static_cast <int32_t >(data[r])));
355+ } else if (type == common::ValueType::TYPE_INT16 ) {
356+ num_vec.append (common::Value (static_cast <int16_t >(data[r])));
357+ } else {
358+ num_vec.append (common::Value (static_cast <int8_t >(data[r])));
359+ }
360+ }
361+ } else if (type == common::ValueType::TYPE_FLOAT64 ) {
362+ auto & num_vec = dynamic_cast <executor::NumericVector<double >&>(target_col);
363+
364+ n_in.seekg (static_cast <std::streamoff>(start_row), std::ios::beg);
365+ std::vector<uint8_t > nulls (actual_rows);
366+ n_in.read (reinterpret_cast <char *>(nulls.data ()), actual_rows);
367+
368+ d_in.seekg (static_cast <std::streamoff>(start_row * 8 ), std::ios::beg);
369+ std::vector<double > data (actual_rows);
370+ d_in.read (reinterpret_cast <char *>(data.data ()), actual_rows * 8 );
371+
372+ for (uint32_t r = 0 ; r < actual_rows; ++r) {
373+ if (nulls[r] != 0U ) {
374+ num_vec.append (common::Value::make_null ());
375+ } else {
376+ num_vec.append (common::Value::make_float64 (data[r]));
377+ }
378+ }
379+ } else if (type == common::ValueType::TYPE_FLOAT32 ) {
380+ auto & num_vec = dynamic_cast <executor::NumericVector<float >&>(target_col);
381+
382+ n_in.seekg (static_cast <std::streamoff>(start_row), std::ios::beg);
383+ std::vector<uint8_t > nulls (actual_rows);
384+ n_in.read (reinterpret_cast <char *>(nulls.data ()), actual_rows);
385+
386+ d_in.seekg (static_cast <std::streamoff>(start_row * 8 ), std::ios::beg);
387+ std::vector<double > data (actual_rows);
388+ d_in.read (reinterpret_cast <char *>(data.data ()), actual_rows * 8 );
389+
390+ for (uint32_t r = 0 ; r < actual_rows; ++r) {
391+ if (nulls[r] != 0U ) {
392+ num_vec.append (common::Value::make_null ());
393+ } else {
394+ num_vec.append (common::Value (static_cast <float >(data[r])));
395+ }
396+ }
397+ } else if (type == common::ValueType::TYPE_DECIMAL ) {
398+ auto & num_vec = dynamic_cast <executor::NumericVector<double >&>(target_col);
399+
400+ n_in.seekg (static_cast <std::streamoff>(start_row), std::ios::beg);
401+ std::vector<uint8_t > nulls (actual_rows);
402+ n_in.read (reinterpret_cast <char *>(nulls.data ()), actual_rows);
403+
404+ d_in.seekg (static_cast <std::streamoff>(start_row * 8 ), std::ios::beg);
405+ std::vector<double > data (actual_rows);
406+ d_in.read (reinterpret_cast <char *>(data.data ()), actual_rows * 8 );
407+
408+ for (uint32_t r = 0 ; r < actual_rows; ++r) {
409+ if (nulls[r] != 0U ) {
410+ num_vec.append (common::Value::make_null ());
411+ } else {
412+ num_vec.append (common::Value::make_float64 (data[r]));
413+ }
414+ }
415+ } else if (type == common::ValueType::TYPE_BOOL ) {
416+ auto & num_vec = dynamic_cast <executor::NumericVector<bool >&>(target_col);
417+
418+ n_in.seekg (static_cast <std::streamoff>(start_row), std::ios::beg);
419+ std::vector<uint8_t > nulls (actual_rows);
420+ n_in.read (reinterpret_cast <char *>(nulls.data ()), actual_rows);
421+
422+ d_in.seekg (static_cast <std::streamoff>(start_row), std::ios::beg);
423+ std::vector<uint8_t > data (actual_rows);
424+ d_in.read (reinterpret_cast <char *>(data.data ()), actual_rows);
425+
426+ for (uint32_t r = 0 ; r < actual_rows; ++r) {
427+ if (nulls[r] != 0U ) {
428+ num_vec.append (common::Value::make_null ());
429+ } else {
430+ num_vec.append (common::Value (data[r] != 0 ));
431+ }
432+ }
433+ } else if (type == common::ValueType::TYPE_TEXT ||
434+ type == common::ValueType::TYPE_VARCHAR ||
435+ type == common::ValueType::TYPE_CHAR ) {
436+ auto & str_vec = dynamic_cast <executor::StringVector&>(target_col);
437+
438+ n_in.seekg (static_cast <std::streamoff>(start_row), std::ios::beg);
439+ std::vector<uint8_t > nulls (actual_rows);
440+ n_in.read (reinterpret_cast <char *>(nulls.data ()), actual_rows);
441+
442+ if (start_row > 0 ) {
443+ for (uint32_t r = 0 ; r < start_row; ++r) {
444+ uint32_t len = 0 ;
445+ if (!d_in.read (reinterpret_cast <char *>(&len), 4 )) break ;
446+ if (len > 0 ) {
447+ d_in.seekg (static_cast <std::streamoff>(len), std::ios::cur);
448+ }
449+ }
450+ }
451+
452+ for (uint32_t r = 0 ; r < actual_rows; ++r) {
453+ uint32_t len = 0 ;
454+ d_in.read (reinterpret_cast <char *>(&len), 4 );
455+ std::string s (len, ' \0 ' );
456+ d_in.read (s.data (), len);
457+ if (nulls[r] != 0U ) {
458+ str_vec.append (common::Value::make_null ());
459+ } else {
460+ str_vec.append (common::Value::make_text (s));
461+ }
462+ }
463+ } else {
464+ throw std::runtime_error (" ColumnarTable::read_batch(col_indices): Unsupported type " +
465+ std::to_string (static_cast <int >(type)));
466+ }
467+ }
468+ out_batch.set_row_count (actual_rows);
469+ return true ;
470+ }
298471} // namespace cloudsql::storage
0 commit comments