| 381 | |
| 382 | #[sqlfunc(sqlname = "length", propagates_nulls = true)] |
| 383 | fn encoded_bytes_char_length(a: &[u8], b: &str) -> Result<i32, EvalError> { |
| 384 | // Convert PostgreSQL-style encoding names[1] to WHATWG-style encoding names[2], |
| 385 | // which the encoding library uses[3]. |
| 386 | // [1]: https://www.postgresql.org/docs/9.5/multibyte.html |
| 387 | // [2]: https://encoding.spec.whatwg.org/ |
| 388 | // [3]: https://github.com/lifthrasiir/rust-encoding/blob/4e79c35ab6a351881a86dbff565c4db0085cc113/src/label.rs |
| 389 | let encoding_name = b.to_lowercase().replace('_', "-").into_boxed_str(); |
| 390 | |
| 391 | let enc = match encoding_from_whatwg_label(&encoding_name) { |
| 392 | Some(enc) => enc, |
| 393 | None => return Err(EvalError::InvalidEncodingName(encoding_name)), |
| 394 | }; |
| 395 | |
| 396 | let decoded_string = match enc.decode(a, DecoderTrap::Strict) { |
| 397 | Ok(s) => s, |
| 398 | Err(e) => { |
| 399 | return Err(EvalError::InvalidByteSequence { |
| 400 | byte_sequence: e.into(), |
| 401 | encoding_name, |
| 402 | }); |
| 403 | } |
| 404 | }; |
| 405 | |
| 406 | let count = decoded_string.chars().count(); |
| 407 | i32::try_from(count).map_err(|_| EvalError::Int32OutOfRange(count.to_string().into())) |
| 408 | } |
| 409 | |
| 410 | // TODO(benesch): remove potentially dangerous usage of `as`. |
| 411 | #[allow(clippy::as_conversions)] |