| 624 | } |
| 625 | |
| 626 | Status WriteHeader() { |
| 627 | // Only called once, as part of initialization |
| 628 | RETURN_NOT_OK(data_buffer_->Resize(CalculateHeaderSize(options_.quoting_header), |
| 629 | /*shrink_to_fit=*/false)); |
| 630 | char* next = reinterpret_cast<char*>(data_buffer_->mutable_data()); |
| 631 | for (int col = 0; col < schema_->num_fields(); ++col) { |
| 632 | const std::string& col_name = schema_->field(col)->name(); |
| 633 | switch (options_.quoting_header) { |
| 634 | case QuotingStyle::None: |
| 635 | if (StopAtStructuralChar(reinterpret_cast<const uint8_t*>(col_name.c_str()), |
| 636 | col_name.length(), options_.delimiter) != |
| 637 | static_cast<int64_t>(col_name.length())) { |
| 638 | return Status::Invalid( |
| 639 | "CSV header may not contain structural characters if quoting style is " |
| 640 | "\"None\". See RFC4180. Invalid value: ", |
| 641 | col_name); |
| 642 | } |
| 643 | memcpy(next, col_name.data(), col_name.size()); |
| 644 | next += col_name.size(); |
| 645 | break; |
| 646 | case QuotingStyle::Needed: |
| 647 | case QuotingStyle::AllValid: |
| 648 | // QuotingStyle::Needed is defined as always quoting string/binary data, |
| 649 | // regardless of whether it contains structural chars. |
| 650 | // We use consistent semantics for header names, which are strings. |
| 651 | *next++ = '"'; |
| 652 | next = Escape(schema_->field(col)->name(), next); |
| 653 | *next++ = '"'; |
| 654 | break; |
| 655 | } |
| 656 | if (col != schema_->num_fields() - 1) { |
| 657 | *next++ = options_.delimiter; |
| 658 | } |
| 659 | } |
| 660 | memcpy(next, options_.eol.data(), options_.eol.size()); |
| 661 | next += options_.eol.size(); |
| 662 | DCHECK_EQ(reinterpret_cast<uint8_t*>(next), |
| 663 | data_buffer_->data() + data_buffer_->size()); |
| 664 | return FlushToSink(); |
| 665 | } |
| 666 | |
| 667 | Status TranslateMinimalBatch(const RecordBatch& batch) { |
| 668 | if (batch.num_rows() == 0) { |
no test coverage detected