From dceaa7172fa44722c3bd0f29bd493795065a7cf5 Mon Sep 17 00:00:00 2001 From: TCeason <33082201+TCeason@users.noreply.github.com> Date: Wed, 8 Jan 2025 21:21:46 +0800 Subject: [PATCH] fix(query): interval total microseconds add overflow check (#17215) --- Cargo.lock | 1 + src/common/column/Cargo.toml | 1 + src/common/column/src/types/native.rs | 19 ++++++++++++++++--- .../functions/02_0079_function_interval.test | 12 ++++++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8feb7a68b923d..45922dbaa2dc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3121,6 +3121,7 @@ dependencies = [ "ethnum", "foreign_vec", "hex", + "log", "match-template", "num-traits", "proptest", diff --git a/src/common/column/Cargo.toml b/src/common/column/Cargo.toml index 1589cce8c863e..b988032f969c0 100644 --- a/src/common/column/Cargo.toml +++ b/src/common/column/Cargo.toml @@ -33,6 +33,7 @@ either = { workspace = true } ethnum = { workspace = true } foreign_vec = { workspace = true } hex = { workspace = true } +log = { workspace = true } match-template = { workspace = true } num-traits = { workspace = true } serde = { workspace = true, features = ["rc"], optional = true } diff --git a/src/common/column/src/types/native.rs b/src/common/column/src/types/native.rs index 217adeb766a1e..ab0b9dd78e15e 100644 --- a/src/common/column/src/types/native.rs +++ b/src/common/column/src/types/native.rs @@ -25,6 +25,7 @@ use borsh::BorshSerialize; use bytemuck::Pod; use bytemuck::Zeroable; use databend_common_base::base::OrderedFloat; +use log::error; use serde_derive::Deserialize; use serde_derive::Serialize; @@ -319,9 +320,21 @@ impl months_days_micros { } pub fn total_micros(&self) -> i64 { - (self.months() as i64 * MICROS_PER_MONTH) - + (self.days() as i64 * MICROS_PER_DAY) - + self.microseconds() + let months_micros = (self.months() as i64).checked_mul(MICROS_PER_MONTH); + let days_micros = (self.days() as i64).checked_mul(MICROS_PER_DAY); + + months_micros + .and_then(|months_micros| days_micros.map(|days_micros| months_micros + days_micros)) + .and_then(|total_micros| total_micros.checked_add(self.microseconds())) + .unwrap_or_else(|| { + error!( + "interval is out of range: months={}, days={}, micros={}", + self.months(), + self.days(), + self.microseconds() + ); + 0 + }) } } 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 c927f407ebbbe..18e47d583f383 100644 --- a/tests/sqllogictests/suites/query/functions/02_0079_function_interval.test +++ b/tests/sqllogictests/suites/query/functions/02_0079_function_interval.test @@ -142,3 +142,15 @@ query T SELECT to_years(10); ---- 10 years + +onlyif http +query T +select to_interval('1200000000 months'); +---- +100000000 years + +onlyif http +query T +select to_interval('120000000000 months'); +---- +00:00:00