This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 9ff4207c193 [bugfix](zonemap string) datetimev2 should always using
scale 6 to produce string (#61529)
9ff4207c193 is described below
commit 9ff4207c19375543df258339c0a0deb7f5750237
Author: yiguolei <[email protected]>
AuthorDate: Fri Mar 20 14:11:40 2026 +0800
[bugfix](zonemap string) datetimev2 should always using scale 6 to produce
string (#61529)
### What problem does this PR solve?
Issue Number: close #xxx
Related PR: #xxx
Problem Summary:
### Release note
None
### Check List (For Author)
- Test <!-- At least one of them must be included. -->
- [ ] Regression test
- [ ] Unit Test
- [ ] Manual test (add detailed scripts or steps below)
- [ ] No need to test or manual test. Explain why:
- [ ] This is a refactor/code format and no logic has been changed.
- [ ] Previous test can cover this change.
- [ ] No code files have been changed.
- [ ] Other reason <!-- Add your reason? -->
- Behavior changed:
- [ ] No.
- [ ] Yes. <!-- Explain the behavior change -->
- Does this need documentation?
- [ ] No.
- [ ] Yes. <!-- Add document PR link here. eg:
https://github.com/apache/doris-website/pull/1214 -->
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label <!-- Add branch pick label that this PR
should merge into -->
---
.../data_type_serde/data_type_datetimev2_serde.cpp | 11 +-
be/test/storage/olap_type_test.cpp | 784 ++++++++++++++++++++-
2 files changed, 766 insertions(+), 29 deletions(-)
diff --git a/be/src/core/data_type_serde/data_type_datetimev2_serde.cpp
b/be/src/core/data_type_serde/data_type_datetimev2_serde.cpp
index e652c23f64c..12f65e86bd7 100644
--- a/be/src/core/data_type_serde/data_type_datetimev2_serde.cpp
+++ b/be/src/core/data_type_serde/data_type_datetimev2_serde.cpp
@@ -528,15 +528,16 @@ void
DataTypeDateTimeV2SerDe::write_one_cell_to_binary(const IColumn& src_column
// Serializes a DateTimeV2 value to its OLAP string representation for ZoneMap
storage.
// This is the inverse of from_olap_string().
//
-// Delegates to CastToString::from_datetimev2(value, scale) with default
scale=-1,
-// meaning microseconds are only shown when nonzero.
+// Always passes scale=6 to CastToString::from_datetimev2 because historically
the Field
+// type for DateTimeV2 always stores values with 6-digit (microsecond)
precision.
+// With scale=6, the fractional part is ALWAYS written, even when
microsecond=0.
//
-// Output format: "YYYY-MM-DD HH:MM:SS[.ffffff]"
+// Output format: "YYYY-MM-DD HH:MM:SS.ffffff"
// Examples:
-// value with microsecond=0 => "2023-10-15 14:30:00"
+// value with microsecond=0 => "2023-10-15 14:30:00.000000"
// value with microsecond=123000 => "2023-10-15 14:30:00.123000"
std::string DataTypeDateTimeV2SerDe::to_olap_string(const Field& field) const {
- return CastToString::from_datetimev2(field.get<TYPE_DATETIMEV2>());
+ return CastToString::from_datetimev2(field.get<TYPE_DATETIMEV2>(), 6);
}
// NOLINTEND(readability-function-cognitive-complexity)
diff --git a/be/test/storage/olap_type_test.cpp
b/be/test/storage/olap_type_test.cpp
index 1b000a5e435..2511b5158a0 100644
--- a/be/test/storage/olap_type_test.cpp
+++ b/be/test/storage/olap_type_test.cpp
@@ -18,6 +18,7 @@
#include <gtest/gtest-message.h>
#include <gtest/gtest-test-part.h>
+#include <cstring>
#include <fstream>
#include <iostream>
@@ -1129,25 +1130,23 @@ TEST_F(OlapTypeTest, ser_deser_datev2) {
}
// ---------------------------------------------------------------------------
-// DateTimeV2 (TYPE_DATETIMEV2): to_olap_string outputs "YYYY-MM-DD
HH:MM:SS[.ffffff]".
+// DateTimeV2 (TYPE_DATETIMEV2): to_olap_string outputs "YYYY-MM-DD
HH:MM:SS.ffffff".
// Internal: DateV2Value<DateTimeV2ValueType>, stored as uint64_t
(bit-packed).
-// to_olap_string calls CastToString::from_datetimev2(value) with DEFAULT
scale=-1.
-// With scale=-1, the microsecond part is appended ONLY if microsecond > 0,
-// and always with 6 digits when present.
+// to_olap_string always calls CastToString::from_datetimev2(value, 6)
because
+// historically the Field type for DateTimeV2 always stores 6-digit
(microsecond) precision.
+// With scale=6, the fractional part is ALWAYS written with 6 digits, even
when microsecond=0.
//
-// Note: the old ZoneMap code in types.h used value.to_string(6) which ALWAYS
-// outputs 6 fractional digits even when microsecond=0.
-//
-// Multiple scale values are tested:
-// scale=0: no fractional seconds (input microseconds are stored but
to_olap_string
-// still uses default scale=-1, so microseconds appear if
non-zero)
-// scale=3: millisecond precision
-// scale=6: microsecond precision (full precision)
+// Multiple serde scale values are tested, but since to_olap_string always
uses scale=6,
+// the output format is the same regardless of the serde's own scale:
+// scale=0: output is still "YYYY-MM-DD HH:MM:SS.000000" (fractional part
always present)
+// scale=3: fractional part always present, 6 digits
+// scale=6: fractional part always present, 6 digits
//
// from_zonemap_string uses from_date_format_str("%Y-%m-%d %H:%i:%s.%f").
// ---------------------------------------------------------------------------
TEST_F(OlapTypeTest, ser_deser_datetimev2_no_microsecond) {
- // Test with scale=0: no fractional seconds expected
+ // Test with scale=0 serde, but to_olap_string always uses scale=6:
+ // fractional part is always written even when microsecond=0.
auto data_type_ptr = DataTypeFactory::instance().create_data_type(
TYPE_DATETIMEV2, /*is_nullable=*/false, /*precision=*/0,
/*scale=*/0);
auto serde = data_type_ptr->get_serde();
@@ -1158,10 +1157,10 @@ TEST_F(OlapTypeTest,
ser_deser_datetimev2_no_microsecond) {
std::string expected_str;
};
std::vector<TestCase> test_cases = {
- // No microseconds → no fractional part in output
- {2023, 6, 15, 14, 30, 59, 0, "2023-06-15 14:30:59"},
- {2000, 1, 1, 0, 0, 0, 0, "2000-01-01 00:00:00"},
- {9999, 12, 31, 23, 59, 59, 0, "9999-12-31 23:59:59"},
+ // No microseconds → fractional part is still written as .000000
(scale=6 always)
+ {2023, 6, 15, 14, 30, 59, 0, "2023-06-15 14:30:59.000000"},
+ {2000, 1, 1, 0, 0, 0, 0, "2000-01-01 00:00:00.000000"},
+ {9999, 12, 31, 23, 59, 59, 0, "9999-12-31 23:59:59.000000"},
};
for (const auto& tc : test_cases) {
@@ -1189,7 +1188,7 @@ TEST_F(OlapTypeTest, ser_deser_datetimev2_no_microsecond)
{
TEST_F(OlapTypeTest, ser_deser_datetimev2_with_microsecond) {
// Test with scale=6 (full microsecond precision)
- // to_olap_string default scale=-1 will output microseconds when > 0
+ // to_olap_string always uses scale=6: fractional part is always written
with 6 digits.
auto data_type_ptr = DataTypeFactory::instance().create_data_type(
TYPE_DATETIMEV2, /*is_nullable=*/false, /*precision=*/0,
/*scale=*/6);
auto serde = data_type_ptr->get_serde();
@@ -1208,8 +1207,8 @@ TEST_F(OlapTypeTest,
ser_deser_datetimev2_with_microsecond) {
{9999, 12, 31, 23, 59, 59, 999999, "9999-12-31 23:59:59.999999"},
// microsecond=100000 → ".100000"
{2023, 3, 15, 12, 0, 0, 100000, "2023-03-15 12:00:00.100000"},
- // microsecond=0 → no fractional part (scale=-1 omits when
microsecond=0)
- {2023, 3, 15, 12, 0, 0, 0, "2023-03-15 12:00:00"},
+ // microsecond=0 → fractional part is still written as .000000
(scale=6 always)
+ {2023, 3, 15, 12, 0, 0, 0, "2023-03-15 12:00:00.000000"},
};
for (const auto& tc : test_cases) {
@@ -1238,10 +1237,10 @@ TEST_F(OlapTypeTest,
ser_deser_datetimev2_with_microsecond) {
TEST_F(OlapTypeTest, ser_deser_datetimev2_scale3) {
// Test with scale=3 (millisecond precision)
- // to_olap_string uses default scale=-1, so behavior is the same as scale=6
- // for the output: microsecond part appears ONLY if > 0, always 6 digits.
- // However, the data type has scale=3, meaning from_zonemap_string should
still
- // be able to parse back the full microsecond value stored in the field.
+ // to_olap_string always uses scale=6: fractional part is always written
with 6 digits.
+ // The data type has scale=3, but to_olap_string ignores this and always
uses scale=6
+ // because historically Field type for DateTimeV2 always stores 6-digit
precision.
+ // from_zonemap_string should still parse back the full microsecond value
stored in the field.
auto data_type_ptr = DataTypeFactory::instance().create_data_type(
TYPE_DATETIMEV2, /*is_nullable=*/false, /*precision=*/0,
/*scale=*/3);
auto serde = data_type_ptr->get_serde();
@@ -1270,4 +1269,741 @@ TEST_F(OlapTypeTest, ser_deser_datetimev2_scale3) {
EXPECT_EQ(restored_val.microsecond(), 123000);
}
}
+
+TEST_F(OlapTypeTest, char_type_with_padding) {
+ auto data_type =
+
DataTypeFactory::instance().create_data_type(FieldType::OLAP_FIELD_TYPE_CHAR,
0, 0, 20);
+ auto serde = data_type->get_serde();
+
+ {
+ char buf[20];
+ memset(buf, 0, sizeof(buf));
+ memcpy(buf, "hello", 5);
+ Slice olap_value(buf, 20);
+
+ std::string expected("hello", 5);
+ expected.append(15, '\0');
+ std::string expected_serde = expected;
+
+ auto field = Field::create_field_from_olap_value<TYPE_CHAR>(
+ StringRef(olap_value.data, olap_value.size));
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(expected_serde, serde_str) << "serde mismatch for CHAR(20)
'hello'"
+ << "\n expected len=" <<
expected_serde.size()
+ << "\n actual len=" <<
serde_str.size();
+ }
+
+ {
+ char buf[20];
+ memset(buf, 'x', 20);
+ Slice olap_value(buf, 20);
+
+ std::string expected(20, 'x');
+ std::string expected_serde = expected;
+
+ auto field = Field::create_field_from_olap_value<TYPE_CHAR>(
+ StringRef(olap_value.data, olap_value.size));
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(expected_serde, serde_str) << "serde mismatch for CHAR(20)
filled 'x'";
+ }
+
+ {
+ char buf[20];
+ memset(buf, 0, 20);
+ Slice olap_value(buf, 20);
+
+ std::string expected(20, '\0');
+ std::string expected_serde = expected;
+
+ auto field = Field::create_field_from_olap_value<TYPE_CHAR>(
+ StringRef(olap_value.data, olap_value.size));
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(expected_serde, serde_str) << "serde mismatch for CHAR(20)
empty"
+ << "\n expected len=" <<
expected_serde.size()
+ << "\n actual len=" <<
serde_str.size();
+ }
+}
+
+TEST_F(OlapTypeTest, varchar_type) {
+ auto data_type = DataTypeFactory::instance().create_data_type(
+ FieldType::OLAP_FIELD_TYPE_VARCHAR, 0, 0, 100);
+ auto serde = data_type->get_serde();
+
+ struct TestCase {
+ std::string input;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {"hello world", "hello world", "hello world"},
+ {"", "", ""},
+ };
+
+ for (auto& tc : test_cases) {
+ Slice olap_value(tc.input.data(), tc.input.size());
+
+ auto field = Field::create_field_from_olap_value<TYPE_VARCHAR>(
+ StringRef(olap_value.data, olap_value.size));
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str)
+ << "serde mismatch for VARCHAR '" << tc.input << "'";
+ }
+}
+
+TEST_F(OlapTypeTest, date_v1_type) {
+ auto data_type = DataTypeFactory::instance().create_data_type(TYPE_DATE,
false);
+ auto serde = data_type->get_serde();
+
+ auto make_olap_date = [](int year, int mon, int day) -> uint24_t {
+ return uint24_t(year * 16 * 32 + mon * 32 + day);
+ };
+
+ struct TestCase {
+ int year, month, day;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {2023, 6, 15, "2023-06-15", "2023-06-15"},
+ {2000, 1, 1, "2000-01-01", "2000-01-01"},
+ {9999, 12, 31, "9999-12-31", "9999-12-31"},
+ {1, 1, 1, "0001-01-01", "0001-01-01"},
+ };
+
+ for (auto& tc : test_cases) {
+ uint24_t olap_value = make_olap_date(tc.year, tc.month, tc.day);
+
+ auto field =
Field::create_field_from_olap_value<TYPE_DATE>(olap_value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str) << "serde mismatch for DATE "
<< tc.expected;
+ }
+}
+
+TEST_F(OlapTypeTest, datetime_v1_type) {
+ auto data_type =
DataTypeFactory::instance().create_data_type(TYPE_DATETIME, false);
+ auto serde = data_type->get_serde();
+
+ struct TestCase {
+ int64_t olap_value;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {20230615120000L, "2023-06-15 12:00:00", "2023-06-15 12:00:00"},
+ {20000101000000L, "2000-01-01 00:00:00", "2000-01-01 00:00:00"},
+ {99991231235959L, "9999-12-31 23:59:59", "9999-12-31 23:59:59"},
+ {20230615123456L, "2023-06-15 12:34:56", "2023-06-15 12:34:56"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto field =
Field::create_field_from_olap_value<TYPE_DATETIME>((uint64_t)tc.olap_value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str) << "serde mismatch for
DATETIME " << tc.expected;
+ }
+}
+
+TEST_F(OlapTypeTest, datev2_type) {
+ auto data_type = DataTypeFactory::instance().create_data_type(TYPE_DATEV2,
false);
+ auto serde = data_type->get_serde();
+
+ auto make_datev2 = [](int year, int month, int day) -> uint32_t {
+ return (year << 9) | (month << 5) | day;
+ };
+
+ struct TestCase {
+ int year, month, day;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {2023, 6, 15, "2023-06-15", "2023-06-15"},
+ {2000, 1, 1, "2000-01-01", "2000-01-01"},
+ {9999, 12, 31, "9999-12-31", "9999-12-31"},
+ {1, 1, 1, "0001-01-01", "0001-01-01"},
+ };
+
+ for (auto& tc : test_cases) {
+ uint32_t olap_value = make_datev2(tc.year, tc.month, tc.day);
+
+ auto field =
Field::create_field_from_olap_value<TYPE_DATEV2>(olap_value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str) << "serde mismatch for DATEV2
" << tc.expected;
+ }
+}
+
+TEST_F(OlapTypeTest, datetimev2_type) {
+ auto make_datetimev2 = [](int year, int month, int day, int hour, int
minute, int second,
+ int microsecond) -> uint64_t {
+ return ((uint64_t)year << 46) | ((uint64_t)month << 42) |
((uint64_t)day << 37) |
+ ((uint64_t)hour << 32) | ((uint64_t)minute << 26) |
((uint64_t)second << 20) |
+ (uint64_t)microsecond;
+ };
+
+ struct TestCase {
+ uint64_t olap_value;
+ std::string expected;
+ std::string expected_serde;
+ std::string desc;
+ };
+ std::vector<TestCase> test_cases = {
+ {make_datetimev2(2023, 6, 15, 12, 34, 56, 123456), "2023-06-15
12:34:56.123456",
+ "2023-06-15 12:34:56.123456", "non-zero microseconds"},
+ {make_datetimev2(2023, 6, 15, 12, 34, 56, 0), "2023-06-15
12:34:56.000000",
+ "2023-06-15 12:34:56", "zero microseconds"},
+ {make_datetimev2(2023, 1, 1, 0, 0, 0, 123000), "2023-01-01
00:00:00.123000",
+ "2023-01-01 00:00:00.123000", "trailing zeros in microseconds"},
+ {make_datetimev2(2000, 1, 1, 0, 0, 0, 0), "2000-01-01
00:00:00.000000",
+ "2000-01-01 00:00:00", "epoch zero microseconds"},
+ {make_datetimev2(2023, 6, 15, 12, 34, 56, 1), "2023-06-15
12:34:56.000001",
+ "2023-06-15 12:34:56.000001", "1 microsecond"},
+ {make_datetimev2(9999, 12, 31, 23, 59, 59, 999999), "9999-12-31
23:59:59.999999",
+ "9999-12-31 23:59:59.999999", "max datetime"},
+ };
+
+ for (int scale = 0; scale <= 6; ++scale) {
+ auto data_type =
+ DataTypeFactory::instance().create_data_type(TYPE_DATETIMEV2,
false, 0, scale);
+ auto serde = data_type->get_serde();
+
+ for (auto& tc : test_cases) {
+ auto field =
Field::create_field_from_olap_value<TYPE_DATETIMEV2>(tc.olap_value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected, serde_str)
+ << "serde mismatch for DATETIMEV2 scale=" << scale << ": "
<< tc.desc
+ << "\n expected: " << tc.expected << "\n serde: " <<
serde_str;
+ }
+ }
+}
+
+TEST_F(OlapTypeTest, datetime_v1_vs_v2_precision_difference) {
+ {
+ auto data_type =
DataTypeFactory::instance().create_data_type(TYPE_DATETIME, false);
+ auto serde = data_type->get_serde();
+
+ int64_t olap_value = 20230615123456L;
+ std::string expected = "2023-06-15 12:34:56";
+ std::string expected_serde = expected;
+ auto field =
Field::create_field_from_olap_value<TYPE_DATETIME>((uint64_t)olap_value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(expected_serde, serde_str) << "serde mismatch for DATETIME
V1";
+ EXPECT_EQ(expected.find('.'), std::string::npos)
+ << "DATETIME V1 should NOT have fractional seconds";
+ }
+
+ {
+ auto make_datetimev2 = [](int year, int month, int day, int hour, int
minute, int second,
+ int microsecond) -> uint64_t {
+ return ((uint64_t)year << 46) | ((uint64_t)month << 42) |
((uint64_t)day << 37) |
+ ((uint64_t)hour << 32) | ((uint64_t)minute << 26) |
((uint64_t)second << 20) |
+ (uint64_t)microsecond;
+ };
+
+ auto data_type =
DataTypeFactory::instance().create_data_type(TYPE_DATETIMEV2, false, 0, 6);
+ auto serde = data_type->get_serde();
+
+ uint64_t olap_value = make_datetimev2(2023, 6, 15, 12, 34, 56, 123456);
+ std::string expected = "2023-06-15 12:34:56.123456";
+ std::string expected_serde = expected;
+ auto field =
Field::create_field_from_olap_value<TYPE_DATETIMEV2>(olap_value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(expected_serde, serde_str) << "serde mismatch for
DATETIMEV2";
+ EXPECT_NE(expected.find('.'), std::string::npos)
+ << "DATETIMEV2 should have fractional seconds";
+ }
+}
+
+TEST_F(OlapTypeTest, decimalv2_type) {
+ auto data_type =
DataTypeFactory::instance().create_data_type(TYPE_DECIMALV2, false, 27, 9);
+ auto serde = data_type->get_serde();
+
+ struct TestCase {
+ int64_t integer;
+ int32_t fraction;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {0, 0, "0.000000000", "0.000000000"},
+ {1, 0, "1.000000000", "1.000000000"},
+ {0, 100000000, "0.100000000", "0.100000000"},
+ {123, 456000000, "123.456000000", "123.456000000"},
+ {-123, -456000000, "-123.456000000", "-123.456000000"},
+ {999999999999999999L, 999999999, "999999999999999999.999999999",
+ "999999999999999999.999999999"},
+ {-999999999999999999L, -999999999, "-999999999999999999.999999999",
+ "-999999999999999999.999999999"},
+ {1, 1, "1.000000001", "1.000000001"},
+ {1, 10, "1.000000010", "1.000000010"},
+ {1, 100, "1.000000100", "1.000000100"},
+ {1, 1000, "1.000001000", "1.000001000"},
+ {1, 10000, "1.000010000", "1.000010000"},
+ {1, 100000, "1.000100000", "1.000100000"},
+ {1, 1000000, "1.001000000", "1.001000000"},
+ {1, 10000000, "1.010000000", "1.010000000"},
+ {1, 100000000, "1.100000000", "1.100000000"},
+ {0, 123456789, "0.123456789", "0.123456789"},
+ {42, 500000000, "42.500000000", "42.500000000"},
+ };
+
+ for (auto& tc : test_cases) {
+ decimal12_t olap_value;
+ olap_value.integer = tc.integer;
+ olap_value.fraction = tc.fraction;
+
+ auto field =
Field::create_field_from_olap_value<TYPE_DECIMALV2>(olap_value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str)
+ << "serde mismatch for DECIMALV2 (" << tc.integer << ", " <<
tc.fraction << ")";
+ }
+}
+
+TEST_F(OlapTypeTest, decimal32_type) {
+ struct TestCase {
+ int32_t value;
+ int precision;
+ int scale;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {0, 9, 0, "0", "0"},
+ {12345, 9, 0, "12345", "12345"},
+ {12345, 9, 2, "12345", "12345"},
+ {12345, 9, 4, "12345", "12345"},
+ {-12345, 9, 2, "-12345", "-12345"},
+ {1, 9, 9, "1", "1"},
+ {999999999, 9, 0, "999999999", "999999999"},
+ {-999999999, 9, 0, "-999999999", "-999999999"},
+ {100000000, 9, 9, "100000000", "100000000"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto data_type = DataTypeFactory::instance().create_data_type(
+ FieldType::OLAP_FIELD_TYPE_DECIMAL32, tc.precision, tc.scale);
+ auto serde = data_type->get_serde();
+
+ int32_t olap_value = tc.value;
+ auto field =
Field::create_field_from_olap_value<TYPE_DECIMAL32>(olap_value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str)
+ << "serde mismatch for DECIMAL32 value=" << tc.value;
+ }
+}
+
+TEST_F(OlapTypeTest, decimal64_type) {
+ struct TestCase {
+ int64_t value;
+ int precision;
+ int scale;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {0, 18, 0, "0", "0"},
+ {123456789012345678L, 18, 0, "123456789012345678",
"123456789012345678"},
+ {123456789012345678L, 18, 6, "123456789012345678",
"123456789012345678"},
+ {-123456789012345678L, 18, 6, "-123456789012345678",
"-123456789012345678"},
+ {1, 18, 18, "1", "1"},
+ {100000, 18, 5, "100000", "100000"},
+ {1000000000000L, 18, 6, "1000000000000", "1000000000000"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto data_type = DataTypeFactory::instance().create_data_type(
+ FieldType::OLAP_FIELD_TYPE_DECIMAL64, tc.precision, tc.scale);
+ auto serde = data_type->get_serde();
+
+ int64_t olap_value = tc.value;
+ auto field =
Field::create_field_from_olap_value<TYPE_DECIMAL64>(olap_value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str)
+ << "serde mismatch for DECIMAL64 value=" << tc.value;
+ }
+}
+
+TEST_F(OlapTypeTest, decimal128i_type) {
+ struct TestCase {
+ int128_t value;
+ int precision;
+ int scale;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {0, 38, 0, "0", "0"},
+ {123456789, 38, 0, "123456789", "123456789"},
+ {123456789, 38, 6, "123456789", "123456789"},
+ {-123456789, 38, 6, "-123456789", "-123456789"},
+ {1, 38, 38, "1", "1"},
+ {(int128_t)999999999999999999L * 1000000000L + 999999999, 38, 9,
+ "999999999999999999999999999", "999999999999999999999999999"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto data_type = DataTypeFactory::instance().create_data_type(
+ FieldType::OLAP_FIELD_TYPE_DECIMAL128I, tc.precision,
tc.scale);
+ auto serde = data_type->get_serde();
+
+ int128_t olap_value = tc.value;
+ auto field =
Field::create_field_from_olap_value<TYPE_DECIMAL128I>(olap_value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str)
+ << "serde mismatch for DECIMAL128I expected=" << tc.expected;
+ }
+}
+
+TEST_F(OlapTypeTest, decimal256_type) {
+ struct TestCase {
+ wide::Int256 value;
+ int precision;
+ int scale;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {wide::Int256(0), 76, 0, "0", "0"},
+ {wide::Int256(123456789), 76, 0, "123456789", "123456789"},
+ {wide::Int256(123456789), 76, 6, "123456789", "123456789"},
+ {wide::Int256(-123456789), 76, 6, "-123456789", "-123456789"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto data_type = DataTypeFactory::instance().create_data_type(
+ FieldType::OLAP_FIELD_TYPE_DECIMAL256, tc.precision, tc.scale);
+ auto serde = data_type->get_serde();
+
+ wide::Int256 olap_value = tc.value;
+ auto field =
Field::create_field_from_olap_value<TYPE_DECIMAL256>(olap_value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str)
+ << "serde mismatch for DECIMAL256 expected=" << tc.expected;
+ }
+}
+
+TEST_F(OlapTypeTest, float_type) {
+ auto data_type = DataTypeFactory::instance().create_data_type(TYPE_FLOAT,
false);
+ auto serde = data_type->get_serde();
+
+ struct TestCase {
+ float value;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {0.0f, "0", "0"},
+ {-0.0f, "-0", "-0"},
+ {1.0f, "1", "1"},
+ {-1.0f, "-1", "-1"},
+ {0.5f, "0.5", "0.5"},
+ {1.5f, "1.5", "1.5"},
+ {0.25f, "0.25", "0.25"},
+ {100.0f, "100", "100"},
+ {0.001f, "0.001", "0.001"},
+ {std::numeric_limits<float>::quiet_NaN(), "NaN", "NaN"},
+ {std::numeric_limits<float>::infinity(), "Infinity", "Infinity"},
+ {-std::numeric_limits<float>::infinity(), "-Infinity",
"-Infinity"},
+ {std::numeric_limits<float>::max(), "3.402823e+38",
"3.402823e+38"},
+ {std::numeric_limits<float>::lowest(), "-3.402823e+38",
"-3.402823e+38"},
+ {std::numeric_limits<float>::min(), "1.175494e-38",
"1.175494e-38"},
+ {std::numeric_limits<float>::denorm_min(), "1.401298e-45",
"1.401298e-45"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto field = Field::create_field<TYPE_FLOAT>(tc.value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str)
+ << "serde mismatch for FLOAT expected='" << tc.expected << "'";
+ }
+}
+
+TEST_F(OlapTypeTest, double_type) {
+ auto data_type = DataTypeFactory::instance().create_data_type(TYPE_DOUBLE,
false);
+ auto serde = data_type->get_serde();
+
+ struct TestCase {
+ double value;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {0.0, "0", "0"},
+ {-0.0, "-0", "-0"},
+ {1.0, "1", "1"},
+ {-1.0, "-1", "-1"},
+ {0.5, "0.5", "0.5"},
+ {1.5, "1.5", "1.5"},
+ {0.25, "0.25", "0.25"},
+ {100.0, "100", "100"},
+ {3.141592653589793, "3.141592653589793", "3.141592653589793"},
+ {0.001, "0.001", "0.001"},
+ {std::numeric_limits<double>::quiet_NaN(), "NaN", "NaN"},
+ {std::numeric_limits<double>::infinity(), "Infinity", "Infinity"},
+ {-std::numeric_limits<double>::infinity(), "-Infinity",
"-Infinity"},
+ {std::numeric_limits<double>::max(), "1.797693134862316e+308",
+ "1.797693134862316e+308"},
+ {std::numeric_limits<double>::lowest(), "-1.797693134862316e+308",
+ "-1.797693134862316e+308"},
+ {std::numeric_limits<double>::min(), "2.225073858507201e-308",
+ "2.225073858507201e-308"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto field = Field::create_field<TYPE_DOUBLE>(tc.value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str)
+ << "serde mismatch for DOUBLE expected='" << tc.expected <<
"'";
+ }
+}
+
+TEST_F(OlapTypeTest, bool_type) {
+ auto data_type =
DataTypeFactory::instance().create_data_type(TYPE_BOOLEAN, false);
+ auto serde = data_type->get_serde();
+
+ struct TestCase {
+ uint8_t value;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {0, "0", "0"},
+ {1, "1", "1"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto field = Field::create_field<TYPE_BOOLEAN>((bool)tc.value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str) << "serde mismatch for BOOL="
<< (int)tc.value;
+ }
+}
+
+TEST_F(OlapTypeTest, tinyint_type) {
+ auto data_type =
DataTypeFactory::instance().create_data_type(TYPE_TINYINT, false);
+ auto serde = data_type->get_serde();
+
+ struct TestCase {
+ int8_t value;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {0, "0", "0"}, {1, "1", "1"}, {-1, "-1", "-1"},
+ {127, "127", "127"}, {-128, "-128", "-128"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto field = Field::create_field<TYPE_TINYINT>(tc.value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str) << "serde mismatch for
TINYINT=" << (int)tc.value;
+ }
+}
+
+TEST_F(OlapTypeTest, smallint_type) {
+ auto data_type =
DataTypeFactory::instance().create_data_type(TYPE_SMALLINT, false);
+ auto serde = data_type->get_serde();
+
+ struct TestCase {
+ int16_t value;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {0, "0", "0"},
+ {1, "1", "1"},
+ {-1, "-1", "-1"},
+ {32767, "32767", "32767"},
+ {-32768, "-32768", "-32768"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto field = Field::create_field<TYPE_SMALLINT>(tc.value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str) << "serde mismatch for
SMALLINT=" << tc.value;
+ }
+}
+
+TEST_F(OlapTypeTest, int_type) {
+ auto data_type = DataTypeFactory::instance().create_data_type(TYPE_INT,
false);
+ auto serde = data_type->get_serde();
+
+ struct TestCase {
+ int32_t value;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {0, "0", "0"},
+ {1, "1", "1"},
+ {-1, "-1", "-1"},
+ {2147483647, "2147483647", "2147483647"},
+ {-2147483648, "-2147483648", "-2147483648"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto field = Field::create_field<TYPE_INT>(tc.value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str) << "serde mismatch for INT="
<< tc.value;
+ }
+}
+
+TEST_F(OlapTypeTest, bigint_type) {
+ auto data_type = DataTypeFactory::instance().create_data_type(TYPE_BIGINT,
false);
+ auto serde = data_type->get_serde();
+
+ struct TestCase {
+ int64_t value;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {0, "0", "0"},
+ {1, "1", "1"},
+ {-1, "-1", "-1"},
+ {9223372036854775807L, "9223372036854775807",
"9223372036854775807"},
+ {-9223372036854775807L - 1, "-9223372036854775808",
"-9223372036854775808"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto field = Field::create_field<TYPE_BIGINT>(tc.value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str)
+ << "serde mismatch for BIGINT expected=" << tc.expected;
+ }
+}
+
+TEST_F(OlapTypeTest, largeint_type) {
+ auto data_type =
DataTypeFactory::instance().create_data_type(TYPE_LARGEINT, false);
+ auto serde = data_type->get_serde();
+
+ struct TestCase {
+ int128_t value;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {(int128_t)0, "0", "0"},
+ {(int128_t)1, "1", "1"},
+ {(int128_t)-1, "-1", "-1"},
+ {(int128_t)9223372036854775807L, "9223372036854775807",
"9223372036854775807"},
+ {(int128_t)(-9223372036854775807L - 1), "-9223372036854775808",
"-9223372036854775808"},
+ {~((int128_t)(1) << 127),
"170141183460469231731687303715884105727",
+ "170141183460469231731687303715884105727"},
+ {(int128_t)(1) << 127, "-170141183460469231731687303715884105728",
+ "-170141183460469231731687303715884105728"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto field = Field::create_field<TYPE_LARGEINT>(tc.value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str)
+ << "serde mismatch for LARGEINT expected=" << tc.expected;
+ }
+}
+
+TEST_F(OlapTypeTest, ipv4_type) {
+ auto data_type = DataTypeFactory::instance().create_data_type(TYPE_IPV4,
false);
+ auto serde = data_type->get_serde();
+
+ struct TestCase {
+ uint32_t value;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {0, "0.0.0.0", "0.0.0.0"},
+ {0xFFFFFFFF, "255.255.255.255", "255.255.255.255"},
+ {0x7F000001, "127.0.0.1", "127.0.0.1"},
+ {0xC0A80001, "192.168.0.1", "192.168.0.1"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto field = Field::create_field<TYPE_IPV4>(tc.value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str)
+ << "serde mismatch for IPV4 expected=" << tc.expected;
+ }
+}
+
+TEST_F(OlapTypeTest, ipv6_type) {
+ auto data_type = DataTypeFactory::instance().create_data_type(TYPE_IPV6,
false);
+ auto serde = data_type->get_serde();
+
+ struct TestCase {
+ uint128_t value;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {(uint128_t)0, "::", "::"},
+ {(uint128_t)1, "::1", "::1"},
+ {(uint128_t)(-1), "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"},
+ };
+
+ for (auto& tc : test_cases) {
+ uint128_t olap_value = tc.value;
+ auto field = Field::create_field<TYPE_IPV6>(olap_value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str)
+ << "serde mismatch for IPV6 expected=" << tc.expected;
+ }
+}
+
+TEST_F(OlapTypeTest, timestamptz_type) {
+ auto data_type =
DataTypeFactory::instance().create_data_type(TYPE_TIMESTAMPTZ, false, 0, 6);
+ auto serde = data_type->get_serde();
+
+ auto make_datetimev2 = [](int year, int month, int day, int hour, int
minute, int second,
+ int microsecond) -> uint64_t {
+ return ((uint64_t)year << 46) | ((uint64_t)month << 42) |
((uint64_t)day << 37) |
+ ((uint64_t)hour << 32) | ((uint64_t)minute << 26) |
((uint64_t)second << 20) |
+ (uint64_t)microsecond;
+ };
+
+ struct TestCase {
+ uint64_t olap_value;
+ std::string expected;
+ std::string expected_serde;
+ };
+ std::vector<TestCase> test_cases = {
+ {make_datetimev2(2023, 6, 15, 12, 34, 56, 123456), "2023-06-15
12:34:56.123456+00:00",
+ "2023-06-15 12:34:56.123456+00:00"},
+ {make_datetimev2(2023, 6, 15, 12, 34, 56, 0), "2023-06-15
12:34:56.000000+00:00",
+ "2023-06-15 12:34:56.000000+00:00"},
+ {make_datetimev2(2000, 1, 1, 0, 0, 0, 0), "2000-01-01
00:00:00.000000+00:00",
+ "2000-01-01 00:00:00.000000+00:00"},
+ };
+
+ for (auto& tc : test_cases) {
+ auto field =
Field::create_field_from_olap_value<TYPE_TIMESTAMPTZ>(tc.olap_value);
+ std::string serde_str = serde->to_olap_string(field);
+
+ EXPECT_EQ(tc.expected_serde, serde_str)
+ << "serde mismatch for TIMESTAMPTZ expected=" << tc.expected;
+ }
+}
} // namespace doris
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]