risingwave_common/session_config/
statement_timeout.rs

1// Copyright 2026 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
16pub struct StatementTimeout(u32);
17
18impl std::str::FromStr for StatementTimeout {
19    type Err = String;
20
21    fn from_str(s: &str) -> Result<Self, Self::Err> {
22        let s = s.trim();
23        if s == "0" {
24            return Ok(Self(0));
25        }
26
27        let (val_str, unit) = s
28            .find(|c: char| !c.is_numeric())
29            .map(|i| s.split_at(i))
30            .ok_or_else(|| "time unit is required: ms s min h d".to_owned())?;
31
32        let val = val_str
33            .parse::<u32>()
34            .map_err(|_| format!("parsing u32 failed: \"{val_str}\""))?;
35
36        let mul = match unit.trim() {
37            "ms" => 1,
38            "s" => 1000,
39            "min" => 60 * 1000,
40            "h" => 60 * 60 * 1000,
41            "d" => 24 * 60 * 60 * 1000,
42            _ => return Err(format!("invalid time unit: \"{unit}\"")),
43        };
44
45        Ok(Self(
46            val.checked_mul(mul).ok_or_else(|| "overflow".to_owned())?,
47        ))
48    }
49}
50
51impl std::fmt::Display for StatementTimeout {
52    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53        write!(f, "{}ms", self.0)
54    }
55}
56
57impl StatementTimeout {
58    pub fn millis(&self) -> u32 {
59        self.0
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn test_parse_statement_timeout() {
69        assert_eq!(
70            "0".parse::<StatementTimeout>().unwrap(),
71            StatementTimeout(0)
72        );
73        assert_eq!(
74            "100ms".parse::<StatementTimeout>().unwrap(),
75            StatementTimeout(100)
76        );
77        assert_eq!(
78            "1s".parse::<StatementTimeout>().unwrap(),
79            StatementTimeout(1000)
80        );
81        assert_eq!(
82            "1min".parse::<StatementTimeout>().unwrap(),
83            StatementTimeout(60000)
84        );
85        assert_eq!(
86            "1h".parse::<StatementTimeout>().unwrap(),
87            StatementTimeout(3600000)
88        );
89        assert_eq!(
90            "1d".parse::<StatementTimeout>().unwrap(),
91            StatementTimeout(86400000)
92        );
93        assert_eq!(
94            " 100 ms ".parse::<StatementTimeout>().unwrap(),
95            StatementTimeout(100)
96        );
97
98        assert!(
99            "100".parse::<StatementTimeout>().is_err(),
100            "should fail without unit"
101        );
102        assert!(
103            "100x".parse::<StatementTimeout>().is_err(),
104            "should fail with invalid unit"
105        );
106    }
107}