1use serde::{Deserialize, Serialize};
8
9use super::{IntervalFields, RangeSubtype};
10
11mod display;
12mod identity;
13mod modifiers;
14mod names;
15mod parsing;
16mod production;
17mod references;
18
19pub use display::TypeDisplayScope;
20pub use identity::{UserTypeIdentity, UserTypeKind};
21
22pub(crate) use modifiers::split_type_modifier_with_control;
23
24#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25pub enum ColumnType {
26 Named(String),
28 SmallInteger,
29 Integer,
30 BigInteger,
31 Oid,
33 Xid,
35 Boolean,
36 Void,
38 Text,
39 RefCursor,
41 Name,
42 Uuid,
43 Varchar(Option<u32>),
44 Bpchar,
46 Character(u32),
50 Real,
51 DoublePrecision,
52 Numeric {
57 precision: Option<u32>,
58 scale: Option<i32>,
59 },
60 Json,
62 JsonB,
64 Bytea,
66 InternalChar,
68 Regproc,
69 Regprocedure,
71 Regclass,
73 Regnamespace,
75 Regrole,
77 Regtype,
78 PgNodeTree,
79 AclItem,
80 Int2Vector,
81 OidVector,
82 AnyArray,
83 Record,
85 Array(Box<ColumnType>),
88 Date,
90 Time,
92 TimePrecision(u32),
94 TimeTz,
96 TimeTzPrecision(u32),
98 Timestamp,
101 TimestampPrecision(u32),
103 TimestampTz,
106 TimestampTzPrecision(u32),
108 Interval,
109 IntervalWithFields {
111 fields: IntervalFields,
112 precision: Option<u32>,
113 },
114 Range(RangeSubtype),
118 Multirange(RangeSubtype),
120 Vector(u32),
122 Tensor(u32),
126 Domain {
129 schema: String,
130 name: String,
131 oid: u32,
132 #[serde(default, skip_serializing_if = "Option::is_none")]
134 array_oid: Option<u32>,
135 base: Box<ColumnType>,
136 },
137 Enum(super::EnumTypeReference),
139 Composite(super::CompositeTypeReference),
141}
142
143pub(crate) fn builtin_array_element_name(type_name: &str) -> Option<&'static str> {
144 Some(match type_name {
145 "_bool" => "bool",
146 "_bytea" => "bytea",
147 "_char" => "\"char\"",
148 "_name" => "name",
149 "_int8" => "int8",
150 "_int2" => "int2",
151 "_int2vector" => "int2vector",
152 "_int4" => "int4",
153 "_regproc" => "regproc",
154 "_regprocedure" => "regprocedure",
155 "_regclass" => "regclass",
156 "_regrole" => "regrole",
157 "_text" => "text",
158 "_refcursor" => "refcursor",
159 "_oid" => "oid",
160 "_oidvector" => "oidvector",
161 "_bpchar" => "bpchar",
162 "_varchar" => "varchar",
163 "_float4" => "float4",
164 "_float8" => "float8",
165 "_aclitem" => "aclitem",
166 "_date" => "date",
167 "_time" => "time",
168 "_timestamp" => "timestamp",
169 "_timestamptz" => "timestamptz",
170 "_interval" => "interval",
171 "_numeric" => "numeric",
172 "_timetz" => "timetz",
173 "_record" => "record",
174 "_uuid" => "uuid",
175 "_json" => "json",
176 "_jsonb" => "jsonb",
177 "_regtype" => "regtype",
178 "_xid" => "xid",
179 "_pg_node_tree" => "pg_node_tree",
180 "_int4range" => "int4range",
181 "_int8range" => "int8range",
182 "_numrange" => "numrange",
183 "_daterange" => "daterange",
184 "_tsrange" => "tsrange",
185 "_tstzrange" => "tstzrange",
186 "_int4multirange" => "int4multirange",
187 "_int8multirange" => "int8multirange",
188 "_nummultirange" => "nummultirange",
189 "_datemultirange" => "datemultirange",
190 "_tsmultirange" => "tsmultirange",
191 "_tstzmultirange" => "tstzmultirange",
192 _ => return None,
193 })
194}
195
196impl ColumnType {
197 #[must_use]
199 pub fn without_type_modifiers(&self) -> Self {
200 self.without_type_modifiers_with_control(
201 &uqa_core::memory::ProductionControl::uncontrolled(),
202 )
203 .expect("ordinary type modifier removal cannot be limited or cancelled")
204 .into_uncontrolled()
205 .expect("ordinary type modifier removal has no reservation")
206 }
207
208 #[must_use]
209 pub const fn temporal_precision(&self) -> Option<u32> {
210 match self {
211 Self::IntervalWithFields { precision, .. } => *precision,
212 Self::TimePrecision(p)
213 | Self::TimeTzPrecision(p)
214 | Self::TimestampPrecision(p)
215 | Self::TimestampTzPrecision(p) => Some(*p),
216 _ => None,
217 }
218 }
219
220 #[must_use]
221 pub const fn without_temporal_modifiers(&self) -> &Self {
222 match self {
223 Self::IntervalWithFields { .. } => &Self::Interval,
224 Self::TimePrecision(_) => &Self::Time,
225 Self::TimeTzPrecision(_) => &Self::TimeTz,
226 Self::TimestampPrecision(_) => &Self::Timestamp,
227 Self::TimestampTzPrecision(_) => &Self::TimestampTz,
228 other => other,
229 }
230 }
231
232 pub(crate) fn with_temporal_precision(
233 self,
234 precision: Option<i64>,
235 ) -> Result<Self, crate::SQLError> {
236 let Some(precision) = precision else {
237 return Ok(self);
238 };
239 if precision < 0 {
240 return Err(crate::SQLError::Routine {
241 sqlstate: "22023".into(),
242 message: format!(
243 "{} precision must not be negative",
244 self.regtype_name().to_uppercase()
245 ),
246 });
247 }
248 let precision = u32::try_from(precision.min(6)).expect("bounded temporal precision");
249 Ok(match self {
250 Self::Time => Self::TimePrecision(precision),
251 Self::TimeTz => Self::TimeTzPrecision(precision),
252 Self::Timestamp => Self::TimestampPrecision(precision),
253 Self::TimestampTz => Self::TimestampTzPrecision(precision),
254 other => other,
255 })
256 }
257
258 pub(crate) fn with_interval_modifiers(
259 fields: IntervalFields,
260 precision: Option<i64>,
261 ) -> Result<Self, crate::SQLError> {
262 let precision = precision
263 .map(|precision| {
264 if precision < 0 {
265 return Err(crate::SQLError::Routine {
266 sqlstate: "22023".into(),
267 message: "INTERVAL precision must not be negative".into(),
268 });
269 }
270 Ok(u32::try_from(precision.min(6)).expect("bounded interval precision"))
271 })
272 .transpose()?;
273 if fields == IntervalFields::All && precision.is_none() {
274 return Ok(Self::Interval);
275 }
276 Ok(Self::IntervalWithFields { fields, precision })
277 }
278
279 #[must_use]
280 pub fn is_integer(&self) -> bool {
281 match self {
282 Self::SmallInteger | Self::Integer | Self::BigInteger | Self::Oid | Self::Xid => true,
283 Self::Domain { base, .. } => base.is_integer(),
284 _ => false,
285 }
286 }
287
288 #[must_use]
289 pub fn is_character_string(&self) -> bool {
290 match self {
291 Self::Text
292 | Self::Name
293 | Self::Varchar(_)
294 | Self::Bpchar
295 | Self::Character(_)
296 | Self::InternalChar
297 | Self::PgNodeTree
298 | Self::AclItem => true,
299 Self::Domain { base, .. } => base.is_character_string(),
300 _ => false,
301 }
302 }
303}