1use 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::Vector(v) => {
36 let components: Vec<String> = v.iter().map(|f| f.to_string()).collect();
37 format!("[{}]", components.join(","))
38 }
39 DataValue::Null => return Ok(DataValue::Null),
40 };
41
42 let digest = md5::compute(input_string.as_bytes());
43 Ok(DataValue::String(format!("{:x}", digest)))
44 }
45}
46
47pub struct Sha1Function;
49
50impl SqlFunction for Sha1Function {
51 fn signature(&self) -> FunctionSignature {
52 FunctionSignature {
53 name: "SHA1",
54 category: FunctionCategory::String,
55 arg_count: ArgCount::Fixed(1),
56 description: "Calculate SHA1 hash of a string",
57 returns: "String (40 character hex digest)",
58 examples: vec![
59 "SHA1('hello') = '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'",
60 "SHA1('test') = 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'",
61 ],
62 }
63 }
64
65 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
66 let input_string = match &args[0] {
67 DataValue::String(s) => s.clone(),
68 DataValue::InternedString(idx) => idx.to_string(), DataValue::Integer(i) => i.to_string(),
70 DataValue::Float(f) => f.to_string(),
71 DataValue::Boolean(b) => b.to_string(),
72 DataValue::DateTime(dt) => dt.to_string(),
73 DataValue::Vector(v) => {
74 let components: Vec<String> = v.iter().map(|f| f.to_string()).collect();
75 format!("[{}]", components.join(","))
76 }
77 DataValue::Null => return Ok(DataValue::Null),
78 };
79
80 let mut hasher = Sha1::new();
81 hasher.update(input_string.as_bytes());
82 let result = hasher.finalize();
83 Ok(DataValue::String(format!("{:x}", result)))
84 }
85}
86
87pub struct Sha256Function;
89
90impl SqlFunction for Sha256Function {
91 fn signature(&self) -> FunctionSignature {
92 FunctionSignature {
93 name: "SHA256",
94 category: FunctionCategory::String,
95 arg_count: ArgCount::Fixed(1),
96 description: "Calculate SHA256 hash of a string",
97 returns: "String (64 character hex digest)",
98 examples: vec![
99 "SHA256('hello') = '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'",
100 "SHA256('test') = '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'",
101 ],
102 }
103 }
104
105 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
106 let input_string = match &args[0] {
107 DataValue::String(s) => s.clone(),
108 DataValue::InternedString(idx) => idx.to_string(), DataValue::Integer(i) => i.to_string(),
110 DataValue::Float(f) => f.to_string(),
111 DataValue::Boolean(b) => b.to_string(),
112 DataValue::DateTime(dt) => dt.to_string(),
113 DataValue::Vector(v) => {
114 let components: Vec<String> = v.iter().map(|f| f.to_string()).collect();
115 format!("[{}]", components.join(","))
116 }
117 DataValue::Null => return Ok(DataValue::Null),
118 };
119
120 let mut hasher = Sha256::new();
121 hasher.update(input_string.as_bytes());
122 let result = hasher.finalize();
123 Ok(DataValue::String(format!("{:x}", result)))
124 }
125}
126
127pub struct Sha512Function;
129
130impl SqlFunction for Sha512Function {
131 fn signature(&self) -> FunctionSignature {
132 FunctionSignature {
133 name: "SHA512",
134 category: FunctionCategory::String,
135 arg_count: ArgCount::Fixed(1),
136 description: "Calculate SHA512 hash of a string",
137 returns: "String (128 character hex digest)",
138 examples: vec![
139 "SHA512('hello') = '9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043'",
140 "SHA512('test') = 'ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff'",
141 ],
142 }
143 }
144
145 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
146 let input_string = match &args[0] {
147 DataValue::String(s) => s.clone(),
148 DataValue::InternedString(idx) => idx.to_string(), DataValue::Integer(i) => i.to_string(),
150 DataValue::Float(f) => f.to_string(),
151 DataValue::Boolean(b) => b.to_string(),
152 DataValue::DateTime(dt) => dt.to_string(),
153 DataValue::Vector(v) => {
154 let components: Vec<String> = v.iter().map(|f| f.to_string()).collect();
155 format!("[{}]", components.join(","))
156 }
157 DataValue::Null => return Ok(DataValue::Null),
158 };
159
160 let mut hasher = Sha512::new();
161 hasher.update(input_string.as_bytes());
162 let result = hasher.finalize();
163 Ok(DataValue::String(format!("{:x}", result)))
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 #[test]
172 fn test_md5() {
173 let func = Md5Function;
174
175 let result = func
177 .evaluate(&[DataValue::String("hello".to_string())])
178 .unwrap();
179 assert_eq!(
180 result,
181 DataValue::String("5d41402abc4b2a76b9719d911017c592".to_string())
182 );
183
184 let result = func.evaluate(&[DataValue::Null]).unwrap();
186 assert_eq!(result, DataValue::Null);
187 }
188
189 #[test]
190 fn test_sha1() {
191 let func = Sha1Function;
192
193 let result = func
195 .evaluate(&[DataValue::String("test".to_string())])
196 .unwrap();
197 assert_eq!(
198 result,
199 DataValue::String("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3".to_string())
200 );
201
202 let result = func.evaluate(&[DataValue::Null]).unwrap();
204 assert_eq!(result, DataValue::Null);
205 }
206
207 #[test]
208 fn test_sha256() {
209 let func = Sha256Function;
210
211 let result = func
213 .evaluate(&[DataValue::String("test".to_string())])
214 .unwrap();
215 assert_eq!(
216 result,
217 DataValue::String(
218 "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08".to_string()
219 )
220 );
221
222 let result = func.evaluate(&[DataValue::Null]).unwrap();
224 assert_eq!(result, DataValue::Null);
225 }
226
227 #[test]
228 fn test_sha512() {
229 let func = Sha512Function;
230
231 let result = func
233 .evaluate(&[DataValue::String("test".to_string())])
234 .unwrap();
235 assert_eq!(result, DataValue::String("ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff".to_string()));
236
237 let result = func.evaluate(&[DataValue::String("".to_string())]).unwrap();
239 assert_eq!(result, DataValue::String("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e".to_string()));
240 }
241}