1use rupg_common::SqlState;
4
5use crate::binary::Recv;
6use crate::error::TypeError;
7
8pub const BIT_MAX_LEN: usize = 2_147_483_640;
10
11fn bit_type(varying: bool, typmod: i32) -> String {
13 if varying { format!("bit varying({typmod})") } else { format!("bit({typmod})") }
14}
15
16fn length_error(len: usize, typmod: i32, varying: bool) -> TypeError {
18 if varying {
19 TypeError::new(
20 SqlState::STRING_DATA_RIGHT_TRUNCATION,
21 format!("bit string too long for type {}", bit_type(true, typmod)),
22 )
23 } else {
24 TypeError::new(
25 SqlState::STRING_DATA_LENGTH_MISMATCH,
26 format!("bit string length {len} does not match type {}", bit_type(false, typmod)),
27 )
28 }
29}
30
31fn check_length(len: usize, typmod: i32, varying: bool) -> Result<(), TypeError> {
33 let Ok(limit) = usize::try_from(typmod) else { return Ok(()) };
34 if limit == 0 || len == limit || varying && len < limit {
35 return Ok(());
36 }
37 Err(length_error(len, typmod, varying))
38}
39
40fn char_at(s: &str, at: usize) -> &str {
42 let len = s[at..].chars().next().map_or(0, char::len_utf8);
43 &s[at..at + len]
44}
45
46pub fn bit_in(s: &str, typmod: i32, varying: bool) -> Result<String, TypeError> {
52 let (hex, digits) = match s.as_bytes().first() {
53 Some(b'b' | b'B') => (false, &s[1..]),
54 Some(b'x' | b'X') => (true, &s[1..]),
55 _ => (false, s),
56 };
57 let start = s.len() - digits.len();
58 let len = if hex {
59 if digits.len() > BIT_MAX_LEN / 4 {
60 return Err(TypeError::new(
61 SqlState::PROGRAM_LIMIT_EXCEEDED,
62 format!("bit string length exceeds the maximum allowed ({BIT_MAX_LEN})"),
63 ));
64 }
65 digits.len() * 4
66 } else {
67 digits.len()
68 };
69 check_length(len, typmod, varying)?;
70 let mut out = String::with_capacity(len);
71 for (i, c) in digits.bytes().enumerate() {
72 if hex {
73 let Some(v) = char::from(c).to_digit(16).filter(|_| c.is_ascii()) else {
74 return Err(TypeError::new(
75 SqlState::INVALID_TEXT_REPRESENTATION,
76 format!("\"{}\" is not a valid hexadecimal digit", char_at(s, start + i)),
77 ));
78 };
79 out.push_str(&format!("{v:04b}"));
80 } else if c == b'0' || c == b'1' {
81 out.push(char::from(c));
82 } else {
83 return Err(TypeError::new(
84 SqlState::INVALID_TEXT_REPRESENTATION,
85 format!("\"{}\" is not a valid binary digit", char_at(s, start + i)),
86 ));
87 }
88 }
89 Ok(out)
90}
91
92pub fn bit_coerce(
98 bits: &str,
99 typmod: i32,
100 varying: bool,
101 explicit: bool,
102) -> Result<String, TypeError> {
103 if check_length(bits.len(), typmod, varying).is_ok() {
104 return Ok(bits.to_string());
105 }
106 if !explicit {
107 return Err(length_error(bits.len(), typmod, varying));
108 }
109 let len = usize::try_from(typmod).unwrap_or(0);
110 let mut out: String = bits.chars().take(len).collect();
111 while out.len() < len {
112 out.push('0');
113 }
114 Ok(out)
115}
116
117pub fn bit_recv(recv: &mut Recv<'_>, typmod: i32, varying: bool) -> Result<String, TypeError> {
123 let len = recv.i32()?;
124 let Some(len) = usize::try_from(len).ok().filter(|&len| len <= BIT_MAX_LEN) else {
125 return Err(TypeError::new(
126 SqlState::INVALID_BINARY_REPRESENTATION,
127 "invalid length in external bit string".to_string(),
128 ));
129 };
130 check_length(len, typmod, varying)?;
131 let bytes = recv.bytes(len.div_ceil(8))?;
132 Ok((0..len).map(|i| if (bytes[i / 8] >> (7 - i % 8)) & 1 == 1 { '1' } else { '0' }).collect())
133}
134
135#[must_use]
137pub fn bit_bytes(bits: &str) -> Vec<u8> {
138 let mut out = vec![0u8; bits.len().div_ceil(8)];
139 for (i, c) in bits.bytes().enumerate() {
140 if c == b'1' {
141 out[i / 8] |= 0x80 >> (i % 8);
142 }
143 }
144 out
145}
146
147pub fn bit_send(bits: &str, out: &mut Vec<u8>) {
149 let len = i32::try_from(bits.len()).unwrap_or(i32::MAX);
150 out.extend_from_slice(&len.to_be_bytes());
151 out.extend_from_slice(&bit_bytes(bits));
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 #[test]
160 fn text_forms() {
161 assert_eq!(bit_in("1011", -1, false).unwrap(), "1011");
162 assert_eq!(bit_in("", -1, false).unwrap(), "");
163 assert_eq!(bit_in("x1f", -1, true).unwrap(), "00011111");
164 assert_eq!(bit_in("X1F", 8, false).unwrap(), "00011111");
165 assert_eq!(bit_in("b101", -1, true).unwrap(), "101");
166 assert_eq!(bit_in("XABC", -1, false).unwrap(), "101010111100");
167 assert_eq!(
168 bit_in("102", -1, true).unwrap_err().message,
169 "\"2\" is not a valid binary digit"
170 );
171 assert_eq!(
172 bit_in("x1g", -1, true).unwrap_err().message,
173 "\"g\" is not a valid hexadecimal digit"
174 );
175 assert_eq!(bit_in("é", -1, true).unwrap_err().message, "\"é\" is not a valid binary digit");
176 let error = bit_in("101", 4, false).unwrap_err();
177 assert_eq!(
178 (error.sqlstate.as_str(), error.message.as_str()),
179 ("22026", "bit string length 3 does not match type bit(4)")
180 );
181 let error = bit_in("1010", 3, true).unwrap_err();
182 assert_eq!(
183 (error.sqlstate.as_str(), error.message.as_str()),
184 ("22001", "bit string too long for type bit varying(3)")
185 );
186 assert_eq!(bit_in("1010", 5, true).unwrap(), "1010");
187 }
188
189 #[test]
190 fn length_casts() {
191 assert_eq!(bit_coerce("101", 5, false, true).unwrap(), "10100");
192 assert_eq!(bit_coerce("10101", 3, false, true).unwrap(), "101");
193 assert_eq!(bit_coerce("101", 2, true, true).unwrap(), "10");
194 assert_eq!(bit_coerce("101", 5, true, true).unwrap(), "101");
195 assert!(bit_coerce("101", 5, false, false).is_err());
196 assert_eq!(bit_coerce("101", -1, false, false).unwrap(), "101");
197 }
198
199 #[test]
200 fn binary_forms() {
201 let mut out = Vec::new();
202 bit_send("1010101010", &mut out);
203 assert_eq!(out, [0, 0, 0, 10, 0xaa, 0x80]);
204 assert_eq!(bit_recv(&mut Recv::new(&out), -1, true).unwrap(), "1010101010");
205 let mut out = Vec::new();
206 bit_send("", &mut out);
207 assert_eq!(out, [0, 0, 0, 0]);
208 assert!(bit_recv(&mut Recv::new(&[0xff, 0xff, 0xff, 0xff]), -1, true).is_err());
209 }
210}