sql_cli/sql/functions/
bitwise_string.rs

1//! Bitwise operations on binary string representations
2
3use crate::data::datatable::DataValue;
4use crate::sql::functions::{ArgCount, FunctionCategory, FunctionSignature, SqlFunction};
5use anyhow::{anyhow, Result};
6
7/// BIT_AND_STR - Bitwise AND on binary strings
8pub struct BitAndStr;
9
10impl SqlFunction for BitAndStr {
11    fn signature(&self) -> FunctionSignature {
12        FunctionSignature {
13            name: "BIT_AND_STR",
14            category: FunctionCategory::Bitwise,
15            arg_count: ArgCount::Fixed(2),
16            description: "Performs bitwise AND on two binary strings",
17            returns: "Binary string result",
18            examples: vec![
19                "SELECT BIT_AND_STR('1101', '1011')",
20                "SELECT BIT_AND_STR(TO_BINARY(13), TO_BINARY(11))",
21            ],
22        }
23    }
24
25    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
26        self.validate_args(args)?;
27
28        let a = args[0].to_string();
29        let b = args[1].to_string();
30
31        // Pad to same length
32        let max_len = a.len().max(b.len());
33        let a_padded = format!("{:0>width$}", a, width = max_len);
34        let b_padded = format!("{:0>width$}", b, width = max_len);
35
36        let result: String = a_padded
37            .chars()
38            .zip(b_padded.chars())
39            .map(|(c1, c2)| match (c1, c2) {
40                ('1', '1') => '1',
41                _ => '0',
42            })
43            .collect();
44
45        Ok(DataValue::String(result))
46    }
47}
48
49/// BIT_OR_STR - Bitwise OR on binary strings
50pub struct BitOrStr;
51
52impl SqlFunction for BitOrStr {
53    fn signature(&self) -> FunctionSignature {
54        FunctionSignature {
55            name: "BIT_OR_STR",
56            category: FunctionCategory::Bitwise,
57            arg_count: ArgCount::Fixed(2),
58            description: "Performs bitwise OR on two binary strings",
59            returns: "Binary string result",
60            examples: vec![
61                "SELECT BIT_OR_STR('1100', '1010')",
62                "SELECT BIT_OR_STR(TO_BINARY(12), TO_BINARY(10))",
63            ],
64        }
65    }
66
67    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
68        self.validate_args(args)?;
69
70        let a = args[0].to_string();
71        let b = args[1].to_string();
72
73        let max_len = a.len().max(b.len());
74        let a_padded = format!("{:0>width$}", a, width = max_len);
75        let b_padded = format!("{:0>width$}", b, width = max_len);
76
77        let result: String = a_padded
78            .chars()
79            .zip(b_padded.chars())
80            .map(|(c1, c2)| match (c1, c2) {
81                ('0', '0') => '0',
82                _ => '1',
83            })
84            .collect();
85
86        Ok(DataValue::String(result))
87    }
88}
89
90/// BIT_XOR_STR - Bitwise XOR on binary strings
91pub struct BitXorStr;
92
93impl SqlFunction for BitXorStr {
94    fn signature(&self) -> FunctionSignature {
95        FunctionSignature {
96            name: "BIT_XOR_STR",
97            category: FunctionCategory::Bitwise,
98            arg_count: ArgCount::Fixed(2),
99            description: "Performs bitwise XOR on two binary strings",
100            returns: "Binary string result",
101            examples: vec![
102                "SELECT BIT_XOR_STR('1100', '1010')",
103                "SELECT BIT_XOR_STR(TO_BINARY(12), TO_BINARY(10))",
104            ],
105        }
106    }
107
108    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
109        self.validate_args(args)?;
110
111        let a = args[0].to_string();
112        let b = args[1].to_string();
113
114        let max_len = a.len().max(b.len());
115        let a_padded = format!("{:0>width$}", a, width = max_len);
116        let b_padded = format!("{:0>width$}", b, width = max_len);
117
118        let result: String = a_padded
119            .chars()
120            .zip(b_padded.chars())
121            .map(|(c1, c2)| if c1 == c2 { '0' } else { '1' })
122            .collect();
123
124        Ok(DataValue::String(result))
125    }
126}
127
128/// BIT_NOT_STR - Bitwise NOT on binary string
129pub struct BitNotStr;
130
131impl SqlFunction for BitNotStr {
132    fn signature(&self) -> FunctionSignature {
133        FunctionSignature {
134            name: "BIT_NOT_STR",
135            category: FunctionCategory::Bitwise,
136            arg_count: ArgCount::Fixed(1),
137            description: "Performs bitwise NOT on a binary string",
138            returns: "Binary string with bits flipped",
139            examples: vec![
140                "SELECT BIT_NOT_STR('1100')",
141                "SELECT BIT_NOT_STR(TO_BINARY(12))",
142            ],
143        }
144    }
145
146    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
147        self.validate_args(args)?;
148
149        let input = args[0].to_string();
150
151        let result: String = input
152            .chars()
153            .map(|c| if c == '0' { '1' } else { '0' })
154            .collect();
155
156        Ok(DataValue::String(result))
157    }
158}
159
160/// BIT_FLIP - Alias for BIT_NOT_STR
161pub struct BitFlip;
162
163impl SqlFunction for BitFlip {
164    fn signature(&self) -> FunctionSignature {
165        FunctionSignature {
166            name: "BIT_FLIP",
167            category: FunctionCategory::Bitwise,
168            arg_count: ArgCount::Fixed(1),
169            description: "Flips all bits in a binary string (alias for BIT_NOT_STR)",
170            returns: "Binary string with bits flipped",
171            examples: vec!["SELECT BIT_FLIP('11011010')"],
172        }
173    }
174
175    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
176        BitNotStr.evaluate(args)
177    }
178}
179
180/// BIT_COUNT - Count number of 1s in binary string
181pub struct BitCount;
182
183impl SqlFunction for BitCount {
184    fn signature(&self) -> FunctionSignature {
185        FunctionSignature {
186            name: "BIT_COUNT",
187            category: FunctionCategory::Bitwise,
188            arg_count: ArgCount::Fixed(1),
189            description: "Counts the number of 1 bits in a binary string",
190            returns: "Integer count of 1 bits",
191            examples: vec![
192                "SELECT BIT_COUNT('11011010')",
193                "SELECT BIT_COUNT(TO_BINARY(218))",
194            ],
195        }
196    }
197
198    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
199        self.validate_args(args)?;
200
201        let input = args[0].to_string();
202        let count = input.chars().filter(|&c| c == '1').count() as i64;
203        Ok(DataValue::Integer(count))
204    }
205}
206
207/// BIT_ROTATE_LEFT - Rotate binary string left by N positions
208pub struct BitRotateLeft;
209
210impl SqlFunction for BitRotateLeft {
211    fn signature(&self) -> FunctionSignature {
212        FunctionSignature {
213            name: "BIT_ROTATE_LEFT",
214            category: FunctionCategory::Bitwise,
215            arg_count: ArgCount::Fixed(2),
216            description: "Rotates a binary string left by N positions",
217            returns: "Rotated binary string",
218            examples: vec![
219                "SELECT BIT_ROTATE_LEFT('11011010', 2)",
220                "SELECT BIT_ROTATE_LEFT(TO_BINARY(218), 3)",
221            ],
222        }
223    }
224
225    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
226        self.validate_args(args)?;
227
228        let input = args[0].to_string();
229        let positions = match &args[1] {
230            DataValue::Integer(n) => *n as usize,
231            DataValue::Float(f) => *f as usize,
232            _ => return Err(anyhow!("Second argument must be a number")),
233        };
234
235        if input.is_empty() {
236            return Ok(DataValue::String(String::new()));
237        }
238
239        let effective_positions = positions % input.len();
240        let result = format!(
241            "{}{}",
242            &input[effective_positions..],
243            &input[..effective_positions]
244        );
245
246        Ok(DataValue::String(result))
247    }
248}
249
250/// BIT_ROTATE_RIGHT - Rotate binary string right by N positions
251pub struct BitRotateRight;
252
253impl SqlFunction for BitRotateRight {
254    fn signature(&self) -> FunctionSignature {
255        FunctionSignature {
256            name: "BIT_ROTATE_RIGHT",
257            category: FunctionCategory::Bitwise,
258            arg_count: ArgCount::Fixed(2),
259            description: "Rotates a binary string right by N positions",
260            returns: "Rotated binary string",
261            examples: vec![
262                "SELECT BIT_ROTATE_RIGHT('11011010', 2)",
263                "SELECT BIT_ROTATE_RIGHT(TO_BINARY(218), 3)",
264            ],
265        }
266    }
267
268    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
269        self.validate_args(args)?;
270
271        let input = args[0].to_string();
272        let positions = match &args[1] {
273            DataValue::Integer(n) => *n as usize,
274            DataValue::Float(f) => *f as usize,
275            _ => return Err(anyhow!("Second argument must be a number")),
276        };
277
278        if input.is_empty() {
279            return Ok(DataValue::String(String::new()));
280        }
281
282        let effective_positions = positions % input.len();
283        let split_point = input.len() - effective_positions;
284        let result = format!("{}{}", &input[split_point..], &input[..split_point]);
285
286        Ok(DataValue::String(result))
287    }
288}
289
290/// BIT_SHIFT_LEFT - Shift binary string left, filling with zeros
291pub struct BitShiftLeft;
292
293impl SqlFunction for BitShiftLeft {
294    fn signature(&self) -> FunctionSignature {
295        FunctionSignature {
296            name: "BIT_SHIFT_LEFT",
297            category: FunctionCategory::Bitwise,
298            arg_count: ArgCount::Fixed(2),
299            description: "Shifts a binary string left by N positions, filling with zeros",
300            returns: "Shifted binary string",
301            examples: vec![
302                "SELECT BIT_SHIFT_LEFT('11011010', 2)",
303                "SELECT BIT_SHIFT_LEFT(TO_BINARY(218), 3)",
304            ],
305        }
306    }
307
308    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
309        self.validate_args(args)?;
310
311        let input = args[0].to_string();
312        let positions = match &args[1] {
313            DataValue::Integer(n) => *n as usize,
314            DataValue::Float(f) => *f as usize,
315            _ => return Err(anyhow!("Second argument must be a number")),
316        };
317
318        if positions >= input.len() {
319            return Ok(DataValue::String("0".repeat(input.len())));
320        }
321
322        let result = format!("{}{}", &input[positions..], "0".repeat(positions));
323
324        Ok(DataValue::String(result))
325    }
326}
327
328/// BIT_SHIFT_RIGHT - Shift binary string right, filling with zeros
329pub struct BitShiftRight;
330
331impl SqlFunction for BitShiftRight {
332    fn signature(&self) -> FunctionSignature {
333        FunctionSignature {
334            name: "BIT_SHIFT_RIGHT",
335            category: FunctionCategory::Bitwise,
336            arg_count: ArgCount::Fixed(2),
337            description: "Shifts a binary string right by N positions, filling with zeros",
338            returns: "Shifted binary string",
339            examples: vec![
340                "SELECT BIT_SHIFT_RIGHT('11011010', 2)",
341                "SELECT BIT_SHIFT_RIGHT(TO_BINARY(218), 3)",
342            ],
343        }
344    }
345
346    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
347        self.validate_args(args)?;
348
349        let input = args[0].to_string();
350        let positions = match &args[1] {
351            DataValue::Integer(n) => *n as usize,
352            DataValue::Float(f) => *f as usize,
353            _ => return Err(anyhow!("Second argument must be a number")),
354        };
355
356        if positions >= input.len() {
357            return Ok(DataValue::String("0".repeat(input.len())));
358        }
359
360        let result = format!(
361            "{}{}",
362            "0".repeat(positions),
363            &input[..input.len() - positions]
364        );
365
366        Ok(DataValue::String(result))
367    }
368}
369
370/// HAMMING_DISTANCE - Count bit differences between two binary strings
371pub struct HammingDistance;
372
373impl SqlFunction for HammingDistance {
374    fn signature(&self) -> FunctionSignature {
375        FunctionSignature {
376            name: "HAMMING_DISTANCE",
377            category: FunctionCategory::Bitwise,
378            arg_count: ArgCount::Fixed(2),
379            description: "Counts the number of differing bits between two binary strings",
380            returns: "Integer count of different bits",
381            examples: vec![
382                "SELECT HAMMING_DISTANCE('1101', '1011')",
383                "SELECT HAMMING_DISTANCE(TO_BINARY(13), TO_BINARY(11))",
384            ],
385        }
386    }
387
388    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
389        self.validate_args(args)?;
390
391        let a = args[0].to_string();
392        let b = args[1].to_string();
393
394        let max_len = a.len().max(b.len());
395        let a_padded = format!("{:0>width$}", a, width = max_len);
396        let b_padded = format!("{:0>width$}", b, width = max_len);
397
398        let distance = a_padded
399            .chars()
400            .zip(b_padded.chars())
401            .filter(|(c1, c2)| c1 != c2)
402            .count() as i64;
403
404        Ok(DataValue::Integer(distance))
405    }
406}