blob: 1958d09de788e71be9605395c9a3ca706be22d58 [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.
*/
#pragma once
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include "paimon/memory/memory_pool.h"
#include "paimon/predicate/literal.h"
#include "paimon/result.h"
#include "paimon/visibility.h"
struct ArrowArray;
struct ArrowSchema;
namespace paimon {
/// Arguments controlling how a variant value is cast to a target type in `Variant::VariantGet`.
struct PAIMON_EXPORT VariantCastArgs {
/// Whether an invalid cast fails the call (true) or yields SQL NULL (false).
bool fail_on_error = true;
/// The time zone used when rendering TIMESTAMP values. Supported forms are `UTC`/`Z`/`GMT`,
/// fixed offsets such as `+08:00`, and IANA region ids such as `Asia/Shanghai`.
std::string zone_id = "UTC";
};
/// A Variant represents a type that contains one of: 1) Primitive: A type and corresponding
/// value (e.g. INT, STRING); 2) Array: An ordered list of Variant values; 3) Object: An
/// unordered collection of string/Variant pairs (i.e. key/value pairs). An object may not
/// contain duplicate keys.
///
/// A Variant is encoded with 2 binaries: the value and the metadata, following the parquet
/// Variant Binary Encoding specification (compatible with the Java / Spark implementation). The
/// encoding allows representation of semi-structured data (e.g. JSON) in a form that can be
/// efficiently queried by path.
///
/// In an Arrow schema, a Variant field is represented as
/// `struct<value: binary not null, metadata: binary not null>` marked with Paimon-specific field
/// metadata; use `Variant::ArrowField` to construct such a field.
class PAIMON_EXPORT Variant {
public:
~Variant();
/// Parses a JSON string as a Variant (duplicate object keys are rejected).
///
/// @param json The JSON document text.
/// @param pool The memory pool used for the variant buffers.
/// @return A result containing the created variant or an error.
static Result<std::unique_ptr<Variant>> FromJson(const std::string& json,
const std::shared_ptr<MemoryPool>& pool);
/// Creates a Variant from already-encoded value and metadata binaries (copied into `pool`).
///
/// @param value The variant value binary.
/// @param value_length The length of the value binary.
/// @param metadata The variant metadata binary.
/// @param metadata_length The length of the metadata binary.
/// @param pool The memory pool used for the variant buffers.
/// @return A result containing the created variant or an error.
static Result<std::unique_ptr<Variant>> Create(const char* value, uint64_t value_length,
const char* metadata, uint64_t metadata_length,
const std::shared_ptr<MemoryPool>& pool);
/// The variant value binary. The view remains valid as long as this variant exists.
std::string_view Value() const;
/// The variant metadata binary. The view remains valid as long as this variant exists.
std::string_view Metadata() const;
/// The size of the variant in bytes (value size + metadata size).
int64_t SizeInBytes() const;
/// Stringifies the variant in JSON format.
///
/// @param zone_id The time zone used when rendering TIMESTAMP values.
/// @return A result containing the JSON text or an error.
Result<std::string> ToJson(const std::string& zone_id = "UTC") const;
/// Extracts a sub-variant value according to a path which starts with a `$`, e.g. `$.key`,
/// `$['key']`, `$["key"]`, `$.array[0]`, and casts the value to the target type.
///
/// @param path The extraction path.
/// @param target_type The target Arrow type (C data interface, consumed by the call); only
/// scalar types are supported. Use `VariantGetArrow` for nested targets.
/// @param cast_args Cast behavior arguments.
/// @return A result containing the extracted literal, or nullopt for SQL NULL (unmatched
/// path, variant null, or an invalid cast with `fail_on_error == false`).
Result<std::optional<Literal>> VariantGet(const std::string& path,
struct ArrowSchema* target_type,
const VariantCastArgs& cast_args) const;
/// Extracts a sub-variant value according to a path which starts with a `$` and casts the
/// value to the (possibly nested) target field type.
///
/// In addition to scalar types, the target may be a STRUCT (cast from a variant object,
/// children matched by field name; unmatched children are null), a MAP with string keys
/// (cast from a variant object), a LIST (cast from a variant array), or a variant-marked
/// field created by `Variant::ArrowField` (the sub-variant is deeply re-encoded).
///
/// @param path The extraction path.
/// @param target_field The target Arrow field (C data interface, consumed by the call).
/// @param cast_args Cast behavior arguments.
/// @return A result containing a length-1 Arrow array of the target type whose single slot
/// holds the result; a null slot represents SQL NULL (unmatched path, variant null,
/// or an invalid cast with `fail_on_error == false`).
Result<std::unique_ptr<struct ArrowArray>> VariantGetArrow(
const std::string& path, struct ArrowSchema* target_field,
const VariantCastArgs& cast_args) const;
/// Extracts a sub-variant value according to a path which starts with a `$` and renders it
/// as JSON text.
///
/// @param path The extraction path.
/// @param zone_id The time zone used when rendering TIMESTAMP values.
/// @return A result containing the JSON text, or nullopt if the path does not match.
Result<std::optional<std::string>> VariantGetJson(const std::string& path,
const std::string& zone_id = "UTC") const;
/// Creates an Arrow field definition for the Variant type.
///
/// This function constructs an Arrow Field (internally
/// `struct<value: binary not null, metadata: binary not null>`) and exports it to the C data
/// interface structure `::ArrowSchema`. It automatically injects Paimon-specific metadata to
/// identify the field as a VARIANT.
///
/// @param field_name The name of the Arrow field.
/// @param nullable Whether the field is nullable.
/// @param metadata A map of key-value metadata to be attached to the field.
/// @return A result containing a unique pointer to the generated `::ArrowSchema` or an error.
static Result<std::unique_ptr<struct ArrowSchema>> ArrowField(
const std::string& field_name, bool nullable = true,
std::unordered_map<std::string, std::string> metadata = {});
private:
class Impl;
explicit Variant(std::unique_ptr<Impl>&& impl);
std::unique_ptr<Impl> impl_;
};
/// Builds a variant-access projection field: a struct field that replaces a VARIANT column in
/// the read schema so that, instead of the full variant, only the described paths are extracted
/// at read time (reading only the required shredded sub-columns from shredded files).
///
/// Example: read `$.age` as INT64 and `$.city` as STRING from variant column `v`:
///
/// VariantAccessBuilder builder;
/// builder.AddField(age_type, "$.age");
/// builder.AddField(city_type, "$.city");
/// auto field = builder.Build("v"); // use in ReadContextBuilder::SetReadSchema
///
/// The resulting struct has one child per added field, named by its position ("0", "1", ...).
class PAIMON_EXPORT VariantAccessBuilder {
public:
VariantAccessBuilder();
~VariantAccessBuilder();
/// Adds an extracted field.
///
/// @param target_type The Arrow type the extracted value is cast to (C data interface,
/// consumed by the call). Nested targets follow `Variant::VariantGetArrow` semantics.
/// @param path The extraction path, e.g. `$.a.b` or `$.array[0]`.
/// @param fail_on_error Whether an invalid cast fails the read (true) or yields SQL NULL.
/// @param zone_id The time zone used when rendering TIMESTAMP values.
Status AddField(struct ArrowSchema* target_type, const std::string& path,
bool fail_on_error = true, const std::string& zone_id = "UTC");
/// Builds the projection field named `field_name`, to be used in the read schema in place
/// of the variant column with the same name.
Result<std::unique_ptr<struct ArrowSchema>> Build(const std::string& field_name) const;
private:
class Impl;
std::unique_ptr<Impl> impl_;
};
} // namespace paimon