mod convert;
mod database;
mod postgres;
mod replay;
pub use convert::{ReadError, Written, read, write};
pub use database::{Abandoned, Answer, Call, Database, OpenCursor, Outcome, Session};
pub use postgres::{Postgres, Stream, Tls};
pub use replay::{Recorder, Replay};
use crate::vocab::SignClause;
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Null,
Int(i64),
Decimal { value: i128, scale: u32 },
Double(f64),
Char(String),
Binary(Vec<u8>),
}
impl Value {
pub fn decimal_text(value: i128, scale: u32) -> String {
let s = scale as usize;
let digits = format!("{:0>width$}", value.unsigned_abs(), width = s + 1);
let (whole, places) = digits.split_at(digits.len() - s);
let sign = if value < 0 { "-" } else { "" };
if s == 0 { format!("{sign}{whole}") } else { format!("{sign}{whole}.{places}") }
}
pub fn parse_decimal(text: &str) -> Option<Value> {
let (negative, digits) = match text.strip_prefix('-') {
Some(d) => (true, d),
None => (false, text.strip_prefix('+').unwrap_or(text)),
};
let (whole, places) = digits.split_once('.').unwrap_or((digits, ""));
if whole.is_empty() || !whole.bytes().chain(places.bytes()).all(|b| b.is_ascii_digit()) {
return None;
}
let magnitude: i128 = format!("{whole}{places}").parse().ok()?;
Some(Value::Decimal { value: if negative { -magnitude } else { magnitude }, scale: places.len() as u32 })
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SqlError {
pub code: i32,
pub state: &'static str,
}
pub const NOT_ASSIGNABLE: SqlError = SqlError { code: -303, state: "42806" };
pub const OUT_OF_RANGE: SqlError = SqlError { code: -304, state: "22003" };
pub const NULL_WITHOUT_INDICATOR: SqlError = SqlError { code: -305, state: "22002" };
pub const BAD_LENGTH: SqlError = SqlError { code: -311, state: "22501" };
pub const UNCONVERTIBLE: SqlError = SqlError { code: -330, state: "22021" };
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum HostType {
SmallInt { signed: bool },
Integer { signed: bool },
BigInt { signed: bool },
Decimal { digits: u32, scale: u32, signed: bool },
Zoned { digits: u32, scale: u32, signed: bool, sign: Option<SignClause> },
Real,
Double,
Char(u32),
VarChar(u32),
Structure(Vec<(usize, HostType)>),
}
pub fn fingerprint(text: &str) -> u32 {
text.bytes().fold(0x811c_9dc5, |h, b| (h ^ u32::from(b)).wrapping_mul(0x0100_0193))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_fingerprint_of_nothing_is_the_fnv_offset() {
assert_eq!(fingerprint(""), 0x811c_9dc5);
assert_ne!(fingerprint("COMMIT"), fingerprint("ROLLBACK"));
}
}