Skip to main content

pgrx_pg_sys/submodules/
oids.rs

1//LICENSE Portions Copyright 2019-2021 ZomboDB, LLC.
2//LICENSE
3//LICENSE Portions Copyright 2021-2023 Technology Concepts & Design, Inc.
4//LICENSE
5//LICENSE Portions Copyright 2023-2023 PgCentral Foundation, Inc. <contact@pgcentral.org>
6//LICENSE
7//LICENSE All rights reserved.
8//LICENSE
9//LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file.
10#![allow(non_camel_case_types)]
11use std::fmt;
12
13use crate as pg_sys;
14use crate::BuiltinOid;
15use crate::Datum;
16use pgrx_sql_entity_graph::metadata::{
17    ArgumentError, ReturnsError, ReturnsRef, SqlMappingRef, SqlTranslatable, TypeOrigin,
18};
19
20/// An [object identifier][pg_docs_oid] in Postgres.
21///
22/// This is meant to be understood purely by equality. There is no sensible "order" for Oids.
23///
24/// # Notes
25/// `Default` shall return a sensical Oid, not necessarily a useful one.
26/// Currently, this means that it returns the invalid Oid.
27///
28/// [pg_docs_oid]: https://www.postgresql.org/docs/current/datatype-oid.html
29#[repr(transparent)]
30#[derive(Copy, Clone, PartialEq, Eq, Hash)]
31#[derive(serde::Deserialize, serde::Serialize)]
32pub struct Oid(pub(crate) u32);
33
34impl Oid {
35    pub const INVALID: Oid = Oid(0);
36
37    /// Generate an Oid from an arbitrary u32.
38    /// # Safety
39    /// This allows you to create an Oid that Postgres won't recognize and throw it into Postgres.
40    /// Don't.
41    ///
42    /// You should know what kind of object the identifier would imply before creating it.
43    /// Postgres may sometimes call very different internal functions based on an Oid input.
44    /// The extension programming interface of Postgres can reach deep, calling functions
45    /// that assume the caller should be trusted like Postgres would trust itself. Because it is.
46    /// Postgres tables can also change at runtime, so if an Oid is not a [BuiltinOid],
47    /// what Postgres does based on an Oid can change dynamically.
48    ///
49    /// The existence of this `unsafe` requirement to create *arbitrary* Oids does not, itself,
50    /// constitute a promise any Oid from Postgres or PGRX is guaranteed to be valid or sensical.
51    /// There are many existing problems in the way of this, for example:
52    /// - `Oid` includes the guaranteed-wrong values [Oid::INVALID]
53    /// - Postgres may return arbitrary-seeming Oids, like [BuiltinOid::UNKNOWNOID]
54    /// - an Oid can arrive in Rust from a table a non-superuser can write
55    /// - PGRX mostly relies on Rust's type system instead of the dynamic typing of Postgres,
56    ///   thus often deliberately does not bother to remember what OID something had.
57    ///
58    /// So this function is merely a reminder. Even for extensions that work with many Oids,
59    /// it is not typical to need to create one from an arbitrary `u32`. Prefer to use a constant,
60    /// or a [BuiltinOid], or to obtain one from querying Postgres, or simply use [Oid::INVALID].
61    /// Marking it as an `unsafe fn` is an invitation to get an Oid from more trustworthy sources.
62    /// This includes [Oid::INVALID], or [BuiltinOid], or by directly calling into Postgres.
63    /// An `unsafe fn` is not an officer of the law empowered to indict C programs for felonies,
64    /// nor cite SQL statements for misdemeanors, nor even truly stop you from foolishness.
65    /// Even "trustworthy" is meant here in a similar sense to how raw pointers can be "trustworthy".
66    /// Often, you should still check if it's null.
67    #[deprecated(since = "0.11.2", note = "safely converts via SPI, use pg_sys::Oid::from(u32)")]
68    pub const unsafe fn from_u32_unchecked(id: u32) -> Oid {
69        Oid(id)
70    }
71
72    /// Creates an Oid from an arbitrary u32.
73    ///
74    /// This is the same as the [`From::from`] implementation, but available in a `const` context.
75    pub const fn from_u32(id: u32) -> Oid {
76        Oid(id)
77    }
78
79    /// Gets an Oid from a u32 if it is a valid builtin declared by Postgres
80    pub const fn from_builtin(id: u32) -> Result<Oid, NotBuiltinOid> {
81        match BuiltinOid::from_u32(id) {
82            Ok(oid) => Ok(oid.value()),
83            Err(e) => Err(e),
84        }
85    }
86
87    pub const fn to_u32(self) -> u32 {
88        self.0
89    }
90}
91
92impl Default for Oid {
93    fn default() -> Oid {
94        Oid::INVALID
95    }
96}
97
98impl fmt::Debug for Oid {
99    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100        fmt::Debug::fmt(&self.0, f)
101    }
102}
103
104impl fmt::Display for Oid {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        fmt::Display::fmt(&self.0, f)
107    }
108}
109
110/// De facto available via SPI
111impl From<u32> for Oid {
112    fn from(word: u32) -> Oid {
113        Oid(word)
114    }
115}
116
117impl From<Oid> for u32 {
118    fn from(oid: Oid) -> u32 {
119        oid.0
120    }
121}
122
123impl From<Oid> for crate::Datum {
124    fn from(oid: Oid) -> Self {
125        Datum::from(oid.0)
126    }
127}
128
129impl From<BuiltinOid> for Oid {
130    fn from(builtin: BuiltinOid) -> Oid {
131        builtin.value()
132    }
133}
134
135unsafe impl SqlTranslatable for Oid {
136    const TYPE_IDENT: &'static str = pgrx_sql_entity_graph::pgrx_resolved_type!(Oid);
137    const TYPE_ORIGIN: TypeOrigin = TypeOrigin::External;
138    const ARGUMENT_SQL: Result<SqlMappingRef, ArgumentError> = Ok(SqlMappingRef::literal("oid"));
139    const RETURN_SQL: Result<ReturnsRef, ReturnsError> =
140        Ok(ReturnsRef::One(SqlMappingRef::literal("oid")));
141}
142
143// Actually implemented inside pgXX_oids.rs
144pub type PgBuiltInOids = BuiltinOid;
145
146#[derive(Debug, Clone, Copy)]
147pub enum NotBuiltinOid {
148    /// the invalid OID
149    Invalid,
150    /// not a known, builtin OID
151    Ambiguous,
152    /// value too large to be a valid OID in this Postgres version
153    TooBig,
154}
155
156impl TryFrom<u32> for BuiltinOid {
157    type Error = NotBuiltinOid;
158    fn try_from(uint: u32) -> Result<BuiltinOid, NotBuiltinOid> {
159        BuiltinOid::from_u32(uint)
160    }
161}
162
163impl TryFrom<Oid> for BuiltinOid {
164    type Error = NotBuiltinOid;
165    fn try_from(oid: Oid) -> Result<BuiltinOid, NotBuiltinOid> {
166        BuiltinOid::from_u32(oid.0)
167    }
168}
169
170impl TryFrom<crate::Datum> for BuiltinOid {
171    type Error = NotBuiltinOid;
172    fn try_from(datum: crate::Datum) -> Result<BuiltinOid, NotBuiltinOid> {
173        let uint = u32::try_from(datum.value()).map_err(|_| NotBuiltinOid::TooBig)?;
174        BuiltinOid::from_u32(uint)
175    }
176}
177
178impl BuiltinOid {
179    pub const fn value(self) -> pg_sys::Oid {
180        Oid(self as u32)
181    }
182
183    pub fn oid(self) -> PgOid {
184        PgOid::from(self)
185    }
186}
187
188#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
189pub enum PgOid {
190    Invalid,
191    Custom(Oid),
192    BuiltIn(BuiltinOid),
193}
194
195impl PgOid {
196    pub const fn from_untagged(oid: Oid) -> PgOid {
197        match BuiltinOid::from_u32(oid.0) {
198            Ok(builtin) => PgOid::BuiltIn(builtin),
199            Err(NotBuiltinOid::Invalid) => PgOid::Invalid,
200            Err(NotBuiltinOid::Ambiguous) => PgOid::Custom(oid),
201            _ => unsafe { core::hint::unreachable_unchecked() },
202        }
203    }
204}
205
206impl From<BuiltinOid> for PgOid {
207    fn from(builtin: BuiltinOid) -> PgOid {
208        PgOid::BuiltIn(builtin)
209    }
210}
211
212impl From<Oid> for PgOid {
213    fn from(oid: Oid) -> PgOid {
214        PgOid::from_untagged(oid)
215    }
216}
217
218impl PgOid {
219    #[inline]
220    pub const fn value(self) -> pg_sys::Oid {
221        match self {
222            PgOid::Invalid => pg_sys::InvalidOid,
223            PgOid::Custom(custom) => custom,
224            PgOid::BuiltIn(builtin) => builtin.value(),
225        }
226    }
227}