risingwave_expr_impl/scalar/
inet.rs1use risingwave_expr::{ExprError, Result, function};
16
17#[function("inet_aton(varchar) -> int8")]
37pub fn inet_aton(str: &str) -> Result<i64> {
38 let mut parts = str.split('.');
39 let mut result = 0;
40 for _ in 0..4 {
41 let part = parts.next().ok_or(ExprError::InvalidParam {
42 name: "str",
43 reason: format!("Invalid IP address: {}", &str).into(),
44 })?;
45 let part = part.parse::<u8>().map_err(|_| ExprError::InvalidParam {
46 name: "str",
47 reason: format!("Invalid IP address: {}", &str).into(),
48 })?;
49 result = (result << 8) | part as i64;
50 }
51 Ok(result)
52}
53
54#[function("inet_ntoa(int8) -> varchar")]
69pub fn inet_ntoa(mut num: i64) -> Result<Box<str>> {
70 if (num > u32::MAX as i64) || (num < 0) {
71 return Err(ExprError::InvalidParam {
72 name: "num",
73 reason: format!("Invalid IP number: {}", num).into(),
74 });
75 }
76 let mut parts = [0u8, 0, 0, 0];
77 for i in (0..4).rev() {
78 parts[i] = (num & 0xFF) as u8;
79 num >>= 8;
80 }
81 let str = parts
82 .iter()
83 .map(|&x| x.to_string())
84 .collect::<Vec<_>>()
85 .join(".");
86 Ok(str.into_boxed_str())
87}
88
89#[cfg(test)]
90mod tests {
91 use std::assert_matches::assert_matches;
92
93 use super::*;
94
95 #[test]
96 fn test_inet_aton() {
97 assert_eq!(inet_aton("10.0.5.9").unwrap(), 167773449);
98 assert_eq!(inet_aton("203.117.31.34").unwrap(), 3413450530);
99
100 if let ExprError::InvalidParam { name, reason } = inet_aton("127.1").unwrap_err() {
101 assert_eq!(name, "str");
102 assert_eq!(reason, "Invalid IP address: 127.1".into());
103 } else {
104 panic!("Expected InvalidParam error");
105 }
106
107 assert_matches!(inet_aton("127.0.1"), Err(ExprError::InvalidParam { .. }));
108 assert_matches!(inet_aton("1.0.0.256"), Err(ExprError::InvalidParam { .. }));
109 assert_matches!(inet_aton("1.0.0.-1"), Err(ExprError::InvalidParam { .. }));
110 }
111
112 #[test]
113 fn test_inet_ntoa() {
114 assert_eq!(inet_ntoa(167773449).unwrap(), "10.0.5.9".into());
115 assert_eq!(inet_ntoa(3413450530).unwrap(), "203.117.31.34".into());
116 assert_eq!(inet_ntoa(0).unwrap(), "0.0.0.0".into());
117 assert_eq!(
118 inet_ntoa(u32::MAX as i64).unwrap(),
119 "255.255.255.255".into()
120 );
121
122 if let ExprError::InvalidParam { name, reason } = inet_ntoa(-1).unwrap_err() {
123 assert_eq!(name, "num");
124 assert_eq!(reason, "Invalid IP number: -1".into());
125 } else {
126 panic!("Expected InvalidParam error");
127 }
128
129 assert_matches!(
130 inet_ntoa(u32::MAX as i64 + 1),
131 Err(ExprError::InvalidParam { .. })
132 );
133 }
134}