From bed61d2179890a1b706ef71994278d9303de94a4 Mon Sep 17 00:00:00 2001 From: TCeason <33082201+TCeason@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:38:33 +0800 Subject: [PATCH] fix(query): Correct sign extension handling in months_days_micros struct (#17086) Casting days to u32 before casting to i128 to prevent sign extension. Casting microseconds to u64 before casting to i128 to prevent sign extension. --- src/common/column/src/types/native.rs | 6 ++++-- .../suites/query/functions/02_0079_function_interval.test | 8 +++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/common/column/src/types/native.rs b/src/common/column/src/types/native.rs index 0a4bff09127b..9fb915813b9d 100644 --- a/src/common/column/src/types/native.rs +++ b/src/common/column/src/types/native.rs @@ -271,8 +271,10 @@ pub struct months_days_micros(pub i128); impl months_days_micros { pub fn new(months: i32, days: i32, microseconds: i64) -> Self { let months_bits = (months as i128) << 96; - let days_bits = (days as i128) << 64; - let micros_bits = microseconds as i128; + // converting to u32 before i128 ensures we’re working with the raw, unsigned bit pattern of the i32 value, + // preventing unwanted sign extension when that value is later used within the i128. + let days_bits = ((days as u32) as i128) << 64; + let micros_bits = (microseconds as u64) as i128; Self(months_bits | days_bits | micros_bits) } diff --git a/tests/sqllogictests/suites/query/functions/02_0079_function_interval.test b/tests/sqllogictests/suites/query/functions/02_0079_function_interval.test index e2a98b40f6c4..771c021ecdca 100644 --- a/tests/sqllogictests/suites/query/functions/02_0079_function_interval.test +++ b/tests/sqllogictests/suites/query/functions/02_0079_function_interval.test @@ -11,7 +11,7 @@ query TT select * from t order by c1; ---- -1 year -1 month 0:00:00.000001 --1 month -1 day -1:00:00 0:00:00.001 +-1 month -1:00:00 0:00:00.001 onlyif http statement error 1006 @@ -22,3 +22,9 @@ query T select to_interval('1 month 1 hour 1 microsecond'); ---- 1 month 1:00:00.000001 + +onlyif http +query T +select to_interval('1 month 1 hour 1 microsecond ago'); +---- +-1 month -1:00:00.000001