1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
use brotli::{CompressorWriter, Decompressor};
use std::io::{Read, Write};
use rusqlite::Error::UserFunctionError;
use crate::common::{register_compression, Encoder};
use crate::rusqlite::{Connection, Result};
/// Register the `brotli` SQL function with the given `SQLite` connection.
/// The function takes a single argument and returns the [Brotli compression](https://en.wikipedia.org/wiki/Brotli) (blob) of that argument.
/// The argument can be either a string or a blob.
/// If the argument is `NULL`, the result is `NULL`.
///
/// # Example
///
/// ```
/// # use sqlite_compressions::rusqlite::{Connection, Result};
/// # use sqlite_compressions::register_brotli_functions;
/// # fn main() -> Result<()> {
/// let db = Connection::open_in_memory()?;
/// register_brotli_functions(&db)?;
/// let result: Vec<u8> = db.query_row("SELECT brotli('hello')", [], |r| r.get(0))?;
/// let expected = b"\x0b\x02\x80\x68\x65\x6c\x6c\x6f\x03";
/// assert_eq!(result, expected);
/// let result: String = db.query_row("SELECT CAST(brotli_decode(brotli('world')) AS TEXT)", [], |r| r.get(0))?;
/// let expected = "world";
/// assert_eq!(result, expected);
/// let result: bool = db.query_row("SELECT brotli_test(brotli('world'))", [], |r| r.get(0))?;
/// let expected = true;
/// assert_eq!(result, expected);
/// # Ok(())
/// # }
/// ```
pub fn register_brotli_functions(conn: &Connection) -> Result<()> {
register_compression::<BrotliEncoder>(conn)
}
pub struct BrotliEncoder;
impl Encoder for BrotliEncoder {
fn enc_name() -> &'static str {
"brotli"
}
fn dec_name() -> &'static str {
"brotli_decode"
}
fn test_name() -> &'static str {
"brotli_test"
}
fn encode(data: &[u8], quality: Option<u32>) -> Result<Vec<u8>> {
let quality = if let Some(param) = quality { param } else { 11 };
let mut encoder = CompressorWriter::new(Vec::new(), 4 * 1024, quality, 22);
encoder
.write_all(data)
.map_err(|e| UserFunctionError(e.into()))?;
Ok(encoder.into_inner())
}
fn decode(data: &[u8]) -> Result<Vec<u8>> {
let mut decompressed = Vec::new();
Decompressor::new(data, 4 * 1024)
.read_to_end(&mut decompressed)
.map_err(|e| UserFunctionError(e.into()))?;
Ok(decompressed)
}
fn test(data: &[u8]) -> bool {
// reuse the same buffer when decompressing
// ideally we should use some null buffer, but flate2 doesn't seem to support that
// note that buffer size does affect performance and depend on the input data size
let mut buffer = [0u8; 4 * 1024];
let mut decoder = Decompressor::new(data, 4 * 1024);
while let Ok(len) = decoder.read(&mut buffer) {
if len == 0 {
return true;
}
}
false
}
}