Repository: apache/arrow
File: cpp/src/parquet/column_writer.cc (C++)

Code before:
  if (array.null_count() != array.length()) {
    RETURN_NOT_OK(functor.Serialize(checked_cast<const ArrayType&>(array), ctx, buffer));
  }
  bool no_nulls =
      this->descr()->schema_node()->is_required() || (array.null_count() == 0);
  if (!maybe_parent_nulls && no_nulls) {
    PARQUET_CATCH_NOT_OK(WriteBatchInternal(num_levels, def_levels, rep_levels, buffer));
  } else {
    PARQUET_CATCH_NOT_OK(WriteBatchSpacedInternal(num_levels, def_levels, rep_levels,
                                                  array.null_bitmap_data(),
                                                  array.offset(), buffer));
  }
  return Status::OK();
}

#define WRITE_SERIALIZE_CASE(ArrowEnum)                                               \
  case ::arrow::Type::ArrowEnum: {                                                    \
    using ArrowType = typename ::arrow::TypeIdTraits<::arrow::Type::ArrowEnum>::Type; \
    return WriteArrowSerialize<ArrowType>(def_levels, rep_levels, num_levels, array,  \
                                          ctx, maybe_parent_nulls);                   \
  }

#define WRITE_ZERO_COPY_CASE(ArrowEnum)                                       \
  case ::arrow::Type::ArrowEnum:                                              \
    return WriteArrowZeroCopy(def_levels, rep_levels, num_levels, array, ctx, \
                              maybe_parent_nulls);

#define ARROW_UNSUPPORTED()                                          \
  std::stringstream ss;                                              \
  ss << "Arrow type " << array.type()->ToString()                    \
     << " cannot be written to Parquet type " << descr_->ToString(); \
  return Status::Invalid(ss.str());

// ----------------------------------------------------------------------
// Write Arrow to BooleanType

template <>
struct SerializeFunctor<BooleanType, ::arrow::BooleanType> {
  Status Serialize(const ::arrow::BooleanArray& data, ArrowWriteContext*, bool* out) {
    for (int64_t i = 0; i < data.length(); i++) {
      *out++ = data.Value(i);
    }
    return Status::OK();
  }
};

template <>
Status TypedColumnWriterImpl<BooleanType>::WriteArrowDense(
    const int16_t* def_levels, const int16_t* rep_levels, int64_t num_levels,
    const ::arrow::Array& array, ArrowWriteContext* ctx, bool maybe_parent_nulls) {
  if (array.type_id() != ::arrow::Type::BOOL) {

Review comment (bug):
In case of an invalid arrow array, value buffer can still be nullptr when `array.null_count() == array.length()` which crashes the following call.

Code after:
      for (int64_t i = 0; i < array.length(); i++) {
        out[i] = static_cast<ParquetCType>(input[i]);
      }
    } else {
      std::copy(input, input + array.length(), out);
    }
    return Status::OK();
  }
};

template <typename ParquetType>
template <typename ArrowType>
Status TypedColumnWriterImpl<ParquetType>::WriteArrowSerialize(
    const int16_t* def_levels, const int16_t* rep_levels, int64_t num_levels,
    const ::arrow::Array& array, ArrowWriteContext* ctx, bool maybe_parent_nulls) {
  using ArrayType = typename ::arrow::TypeTraits<ArrowType>::ArrayType;
  using ParquetCType = typename ParquetType::c_type;

  ParquetCType* buffer = nullptr;
  PARQUET_THROW_NOT_OK(ctx->GetScratchData<ParquetCType>(array.length(), &buffer));

  SerializeFunctor<ParquetType, ArrowType> functor;
  // The value buffer could be empty if all values are nulls.
  // The output buffer will then remain uninitialized, but that's ok since
  // null value slots are not written in Parquet.
  if (array.null_count() != array.length()) {
    RETURN_NOT_OK(functor.Serialize(checked_cast<const ArrayType&>(array), ctx, buffer));
  }
  bool no_nulls =
      this->descr()->schema_node()->is_required() || (array.null_count() == 0);
  if (!maybe_parent_nulls && no_nulls) {
    PARQUET_CATCH_NOT_OK(WriteBatchInternal(num_levels, def_levels, rep_levels, buffer));
  } else {
    PARQUET_CATCH_NOT_OK(WriteBatchSpacedInternal(num_levels, def_levels, rep_levels,
                                                  array.null_bitmap_data(),
                                                  array.offset(), buffer));
  }
  return Status::OK();
}

#define WRITE_SERIALIZE_CASE(ArrowEnum)                                               \
  case ::arrow::Type::ArrowEnum: {                                                    \
    using ArrowType = typename ::arrow::TypeIdTraits<::arrow::Type::ArrowEnum>::Type; \
    return WriteArrowSerialize<ArrowType>(def_levels, rep_levels, num_levels, array,  \
                                          ctx, maybe_parent_nulls);                   \
  }

#define WRITE_ZERO_COPY_CASE(ArrowEnum)                                       \
  case ::arrow::Type::ArrowEnum:                                              \
    return WriteArrowZeroCopy(def_levels, rep_levels, num_levels, array, ctx, \
                              maybe_parent_nulls);