blob: 2460c0a0051978dcd9f6c262cf594b29d349d80c [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "iceberg/row/manifest_wrapper.h"
#include <iterator>
#include <map>
#include <memory>
#include <span>
#include <type_traits>
#include <vector>
#include "iceberg/manifest/manifest_reader_internal.h"
#include "iceberg/util/macros.h"
namespace iceberg {
namespace {
enum class DataFileFieldPosition : size_t {
kContent = 0,
kFilePath = 1,
kFileFormat = 2,
kSpecId = 3,
kPartition = 4,
kRecordCount = 5,
kFileSize = 6,
kColumnSizes = 7,
kValueCounts = 8,
kNullValueCounts = 9,
kNanValueCounts = 10,
kLowerBounds = 11,
kUpperBounds = 12,
kKeyMetadata = 13,
kSplitOffsets = 14,
kEqualityIds = 15,
kSortOrderId = 16,
kFirstRowId = 17,
kReferencedDataFile = 18,
kContentOffset = 19,
kContentSize = 20,
kNextUnusedId = 21,
};
template <typename T>
requires std::is_same_v<T, std::vector<uint8_t>> || std::is_same_v<T, std::string>
std::string_view ToView(const T& value) {
return {reinterpret_cast<const char*>(value.data()), value.size()}; // NOLINT
}
Scalar ToScalar(const int32_t value) { return value; }
Scalar ToScalar(const int64_t value) { return value; }
Scalar ToScalar(const std::vector<uint8_t>& value) { return ToView(value); }
template <typename T>
Result<Scalar> FromOptional(const std::optional<T>& value) {
if (value.has_value()) {
return value.value();
}
return std::monostate{};
}
Result<Scalar> FromOptionalString(const std::optional<std::string>& value) {
if (value.has_value()) {
return ToView(value.value());
}
return std::monostate{};
}
template <typename T>
class VectorArrayLike : public ArrayLike {
public:
explicit VectorArrayLike(std::span<const T> values) : values_(values) {}
Result<Scalar> GetElement(size_t pos) const override {
if (pos >= size()) {
return InvalidArgument("Invalid array index: {}", pos);
}
return ToScalar(values_[pos]);
}
size_t size() const override { return values_.size(); }
private:
std::span<const T> values_;
};
template <typename V>
class IntMapLike : public MapLike {
public:
explicit IntMapLike(const std::map<int32_t, V>& values) : values_(values) {}
Result<Scalar> GetKey(size_t pos) const override {
if (pos >= size()) {
return InvalidArgument("Invalid map index: {}", pos);
}
return std::next(values_.get().cbegin(), pos)->first;
}
Result<Scalar> GetValue(size_t pos) const override {
if (pos >= size()) {
return InvalidArgument("Invalid map index: {}", pos);
}
return ToScalar(std::next(values_.get().cbegin(), pos)->second);
}
size_t size() const override { return values_.get().size(); }
private:
std::reference_wrapper<const std::map<int32_t, V>> values_;
};
template <typename V>
Result<Scalar> FromOptionalMap(const std::map<int32_t, V>& values) {
if (values.empty()) {
return std::monostate{};
}
return std::make_shared<IntMapLike<V>>(values);
}
template <typename T>
Result<Scalar> FromOptionalVector(const std::vector<T>& values) {
if (values.empty()) {
return std::monostate{};
}
return std::make_shared<VectorArrayLike<T>>(values);
}
Result<Scalar> FromOptionalBytes(const std::vector<uint8_t>& value) {
if (value.empty()) {
return std::monostate{};
}
return ToView(value);
}
} // namespace
Result<Scalar> PartitionFieldSummaryStructLike::GetField(size_t pos) const {
if (pos >= num_fields()) {
return InvalidArgument("Invalid partition field summary index: {}", pos);
}
switch (pos) {
case 0:
return summary_.get().contains_null;
case 1:
return FromOptional(summary_.get().contains_nan);
case 2:
return FromOptional(
summary_.get().lower_bound.transform(ToView<std::vector<uint8_t>>));
case 3:
return FromOptional(
summary_.get().upper_bound.transform(ToView<std::vector<uint8_t>>));
default:
return InvalidArgument("Invalid partition field summary index: {}", pos);
}
}
Result<Scalar> PartitionFieldSummaryArrayLike::GetElement(size_t pos) const {
if (pos >= size()) {
return InvalidArgument("Invalid partition field summary index: {}", pos);
}
if (summary_ == nullptr) {
summary_ = std::make_shared<PartitionFieldSummaryStructLike>(summaries_.get()[pos]);
} else {
summary_->Reset(summaries_.get()[pos]);
}
return summary_;
}
Result<Scalar> ManifestFileStructLike::GetField(size_t pos) const {
if (pos >= num_fields()) {
return InvalidArgument("Invalid manifest file field index: {}", pos);
}
ICEBERG_ASSIGN_OR_RAISE(auto field,
ManifestFileFieldFromIndex(static_cast<int32_t>(pos)));
const auto& manifest_file = manifest_file_.get();
switch (field) {
case ManifestFileField::kManifestPath:
return ToView(manifest_file.manifest_path);
case ManifestFileField::kManifestLength:
return manifest_file.manifest_length;
case ManifestFileField::kPartitionSpecId:
return manifest_file.partition_spec_id;
case ManifestFileField::kContent:
return static_cast<int32_t>(manifest_file.content);
case ManifestFileField::kSequenceNumber:
return manifest_file.sequence_number;
case ManifestFileField::kMinSequenceNumber:
return manifest_file.min_sequence_number;
case ManifestFileField::kAddedSnapshotId:
return FromOptional(manifest_file.added_snapshot_id);
case ManifestFileField::kAddedFilesCount:
return FromOptional(manifest_file.added_files_count);
case ManifestFileField::kExistingFilesCount:
return FromOptional(manifest_file.existing_files_count);
case ManifestFileField::kDeletedFilesCount:
return FromOptional(manifest_file.deleted_files_count);
case ManifestFileField::kAddedRowsCount:
return FromOptional(manifest_file.added_rows_count);
case ManifestFileField::kExistingRowsCount:
return FromOptional(manifest_file.existing_rows_count);
case ManifestFileField::kDeletedRowsCount:
return FromOptional(manifest_file.deleted_rows_count);
case ManifestFileField::kPartitionFieldSummary: {
if (summaries_ == nullptr) {
summaries_ =
std::make_shared<PartitionFieldSummaryArrayLike>(manifest_file.partitions);
} else {
summaries_->Reset(manifest_file.partitions);
}
return summaries_;
}
case ManifestFileField::kKeyMetadata:
return ToView(manifest_file.key_metadata);
case ManifestFileField::kFirstRowId:
return FromOptional(manifest_file.first_row_id);
case ManifestFileField::kNextUnusedId:
return InvalidArgument("Invalid manifest file field index: {}", pos);
}
return InvalidArgument("Invalid manifest file field index: {}", pos);
}
size_t ManifestFileStructLike::num_fields() const {
return static_cast<size_t>(ManifestFileField::kNextUnusedId);
}
std::unique_ptr<StructLike> FromManifestFile(const ManifestFile& file) {
return std::make_unique<ManifestFileStructLike>(file);
}
Result<Scalar> DataFileStructLike::GetField(size_t pos) const {
if (pos >= num_fields()) {
return InvalidArgument("Invalid data file field index: {}", pos);
}
const auto& data_file = data_file_.get();
switch (static_cast<DataFileFieldPosition>(pos)) {
case DataFileFieldPosition::kContent:
return static_cast<int32_t>(data_file.content);
case DataFileFieldPosition::kFilePath:
return ToView(data_file.file_path);
case DataFileFieldPosition::kFileFormat:
return ToString(data_file.file_format);
case DataFileFieldPosition::kSpecId:
return FromOptional(data_file.partition_spec_id);
case DataFileFieldPosition::kPartition: {
partition_ = std::make_shared<PartitionValues>(data_file.partition);
return partition_;
}
case DataFileFieldPosition::kRecordCount:
return data_file.record_count;
case DataFileFieldPosition::kFileSize:
return data_file.file_size_in_bytes;
case DataFileFieldPosition::kColumnSizes:
return FromOptionalMap(data_file.column_sizes);
case DataFileFieldPosition::kValueCounts:
return FromOptionalMap(data_file.value_counts);
case DataFileFieldPosition::kNullValueCounts:
return FromOptionalMap(data_file.null_value_counts);
case DataFileFieldPosition::kNanValueCounts:
return FromOptionalMap(data_file.nan_value_counts);
case DataFileFieldPosition::kLowerBounds:
return FromOptionalMap(data_file.lower_bounds);
case DataFileFieldPosition::kUpperBounds:
return FromOptionalMap(data_file.upper_bounds);
case DataFileFieldPosition::kKeyMetadata:
return FromOptionalBytes(data_file.key_metadata);
case DataFileFieldPosition::kSplitOffsets:
return FromOptionalVector(data_file.split_offsets);
case DataFileFieldPosition::kEqualityIds:
return FromOptionalVector(data_file.equality_ids);
case DataFileFieldPosition::kSortOrderId:
return FromOptional(data_file.sort_order_id);
case DataFileFieldPosition::kFirstRowId:
return FromOptional(data_file.first_row_id);
case DataFileFieldPosition::kReferencedDataFile:
return FromOptionalString(data_file.referenced_data_file);
case DataFileFieldPosition::kContentOffset:
return FromOptional(data_file.content_offset);
case DataFileFieldPosition::kContentSize:
return FromOptional(data_file.content_size_in_bytes);
case DataFileFieldPosition::kNextUnusedId:
return InvalidArgument("Invalid data file field index: {}", pos);
}
return InvalidArgument("Invalid data file field index: {}", pos);
}
size_t DataFileStructLike::num_fields() const {
return static_cast<size_t>(DataFileFieldPosition::kNextUnusedId);
}
} // namespace iceberg