pgx_pg_sys/submodules/
oids.rs

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