blob: d52ea289df1a2c350babbc85f1958e9fee2c57ce [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 "exec/sink/writer/iceberg/partition_transformers.h"
#include <any>
#include <cmath>
#include "core/types.h"
#include "format/table/iceberg/partition_spec.h"
namespace doris {
namespace {
template <typename T>
std::string floating_point_partition_value_to_string(T value) {
if (std::isnan(value)) {
return "NaN";
}
if (std::isinf(value)) {
return value > 0 ? "Infinity" : "-Infinity";
}
return std::to_string(value);
}
} // namespace
const std::chrono::sys_days PartitionColumnTransformUtils::EPOCH = std::chrono::sys_days(
std::chrono::year {1970} / std::chrono::January / std::chrono::day {1});
std::unique_ptr<PartitionColumnTransform> PartitionColumnTransforms::create(
const doris::iceberg::PartitionField& field, const DataTypePtr& source_type) {
auto& transform = field.transform();
// Identity/void only carry values; computed binary partition transforms are unsupported.
if (source_type->get_primitive_type() == TYPE_VARBINARY && transform != "identity" &&
transform != "void") {
throw Exception(ErrorCode::NOT_IMPLEMENTED_ERROR,
"VARBINARY partition transform {} is not supported", transform);
}
static const std::regex has_width(R"((\w+)\[(\d+)\])");
std::smatch width_match;
if (std::regex_match(transform, width_match, has_width)) {
std::string name = width_match[1];
int parsed_width = std::stoi(width_match[2]);
if (name == "truncate") {
switch (source_type->get_primitive_type()) {
case TYPE_INT: {
return std::make_unique<IntegerTruncatePartitionColumnTransform>(source_type,
parsed_width);
}
case TYPE_BIGINT: {
return std::make_unique<BigintTruncatePartitionColumnTransform>(source_type,
parsed_width);
}
case TYPE_VARCHAR:
case TYPE_CHAR:
case TYPE_STRING: {
return std::make_unique<StringTruncatePartitionColumnTransform>(source_type,
parsed_width);
}
case TYPE_DECIMALV2: {
return std::make_unique<DecimalTruncatePartitionColumnTransform<TYPE_DECIMALV2>>(
source_type, parsed_width);
}
case TYPE_DECIMAL32: {
return std::make_unique<DecimalTruncatePartitionColumnTransform<TYPE_DECIMAL32>>(
source_type, parsed_width);
}
case TYPE_DECIMAL64: {
return std::make_unique<DecimalTruncatePartitionColumnTransform<TYPE_DECIMAL64>>(
source_type, parsed_width);
}
case TYPE_DECIMAL128I: {
return std::make_unique<DecimalTruncatePartitionColumnTransform<TYPE_DECIMAL128I>>(
source_type, parsed_width);
}
case TYPE_DECIMAL256: {
return std::make_unique<DecimalTruncatePartitionColumnTransform<TYPE_DECIMAL256>>(
source_type, parsed_width);
}
default: {
throw doris::Exception(doris::ErrorCode::INTERNAL_ERROR,
"Unsupported type {} for partition column transform {}",
source_type->get_name(), transform);
}
}
} else if (name == "bucket") {
switch (source_type->get_primitive_type()) {
case TYPE_INT: {
return std::make_unique<IntBucketPartitionColumnTransform>(source_type,
parsed_width);
}
case TYPE_BIGINT: {
return std::make_unique<BigintBucketPartitionColumnTransform>(source_type,
parsed_width);
}
case TYPE_VARCHAR:
case TYPE_CHAR:
case TYPE_STRING: {
return std::make_unique<StringBucketPartitionColumnTransform>(source_type,
parsed_width);
}
case TYPE_DATEV2: {
return std::make_unique<DateBucketPartitionColumnTransform>(source_type,
parsed_width);
}
case TYPE_DATETIMEV2: {
return std::make_unique<TimestampBucketPartitionColumnTransform>(source_type,
parsed_width);
}
case TYPE_DECIMALV2: {
return std::make_unique<DecimalBucketPartitionColumnTransform<TYPE_DECIMALV2>>(
source_type, parsed_width);
}
case TYPE_DECIMAL32: {
return std::make_unique<DecimalBucketPartitionColumnTransform<TYPE_DECIMAL32>>(
source_type, parsed_width);
}
case TYPE_DECIMAL64: {
return std::make_unique<DecimalBucketPartitionColumnTransform<TYPE_DECIMAL64>>(
source_type, parsed_width);
}
case TYPE_DECIMAL128I: {
return std::make_unique<DecimalBucketPartitionColumnTransform<TYPE_DECIMAL128I>>(
source_type, parsed_width);
}
case TYPE_DECIMAL256: {
return std::make_unique<DecimalBucketPartitionColumnTransform<TYPE_DECIMAL256>>(
source_type, parsed_width);
}
default: {
throw doris::Exception(doris::ErrorCode::INTERNAL_ERROR,
"Unsupported type {} for partition column transform {}",
source_type->get_name(), transform);
}
}
}
}
if (transform == "identity") {
return std::make_unique<IdentityPartitionColumnTransform>(source_type);
} else if (transform == "year") {
switch (source_type->get_primitive_type()) {
case TYPE_DATEV2: {
return std::make_unique<DateYearPartitionColumnTransform>(source_type);
}
case TYPE_DATETIMEV2: {
return std::make_unique<TimestampYearPartitionColumnTransform>(source_type);
}
default: {
throw doris::Exception(doris::ErrorCode::INTERNAL_ERROR,
"Unsupported type {} for partition column transform {}",
source_type->get_name(), transform);
}
}
} else if (transform == "month") {
switch (source_type->get_primitive_type()) {
case TYPE_DATEV2: {
return std::make_unique<DateMonthPartitionColumnTransform>(source_type);
}
case TYPE_DATETIMEV2: {
return std::make_unique<TimestampMonthPartitionColumnTransform>(source_type);
}
default: {
throw doris::Exception(doris::ErrorCode::INTERNAL_ERROR,
"Unsupported type {} for partition column transform {}",
source_type->get_name(), transform);
}
}
} else if (transform == "day") {
switch (source_type->get_primitive_type()) {
case TYPE_DATEV2: {
return std::make_unique<DateDayPartitionColumnTransform>(source_type);
}
case TYPE_DATETIMEV2: {
return std::make_unique<TimestampDayPartitionColumnTransform>(source_type);
}
default: {
throw doris::Exception(doris::ErrorCode::INTERNAL_ERROR,
"Unsupported type {} for partition column transform {}",
source_type->get_name(), transform);
}
}
} else if (transform == "hour") {
switch (source_type->get_primitive_type()) {
case TYPE_DATETIMEV2: {
return std::make_unique<TimestampHourPartitionColumnTransform>(source_type);
}
default: {
throw doris::Exception(doris::ErrorCode::INTERNAL_ERROR,
"Unsupported type {} for partition column transform {}",
source_type->get_name(), transform);
}
}
} else if (transform == "void") {
return std::make_unique<VoidPartitionColumnTransform>(source_type);
} else {
throw doris::Exception(doris::ErrorCode::INTERNAL_ERROR,
"Unsupported type {} for partition column transform {}",
source_type->get_name(), transform);
}
}
std::string PartitionColumnTransform::name() const {
return "default";
}
std::string PartitionColumnTransform::to_human_string(const DataTypePtr type,
const std::any& value) const {
return get_partition_value(type, value);
}
std::string PartitionColumnTransform::get_partition_value(const DataTypePtr type,
const std::any& value) const {
if (value.has_value()) {
switch (type->get_primitive_type()) {
case TYPE_BOOLEAN: {
return std::any_cast<uint8_t>(value) ? "true" : "false";
}
case TYPE_TINYINT: {
return std::to_string(std::any_cast<Int8>(value));
}
case TYPE_SMALLINT: {
return std::to_string(std::any_cast<Int16>(value));
}
case TYPE_INT: {
return std::to_string(std::any_cast<Int32>(value));
}
case TYPE_BIGINT: {
return std::to_string(std::any_cast<Int64>(value));
}
case TYPE_FLOAT: {
return floating_point_partition_value_to_string(std::any_cast<Float32>(value));
}
case TYPE_DOUBLE: {
return floating_point_partition_value_to_string(std::any_cast<Float64>(value));
}
case TYPE_VARCHAR:
case TYPE_CHAR:
case TYPE_STRING: {
return std::any_cast<std::string>(value);
}
case TYPE_DATE: {
char buf[64];
char* pos = std::any_cast<VecDateTimeValue>(value).to_string(buf);
return std::string(buf, pos - buf - 1);
}
case TYPE_DATETIME: {
char buf[64];
char* pos = std::any_cast<VecDateTimeValue>(value).to_string(buf);
return std::string(buf, pos - buf - 1);
}
case TYPE_DATEV2: {
char buf[64];
char* pos = std::any_cast<DateV2Value<DateV2ValueType>>(value).to_string(buf);
return std::string(buf, pos - buf - 1);
}
case TYPE_DATETIMEV2: {
char buf[64];
char* pos = std::any_cast<DateV2Value<DateTimeV2ValueType>>(value).to_string(
buf, type->get_scale());
return std::string(buf, pos - buf - 1);
}
case TYPE_DECIMALV2: {
return std::any_cast<Decimal128V2>(value).to_string(type->get_scale());
}
case TYPE_DECIMAL32: {
return std::any_cast<Decimal32>(value).to_string(type->get_scale());
}
case TYPE_DECIMAL64: {
return std::any_cast<Decimal64>(value).to_string(type->get_scale());
}
case TYPE_DECIMAL128I: {
return std::any_cast<Decimal128V3>(value).to_string(type->get_scale());
}
case TYPE_DECIMAL256: {
return std::any_cast<Decimal256>(value).to_string(type->get_scale());
}
default: {
throw doris::Exception(doris::ErrorCode::INTERNAL_ERROR,
"Unsupported type {} for partition", type->get_name());
}
}
}
return "null";
}
} // namespace doris