diesel/pg/types/
pg_lsn.rs

1use diesel_derives::AsExpression;
2use diesel_derives::FromSqlRow;
3
4use super::sql_types;
5use crate::deserialize::{self, FromSql};
6use crate::pg::{Pg, PgValue};
7use crate::serialize::{self, IsNull, Output, ToSql};
8use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
9
10/// A type encoding a position in the PostgreSQL *Write Ahead Log* (WAL).
11/// In Postgres, it is represented as an unsigned 64 bit integer.
12#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, AsExpression, FromSqlRow)]
13#[diesel(sql_type = sql_types::PgLsn)]
14pub struct PgLsn(pub u64);
15
16#[cfg(feature = "postgres_backend")]
17impl FromSql<sql_types::PgLsn, Pg> for PgLsn {
18    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
19        let mut bytes = value.as_bytes();
20        if bytes.len() < 8 {
21            return emit_size_error(
22                "Received less than 8 bytes while decoding a pg_lsn. \
23                    Was an Integer expression accidentally marked as pg_lsn?",
24            );
25        }
26
27        if bytes.len() > 8 {
28            return emit_size_error(
29                "Received more than 8 bytes while decoding a pg_lsn. \
30                    Was an expression of a different type expression accidentally marked as pg_lsn?"
31            );
32        }
33        let val = bytes
34            .read_u64::<NetworkEndian>()
35            .map_err(|e| Box::new(e) as Box<_>)?;
36        Ok(PgLsn(val))
37    }
38}
39
40#[cold]
41#[inline(never)]
42fn emit_size_error<T>(var_name: &str) -> deserialize::Result<T> {
43    deserialize::Result::Err(var_name.into())
44}
45
46#[cfg(feature = "postgres_backend")]
47impl ToSql<sql_types::PgLsn, Pg> for PgLsn {
48    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
49        out.write_u64::<NetworkEndian>(self.0)
50            .map(|_| IsNull::No)
51            .map_err(Into::into)
52    }
53}
54
55#[cfg(test)]
56#[diesel_test_helper::test]
57fn lsn_roundtrip() {
58    use crate::query_builder::bind_collector::ByteWrapper;
59
60    let mut buffer = Vec::new();
61    let mut bytes = Output::test(ByteWrapper(&mut buffer));
62    let input_lsn = PgLsn(0x525400fbc61617ff);
63    ToSql::<sql_types::PgLsn, Pg>::to_sql(&input_lsn, &mut bytes).unwrap();
64    let output_lsn: PgLsn = FromSql::from_sql(PgValue::for_test(&buffer)).unwrap();
65    assert_eq!(input_lsn, output_lsn);
66}