blob: 455fa266327380a2a39ae663c0013a45ed409bed [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/variant.h"
#include <utility>
#include "arrow/api.h"
#include "arrow/c/bridge.h"
#include "paimon/common/data/variant/generic_variant.h"
#include "paimon/common/data/variant/variant_access_utils.h"
#include "paimon/common/data/variant/variant_defs.h"
#include "paimon/common/data/variant/variant_get.h"
#include "paimon/common/data/variant/variant_path_segment.h"
#include "paimon/common/data/variant/variant_type_utils.h"
#include "paimon/common/types/data_field.h"
#include "paimon/common/utils/arrow/mem_utils.h"
#include "paimon/common/utils/arrow/status_utils.h"
namespace paimon {
class Variant::Impl {
public:
Impl(std::shared_ptr<GenericVariant> variant, std::shared_ptr<MemoryPool> pool)
: variant_(std::move(variant)), pool_(std::move(pool)), arrow_pool_(GetArrowPool(pool_)) {}
const std::shared_ptr<GenericVariant>& GetVariant() const {
return variant_;
}
const std::shared_ptr<MemoryPool>& GetPool() const {
return pool_;
}
const std::shared_ptr<arrow::MemoryPool>& GetArrowMemoryPool() const {
return arrow_pool_;
}
private:
std::shared_ptr<GenericVariant> variant_;
std::shared_ptr<MemoryPool> pool_;
std::shared_ptr<arrow::MemoryPool> arrow_pool_;
};
Variant::Variant(std::unique_ptr<Impl>&& impl) : impl_(std::move(impl)) {}
Variant::~Variant() = default;
Result<std::unique_ptr<Variant>> Variant::FromJson(const std::string& json,
const std::shared_ptr<MemoryPool>& pool) {
PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<GenericVariant> variant,
GenericVariant::FromJson(json, pool));
auto impl = std::make_unique<Impl>(std::move(variant), pool);
return std::unique_ptr<Variant>(new Variant(std::move(impl)));
}
Result<std::unique_ptr<Variant>> Variant::Create(const char* value, uint64_t value_length,
const char* metadata, uint64_t metadata_length,
const std::shared_ptr<MemoryPool>& pool) {
PAIMON_ASSIGN_OR_RAISE(
std::shared_ptr<GenericVariant> variant,
GenericVariant::Create(std::string_view(value, value_length),
std::string_view(metadata, metadata_length), pool));
auto impl = std::make_unique<Impl>(std::move(variant), pool);
return std::unique_ptr<Variant>(new Variant(std::move(impl)));
}
std::string_view Variant::Value() const {
return impl_->GetVariant()->RawValue();
}
std::string_view Variant::Metadata() const {
return impl_->GetVariant()->Metadata();
}
int64_t Variant::SizeInBytes() const {
return impl_->GetVariant()->SizeInBytes();
}
Result<std::string> Variant::ToJson(const std::string& zone_id) const {
return impl_->GetVariant()->ToJson(zone_id);
}
Result<std::optional<Literal>> Variant::VariantGet(const std::string& path,
struct ArrowSchema* target_type,
const VariantCastArgs& cast_args) const {
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(std::shared_ptr<arrow::Field> target_field,
arrow::ImportField(target_type));
return VariantGetExecutor::Get(impl_->GetVariant(), path, target_field->type(), cast_args);
}
Result<std::unique_ptr<struct ArrowArray>> Variant::VariantGetArrow(
const std::string& path, struct ArrowSchema* target_field,
const VariantCastArgs& cast_args) const {
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(std::shared_ptr<arrow::Field> field,
arrow::ImportField(target_field));
PAIMON_ASSIGN_OR_RAISE(
std::shared_ptr<arrow::Array> array,
VariantGetExecutor::GetAsArrow(impl_->GetVariant(), path, field, cast_args,
impl_->GetPool(), impl_->GetArrowMemoryPool()));
auto result = std::make_unique<struct ArrowArray>();
PAIMON_RETURN_NOT_OK_FROM_ARROW(arrow::ExportArray(*array, result.get()));
return result;
}
Result<std::optional<std::string>> Variant::VariantGetJson(const std::string& path,
const std::string& zone_id) const {
PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<GenericVariant> extracted,
VariantGetExecutor::ExtractByPath(impl_->GetVariant(), path));
if (extracted == nullptr) {
return std::optional<std::string>(std::nullopt);
}
PAIMON_ASSIGN_OR_RAISE(std::string json, extracted->ToJson(zone_id));
return std::optional<std::string>(std::move(json));
}
Result<std::unique_ptr<struct ArrowSchema>> Variant::ArrowField(
const std::string& field_name, bool nullable,
std::unordered_map<std::string, std::string> metadata) {
auto variant_field = VariantTypeUtils::ToArrowField(field_name, nullable, std::move(metadata));
auto field = std::make_unique<struct ArrowSchema>();
PAIMON_RETURN_NOT_OK_FROM_ARROW(arrow::ExportField(*variant_field, field.get()));
return field;
}
class VariantAccessBuilder::Impl {
public:
arrow::FieldVector fields;
};
VariantAccessBuilder::VariantAccessBuilder() : impl_(std::make_unique<Impl>()) {}
VariantAccessBuilder::~VariantAccessBuilder() = default;
Status VariantAccessBuilder::AddField(struct ArrowSchema* target_type, const std::string& path,
bool fail_on_error, const std::string& zone_id) {
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(std::shared_ptr<arrow::Field> target,
arrow::ImportField(target_type));
// Validate the path eagerly so mistakes fail at build time, not at read time.
PAIMON_RETURN_NOT_OK(VariantPathSegment::Parse(path));
// Keep the target field's own metadata (e.g. the variant extension marker of a
// `Variant::ArrowField` target, which drives the deep re-encode cast) and add the access
// description to it.
std::vector<std::string> keys = {DataField::DESCRIPTION};
std::vector<std::string> values = {
VariantAccessUtils::BuildVariantMetadata(path, fail_on_error, zone_id)};
if (target->metadata() != nullptr) {
for (int64_t i = 0; i < target->metadata()->size(); ++i) {
if (target->metadata()->key(i) == DataField::DESCRIPTION) {
continue;
}
keys.push_back(target->metadata()->key(i));
values.push_back(target->metadata()->value(i));
}
}
impl_->fields.push_back(arrow::field(std::to_string(impl_->fields.size()), target->type(),
/*nullable=*/true,
arrow::KeyValueMetadata::Make(keys, values)));
return Status::OK();
}
Result<std::unique_ptr<struct ArrowSchema>> VariantAccessBuilder::Build(
const std::string& field_name) const {
if (impl_->fields.empty()) {
return Status::Invalid("a variant-access projection needs at least one field");
}
auto access_field =
arrow::field(field_name, arrow::struct_(impl_->fields), /*nullable=*/true,
arrow::KeyValueMetadata::Make({VariantDefs::kExtensionTypeKey},
{VariantDefs::kExtensionTypeValue}));
auto field = std::make_unique<struct ArrowSchema>();
PAIMON_RETURN_NOT_OK_FROM_ARROW(arrow::ExportField(*access_field, field.get()));
return field;
}
} // namespace paimon