Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 30 additions & 15 deletions src/iceberg/expression/literal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

#include <cmath>
#include <concepts>
#include <sstream>

#include "iceberg/exception.h"

Expand Down Expand Up @@ -126,22 +125,28 @@ Literal::Literal(Value value, std::shared_ptr<PrimitiveType> type)
: value_(std::move(value)), type_(std::move(type)) {}

// Factory methods
Literal Literal::Boolean(bool value) { return {Value{value}, iceberg::boolean()}; }
Literal Literal::Boolean(bool value) { return {Value{value}, boolean()}; }

Literal Literal::Int(int32_t value) { return {Value{value}, iceberg::int32()}; }
Literal Literal::Int(int32_t value) { return {Value{value}, int32()}; }

Literal Literal::Long(int64_t value) { return {Value{value}, iceberg::int64()}; }
Literal Literal::Date(int32_t value) { return {Value{value}, date()}; }

Literal Literal::Float(float value) { return {Value{value}, iceberg::float32()}; }
Literal Literal::Long(int64_t value) { return {Value{value}, int64()}; }

Literal Literal::Double(double value) { return {Value{value}, iceberg::float64()}; }
Literal Literal::Time(int64_t value) { return {Value{value}, time()}; }

Literal Literal::String(std::string value) {
return {Value{std::move(value)}, iceberg::string()};
}
Literal Literal::Timestamp(int64_t value) { return {Value{value}, timestamp()}; }

Literal Literal::TimestampTz(int64_t value) { return {Value{value}, timestamp_tz()}; }

Literal Literal::Float(float value) { return {Value{value}, float32()}; }

Literal Literal::Double(double value) { return {Value{value}, float64()}; }

Literal Literal::String(std::string value) { return {Value{std::move(value)}, string()}; }

Literal Literal::Binary(std::vector<uint8_t> value) {
return {Value{std::move(value)}, iceberg::binary()};
return {Value{std::move(value)}, binary()};
}

