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