sql_cli/sql/functions/
hash.rs1use anyhow::Result;
2use md5;
3use sha1::Sha1;
4use sha2::{Digest, Sha256, Sha512};
5
6use crate::data::datatable::DataValue;
7use crate::sql::functions::{ArgCount, FunctionCategory, FunctionSignature, SqlFunction};
8
9pub struct Md5Function;
11
12impl SqlFunction for Md5Function {
13 fn signature(&self) -> FunctionSignature {
14 FunctionSignature {
15 name: "MD5",
16 category: FunctionCategory::String,
17 arg_count: ArgCount::Fixed(1),
18 description: "Calculate MD5 hash of a string",
19 returns: "String (32 character hex digest)",
20 examples: vec![
21 "MD5('hello') = '5d41402abc4b2a76b9719d911017c592'",
22 "MD5('test') = '098f6bcd4621d373cade4e832627b4f6'",
23 ],
24 }
25 }
26
27 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
28 let input_string = match &args[0] {
29 DataValue::String(s) => s.clone(),
30 DataValue::InternedString(idx) => idx.to_string(), DataValue::Integer(i) => i.to_string(),
32 DataValue::Float(f) => f.to_string(),
33 DataValue::Boolean(b) => b.to_string(),
34 DataValue::DateTime(dt) => dt.to_string(),
35 DataValue::Null => return Ok(DataValue::Null),
36 };
37
38 let digest = md5::compute(input_string.as_bytes());
39 Ok(DataValue::String(format!("{:x}", digest)))
40 }
41}
42
43pub struct Sha1Function;
45
46impl SqlFunction for Sha1Function {
47 fn signature(&self) -> FunctionSignature {
48 FunctionSignature {
49 name: "SHA1",
50 category: FunctionCategory::String,
51 arg_count: ArgCount::Fixed(1),
52 description: "Calculate SHA1 hash of a string",
53 returns: "String (40 character hex digest)",
54 examples: vec![
55 "SHA1('hello') = '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'",
56 "SHA1('test') = 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'",
57 ],
58 }
59 }
60
61 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
62 let input_string = match &args[0] {
63 DataValue::String(s) => s.clone(),
64 DataValue::InternedString(idx) => idx.to_string(), DataValue::Integer(i) => i.to_string(),
66 DataValue::Float(f) => f.to_string(),
67 DataValue::Boolean(b) => b.to_string(),
68 DataValue::DateTime(dt) => dt.to_string(),
69 DataValue::Null => return Ok(DataValue::Null),
70 };
71
72 let mut hasher = Sha1::new();
73 hasher.update(input_string.as_bytes());
74 let result = hasher.finalize();
75 Ok(DataValue::String(format!("{:x}", result)))
76 }
77}
78
79pub struct Sha256Function;
81
82impl SqlFunction for Sha256Function {
83 fn signature(&self) -> FunctionSignature {
84 FunctionSignature {
85 name: "SHA256",
86 category: FunctionCategory::String,
87 arg_count: ArgCount::Fixed(1),
88 description: "Calculate SHA256 hash of a string",
89 returns: "String (64 character hex digest)",
90 examples: vec![
91 "SHA256('hello') = '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'",
92 "SHA256('test') = '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'",
93 ],
94 }
95 }
96
97 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
98 let input_string = match &args[0] {
99 DataValue::String(s) => s.clone(),
100 DataValue::InternedString(idx) => idx.to_string(), DataValue::Integer(i) => i.to_string(),
102 DataValue::Float(f) => f.to_string(),
103 DataValue::Boolean(b) => b.to_string(),
104 DataValue::DateTime(dt) => dt.to_string(),
105 DataValue::Null => return Ok(DataValue::Null),
106 };
107
108 let mut hasher = Sha256::new();
109 hasher.update(input_string.as_bytes());
110 let result = hasher.finalize();
111 Ok(DataValue::String(format!("{:x}", result)))
112 }
113}
114
115pub struct Sha512Function;
117
118impl SqlFunction for Sha512Function {
119 fn signature(&self) -> FunctionSignature {
120 FunctionSignature {
121 name: "SHA512",
122 category: FunctionCategory::String,
123 arg_count: ArgCount::Fixed(1),
124 description: "Calculate SHA512 hash of a string",
125 returns: "String (128 character hex digest)",
126 examples: vec![
127 "SHA512('hello') = '9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043'",
128 "SHA512('test') = 'ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff'",
129 ],
130 }
131 }
132
133 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
134 let input_string = match &args[0] {
135 DataValue::String(s) => s.clone(),
136 DataValue::InternedString(idx) => idx.to_string(), DataValue::Integer(i) => i.to_string(),
138 DataValue::Float(f) => f.to_string(),
139 DataValue::Boolean(b) => b.to_string(),
140 DataValue::DateTime(dt) => dt.to_string(),
141 DataValue::Null => return Ok(DataValue::Null),
142 };
143
144 let mut hasher = Sha512::new();
145 hasher.update(input_string.as_bytes());
146 let result = hasher.finalize();
147 Ok(DataValue::String(format!("{:x}", result)))
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn test_md5() {
157 let func = Md5Function;
158
159 let result = func
161 .evaluate(&[DataValue::String("hello".to_string())])
162 .unwrap();
163 assert_eq!(
164 result,
165 DataValue::String("5d41402abc4b2a76b9719d911017c592".to_string())
166 );
167
168 let result = func.evaluate(&[DataValue::Null]).unwrap();
170 assert_eq!(result, DataValue::Null);
171 }
172
173 #[test]
174 fn test_sha1() {
175 let func = Sha1Function;
176
177 let result = func
179 .evaluate(&[DataValue::String("test".to_string())])
180 .unwrap();
181 assert_eq!(
182 result,
183 DataValue::String("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3".to_string())
184 );
185
186 let result = func.evaluate(&[DataValue::Null]).unwrap();
188 assert_eq!(result, DataValue::Null);
189 }
190
191 #[test]
192 fn test_sha256() {
193 let func = Sha256Function;
194
195 let result = func
197 .evaluate(&[DataValue::String("test".to_string())])
198 .unwrap();
199 assert_eq!(
200 result,
201 DataValue::String(
202 "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08".to_string()
203 )
204 );
205
206 let result = func.evaluate(&[DataValue::Null]).unwrap();
208 assert_eq!(result, DataValue::Null);
209 }
210
211 #[test]
212 fn test_sha512() {
213 let func = Sha512Function;
214
215 let result = func
217 .evaluate(&[DataValue::String("test".to_string())])
218 .unwrap();
219 assert_eq!(result, DataValue::String("ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff".to_string()));
220
221 let result = func.evaluate(&[DataValue::String("".to_string())]).unwrap();
223 assert_eq!(result, DataValue::String("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e".to_string()));
224 }
225}