ColumnarResults::ColumnarResults(const std::shared_ptr<RowSetMemoryOwner> row_set_mem_owner, const ResultSet& rows, const size_t num_columns, const std::vector<SQLTypeInfo>& target_types) : column_buffers_(num_columns), num_rows_(use_parallel_algorithms(rows) ? rows.entryCount() : rows.rowCount()), target_types_(target_types) { column_buffers_.resize(num_columns); for (size_t i = 0; i < num_columns; ++i) { const bool is_varlen = target_types[i].is_array() || (target_types[i].is_string() && target_types[i].get_compression() == kENCODING_NONE); if (is_varlen) { throw ColumnarConversionNotSupported(); } column_buffers_[i] = reinterpret_cast<const int8_t*>(checked_malloc(num_rows_ * target_types[i].get_size())); row_set_mem_owner->addColBuffer(column_buffers_[i]); } std::atomic<size_t> row_idx{0}; const auto do_work = [num_columns, &target_types, this](const std::vector<TargetValue>& crt_row, const size_t row_idx) { for (size_t i = 0; i < num_columns; ++i) { const auto col_val = crt_row[i]; const auto scalar_col_val = boost::get<ScalarTargetValue>(&col_val); CHECK(scalar_col_val); auto i64_p = boost::get<int64_t>(scalar_col_val); const auto& type_info = target_types[i]; if (i64_p) { const auto val = fixed_encoding_nullable_val(*i64_p, type_info); switch (target_types[i].get_size()) { case 1: ((int8_t*)column_buffers_[i])[row_idx] = static_cast<int8_t>(val); break; case 2: ((int16_t*)column_buffers_[i])[row_idx] = static_cast<int16_t>(val); break; case 4: ((int32_t*)column_buffers_[i])[row_idx] = static_cast<int32_t>(val); break; case 8: ((int64_t*)column_buffers_[i])[row_idx] = val; break; default: CHECK(false); } } else { CHECK(target_types[i].is_fp()); switch (target_types[i].get_type()) { case kFLOAT: { auto float_p = boost::get<float>(scalar_col_val); ((float*)column_buffers_[i])[row_idx] = static_cast<float>(*float_p); break; } case kDOUBLE: { auto double_p = boost::get<double>(scalar_col_val); ((double*)column_buffers_[i])[row_idx] = static_cast<double>(*double_p); break; } default: CHECK(false); } } } }; if (use_parallel_algorithms(rows)) { const size_t worker_count = cpu_threads(); std::vector<std::future<void>> conversion_threads; const auto entry_count = rows.entryCount(); for (size_t i = 0, start_entry = 0, stride = (entry_count + worker_count - 1) / worker_count; i < worker_count && start_entry < entry_count; ++i, start_entry += stride) { const auto end_entry = std::min(start_entry + stride, entry_count); conversion_threads.push_back(std::async(std::launch::async, [&rows, &do_work, &row_idx](const size_t start, const size_t end) { for (size_t i = start; i < end; ++i) { const auto crt_row = rows.getRowAtNoTranslations(i); if (!crt_row.empty()) { do_work(crt_row, row_idx.fetch_add(1)); } } }, start_entry, end_entry)); } for (auto& child : conversion_threads) { child.wait(); } for (auto& child : conversion_threads) { child.get(); } num_rows_ = row_idx; rows.setCachedRowCount(num_rows_); return; } while (true) { const auto crt_row = rows.getNextRow(false, false); if (crt_row.empty()) { break; } do_work(crt_row, row_idx); ++row_idx; } rows.moveToBegin(); }