1use super::{builtin_array_element_name, split_type_modifier_with_control, ColumnType};
10use crate::ast::{IntervalFields, RangeSubtype};
11use std::borrow::Cow;
12use uqa_core::memory::{Produced, ProductionControl, ProductionString};
13use uqa_core::ValueRetentionError;
14
15impl ColumnType {
16 pub fn from_sql_name(name: &str) -> Result<Self, crate::SQLError> {
18 Self::from_sql_name_with_control(name, &ProductionControl::uncontrolled()).map(|value| {
19 value
20 .into_uncontrolled()
21 .expect("ordinary type parsing has no reservation")
22 })
23 }
24
25 #[expect(
27 clippy::too_many_lines,
28 reason = "one type grammar preserves every accepted spelling and diagnostic"
29 )]
30 pub fn from_sql_name_with_control(
31 name: &str,
32 control: &ProductionControl<'_>,
33 ) -> Result<Produced<Self>, crate::SQLError> {
34 let normalized = normalized_type_name(name, control)?;
35 if let Some(element) = builtin_array_element_name(&normalized) {
36 return Self::array_with_control(
37 Self::from_sql_name_with_control(element, control)?,
38 control,
39 )
40 .map_err(Into::into);
41 }
42 if let Some(element) = normalized.strip_suffix("[]") {
43 let element_type = Self::from_sql_name_with_control(element, control)?;
44 if matches!(*element_type, Self::Void) {
45 return Err(crate::SQLError::Routine {
46 sqlstate: "42704".into(),
47 message: format!("type \"{}\" does not exist", normalized.as_ref()),
48 });
49 }
50 return Self::array_with_control(element_type, control).map_err(Into::into);
51 }
52 let (base, modifier) = split_type_modifier_with_control(&normalized, control)?;
53 let base = base.strip_prefix("pg_catalog.").unwrap_or(&base);
54 let temporal_precision = || {
55 modifier
56 .map(|value| {
57 value.trim().parse::<i64>().map_err(|_| {
58 crate::SQLError::TypeMismatch(format!(
59 "invalid temporal precision: {value}"
60 ))
61 })
62 })
63 .transpose()
64 };
65 let character_length = || -> Result<Option<u32>, crate::SQLError> {
66 modifier
67 .map(|value| {
68 value
69 .parse::<u32>()
70 .ok()
71 .filter(|length| *length > 0)
72 .ok_or_else(|| {
73 crate::SQLError::TypeMismatch(format!(
74 "character length must be greater than zero, got {value}"
75 ))
76 })
77 })
78 .transpose()
79 };
80 let parsed = match base {
81 "smallint" | "int2" => Ok(Self::SmallInteger),
82 "integer" | "int" | "int4" => Ok(Self::Integer),
83 "bigint" | "int8" => Ok(Self::BigInteger),
84 "oid" => Ok(Self::Oid),
85 "xid" => Ok(Self::Xid),
86 "boolean" | "bool" => Ok(Self::Boolean),
87 "void" => Ok(Self::Void),
88 "text" => Ok(Self::Text),
89 "refcursor" => Ok(Self::RefCursor),
90 "name" => Ok(Self::Name),
91 "uuid" => Ok(Self::Uuid),
92 "varchar" | "character varying" => Ok(Self::Varchar(character_length()?)),
93 "character" | "char" => Ok(Self::Character(character_length()?.unwrap_or(1))),
94 "bpchar" => Ok(character_length()?.map_or(Self::Bpchar, Self::Character)),
95 "real" | "float4" => Ok(Self::Real),
96 "double" | "double precision" | "float8" => Ok(Self::DoublePrecision),
97 "numeric" | "decimal" => {
98 let (precision, scale) = match modifier {
99 None => (None, None),
100 Some(modifier) => {
101 let mut parts = modifier.split(',').map(str::trim);
102 let precision = parts
103 .next()
104 .and_then(|value| value.parse::<u32>().ok())
105 .ok_or_else(|| {
106 crate::SQLError::TypeMismatch(format!(
107 "invalid numeric modifier `{modifier}`"
108 ))
109 })?;
110 let scale = parts
111 .next()
112 .map(|value| value.parse::<i32>())
113 .transpose()
114 .map_err(|_| {
115 crate::SQLError::TypeMismatch(format!(
116 "invalid numeric modifier `{modifier}`"
117 ))
118 })?
119 .unwrap_or(0);
120 if parts.next().is_some() {
121 return Err(crate::SQLError::TypeMismatch(format!(
122 "invalid numeric modifier `{modifier}`"
123 )));
124 }
125 (Some(precision), Some(scale))
126 }
127 };
128 Ok(Self::Numeric { precision, scale })
129 }
130 "json" => Ok(Self::Json),
131 "jsonb" => Ok(Self::JsonB),
132 "bytea" => Ok(Self::Bytea),
133 "\"char\"" => Ok(Self::InternalChar),
134 "regproc" => Ok(Self::Regproc),
135 "regprocedure" => Ok(Self::Regprocedure),
136 "regclass" => Ok(Self::Regclass),
137 "regnamespace" => Ok(Self::Regnamespace),
138 "regrole" => Ok(Self::Regrole),
139 "regtype" => Ok(Self::Regtype),
140 "pg_node_tree" => Ok(Self::PgNodeTree),
141 "aclitem" => Ok(Self::AclItem),
142 "int2vector" => Ok(Self::Int2Vector),
143 "oidvector" => Ok(Self::OidVector),
144 "anyarray" => Ok(Self::AnyArray),
145 "record" => Ok(Self::Record),
146 "date" => Ok(Self::Date),
147 "time" | "time without time zone" => {
148 Self::Time.with_temporal_precision(temporal_precision()?)
149 }
150 "timetz" | "time with time zone" => {
151 Self::TimeTz.with_temporal_precision(temporal_precision()?)
152 }
153 "timestamp" | "datetime" | "timestamp without time zone" => {
154 Self::Timestamp.with_temporal_precision(temporal_precision()?)
155 }
156 "timestamptz" | "timestamp with time zone" => {
157 Self::TimestampTz.with_temporal_precision(temporal_precision()?)
158 }
159 "interval" => Self::with_interval_modifiers(IntervalFields::All, temporal_precision()?),
160 other if other.starts_with("interval ") => {
161 let fields = IntervalFields::from_sql_suffix(&other[9..]).ok_or_else(|| {
162 crate::SQLError::TypeMismatch(format!("invalid interval fields: {other}"))
163 })?;
164 Self::with_interval_modifiers(fields, temporal_precision()?)
165 }
166 "int4range" => Ok(Self::Range(RangeSubtype::Integer)),
167 "int8range" => Ok(Self::Range(RangeSubtype::BigInteger)),
168 "numrange" => Ok(Self::Range(RangeSubtype::Numeric)),
169 "daterange" => Ok(Self::Range(RangeSubtype::Date)),
170 "tsrange" => Ok(Self::Range(RangeSubtype::Timestamp)),
171 "tstzrange" => Ok(Self::Range(RangeSubtype::TimestampTz)),
172 "int4multirange" => Ok(Self::Multirange(RangeSubtype::Integer)),
173 "int8multirange" => Ok(Self::Multirange(RangeSubtype::BigInteger)),
174 "nummultirange" => Ok(Self::Multirange(RangeSubtype::Numeric)),
175 "datemultirange" => Ok(Self::Multirange(RangeSubtype::Date)),
176 "tsmultirange" => Ok(Self::Multirange(RangeSubtype::Timestamp)),
177 "tstzmultirange" => Ok(Self::Multirange(RangeSubtype::TimestampTz)),
178 "vector" => modifier
179 .and_then(|value| value.parse::<u32>().ok())
180 .filter(|dimension| *dimension > 0)
181 .map(Self::Vector)
182 .ok_or_else(|| crate::SQLError::TypeMismatch("VECTOR requires a dimension".into())),
183 "tensor" => modifier
184 .and_then(|value| value.parse::<u32>().ok())
185 .filter(|dimension| *dimension > 0)
186 .map(Self::Tensor)
187 .ok_or_else(|| crate::SQLError::TypeMismatch("TENSOR requires a dimension".into())),
188 other => Err(crate::SQLError::Unsupported(format!(
189 "SQL type `{other}` is not supported"
190 ))),
191 }?;
192 control
193 .finish(parsed, control.empty_reservation())
194 .map_err(Into::into)
195 }
196}
197
198fn normalized_type_name<'a>(
199 name: &'a str,
200 control: &ProductionControl<'_>,
201) -> Result<Produced<Cow<'a, str>>, ValueRetentionError> {
202 control.check()?;
203 let name = name.trim();
204 let mut uppercase = false;
205 for chunk in name.as_bytes().chunks(4096) {
206 control.check()?;
207 if chunk.iter().any(u8::is_ascii_uppercase) {
208 uppercase = true;
209 break;
210 }
211 }
212 if !uppercase {
213 return control.finish(Cow::Borrowed(name), control.empty_reservation());
214 }
215 let mut normalized = ProductionString::new(*control);
216 normalized.reserve(name.len())?;
217 for character in name.chars() {
218 normalized.push(character.to_ascii_lowercase())?;
219 }
220 let (normalized, memory) = normalized.finish()?.into_parts();
221 control.finish(Cow::Owned(normalized), memory)
222}