PgLsn type.
This commit is contained in:
parent
77aa702e6c
commit
f3cbc8ce04
@ -24,6 +24,9 @@ pub mod types;
|
||||
/// A Postgres OID.
|
||||
pub type Oid = u32;
|
||||
|
||||
/// A Postgres Log Sequence Number (LSN).
|
||||
pub type Lsn = u64;
|
||||
|
||||
/// An enum indicating if a value is `NULL` or not.
|
||||
pub enum IsNull {
|
||||
/// The value is `NULL`.
|
||||
|
@ -8,7 +8,7 @@ use std::io::Read;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
use std::str;
|
||||
|
||||
use crate::{write_nullable, FromUsize, IsNull, Oid};
|
||||
use crate::{write_nullable, FromUsize, IsNull, Lsn, Oid};
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
@ -142,6 +142,22 @@ pub fn int8_from_sql(mut buf: &[u8]) -> Result<i64, StdBox<dyn Error + Sync + Se
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
/// Serializes a `PG_LSN` value.
|
||||
#[inline]
|
||||
pub fn lsn_to_sql(v: Lsn, buf: &mut BytesMut) {
|
||||
buf.put_u64(v);
|
||||
}
|
||||
|
||||
/// Deserializes a `PG_LSN` value.
|
||||
#[inline]
|
||||
pub fn lsn_from_sql(mut buf: &[u8]) -> Result<Lsn, StdBox<dyn Error + Sync + Send>> {
|
||||
let v = buf.read_u64::<BigEndian>()?;
|
||||
if !buf.is_empty() {
|
||||
return Err("invalid buffer size".into());
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
/// Serializes a `FLOAT4` value.
|
||||
#[inline]
|
||||
pub fn float4_to_sql(v: f32, buf: &mut BytesMut) {
|
||||
|
@ -130,6 +130,9 @@ use crate::type_gen::{Inner, Other};
|
||||
#[doc(inline)]
|
||||
pub use postgres_protocol::Oid;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use pg_lsn::PgLsn;
|
||||
|
||||
pub use crate::special::{Date, Timestamp};
|
||||
use bytes::BytesMut;
|
||||
|
||||
@ -204,6 +207,7 @@ mod uuid_08;
|
||||
#[cfg(feature = "with-time-0_2")]
|
||||
extern crate time_02 as time;
|
||||
|
||||
mod pg_lsn;
|
||||
#[doc(hidden)]
|
||||
pub mod private;
|
||||
mod special;
|
||||
|
79
postgres-types/src/pg_lsn.rs
Normal file
79
postgres-types/src/pg_lsn.rs
Normal file
@ -0,0 +1,79 @@
|
||||
//! Log Sequence Number (LSN) type for PostgreSQL Write-Ahead Log
|
||||
//! (WAL), also known as the transaction log.
|
||||
|
||||
use bytes::BytesMut;
|
||||
use postgres_protocol::types;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::{FromSql, IsNull, ToSql, Type};
|
||||
|
||||
/// Postgres `PG_LSN` type.
|
||||
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub struct PgLsn(u64);
|
||||
|
||||
/// Error parsing LSN.
|
||||
#[derive(Debug)]
|
||||
pub struct ParseLsnError(());
|
||||
|
||||
impl From<u64> for PgLsn {
|
||||
fn from(lsn_u64: u64) -> Self {
|
||||
PgLsn(lsn_u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PgLsn> for u64 {
|
||||
fn from(lsn: PgLsn) -> u64 {
|
||||
lsn.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for PgLsn {
|
||||
type Err = ParseLsnError;
|
||||
|
||||
fn from_str(lsn_str: &str) -> Result<Self, Self::Err> {
|
||||
let split: Vec<&str> = lsn_str.split('/').collect();
|
||||
if split.len() == 2 {
|
||||
let (hi, lo) = (
|
||||
u64::from_str_radix(split[0], 16).map_err(|_| ParseLsnError(()))?,
|
||||
u64::from_str_radix(split[1], 16).map_err(|_| ParseLsnError(()))?,
|
||||
);
|
||||
Ok(PgLsn((hi << 32) | lo))
|
||||
} else {
|
||||
Err(ParseLsnError(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PgLsn {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:X}/{:X}", self.0 >> 32, self.0 & 0x00000000ffffffff)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PgLsn {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_fmt(format_args!("{}", self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromSql<'a> for PgLsn {
|
||||
fn from_sql(_: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
|
||||
let v = types::lsn_from_sql(raw)?;
|
||||
Ok(v.into())
|
||||
}
|
||||
|
||||
accepts!(PG_LSN);
|
||||
}
|
||||
|
||||
impl ToSql for PgLsn {
|
||||
fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
|
||||
types::lsn_to_sql((*self).into(), out);
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
||||
accepts!(PG_LSN);
|
||||
|
||||
to_sql_checked!();
|
||||
}
|
@ -6,8 +6,9 @@ use std::f64;
|
||||
use std::fmt;
|
||||
use std::net::IpAddr;
|
||||
use std::result;
|
||||
use std::str::FromStr;
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
use tokio_postgres::types::{FromSql, FromSqlOwned, IsNull, Kind, ToSql, Type, WrongType};
|
||||
use tokio_postgres::types::{FromSql, FromSqlOwned, IsNull, Kind, PgLsn, ToSql, Type, WrongType};
|
||||
|
||||
use crate::connect;
|
||||
use bytes::BytesMut;
|
||||
@ -135,6 +136,18 @@ async fn test_i64_params() {
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_lsn_params() {
|
||||
test_type(
|
||||
"PG_LSN",
|
||||
&[
|
||||
(Some(PgLsn::from_str("2B/1757980").unwrap()), "'2B/1757980'"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_f32_params() {
|
||||
test_type(
|
||||
|
Loading…
Reference in New Issue
Block a user