Skip to content

Commit 2cb617e

Browse files
committed
feat: Implement Type Casting and toString for Literals
1 parent c452916 commit 2cb617e

4 files changed

Lines changed: 65 additions & 65 deletions

File tree

src/iceberg/expression/literal.cc

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,17 @@
1919

2020
#include "iceberg/expression/literal.h"
2121

22+
#include <cmath>
2223
#include <concepts>
2324
#include <cstdint>
25+
#include <string>
2426

2527
#include "iceberg/exception.h"
2628
#include "iceberg/util/conversions.h"
2729
#include "iceberg/util/macros.h"
2830
#include "iceberg/util/date_time_util.h"
31+
#include "iceberg/type_fwd.h"
32+
#include "iceberg/util/macros.h"
2933

3034
namespace iceberg {
3135

@@ -103,7 +107,6 @@ Result<Literal> LiteralCaster::CastFromInt(
103107
return Literal::Double(static_cast<double>(int_val));
104108
case TypeId::kDate:
105109
return Literal::Date(int_val);
106-
// TODO(Li Feiyang): Implement cast from Int to decimal
107110
default:
108111
return NotSupported("Cast from Int to {} is not implemented",
109112
target_type->ToString());
@@ -144,7 +147,6 @@ Result<Literal> LiteralCaster::CastFromLong(
144147
return Literal::Timestamp(long_val);
145148
case TypeId::kTimestampTz:
146149
return Literal::TimestampTz(long_val);
147-
// TODO(Li Feiyang): Implement cast from Long to decimal, TimestampNs and
148150
default:
149151
return NotSupported("Cast from Long to {} is not supported",
150152
target_type->ToString());
@@ -158,7 +160,6 @@ Result<Literal> LiteralCaster::CastFromFloat(
158160
switch (target_type->type_id()) {
159161
case TypeId::kDouble:
160162
return Literal::Double(static_cast<double>(float_val));
161-
// TODO(Li Feiyang): Implement cast from Float to decimal
162163
default:
163164
return NotSupported("Cast from Float to {} is not supported",
164165
target_type->ToString());
@@ -194,10 +195,9 @@ Result<Literal> LiteralCaster::CastFromString(
194195
case TypeId::kTime:
195196
case TypeId::kTimestamp:
196197
case TypeId::kTimestampTz:
198+
case TypeId::kUuid:
197199
return NotImplemented("Cast from String to {} is not implemented yet",
198200
target_type->ToString());
199-
// TODO(Li Feiyang): Implement cast from String to uuid and decimal
200-
201201
default:
202202
return NotSupported("Cast from String to {} is not supported",
203203
target_type->ToString());
@@ -256,8 +256,7 @@ Result<Literal> LiteralCaster::CastFromFixed(
256256
const Literal& literal, const std::shared_ptr<PrimitiveType>& target_type) {
257257
switch (target_type->type_id()) {
258258
case TypeId::kBinary:
259-
return Literal::Binary(
260-
std::get<std::vector<uint8_t>>(literal.value_)); // 直接拷贝+move
259+
return Literal::Binary(std::get<std::vector<uint8_t>>(literal.value_));
261260
default:
262261
return NotSupported("Cast from Fixed to {} is not supported",
263262
target_type->ToString());
@@ -413,6 +412,13 @@ std::partial_ordering Literal::operator<=>(const Literal& other) const {
413412
}
414413

415414
std::string Literal::ToString() const {
415+
auto unsupported_error = [this]() {
416+
return std::format("ToString not supported for type: {}", type_->ToString());
417+
};
418+
auto invalid_argument = [this]() {
419+
return std::format("Invalid argument for type: {}", type_->ToString());
420+
};
421+
416422
if (std::holds_alternative<BelowMin>(value_)) {
417423
return "belowMin";
418424
}
@@ -440,14 +446,13 @@ std::string Literal::ToString() const {
440446
return std::to_string(std::get<double>(value_));
441447
}
442448
case TypeId::kString: {
443-
return std::get<std::string>(value_);
449+
return "\"" + std::get<std::string>(value_) + "\"";
444450
}
445451
case TypeId::kBinary:
446452
case TypeId::kFixed: {
447453
const auto& binary_data = std::get<std::vector<uint8_t>>(value_);
448454
std::string result = "X'";
449-
result.reserve(2 + binary_data.size() * 2 +
450-
1); // 2 chars per byte and 2 + 1 for prefix and suffix
455+
result.reserve(/*prefix*/ 2 + /*suffix*/ 1 + /*data*/ binary_data.size() * 2);
451456
for (const auto& byte : binary_data) {
452457
std::format_to(std::back_inserter(result), "{:02X}", byte);
453458
}
@@ -462,12 +467,8 @@ std::string Literal::ToString() const {
462467
case TypeId::kDate: {
463468
return std::to_string(std::get<int32_t>(value_));
464469
}
465-
case TypeId::kDecimal:
466-
case TypeId::kUuid: {
467-
throw NotImplemented("kDecimal and kUuid are not implemented yet");
468-
}
469470
default: {
470-
throw IcebergError("Unknown type: " + type_->ToString());
471+
return unsupported_error();
471472
}
472473
}
473474
}
@@ -499,6 +500,9 @@ Result<Literal> LiteralCaster::CastTo(const Literal& literal,
499500

500501
// Delegate to specific cast functions based on source type
501502
switch (source_type_id) {
503+
case TypeId::kBoolean:
504+
// No casts defined for Boolean, other than to itself.
505+
break;
502506
case TypeId::kInt:
503507
return CastFromInt(literal, target_type);
504508
case TypeId::kLong:
@@ -517,12 +521,11 @@ Result<Literal> LiteralCaster::CastTo(const Literal& literal,
517521
return CastFromTimestamp(literal, target_type);
518522
case TypeId::kTimestampTz:
519523
return CastFromTimestampTz(literal, target_type);
520-
case TypeId::kBoolean:
521524
default:
522525
break;
523526
}
524527

525-
return NotSupported("Cast from {} to {} is not implemented", literal.type_->ToString(),
528+
return NotSupported("Cast from {} to {} is not supported", literal.type_->ToString(),
526529
target_type->ToString());
527530
}
528531

src/iceberg/expression/literal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class ICEBERG_EXPORT Literal : public util::Formattable {
5757
double, // for double
5858
std::string, // for string
5959
std::vector<uint8_t>, // for binary, fixed
60-
std::array<uint8_t, 16>, // for uuid and decimal
60+
std::array<uint8_t, 16>, // for uuid
6161
BelowMin, AboveMax>;
6262

6363
/// \brief Factory methods for primitive types

src/iceberg/test/literal_test.cc

Lines changed: 43 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ void AssertCastSucceeds(const Result<Literal>& result, TypeId expected_type_id,
4040
ASSERT_THAT(result, IsOk());
4141
EXPECT_EQ(result->type()->type_id(), expected_type_id);
4242
ASSERT_NO_THROW(EXPECT_EQ(std::get<T>(result->value()), expected_value))
43-
<< "Value type mismatch in std::get. Expected type for TypeId "
43+
<< "Type mismatch in std::get. Expected type for TypeId "
4444
<< static_cast<int>(expected_type_id);
4545
}
4646

@@ -146,15 +146,15 @@ TEST(LiteralTest, LongCastTo) {
146146

147147
// Cast to Time
148148
AssertCastSucceeds(long_literal.CastTo(iceberg::time()), TypeId::kTime,
149-
static_cast<int64_t>(42L));
149+
static_cast<int64_t>(42));
150150

151151
// Cast to Timestamp
152152
AssertCastSucceeds(long_literal.CastTo(iceberg::timestamp()), TypeId::kTimestamp,
153-
static_cast<int64_t>(42L));
153+
static_cast<int64_t>(42));
154154

155155
// Cast to TimestampTz
156156
AssertCastSucceeds(long_literal.CastTo(iceberg::timestamp_tz()), TypeId::kTimestampTz,
157-
static_cast<int64_t>(42L));
157+
static_cast<int64_t>(42));
158158
}
159159

160160
TEST(LiteralTest, LongCastToIntOverflow) {
@@ -203,11 +203,11 @@ TEST(LiteralTest, FloatComparison) {
203203
}
204204

205205
TEST(LiteralTest, FloatCastTo) {
206-
auto float_literal = Literal::Float(3.14f);
206+
auto float_literal = Literal::Float(2.0f);
207207

208208
// Cast to Double
209209
AssertCastSucceeds(float_literal.CastTo(iceberg::float64()), TypeId::kDouble,
210-
static_cast<double>(3.14f));
210+
static_cast<double>(2.0f));
211211
}
212212

213213
// Double type tests
@@ -233,10 +233,10 @@ TEST(LiteralTest, DoubleComparison) {
233233
}
234234

235235
TEST(LiteralTest, DoubleCastTo) {
236-
auto double_literal = Literal::Double(3.14);
236+
auto double_literal = Literal::Double(2.0);
237237

238238
// Cast to Float
239-
AssertCastSucceeds(double_literal.CastTo(iceberg::float32()), TypeId::kFloat, 3.14f);
239+
AssertCastSucceeds(double_literal.CastTo(iceberg::float32()), TypeId::kFloat, 2.0f);
240240
}
241241

242242
TEST(LiteralTest, DoubleCastToOverflow) {
@@ -263,8 +263,8 @@ TEST(LiteralTest, StringBasics) {
263263
EXPECT_EQ(string_literal.type()->type_id(), TypeId::kString);
264264
EXPECT_EQ(empty_string.type()->type_id(), TypeId::kString);
265265

266-
EXPECT_EQ(string_literal.ToString(), "hello world");
267-
EXPECT_EQ(empty_string.ToString(), "");
266+
EXPECT_EQ(string_literal.ToString(), "\"hello world\"");
267+
EXPECT_EQ(empty_string.ToString(), "\"\"");
268268
}
269269

270270
TEST(LiteralTest, StringComparison) {
@@ -304,6 +304,18 @@ TEST(LiteralTest, BinaryComparison) {
304304
EXPECT_EQ(binary2 <=> binary1, std::partial_ordering::greater);
305305
}
306306

307+
TEST(LiteralTest, BinaryCastTo) {
308+
std::vector<uint8_t> data4 = {0x01, 0x02, 0x03, 0x04};
309+
auto binary_literal = Literal::Binary(data4);
310+
311+
// Cast to Fixed with matching length
312+
AssertCastSucceeds(binary_literal.CastTo(iceberg::fixed(4)), TypeId::kFixed, data4);
313+
314+
// Cast to Fixed with different length should fail
315+
EXPECT_THAT(binary_literal.CastTo(iceberg::fixed(5)),
316+
IsError(ErrorKind::kInvalidArgument));
317+
}
318+
307319
// Fixed type tests
308320
TEST(LiteralTest, FixedBasics) {
309321
std::vector<uint8_t> data = {0x01, 0x02, 0x03, 0xFF};
@@ -331,6 +343,20 @@ TEST(LiteralTest, FixedComparison) {
331343
EXPECT_EQ(fixed2 <=> fixed1, std::partial_ordering::greater);
332344
}
333345

346+
TEST(LiteralTest, FixedCastTo) {
347+
std::vector<uint8_t> data4 = {0x01, 0x02, 0x03, 0x04};
348+
auto fixed_literal = Literal::Fixed(data4);
349+
350+
// Cast to Binary
351+
AssertCastSucceeds(fixed_literal.CastTo(iceberg::binary()), TypeId::kBinary, data4);
352+
353+
// Cast to Fixed with same length
354+
AssertCastSucceeds(fixed_literal.CastTo(iceberg::fixed(4)), TypeId::kFixed, data4);
355+
356+
// Cast to Fixed with different length should fail
357+
EXPECT_THAT(fixed_literal.CastTo(iceberg::fixed(5)), IsError(ErrorKind::kNotSupported));
358+
}
359+
334360
// Date type tests
335361
TEST(LiteralTest, DateBasics) {
336362
auto date_literal = Literal::Date(19489); // May 15, 2023
@@ -421,32 +447,6 @@ TEST(LiteralTest, TimestampTzComparison) {
421447
EXPECT_EQ(timestamptz2 <=> timestamptz1, std::partial_ordering::greater);
422448
}
423449

424-
TEST(LiteralTest, BinaryCastTo) {
425-
std::vector<uint8_t> data4 = {0x01, 0x02, 0x03, 0x04};
426-
auto binary_literal = Literal::Binary(data4);
427-
428-
// Cast to Fixed with matching length
429-
AssertCastSucceeds(binary_literal.CastTo(iceberg::fixed(4)), TypeId::kFixed, data4);
430-
431-
// Cast to Fixed with different length should fail
432-
EXPECT_THAT(binary_literal.CastTo(iceberg::fixed(5)),
433-
IsError(ErrorKind::kInvalidArgument));
434-
}
435-
436-
TEST(LiteralTest, FixedCastTo) {
437-
std::vector<uint8_t> data4 = {0x01, 0x02, 0x03, 0x04};
438-
auto fixed_literal = Literal::Fixed(data4);
439-
440-
// Cast to Binary
441-
AssertCastSucceeds(fixed_literal.CastTo(iceberg::binary()), TypeId::kBinary, data4);
442-
443-
// Cast to Fixed with same length
444-
AssertCastSucceeds(fixed_literal.CastTo(iceberg::fixed(4)), TypeId::kFixed, data4);
445-
446-
// Cast to Fixed with different length should fail
447-
EXPECT_THAT(fixed_literal.CastTo(iceberg::fixed(5)), IsError(ErrorKind::kNotSupported));
448-
}
449-
450450
// Cross-type comparison tests
451451
TEST(LiteralTest, CrossTypeComparison) {
452452
auto int_literal = Literal::Int(42);
@@ -456,22 +456,18 @@ TEST(LiteralTest, CrossTypeComparison) {
456456
EXPECT_EQ(int_literal <=> string_literal, std::partial_ordering::unordered);
457457
}
458458

459-
// Special value tests
460-
TEST(LiteralTest, SpecialValues) {
459+
// Same type cast tests
460+
TEST(LiteralTest, SameTypeCast) {
461461
auto int_literal = Literal::Int(42);
462462

463-
EXPECT_FALSE(int_literal.IsAboveMax());
464-
EXPECT_FALSE(int_literal.IsBelowMin());
463+
AssertCastSucceeds(int_literal.CastTo(iceberg::int32()), TypeId::kInt, 42);
465464
}
466465

467-
// Same type cast test
468-
TEST(LiteralTest, SameTypeCast) {
466+
// Special value tests
467+
TEST(LiteralTest, SpecialValues) {
469468
auto int_literal = Literal::Int(42);
470-
471-
auto same_type_result = int_literal.CastTo(iceberg::int32());
472-
ASSERT_THAT(same_type_result, IsOk());
473-
EXPECT_EQ(same_type_result->type()->type_id(), TypeId::kInt);
474-
EXPECT_EQ(same_type_result->ToString(), "42");
469+
EXPECT_FALSE(int_literal.IsAboveMax());
470+
EXPECT_FALSE(int_literal.IsBelowMin());
475471
}
476472

477473
// Float special values tests

src/iceberg/transform_function.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include "iceberg/expression/literal.h"
2929
#include "iceberg/type.h"
30+
#include "iceberg/util/int128.h"
3031
#include "iceberg/util/murmurhash3_internal.h"
3132
#include "iceberg/util/truncate_util.h"
3233

0 commit comments

Comments
 (0)