Skip to content

Commit cf43748

Browse files
committed
add string
1 parent c9050af commit cf43748

File tree

2 files changed

+123
-1
lines changed

2 files changed

+123
-1
lines changed

src/iceberg/expression/literal.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ Result<Literal> LiteralCaster::CastFromString(
214214
// Parse "YYYY-MM-DD" into days since 1970-01-01 epoch.
215215
in >> std::get_time(&tm, "%Y-%m-%d");
216216

217-
if (in.fail() || in.peek() != EOF) {
217+
if (in.fail() || tm.tm_mday == 0 || in.peek() != EOF) {
218218
return NotSupported("Failed to parse '{}' as a valid Date (expected YYYY-MM-DD)",
219219
str_val);
220220
}

test/literal_test.cc

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,120 @@ TEST(LiteralTest, StringComparison) {
290290
EXPECT_EQ(string2 <=> string1, std::partial_ordering::greater);
291291
}
292292

293+
TEST(LiteralTest, StringCastToDate) {
294+
// Test standard date format
295+
auto literal1 = Literal::String("2023-05-15");
296+
auto result1 = literal1.CastTo(iceberg::date());
297+
ASSERT_THAT(result1, IsOk());
298+
EXPECT_EQ(result1->type()->type_id(), TypeId::kDate);
299+
EXPECT_EQ(result1->ToString(), "19492");
300+
301+
// Test epoch
302+
auto literal_epoch = Literal::String("1970-01-01");
303+
auto result_epoch = literal_epoch.CastTo(iceberg::date());
304+
ASSERT_THAT(result_epoch, IsOk());
305+
EXPECT_EQ(result_epoch->ToString(), "0");
306+
307+
// Test pre-epoch
308+
auto literal_pre_epoch = Literal::String("1969-12-31");
309+
auto result_pre_epoch = literal_pre_epoch.CastTo(iceberg::date());
310+
ASSERT_THAT(result_pre_epoch, IsOk());
311+
EXPECT_EQ(result_pre_epoch->ToString(), "-1");
312+
313+
// Invalid Formats
314+
auto invalid1 = Literal::String("2023/05/15");
315+
EXPECT_THAT(invalid1.CastTo(iceberg::date()), IsError(ErrorKind::kNotSupported));
316+
317+
auto invalid2 = Literal::String("2023-05-15 extra");
318+
EXPECT_THAT(invalid2.CastTo(iceberg::date()), IsError(ErrorKind::kNotSupported));
319+
320+
auto invalid3 = Literal::String("2023-05");
321+
EXPECT_THAT(invalid3.CastTo(iceberg::date()), IsError(ErrorKind::kNotSupported));
322+
}
323+
324+
TEST(LiteralTest, StringCastToTime) {
325+
// Test without fractional part
326+
auto literal1 = Literal::String("12:00:00");
327+
auto result1 = literal1.CastTo(iceberg::time());
328+
ASSERT_THAT(result1, IsOk());
329+
EXPECT_EQ(result1->type()->type_id(), TypeId::kTime);
330+
EXPECT_EQ(result1->ToString(), "43200000000"); // 12h in microseconds
331+
332+
// Test with full fractional part
333+
auto literal2 = Literal::String("12:34:56.123456");
334+
auto result2 = literal2.CastTo(iceberg::time());
335+
ASSERT_THAT(result2, IsOk());
336+
EXPECT_EQ(result2->ToString(), "45296123456");
337+
338+
// Test with fractional part that needs padding
339+
auto literal3 = Literal::String("01:02:03.123");
340+
auto result3 = literal3.CastTo(iceberg::time());
341+
ASSERT_THAT(result3, IsOk());
342+
EXPECT_EQ(result3->ToString(), "3723123000"); // .123 becomes .123000
343+
344+
// Test with fractional part that needs truncation
345+
auto literal4 = Literal::String("23:59:59.987654321");
346+
auto result4 = literal4.CastTo(iceberg::time());
347+
ASSERT_THAT(result4, IsOk());
348+
EXPECT_EQ(result4->ToString(), "86399987654");
349+
350+
// Invalid Formats
351+
auto invalid1 = Literal::String("12-00-00");
352+
EXPECT_THAT(invalid1.CastTo(iceberg::time()), IsError(ErrorKind::kNotSupported));
353+
354+
auto invalid2 = Literal::String("12:00:00 extra");
355+
EXPECT_THAT(invalid2.CastTo(iceberg::time()), IsError(ErrorKind::kNotSupported));
356+
357+
auto invalid3 = Literal::String("25:00:00");
358+
EXPECT_THAT(invalid3.CastTo(iceberg::time()), IsError(ErrorKind::kNotSupported));
359+
}
360+
361+
TEST(LiteralTest, StringCastToTimestamp) {
362+
// Test without fractional part
363+
auto literal1 = Literal::String("2023-05-15T12:00:00");
364+
auto result1 = literal1.CastTo(iceberg::timestamp());
365+
ASSERT_THAT(result1, IsOk());
366+
EXPECT_EQ(result1->type()->type_id(), TypeId::kTimestamp);
367+
EXPECT_EQ(result1->ToString(), "1684152000000000");
368+
369+
// Test with full fractional part
370+
auto literal2 = Literal::String("2023-05-15T12:34:56.123456");
371+
auto result2 = literal2.CastTo(iceberg::timestamp());
372+
ASSERT_THAT(result2, IsOk());
373+
EXPECT_EQ(result2->ToString(), "1684154096123456");
374+
375+
// Invalid Formats
376+
auto invalid1 = Literal::String("2023-05-15 12:00:00");
377+
EXPECT_THAT(invalid1.CastTo(iceberg::timestamp()), IsError(ErrorKind::kNotSupported));
378+
379+
auto invalid2 = Literal::String("2023-05-15T12:00:00Z");
380+
EXPECT_THAT(invalid2.CastTo(iceberg::timestamp()), IsError(ErrorKind::kNotSupported));
381+
}
382+
383+
TEST(LiteralTest, StringCastToTimestampTz) {
384+
// Test with 'Z' suffix and fractional part
385+
auto literal1 = Literal::String("2023-05-15T12:34:56.123456Z");
386+
auto result1 = literal1.CastTo(iceberg::timestamp_tz());
387+
ASSERT_THAT(result1, IsOk());
388+
EXPECT_EQ(result1->type()->type_id(), TypeId::kTimestampTz);
389+
EXPECT_EQ(result1->ToString(), "1684154096123456");
390+
391+
// Test without 'Z' suffix (should still be interpreted as UTC per spec)
392+
auto literal2 = Literal::String("2023-05-15T12:00:00");
393+
auto result2 = literal2.CastTo(iceberg::timestamp_tz());
394+
ASSERT_THAT(result2, IsOk());
395+
EXPECT_EQ(result2->ToString(), "1684152000000000");
396+
397+
// Invalid & Unsupported Formats
398+
auto unsupported1 = Literal::String("2023-05-15T12:00:00+08:00");
399+
EXPECT_THAT(unsupported1.CastTo(iceberg::timestamp_tz()),
400+
IsError(ErrorKind::kNotSupported));
401+
402+
auto invalid2 = Literal::String("2023-05-15T12:00:00Z oops");
403+
EXPECT_THAT(invalid2.CastTo(iceberg::timestamp_tz()),
404+
IsError(ErrorKind::kNotSupported));
405+
}
406+
293407
// Binary type tests
294408
TEST(LiteralTest, BinaryBasics) {
295409
std::vector<uint8_t> data = {0x01, 0x02, 0x03, 0xFF};
@@ -534,6 +648,14 @@ TEST(LiteralTest, CrossTypeComparison) {
534648
EXPECT_EQ(int_literal <=> string_literal, std::partial_ordering::unordered);
535649
}
536650

651+
// Special value tests
652+
TEST(LiteralTest, SpecialValues) {
653+
auto int_literal = Literal::Int(42);
654+
655+
EXPECT_FALSE(int_literal.IsAboveMax());
656+
EXPECT_FALSE(int_literal.IsBelowMin());
657+
}
658+
537659
// Same type cast test
538660
TEST(LiteralTest, SameTypeCast) {
539661
auto int_literal = Literal::Int(42);

0 commit comments

Comments
 (0)