Skip to main content

postgresql_protocol/
oid.rs

1//! PostgreSQL type object identifiers and the binary/text format marker.
2
3use std::fmt;
4
5/// A PostgreSQL type object identifier (OID).
6pub type Oid = u32;
7
8/// `bool`
9pub const BOOLOID: Oid = 16;
10/// `bytea`
11pub const BYTEAOID: Oid = 17;
12/// `name`
13pub const NAMEOID: Oid = 19;
14/// `int8`
15pub const INT8OID: Oid = 20;
16/// `int2`
17pub const INT2OID: Oid = 21;
18/// `int4`
19pub const INT4OID: Oid = 23;
20/// `text`
21pub const TEXTOID: Oid = 25;
22/// `oid`
23pub const OIDOID: Oid = 26;
24/// `json`
25pub const JSONOID: Oid = 114;
26/// `float4`
27pub const FLOAT4OID: Oid = 700;
28/// `float8`
29pub const FLOAT8OID: Oid = 701;
30/// `inet`
31pub const INETOID: Oid = 869;
32/// `cidr`
33pub const CIDROID: Oid = 650;
34/// `varchar`
35pub const VARCHAROID: Oid = 1043;
36/// `bpchar` (blank-padded `char(n)`)
37pub const BPCHAROID: Oid = 1042;
38/// `date`
39pub const DATEOID: Oid = 1082;
40/// `time`
41pub const TIMEOID: Oid = 1083;
42/// `timestamp` (without time zone)
43pub const TIMESTAMPOID: Oid = 1114;
44/// `timestamptz`
45pub const TIMESTAMPTZOID: Oid = 1184;
46/// `interval`
47pub const INTERVALOID: Oid = 1186;
48/// `timetz`
49pub const TIMETZOID: Oid = 1266;
50/// `numeric`
51pub const NUMERICOID: Oid = 1700;
52/// `uuid`
53pub const UUIDOID: Oid = 2950;
54/// `jsonb`
55pub const JSONBOID: Oid = 3802;
56
57/// `name[]`
58pub const NAME_ARRAY_OID: Oid = 1003;
59/// `bpchar[]`
60pub const BPCHAR_ARRAY_OID: Oid = 1014;
61/// `int2[]`
62pub const INT2_ARRAY_OID: Oid = 1005;
63/// `int4[]`
64pub const INT4_ARRAY_OID: Oid = 1007;
65/// `text[]`
66pub const TEXT_ARRAY_OID: Oid = 1009;
67/// `int8[]`
68pub const INT8_ARRAY_OID: Oid = 1016;
69/// `float4[]`
70pub const FLOAT4_ARRAY_OID: Oid = 1021;
71/// `float8[]`
72pub const FLOAT8_ARRAY_OID: Oid = 1022;
73/// `bool[]`
74pub const BOOL_ARRAY_OID: Oid = 1000;
75/// `bytea[]`
76pub const BYTEA_ARRAY_OID: Oid = 1001;
77/// `uuid[]`
78pub const UUID_ARRAY_OID: Oid = 2951;
79/// `timestamptz[]`
80pub const TIMESTAMPTZ_ARRAY_OID: Oid = 1185;
81/// `date[]`
82pub const DATE_ARRAY_OID: Oid = 1182;
83/// `timestamp[]`
84pub const TIMESTAMP_ARRAY_OID: Oid = 1115;
85/// `varchar[]`
86pub const VARCHAR_ARRAY_OID: Oid = 1015;
87/// `json[]`
88pub const JSON_ARRAY_OID: Oid = 199;
89/// `inet[]`
90pub const INET_ARRAY_OID: Oid = 1041;
91/// `cidr[]`
92pub const CIDR_ARRAY_OID: Oid = 651;
93/// `time[]`
94pub const TIME_ARRAY_OID: Oid = 1183;
95/// `timetz[]`
96pub const TIMETZ_ARRAY_OID: Oid = 1270;
97/// `interval[]`
98pub const INTERVAL_ARRAY_OID: Oid = 1187;
99/// `numeric[]`
100pub const NUMERIC_ARRAY_OID: Oid = 1231;
101/// `jsonb[]`
102pub const JSONB_ARRAY_OID: Oid = 3807;
103
104/// The wire format of a value: text or binary.
105#[derive(Debug, Clone, Copy, PartialEq, Eq)]
106pub enum Format {
107    /// Human-readable text encoding.
108    Text,
109    /// PostgreSQL binary encoding.
110    Binary,
111}
112
113impl Format {
114    /// The protocol code for this format (`0` = text, `1` = binary).
115    pub const fn code(self) -> i16 {
116        match self {
117            Format::Text => 0,
118            Format::Binary => 1,
119        }
120    }
121}
122
123/// Returns the array type OID for the given element type.
124///
125/// Returns `None` for a type that has no array counterpart here (for example
126/// `interval` before it was added, or any extension type): silently claiming
127/// `int4[]` would make the server interpret the values as the wrong type.
128pub const fn array_oid(elem: Oid) -> Option<Oid> {
129    Some(match elem {
130        INT2OID => INT2_ARRAY_OID,
131        INT4OID => INT4_ARRAY_OID,
132        INT8OID => INT8_ARRAY_OID,
133        FLOAT4OID => FLOAT4_ARRAY_OID,
134        FLOAT8OID => FLOAT8_ARRAY_OID,
135        BOOLOID => BOOL_ARRAY_OID,
136        TEXTOID => TEXT_ARRAY_OID,
137        NAMEOID => NAME_ARRAY_OID,
138        VARCHAROID => VARCHAR_ARRAY_OID,
139        BPCHAROID => BPCHAR_ARRAY_OID,
140        BYTEAOID => BYTEA_ARRAY_OID,
141        UUIDOID => UUID_ARRAY_OID,
142        JSONOID => JSON_ARRAY_OID,
143        JSONBOID => JSONB_ARRAY_OID,
144        INETOID => INET_ARRAY_OID,
145        CIDROID => CIDR_ARRAY_OID,
146        DATEOID => DATE_ARRAY_OID,
147        TIMEOID => TIME_ARRAY_OID,
148        TIMETZOID => TIMETZ_ARRAY_OID,
149        TIMESTAMPTZOID => TIMESTAMPTZ_ARRAY_OID,
150        TIMESTAMPOID => TIMESTAMP_ARRAY_OID,
151        INTERVALOID => INTERVAL_ARRAY_OID,
152        NUMERICOID => NUMERIC_ARRAY_OID,
153        _ => return None,
154    })
155}
156
157/// Like [`array_oid`], for use in `const` contexts where a missing mapping has
158/// to fail at compile time instead of silently declaring the wrong type.
159///
160/// # Panics
161///
162/// Panics during constant evaluation when `elem` has no array counterpart.
163pub const fn array_oid_checked(elem: Oid) -> Oid {
164    match array_oid(elem) {
165        Some(oid) => oid,
166        None => panic!("this type has no PostgreSQL array type"),
167    }
168}
169
170/// A PostgreSQL type: its OID and canonical name.
171#[derive(Debug, Clone, Copy, PartialEq, Eq)]
172pub struct PgType {
173    /// The type's object identifier.
174    pub oid: Oid,
175    /// The canonical PostgreSQL name (e.g. `int4`, `_int4`).
176    pub name: &'static str,
177}
178
179impl PgType {
180    /// Creates a new type descriptor.
181    pub const fn new(oid: Oid, name: &'static str) -> Self {
182        PgType {
183            oid,
184            name,
185        }
186    }
187
188    /// Returns the array type whose element type is `self`.
189    ///
190    /// # Panics
191    ///
192    /// Panics when this type has no array counterpart; use
193    /// [`array_oid`] to handle that case.
194    pub const fn array_of(self) -> PgType {
195        let Some(oid) = array_oid(self.oid) else {
196            panic!("this type has no array type")
197        };
198        PgType {
199            oid,
200            name: "",
201        }
202    }
203}
204
205impl fmt::Display for PgType {
206    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207        write!(f, "{}", self.name)
208    }
209}
210
211/// `int2`
212pub static INT2: PgType = PgType::new(INT2OID, "int2");
213/// `int4`
214pub static INT4: PgType = PgType::new(INT4OID, "int4");
215/// `int8`
216pub static INT8: PgType = PgType::new(INT8OID, "int8");
217/// `float4`
218pub static FLOAT4: PgType = PgType::new(FLOAT4OID, "float4");
219/// `float8`
220pub static FLOAT8: PgType = PgType::new(FLOAT8OID, "float8");
221/// `bool`
222pub static BOOL: PgType = PgType::new(BOOLOID, "bool");
223/// `text`
224pub static TEXT: PgType = PgType::new(TEXTOID, "text");
225/// `varchar`
226pub static VARCHAR: PgType = PgType::new(VARCHAROID, "varchar");
227/// `bytea`
228pub static BYTEA: PgType = PgType::new(BYTEAOID, "bytea");
229/// `uuid`
230pub static UUID: PgType = PgType::new(UUIDOID, "uuid");
231/// `json`
232pub static JSON: PgType = PgType::new(JSONOID, "json");
233/// `jsonb`
234pub static JSONB: PgType = PgType::new(JSONBOID, "jsonb");
235/// `inet`
236pub static INET: PgType = PgType::new(INETOID, "inet");
237/// `cidr`
238pub static CIDR: PgType = PgType::new(CIDROID, "cidr");
239/// `date`
240pub static DATE: PgType = PgType::new(DATEOID, "date");
241/// `time`
242pub static TIME: PgType = PgType::new(TIMEOID, "time");
243/// `timetz`
244pub static TIMETZ: PgType = PgType::new(TIMETZOID, "timetz");
245/// `timestamp`
246pub static TIMESTAMP: PgType = PgType::new(TIMESTAMPOID, "timestamp");
247/// `timestamptz`
248pub static TIMESTAMPTZ: PgType = PgType::new(TIMESTAMPTZOID, "timestamptz");
249/// `interval`
250pub static INTERVAL: PgType = PgType::new(INTERVALOID, "interval");
251/// `numeric`
252pub static NUMERIC: PgType = PgType::new(NUMERICOID, "numeric");
253
254/// Maps an array type OID back to its element type, when known.
255pub const fn array_element(oid: Oid) -> Option<PgType> {
256    let elem = match oid {
257        INT2_ARRAY_OID => INT2OID,
258        INT4_ARRAY_OID => INT4OID,
259        INT8_ARRAY_OID => INT8OID,
260        FLOAT4_ARRAY_OID => FLOAT4OID,
261        FLOAT8_ARRAY_OID => FLOAT8OID,
262        BOOL_ARRAY_OID => BOOLOID,
263        TEXT_ARRAY_OID => TEXTOID,
264        NAME_ARRAY_OID => NAMEOID,
265        VARCHAR_ARRAY_OID => VARCHAROID,
266        BPCHAR_ARRAY_OID => BPCHAROID,
267        BYTEA_ARRAY_OID => BYTEAOID,
268        UUID_ARRAY_OID => UUIDOID,
269        JSON_ARRAY_OID => JSONOID,
270        JSONB_ARRAY_OID => JSONBOID,
271        INET_ARRAY_OID => INETOID,
272        CIDR_ARRAY_OID => CIDROID,
273        DATE_ARRAY_OID => DATEOID,
274        TIME_ARRAY_OID => TIMEOID,
275        TIMETZ_ARRAY_OID => TIMETZOID,
276        TIMESTAMPTZ_ARRAY_OID => TIMESTAMPTZOID,
277        TIMESTAMP_ARRAY_OID => TIMESTAMPOID,
278        INTERVAL_ARRAY_OID => INTERVALOID,
279        NUMERIC_ARRAY_OID => NUMERICOID,
280        _ => return None,
281    };
282    Some(PgType::new(elem, ""))
283}
284
285/// Returns `true` if `oid` is a known array type.
286pub const fn is_array(oid: Oid) -> bool {
287    array_element(oid).is_some()
288}
289
290#[cfg(test)]
291mod tests {
292    use super::*;
293
294    #[test]
295    fn array_of_known() {
296        assert_eq!(INT2.array_of().oid, INT2_ARRAY_OID);
297        assert_eq!(INT4.array_of().oid, INT4_ARRAY_OID);
298        assert_eq!(TEXT.array_of().oid, TEXT_ARRAY_OID);
299        assert_eq!(VARCHAR.array_of().oid, VARCHAR_ARRAY_OID);
300        assert_eq!(UUID.array_of().oid, UUID_ARRAY_OID);
301        assert_eq!(TIMESTAMPTZ.array_of().oid, TIMESTAMPTZ_ARRAY_OID);
302        assert_eq!(array_oid(INTERVALOID), Some(INTERVAL_ARRAY_OID));
303        assert_eq!(array_oid(JSONBOID), Some(JSONB_ARRAY_OID));
304        assert_eq!(array_oid(NAMEOID), Some(NAME_ARRAY_OID));
305    }
306
307    #[test]
308    fn unknown_element_has_no_array_oid() {
309        assert_eq!(array_oid(4242), None);
310    }
311
312    #[test]
313    fn element_roundtrip() {
314        assert_eq!(array_element(INT2_ARRAY_OID).unwrap().oid, INT2OID);
315        assert!(array_element(TEXTOID).is_none());
316        assert!(is_array(UUID_ARRAY_OID));
317        assert!(!is_array(UUIDOID));
318    }
319}