Result<Literal> Literal::Deserialize(std::span<const uint8_t> data,
Expand Down Expand Up @@ -188,8 +193,9 @@ std::partial_ordering Literal::operator<=>(const Literal& other) const {
return std::partial_ordering::unordered;
}

// If either value is AboveMax or BelowMin, comparison is unordered
if (IsAboveMax() || IsBelowMin() || other.IsAboveMax() || other.IsBelowMin()) {
// If either value is AboveMax, BelowMin or null, comparison is unordered
if (IsAboveMax() || IsBelowMin() || other.IsAboveMax() || other.IsBelowMin() ||
IsNull() || other.IsNull()) {
return std::partial_ordering::unordered;
}

Expand All @@ -202,13 +208,16 @@ std::partial_ordering Literal::operator<=>(const Literal& other) const {
return this_val ? std::partial_ordering::greater : std::partial_ordering::less;
}

case TypeId::kInt: {
case TypeId::kInt:
case TypeId::kDate: {
auto this_val = std::get<int32_t>(value_);
auto other_val = std::get<int32_t>(other.value_);
return this_val <=> other_val;
}

case TypeId::kLong: {
case TypeId::kLong:
case TypeId::kTimestamp:
case TypeId::kTimestampTz: {
auto this_val = std::get<int64_t>(value_);
auto other_val = std::get<int64_t>(other.value_);
return this_val <=> other_val;
Expand Down Expand Up @@ -253,6 +262,9 @@ std::string Literal::ToString() const {
if (std::holds_alternative<AboveMax>(value_)) {
return "aboveMax";
}
if (std::holds_alternative<std::monostate>(value_)) {
return "null";
}

switch (type_->type_id()) {
case TypeId::kBoolean: {
Expand Down Expand Up @@ -301,6 +313,8 @@ bool Literal::IsBelowMin() const { return std::holds_alternative<BelowMin>(value

bool Literal::IsAboveMax() const { return std::holds_alternative<AboveMax>(value_); }

bool Literal::IsNull() const { return std::holds_alternative<std::monostate>(value_); }

// LiteralCaster implementation

Result<Literal> LiteralCaster::CastTo(const Literal& literal,
Expand All @@ -312,7 +326,8 @@ Result<Literal> LiteralCaster::CastTo(const Literal& literal,

// Handle special values
if (std::holds_alternative<Literal::BelowMin>(literal.value_) ||
std::holds_alternative<Literal::AboveMax>(literal.value_)) {
std::holds_alternative<Literal::AboveMax>(literal.value_) ||
std::holds_alternative<std::monostate>(literal.value_)) {
// Cannot cast type for special values
return NotSupported("Cannot cast type for {}", literal.ToString());
}
Expand Down
33 changes: 24 additions & 9 deletions src/iceberg/expression/literal.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ namespace iceberg {

/// \brief Literal is a literal value that is associated with a primitive type.
class ICEBERG_EXPORT Literal {
private:
public:
/// \brief Sentinel value to indicate that the literal value is below the valid range
/// of a specific primitive type. It can happen when casting a literal to a narrower
/// primitive type.
Expand All @@ -48,27 +48,35 @@ class ICEBERG_EXPORT Literal {
bool operator==(const AboveMax&) const = default;
std::strong_ordering operator<=>(const AboveMax&) const = default;
};

using Value = std::variant<bool, // for boolean
int32_t, // for int, date
int64_t, // for long, timestamp, timestamp_tz, time
float, // for float
double, // for double
std::string, // for string
using Value = std::variant<std::monostate, // for null
bool, // for boolean
int32_t, // for int, date
int64_t, // for long, timestamp, timestamp_tz, time
float, // for float
double, // for double
std::string, // for string
std::vector<uint8_t>, // for binary, fixed
std::array<uint8_t, 16>, // for uuid and decimal
BelowMin, AboveMax>;

public:
/// \brief Factory methods for primitive types
static Literal Boolean(bool value);
static Literal Int(int32_t value);
static Literal Date(int32_t value);
static Literal Long(int64_t value);
static Literal Time(int64_t value);
static Literal Timestamp(int64_t value);
static Literal TimestampTz(int64_t value);
static Literal Float(float value);
static Literal Double(double value);
static Literal String(std::string value);
static Literal Binary(std::vector<uint8_t> value);

/// \brief Create a literal representing a null value.
static Literal Null(std::shared_ptr<PrimitiveType> type) {
return {Value{std::monostate{}}, std::move(type)};
}

/// \brief Restore a literal from single-value serialization.
///
/// See [this spec](https://iceberg.apache.org/spec/#binary-single-value-serialization)
Expand All @@ -85,6 +93,9 @@ class ICEBERG_EXPORT Literal {
/// \brief Get the literal type.
const std::shared_ptr<PrimitiveType>& type() const;

/// \brief Get the literal value.
const Value& value() const { return value_; }

/// \brief Converts this literal to a literal of the given type.
///
/// When a predicate is bound to a concrete data column, literals are converted to match
Expand Down Expand Up @@ -123,6 +134,10 @@ class ICEBERG_EXPORT Literal {
/// \return true if this literal represents a BelowMin value, false otherwise
bool IsBelowMin() const;

/// Check if this literal is null.
/// \return true if this literal is null, false otherwise
bool IsNull() const;

std::string ToString() const;

private:
Expand Down
10 changes: 6 additions & 4 deletions src/iceberg/transform.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include <memory>
#include <variant>

#include "iceberg/arrow_c_data.h"
#include "iceberg/expression/literal.h"
#include "iceberg/iceberg_export.h"
#include "iceberg/result.h"
#include "iceberg/type_fwd.h"
Expand Down Expand Up @@ -170,14 +170,16 @@ class ICEBERG_EXPORT TransformFunction {
public:
virtual ~TransformFunction() = default;
TransformFunction(TransformType transform_type, std::shared_ptr<Type> source_type);
/// \brief Transform an input array to a new array
virtual Result<ArrowArray> Transform(const ArrowArray& data) = 0;
/// \brief Transform an input Literal to a new Literal
///
/// All transforms must return null for a null input value.
virtual Result<Literal> Transform(const Literal& literal) = 0;
/// \brief Get the transform type
TransformType transform_type() const;
/// \brief Get the source type of transform function
const std::shared_ptr<Type>& source_type() const;
/// \brief Get the result type of transform function
virtual Result<std::shared_ptr<Type>> ResultType() const = 0;
virtual std::shared_ptr<Type> ResultType() const = 0;

friend bool operator==(const TransformFunction& lhs, const TransformFunction& rhs) {
return lhs.Equals(rhs);
Expand Down
Loading
Loading