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