diesel/pg/types/
integers.rs

1use crate::deserialize::{self, Defaultable, FromSql};
2use crate::pg::{Pg, PgValue};
3use crate::serialize::{self, IsNull, Output, ToSql};
4use crate::sql_types;
5use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
6
7#[cfg(feature = "postgres_backend")]
8impl FromSql<sql_types::Oid, Pg> for u32 {
9    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
10        let mut bytes = bytes.as_bytes();
11        bytes.read_u32::<NetworkEndian>().map_err(Into::into)
12    }
13}
14
15#[cfg(feature = "postgres_backend")]
16impl ToSql<sql_types::Oid, Pg> for u32 {
17    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
18        out.write_u32::<NetworkEndian>(*self)
19            .map(|_| IsNull::No)
20            .map_err(Into::into)
21    }
22}
23
24#[cfg(feature = "postgres_backend")]
25impl FromSql<sql_types::SmallInt, Pg> for i16 {
26    #[inline(always)]
27    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
28        let mut bytes = value.as_bytes();
29        if bytes.len() < 2 {
30            return emit_size_error(
31                "Received less than 2 bytes while decoding an i16. \
32                    Was an expression of a different type accidentally marked as SmallInt?",
33            );
34        }
35
36        if bytes.len() > 2 {
37            return emit_size_error(
38                "Received more than 2 bytes while decoding an i16. \
39                    Was an Integer expression accidentally marked as SmallInt?",
40            );
41        }
42        bytes
43            .read_i16::<NetworkEndian>()
44            .map_err(|e| Box::new(e) as Box<_>)
45    }
46}
47
48#[cfg(feature = "postgres_backend")]
49impl FromSql<sql_types::Integer, Pg> for i32 {
50    #[inline(always)]
51    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
52        let mut bytes = value.as_bytes();
53        if bytes.len() < 4 {
54            return emit_size_error(
55                "Received less than 4 bytes while decoding an i32. \
56                    Was an SmallInt expression accidentally marked as Integer?",
57            );
58        }
59
60        if bytes.len() > 4 {
61            return emit_size_error(
62                "Received more than 4 bytes while decoding an i32. \
63                    Was an BigInt expression accidentally marked as Integer?",
64            );
65        }
66        bytes
67            .read_i32::<NetworkEndian>()
68            .map_err(|e| Box::new(e) as Box<_>)
69    }
70}
71
72#[cold]
73#[inline(never)]
74fn emit_size_error<T>(var_name: &str) -> deserialize::Result<T> {
75    deserialize::Result::Err(var_name.into())
76}
77
78#[cfg(feature = "postgres_backend")]
79impl FromSql<sql_types::BigInt, Pg> for i64 {
80    #[inline(always)]
81    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
82        let mut bytes = value.as_bytes();
83        if bytes.len() < 8 {
84            return emit_size_error(
85                "Received less than 8 bytes while decoding an i64. \
86                    Was an Integer expression accidentally marked as BigInt?",
87            );
88        }
89
90        if bytes.len() > 8 {
91            return emit_size_error(
92                "Received more than 8 bytes while decoding an i64. \
93                    Was an expression of a different type expression accidentally marked as BigInt?"
94            );
95        }
96        bytes
97            .read_i64::<NetworkEndian>()
98            .map_err(|e| Box::new(e) as Box<_>)
99    }
100}
101
102#[cfg(feature = "postgres_backend")]
103impl ToSql<sql_types::SmallInt, Pg> for i16 {
104    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
105        out.write_i16::<NetworkEndian>(*self)
106            .map(|_| IsNull::No)
107            .map_err(|e| Box::new(e) as Box<_>)
108    }
109}
110
111#[cfg(feature = "postgres_backend")]
112impl ToSql<sql_types::Integer, Pg> for i32 {
113    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
114        out.write_i32::<NetworkEndian>(*self)
115            .map(|_| IsNull::No)
116            .map_err(|e| Box::new(e) as Box<_>)
117    }
118}
119
120#[cfg(feature = "postgres_backend")]
121impl ToSql<sql_types::BigInt, Pg> for i64 {
122    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
123        out.write_i64::<NetworkEndian>(*self)
124            .map(|_| IsNull::No)
125            .map_err(|e| Box::new(e) as Box<_>)
126    }
127}
128
129#[cfg(feature = "postgres_backend")]
130impl Defaultable for i32 {
131    fn default_value() -> Self {
132        Self::default()
133    }
134}
135
136#[cfg(feature = "postgres_backend")]
137impl Defaultable for i64 {
138    fn default_value() -> Self {
139        Self::default()
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use super::*;
146    use crate::query_builder::bind_collector::ByteWrapper;
147
148    #[diesel_test_helper::test]
149    fn i16_to_sql() {
150        let mut buffer = Vec::new();
151        let mut bytes = Output::test(ByteWrapper(&mut buffer));
152        ToSql::<sql_types::SmallInt, Pg>::to_sql(&1i16, &mut bytes).unwrap();
153        ToSql::<sql_types::SmallInt, Pg>::to_sql(&0i16, &mut bytes).unwrap();
154        ToSql::<sql_types::SmallInt, Pg>::to_sql(&-1i16, &mut bytes).unwrap();
155        assert_eq!(buffer, vec![0, 1, 0, 0, 255, 255]);
156    }
157
158    #[diesel_test_helper::test]
159    fn i32_to_sql() {
160        let mut buffer = Vec::new();
161        let mut bytes = Output::test(ByteWrapper(&mut buffer));
162        ToSql::<sql_types::Integer, Pg>::to_sql(&1i32, &mut bytes).unwrap();
163        ToSql::<sql_types::Integer, Pg>::to_sql(&0i32, &mut bytes).unwrap();
164        ToSql::<sql_types::Integer, Pg>::to_sql(&-1i32, &mut bytes).unwrap();
165        assert_eq!(buffer, vec![0, 0, 0, 1, 0, 0, 0, 0, 255, 255, 255, 255]);
166    }
167
168    #[diesel_test_helper::test]
169    fn i64_to_sql() {
170        let mut buffer = Vec::new();
171        let mut bytes = Output::test(ByteWrapper(&mut buffer));
172        ToSql::<sql_types::BigInt, Pg>::to_sql(&1i64, &mut bytes).unwrap();
173        ToSql::<sql_types::BigInt, Pg>::to_sql(&0i64, &mut bytes).unwrap();
174        ToSql::<sql_types::BigInt, Pg>::to_sql(&-1i64, &mut bytes).unwrap();
175        assert_eq!(
176            buffer,
177            vec![
178                0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255,
179                255,
180            ]
181        );
182    }
183}