use crate::data::datatable::DataValue;
use crate::sql::functions::{ArgCount, FunctionCategory, FunctionSignature, SqlFunction};
use anyhow::{anyhow, Result};
pub struct BitAndStr;
impl SqlFunction for BitAndStr {
fn signature(&self) -> FunctionSignature {
FunctionSignature {
name: "BIT_AND_STR",
category: FunctionCategory::Bitwise,
arg_count: ArgCount::Fixed(2),
description: "Performs bitwise AND on two binary strings",
returns: "Binary string result",
examples: vec![
"SELECT BIT_AND_STR('1101', '1011')",
"SELECT BIT_AND_STR(TO_BINARY(13), TO_BINARY(11))",
],
}
}
fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
self.validate_args(args)?;
let a = args[0].to_string();
let b = args[1].to_string();
let max_len = a.len().max(b.len());
let a_padded = format!("{:0>width$}", a, width = max_len);
let b_padded = format!("{:0>width$}", b, width = max_len);
let result: String = a_padded
.chars()
.zip(b_padded.chars())
.map(|(c1, c2)| match (c1, c2) {
('1', '1') => '1',
_ => '0',
})
.collect();
Ok(DataValue::String(result))
}
}
pub struct BitOrStr;
impl SqlFunction for BitOrStr {
fn signature(&self) -> FunctionSignature {
FunctionSignature {
name: "BIT_OR_STR",
category: FunctionCategory::Bitwise,
arg_count: ArgCount::Fixed(2),
description: "Performs bitwise OR on two binary strings",
returns: "Binary string result",
examples: vec![
"SELECT BIT_OR_STR('1100', '1010')",
"SELECT BIT_OR_STR(TO_BINARY(12), TO_BINARY(10))",
],
}
}
fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
self.validate_args(args)?;
let a = args[0].to_string();
let b = args[1].to_string();
let max_len = a.len().max(b.len());
let a_padded = format!("{:0>width$}", a, width = max_len);
let b_padded = format!("{:0>width$}", b, width = max_len);
let result: String = a_padded
.chars()
.zip(b_padded.chars())
.map(|(c1, c2)| match (c1, c2) {
('0', '0') => '0',
_ => '1',
})
.collect();
Ok(DataValue::String(result))
}
}
pub struct BitXorStr;
impl SqlFunction for BitXorStr {
fn signature(&self) -> FunctionSignature {
FunctionSignature {
name: "BIT_XOR_STR",
category: FunctionCategory::Bitwise,
arg_count: ArgCount::Fixed(2),
description: "Performs bitwise XOR on two binary strings",
returns: "Binary string result",
examples: vec![
"SELECT BIT_XOR_STR('1100', '1010')",
"SELECT BIT_XOR_STR(TO_BINARY(12), TO_BINARY(10))",
],
}
}
fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
self.validate_args(args)?;
let a = args[0].to_string();
let b = args[1].to_string();
let max_len = a.len().max(b.len());
let a_padded = format!("{:0>width$}", a, width = max_len);
let b_padded = format!("{:0>width$}", b, width = max_len);
let result: String = a_padded
.chars()
.zip(b_padded.chars())
.map(|(c1, c2)| if c1 == c2 { '0' } else { '1' })
.collect();
Ok(DataValue::String(result))
}
}
pub struct BitNotStr;
impl SqlFunction for BitNotStr {
fn signature(&self) -> FunctionSignature {
FunctionSignature {
name: "BIT_NOT_STR",
category: FunctionCategory::Bitwise,
arg_count: ArgCount::Fixed(1),
description: "Performs bitwise NOT on a binary string",
returns: "Binary string with bits flipped",
examples: vec![
"SELECT BIT_NOT_STR('1100')",
"SELECT BIT_NOT_STR(TO_BINARY(12))",
],
}
}
fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
self.validate_args(args)?;
let input = args[0].to_string();
let result: String = input
.chars()
.map(|c| if c == '0' { '1' } else { '0' })
.collect();
Ok(DataValue::String(result))
}
}
pub struct BitFlip;
impl SqlFunction for BitFlip {
fn signature(&self) -> FunctionSignature {
FunctionSignature {
name: "BIT_FLIP",
category: FunctionCategory::Bitwise,
arg_count: ArgCount::Fixed(1),
description: "Flips all bits in a binary string (alias for BIT_NOT_STR)",
returns: "Binary string with bits flipped",
examples: vec!["SELECT BIT_FLIP('11011010')"],
}
}
fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
BitNotStr.evaluate(args)
}
}
pub struct BitCount;
impl SqlFunction for BitCount {
fn signature(&self) -> FunctionSignature {
FunctionSignature {
name: "BIT_COUNT",
category: FunctionCategory::Bitwise,
arg_count: ArgCount::Fixed(1),
description: "Counts the number of 1 bits in a binary string or integer (popcount)",
returns: "Integer count of 1 bits",
examples: vec![
"SELECT BIT_COUNT('11011010') -- Returns 5",
"SELECT BIT_COUNT(218) -- Returns 5 (same value, as integer)",
"SELECT BIT_COUNT(TO_BINARY(218))",
],
}
}
fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
self.validate_args(args)?;
let count = match &args[0] {
DataValue::Null => return Ok(DataValue::Null),
DataValue::Integer(n) => (*n as u64).count_ones() as i64,
DataValue::String(s) => s.chars().filter(|&c| c == '1').count() as i64,
other => other.to_string().chars().filter(|&c| c == '1').count() as i64,
};
Ok(DataValue::Integer(count))
}
}
pub struct BitRotateLeft;
impl SqlFunction for BitRotateLeft {
fn signature(&self) -> FunctionSignature {
FunctionSignature {
name: "BIT_ROTATE_LEFT",
category: FunctionCategory::Bitwise,
arg_count: ArgCount::Fixed(2),
description: "Rotates a binary string left by N positions",
returns: "Rotated binary string",
examples: vec![
"SELECT BIT_ROTATE_LEFT('11011010', 2)",
"SELECT BIT_ROTATE_LEFT(TO_BINARY(218), 3)",
],
}
}
fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
self.validate_args(args)?;
let input = args[0].to_string();
let positions = match &args[1] {
DataValue::Integer(n) => *n as usize,
DataValue::Float(f) => *f as usize,
_ => return Err(anyhow!("Second argument must be a number")),
};
if input.is_empty() {
return Ok(DataValue::String(String::new()));
}
let effective_positions = positions % input.len();
let result = format!(
"{}{}",
&input[effective_positions..],
&input[..effective_positions]
);
Ok(DataValue::String(result))
}
}
pub struct BitRotateRight;
impl SqlFunction for BitRotateRight {
fn signature(&self) -> FunctionSignature {
FunctionSignature {
name: "BIT_ROTATE_RIGHT",
category: FunctionCategory::Bitwise,
arg_count: ArgCount::Fixed(2),
description: "Rotates a binary string right by N positions",
returns: "Rotated binary string",
examples: vec![
"SELECT BIT_ROTATE_RIGHT('11011010', 2)",
"SELECT BIT_ROTATE_RIGHT(TO_BINARY(218), 3)",
],
}
}
fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
self.validate_args(args)?;
let input = args[0].to_string();
let positions = match &args[1] {
DataValue::Integer(n) => *n as usize,
DataValue::Float(f) => *f as usize,
_ => return Err(anyhow!("Second argument must be a number")),
};
if input.is_empty() {
return Ok(DataValue::String(String::new()));
}
let effective_positions = positions % input.len();
let split_point = input.len() - effective_positions;
let result = format!("{}{}", &input[split_point..], &input[..split_point]);
Ok(DataValue::String(result))
}
}
pub struct BitShiftLeft;
impl SqlFunction for BitShiftLeft {
fn signature(&self) -> FunctionSignature {
FunctionSignature {
name: "BIT_SHIFT_LEFT",
category: FunctionCategory::Bitwise,
arg_count: ArgCount::Fixed(2),
description: "Shifts a binary string left by N positions, filling with zeros",
returns: "Shifted binary string",
examples: vec![
"SELECT BIT_SHIFT_LEFT('11011010', 2)",
"SELECT BIT_SHIFT_LEFT(TO_BINARY(218), 3)",
],
}
}
fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
self.validate_args(args)?;
let input = args[0].to_string();
let positions = match &args[1] {
DataValue::Integer(n) => *n as usize,
DataValue::Float(f) => *f as usize,
_ => return Err(anyhow!("Second argument must be a number")),
};
if positions >= input.len() {
return Ok(DataValue::String("0".repeat(input.len())));
}
let result = format!("{}{}", &input[positions..], "0".repeat(positions));
Ok(DataValue::String(result))
}
}
pub struct BitShiftRight;
impl SqlFunction for BitShiftRight {
fn signature(&self) -> FunctionSignature {
FunctionSignature {
name: "BIT_SHIFT_RIGHT",
category: FunctionCategory::Bitwise,
arg_count: ArgCount::Fixed(2),
description: "Shifts a binary string right by N positions, filling with zeros",
returns: "Shifted binary string",
examples: vec![
"SELECT BIT_SHIFT_RIGHT('11011010', 2)",
"SELECT BIT_SHIFT_RIGHT(TO_BINARY(218), 3)",
],
}
}
fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
self.validate_args(args)?;
let input = args[0].to_string();
let positions = match &args[1] {
DataValue::Integer(n) => *n as usize,
DataValue::Float(f) => *f as usize,
_ => return Err(anyhow!("Second argument must be a number")),
};
if positions >= input.len() {
return Ok(DataValue::String("0".repeat(input.len())));
}
let result = format!(
"{}{}",
"0".repeat(positions),
&input[..input.len() - positions]
);
Ok(DataValue::String(result))
}
}
pub struct HammingDistance;
impl SqlFunction for HammingDistance {
fn signature(&self) -> FunctionSignature {
FunctionSignature {
name: "HAMMING_DISTANCE",
category: FunctionCategory::Bitwise,
arg_count: ArgCount::Fixed(2),
description: "Counts the number of differing bits between two binary strings",
returns: "Integer count of different bits",
examples: vec![
"SELECT HAMMING_DISTANCE('1101', '1011')",
"SELECT HAMMING_DISTANCE(TO_BINARY(13), TO_BINARY(11))",
],
}
}
fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
self.validate_args(args)?;
let a = args[0].to_string();
let b = args[1].to_string();
let max_len = a.len().max(b.len());
let a_padded = format!("{:0>width$}", a, width = max_len);
let b_padded = format!("{:0>width$}", b, width = max_len);
let distance = a_padded
.chars()
.zip(b_padded.chars())
.filter(|(c1, c2)| c1 != c2)
.count() as i64;
Ok(DataValue::Integer(distance))
}
}