This is an automated email from the ASF dual-hosted git repository.

kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new ce94fbabae GH-34823: [C++][ORC] Fix ORC CHAR type mapping (#34836)
ce94fbabae is described below

commit ce94fbabae53fb53fef600f224dd44fc69b713b4
Author: Gang Wu <[email protected]>
AuthorDate: Mon Apr 3 13:54:10 2023 +0800

    GH-34823: [C++][ORC] Fix ORC CHAR type mapping (#34836)
    
    ### Rationale for this change
    
    Currently the ORC CHAR type is mapped to Arrow FIXED_SIZE_BINARY type. 
However, the meaning of length differs between these types. The length of ORC 
CHAR type means number of UTF8 characters while that of Arrow FIXED_SIZE_BINARY 
means number of bytes.
    
    ### What changes are included in this PR?
    
    Use Arrow String type to read from ORC CHAR type.
    
    ### Are these changes tested?
    
    Make sure all tests pass.
    
    ### Are there any user-facing changes?
    
    Yes, the doc has been updated as well.
    * Closes: #34823
    
    Lead-authored-by: Gang Wu <[email protected]>
    Co-authored-by: Sutou Kouhei <[email protected]>
    Signed-off-by: Sutou Kouhei <[email protected]>
---
 cpp/src/arrow/adapters/orc/adapter_test.cc | 53 ++++++++++++++++++++++++++++++
 cpp/src/arrow/adapters/orc/util.cc         | 22 ++-----------
 docs/source/cpp/orc.rst                    |  9 +++--
 3 files changed, 61 insertions(+), 23 deletions(-)

diff --git a/cpp/src/arrow/adapters/orc/adapter_test.cc 
b/cpp/src/arrow/adapters/orc/adapter_test.cc
index ff194e945d..890e9e8972 100644
--- a/cpp/src/arrow/adapters/orc/adapter_test.cc
+++ b/cpp/src/arrow/adapters/orc/adapter_test.cc
@@ -453,6 +453,59 @@ TEST(TestAdapterRead, ReadIntAndStringFileMultipleStripes) 
{
   EXPECT_EQ(num_rows / reader_batch_size, batches);
 }
 
+TEST(TestAdapterRead, ReadCharAndVarcharType) {
+  MemoryOutputStream mem_stream(kDefaultMemStreamSize);
+  auto orc_type = 
liborc::Type::buildTypeFromString("struct<c1:char(6),c2:varchar(6)>");
+  auto writer = CreateWriter(/*stripe_size=*/1024, *orc_type, &mem_stream);
+
+  constexpr int64_t row_count = 2;
+  auto batch = writer->createRowBatch(row_count);
+  auto struct_batch = 
internal::checked_cast<liborc::StructVectorBatch*>(batch.get());
+
+  // Verify that longer data will be truncated by ORC char and varchar types.
+  // In addition, ORC char type will pad the data with spaces if the data is 
shorter.
+  const std::vector<std::string> data = {"abcd", "ABCDEFGH"};
+  const std::vector<std::vector<std::string>> expected_data = {{"abcd  ", 
"ABCDEF"},
+                                                               {"abcd", 
"ABCDEF"}};
+
+  for (uint64_t col = 0; col < orc_type->getSubtypeCount(); ++col) {
+    auto str_batch =
+        
internal::checked_cast<liborc::StringVectorBatch*>(struct_batch->fields[col]);
+    str_batch->hasNulls = false;
+    str_batch->numElements = row_count;
+    for (int64_t row = 0; row < row_count; ++row) {
+      str_batch->data[row] = const_cast<char*>(data[row].c_str());
+      str_batch->length[row] = static_cast<int64_t>(data[row].size());
+    }
+  }
+  batch->numElements = row_count;
+  writer->add(*batch);
+  writer->close();
+
+  std::shared_ptr<io::RandomAccessFile> 
in_stream(std::make_shared<io::BufferReader>(
+      reinterpret_cast<const uint8_t*>(mem_stream.getData()),
+      static_cast<int64_t>(mem_stream.getLength())));
+  ASSERT_OK_AND_ASSIGN(
+      auto reader, adapters::orc::ORCFileReader::Open(in_stream, 
default_memory_pool()));
+  ASSERT_EQ(row_count, reader->NumberOfRows());
+  ASSERT_EQ(1, reader->NumberOfStripes());
+
+  EXPECT_OK_AND_ASSIGN(auto stripe_reader, 
reader->NextStripeReader(row_count));
+  std::shared_ptr<RecordBatch> record_batch;
+  ASSERT_OK(stripe_reader->ReadNext(&record_batch));
+  ASSERT_NE(nullptr, record_batch);
+  ASSERT_EQ(row_count, record_batch->num_rows());
+
+  for (int col = 0; col < record_batch->num_columns(); ++col) {
+    auto str_array = 
checked_pointer_cast<StringArray>(record_batch->column(col));
+    for (int row = 0; row < row_count; ++row) {
+      EXPECT_EQ(expected_data[col][row], str_array->GetString(row));
+    }
+  }
+  ASSERT_OK(stripe_reader->ReadNext(&record_batch));
+  ASSERT_EQ(nullptr, record_batch);
+}
+
 // Trivial
 
 class TestORCWriterTrivialNoWrite : public ::testing::Test {};
diff --git a/cpp/src/arrow/adapters/orc/util.cc 
b/cpp/src/arrow/adapters/orc/util.cc
index 6e9f9a288b..d09ddb0d19 100644
--- a/cpp/src/arrow/adapters/orc/util.cc
+++ b/cpp/src/arrow/adapters/orc/util.cc
@@ -238,22 +238,6 @@ Status AppendBinaryBatch(liborc::ColumnVectorBatch* 
column_vector_batch, int64_t
   return Status::OK();
 }
 
-Status AppendFixedBinaryBatch(liborc::ColumnVectorBatch* column_vector_batch,
-                              int64_t offset, int64_t length, ArrayBuilder* 
abuilder) {
-  auto builder = checked_cast<FixedSizeBinaryBuilder*>(abuilder);
-  auto batch = checked_cast<liborc::StringVectorBatch*>(column_vector_batch);
-
-  const bool has_nulls = batch->hasNulls;
-  for (int64_t i = offset; i < length + offset; i++) {
-    if (!has_nulls || batch->notNull[i]) {
-      RETURN_NOT_OK(builder->Append(batch->data[i]));
-    } else {
-      RETURN_NOT_OK(builder->AppendNull());
-    }
-  }
-  return Status::OK();
-}
-
 Status AppendDecimalBatch(const liborc::Type* type,
                           liborc::ColumnVectorBatch* column_vector_batch, 
int64_t offset,
                           int64_t length, ArrayBuilder* abuilder) {
@@ -370,13 +354,12 @@ Status AppendBatch(const liborc::Type* type, 
liborc::ColumnVectorBatch* batch,
                                     double>(batch, offset, length, builder);
     case liborc::BOOLEAN:
       return AppendBoolBatch(batch, offset, length, builder);
+    case liborc::CHAR:
     case liborc::VARCHAR:
     case liborc::STRING:
       return AppendBinaryBatch<StringBuilder>(batch, offset, length, builder);
     case liborc::BINARY:
       return AppendBinaryBatch<BinaryBuilder>(batch, offset, length, builder);
-    case liborc::CHAR:
-      return AppendFixedBinaryBatch(batch, offset, length, builder);
     case liborc::DATE:
       return AppendNumericBatchCast<Date32Builder, int32_t, 
liborc::LongVectorBatch,
                                     int64_t>(batch, offset, length, builder);
@@ -1113,13 +1096,12 @@ Result<std::shared_ptr<DataType>> GetArrowType(const 
liborc::Type* type) {
       return float32();
     case liborc::DOUBLE:
       return float64();
+    case liborc::CHAR:
     case liborc::VARCHAR:
     case liborc::STRING:
       return utf8();
     case liborc::BINARY:
       return binary();
-    case liborc::CHAR:
-      return fixed_size_binary(static_cast<int>(type->getMaximumLength()));
     case liborc::TIMESTAMP:
       // Values of TIMESTAMP type are stored in the writer timezone in the Orc 
file.
       // Values are read back in the reader timezone. However, the writer 
timezone
diff --git a/docs/source/cpp/orc.rst b/docs/source/cpp/orc.rst
index 58f9fffc62..a9e5f02865 100644
--- a/docs/source/cpp/orc.rst
+++ b/docs/source/cpp/orc.rst
@@ -85,10 +85,10 @@ Here are a list of ORC types and mapped Arrow types.
 +-------------------+-----------------------------------+-----------+
 | DATE              | Date32                            |           |
 +-------------------+-----------------------------------+-----------+
-| VARCHAR           | String                            |           |
+| VARCHAR           | String                            | \(3)      |
++-------------------+-----------------------------------+-----------+
+| CHAR              | String                            | \(3)      |
 +-------------------+-----------------------------------+-----------+
-
-*Unsupported ORC types:* CHAR.
 
 * \(1) On the read side the ORC type is read as the first corresponding Arrow 
type in the table.
 
@@ -97,6 +97,9 @@ Here are a list of ORC types and mapped Arrow types.
   as the Arrow Timestamp type with :cpp:enumerator:`arrow::TimeUnit::NANO` and 
timezone is set to
   UTC for ORC TIMESTAMP_INSTANT type only.
 
+* \(3) On the read side both ORC CHAR and VARCHAR types are read as the Arrow 
String type. ORC CHAR
+  and VARCHAR types are not supported on the write side.
+
 Compression
 -----------
 

Reply via email to