blob: 36978d04f1c9d736f482244171535619474ff542 [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 "paimon/data/shredding/map_shared_shredding_schema_utils.h"
#include <unordered_set>
#include <utility>
#include <vector>
#include "arrow/c/bridge.h"
#include "arrow/type.h"
#include "arrow/util/key_value_metadata.h"
#include "fmt/format.h"
#include "paimon/common/data/shredding/map_shared_shredding_utils.h"
#include "paimon/common/types/data_field.h"
#include "paimon/common/utils/arrow/status_utils.h"
namespace paimon {
class MapSharedShreddingAccessBuilder::Impl {
public:
Impl(const std::shared_ptr<arrow::Field>& _map_field,
const std::shared_ptr<arrow::MapType>& _map_type)
: map_field(_map_field), map_type(_map_type) {}
std::shared_ptr<arrow::Field> map_field;
std::shared_ptr<arrow::MapType> map_type;
std::vector<std::string> keys;
std::unordered_set<std::string> unique_keys;
};
MapSharedShreddingAccessBuilder::~MapSharedShreddingAccessBuilder() = default;
MapSharedShreddingAccessBuilder::MapSharedShreddingAccessBuilder(std::unique_ptr<Impl>&& impl)
: impl_(std::move(impl)) {}
Result<std::unique_ptr<MapSharedShreddingAccessBuilder>> MapSharedShreddingAccessBuilder::Create(
struct ArrowSchema* map_field) {
if (!map_field) {
return Status::Invalid("MAP field is null");
}
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(std::shared_ptr<arrow::Field> field,
arrow::ImportField(map_field));
if (field->type()->id() != arrow::Type::MAP) {
return Status::Invalid(
fmt::format("MapSharedShreddingAccessBuilder requires MAP field, got {}",
field->type()->ToString()));
}
auto map_type = arrow::internal::checked_pointer_cast<arrow::MapType>(field->type());
if (map_type->key_type()->id() != arrow::Type::STRING) {
return Status::Invalid(fmt::format(
"MapSharedShreddingAccessBuilder only supports MAP with STRING keys, got {}",
map_type->key_type()->ToString()));
}
auto impl = std::make_unique<Impl>(field, map_type);
return std::unique_ptr<MapSharedShreddingAccessBuilder>(
new MapSharedShreddingAccessBuilder(std::move(impl)));
}
Status MapSharedShreddingAccessBuilder::AddKey(const std::string& key) {
if (key.find(',') != std::string::npos) {
return Status::Invalid(
fmt::format("selected MAP key {} must not contain the ',' delimiter", key));
}
if (!impl_->unique_keys.insert(key).second) {
return Status::Invalid(fmt::format("selected MAP key must not be duplicated: {}", key));
}
impl_->keys.push_back(key);
return Status::OK();
}
Result<std::unique_ptr<struct ArrowSchema>> MapSharedShreddingAccessBuilder::Build() const {
if (impl_->keys.empty()) {
return Status::Invalid(
"shared shredding MAP selected-key projection needs at least one key");
}
arrow::FieldVector fields;
fields.reserve(impl_->keys.size());
std::string encoded_keys;
for (size_t i = 0; i < impl_->keys.size(); ++i) {
if (i != 0) {
encoded_keys.push_back(',');
}
encoded_keys.append(impl_->keys[i]);
fields.push_back(arrow::field(impl_->keys[i], impl_->map_type->item_type(),
/*nullable=*/true));
}
auto metadata = arrow::KeyValueMetadata::Make({DataField::MAP_SELECTED_KEYS}, {encoded_keys});
auto access_field = impl_->map_field->WithType(arrow::struct_(std::move(fields)))
->WithMetadata(std::move(metadata));
auto field = std::make_unique<struct ArrowSchema>();
PAIMON_RETURN_NOT_OK_FROM_ARROW(arrow::ExportField(*access_field, field.get()));
return field;
}
Result<std::unique_ptr<::ArrowSchema>> MapSharedShreddingSchemaUtils::LogicalToPhysicalSchema(
std::unique_ptr<::ArrowSchema> logical_schema,
const std::map<std::string, int32_t>& field_to_num_columns) {
if (!logical_schema) {
return Status::Invalid("logical schema is null");
}
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(std::shared_ptr<arrow::Schema> arrow_logical_schema,
arrow::ImportSchema(logical_schema.get()));
PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<arrow::Schema> physical_schema,
MapSharedShreddingUtils::LogicalToPhysicalSchema(arrow_logical_schema,
field_to_num_columns));
auto c_schema = std::make_unique<::ArrowSchema>();
PAIMON_RETURN_NOT_OK_FROM_ARROW(arrow::ExportSchema(*physical_schema, c_schema.get()));
return c_schema;
}
Result<std::unique_ptr<::ArrowSchema>> MapSharedShreddingSchemaUtils::AttachMetadataToSchema(
std::unique_ptr<::ArrowSchema> physical_schema,
const std::map<std::string, MapSharedShreddingFieldMeta>& field_name_to_meta,
const std::string& compression) {
if (!physical_schema) {
return Status::Invalid("physical schema is null");
}
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(std::shared_ptr<arrow::Schema> arrow_physical_schema,
arrow::ImportSchema(physical_schema.get()));
arrow::FieldVector updated_fields = arrow_physical_schema->fields();
for (const auto& [field_name, field_meta] : field_name_to_meta) {
int32_t field_index = arrow_physical_schema->GetFieldIndex(field_name);
if (field_index < 0) {
return Status::Invalid(fmt::format(
"Shared-shredding field '{}' not found in physical schema.", field_name));
}
const auto& field = arrow_physical_schema->field(field_index);
auto metadata = field->metadata() ? field->metadata()->Copy()
: std::make_shared<arrow::KeyValueMetadata>();
PAIMON_RETURN_NOT_OK(
MapSharedShreddingUtils::SerializeMetadata(field_meta, compression, metadata.get()));
updated_fields[field_index] = field->WithMetadata(metadata);
}
auto updated_schema =
arrow::schema(std::move(updated_fields), arrow_physical_schema->metadata());
auto c_schema = std::make_unique<::ArrowSchema>();
PAIMON_RETURN_NOT_OK_FROM_ARROW(arrow::ExportSchema(*updated_schema, c_schema.get()));
return c_schema;
}
Result<MapSharedShreddingFieldMeta> MapSharedShreddingSchemaUtils::ExtractMetadataFromField(
std::unique_ptr<::ArrowSchema> physical_schema, const std::string& field_name) {
if (!physical_schema) {
return Status::Invalid("physical schema is null");
}
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(std::shared_ptr<arrow::Schema> arrow_physical_schema,
arrow::ImportSchema(physical_schema.get()));
const auto& field = arrow_physical_schema->GetFieldByName(field_name);
if (!field) {
return Status::Invalid(
fmt::format("Shared-shredding field '{}' not found in physical schema.", field_name));
}
auto metadata =
field->metadata() ? field->metadata()->Copy() : std::shared_ptr<arrow::KeyValueMetadata>();
return MapSharedShreddingUtils::DeserializeMetadata(metadata);
}
} // namespace paimon