1use crate::{
16 DataType,
17 data_type::{FloatPrecision, IntegerSize, JsonStorageFormat},
18};
19
20use crate::{DdlRenderer, FormulaRenderer, SqlRenderer};
21
22#[must_use]
27pub fn render_data_type_ansi(dt: &DataType) -> String {
28 match dt {
29 DataType::Integer(i) => match i.size {
30 IntegerSize::Tiny => "TINYINT",
31 IntegerSize::Small => "SMALLINT",
32 IntegerSize::Standard => "INTEGER",
33 IntegerSize::Big => "BIGINT",
34 }
35 .to_string(),
36 DataType::Decimal(d) => format!("DECIMAL({}, {})", d.precision, d.scale),
37 DataType::Float(f) => match f.precision {
38 FloatPrecision::Single => "FLOAT",
39 FloatPrecision::Double => "DOUBLE PRECISION",
40 }
41 .to_string(),
42 DataType::Boolean(_) => "BOOLEAN".to_string(),
43 DataType::Char(c) => format!("CHAR({})", c.length),
44 DataType::VarChar(vc) => match vc.max_length {
45 Some(len) => format!("VARCHAR({len})"),
46 None => "TEXT".to_string(),
47 },
48 DataType::Text(_) => "TEXT".to_string(),
49 DataType::Binary(b) => format!("BINARY({})", b.length),
50 DataType::VarBinary(vb) => match vb.max_length {
51 Some(len) => format!("VARBINARY({len})"),
52 None => "BLOB".to_string(),
53 },
54 DataType::Date(_) => "DATE".to_string(),
55 DataType::Time(t) => {
56 if t.precision > 0 {
57 format!("TIME({})", t.precision)
58 } else {
59 "TIME".to_string()
60 }
61 }
62 DataType::Timestamp(ts) => {
63 if ts.precision > 0 {
64 format!("TIMESTAMP({})", ts.precision)
65 } else {
66 "TIMESTAMP".to_string()
67 }
68 }
69 DataType::TimestampTz(ts) => {
70 let base = "TIMESTAMP WITH TIME ZONE";
71 if ts.precision > 0 { format!("{base}({})", ts.precision) } else { base.to_string() }
72 }
73 DataType::DateTime(dt_inner) => {
74 if dt_inner.precision > 0 {
75 format!("DATETIME({})", dt_inner.precision)
76 } else {
77 "DATETIME".to_string()
78 }
79 }
80 DataType::Interval(_) => "INTERVAL".to_string(),
81 DataType::Uuid(_) => "UUID".to_string(),
82 DataType::Json(j) => match j.storage_format {
83 JsonStorageFormat::Binary => "JSONB".to_string(),
84 JsonStorageFormat::Text => "JSON".to_string(),
85 },
86 DataType::Array(arr) => {
87 let elem = render_data_type_ansi(&arr.element_type);
88 format!("{elem}[]")
89 }
90 DataType::Map(_) => "JSON".to_string(),
91 }
92}
93
94#[must_use]
106pub fn render_cast_type_ansi(dt: &DataType) -> String {
107 match dt {
108 DataType::Boolean(_) => "BOOLEAN".to_owned(),
109 DataType::Integer(i) => match i.size {
110 IntegerSize::Tiny | IntegerSize::Small => "SMALLINT".to_owned(),
111 IntegerSize::Standard => "INTEGER".to_owned(),
112 IntegerSize::Big => "BIGINT".to_owned(),
113 },
114 DataType::Decimal(d) => format!("DECIMAL({}, {})", d.precision, d.scale),
115 DataType::Float(f) => match f.precision {
116 FloatPrecision::Double => "DOUBLE PRECISION".to_owned(),
117 FloatPrecision::Single => "REAL".to_owned(),
118 },
119 DataType::Char(c) => format!("CHAR({})", c.length),
120 DataType::VarChar(v) => match v.max_length {
121 Some(n) => format!("VARCHAR({n})"),
122 None => "VARCHAR".to_owned(),
123 },
124 DataType::Date(_) => "DATE".to_owned(),
125 DataType::Time(_) => "TIME".to_owned(),
126 DataType::Timestamp(_) | DataType::DateTime(_) => "TIMESTAMP".to_owned(),
127 DataType::TimestampTz(_) => "TIMESTAMP WITH TIME ZONE".to_owned(),
128 DataType::Binary(_) => "BINARY".to_owned(),
129 DataType::VarBinary(_) => "VARBINARY".to_owned(),
130 DataType::Json(_) => "JSON".to_owned(),
131 DataType::Uuid(_) => "UUID".to_owned(),
132 _ => "TEXT".to_owned(),
133 }
134}
135
136pub struct AnsiDialect;
142
143impl SqlRenderer for AnsiDialect {
144 fn render_data_type(&self, dt: &DataType) -> String {
145 render_data_type_ansi(dt)
146 }
147
148 fn quote_identifier(&self, name: &str) -> String {
149 format!("\"{name}\"")
150 }
151
152 fn qualify_name(&self, schema: Option<&str>, name: &str) -> String {
153 match schema {
154 Some(s) => format!("{}.{}", self.quote_identifier(s), self.quote_identifier(name)),
155 None => self.quote_identifier(name),
156 }
157 }
158
159 fn render_current_timestamp(&self) -> String {
160 "CURRENT_TIMESTAMP".to_string()
161 }
162
163 fn is_agnostic_dialect(&self) -> bool {
164 true
165 }
166
167 fn dialect_name(&self) -> &'static str {
168 "ansi"
169 }
170
171 fn to_formula_renderer(&self) -> Box<dyn FormulaRenderer> {
172 Box::new(Self)
173 }
174
175 fn sid_spelling(&self) -> crate::SidSpelling {
178 crate::ANSI_SID_SPELLING
179 }
180}
181
182impl DdlRenderer for AnsiDialect {}
183
184impl FormulaRenderer for AnsiDialect {}
185
186impl crate::ReplicationRenderer for AnsiDialect {}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191
192 #[test]
193 fn agnostic_is_agnostic() {
194 let d = AnsiDialect;
195 assert!(d.is_agnostic_dialect());
196 assert_eq!(d.dialect_name(), "ansi");
197 }
198
199 #[test]
200 fn agnostic_quotes_with_double_quotes() {
201 let d = AnsiDialect;
202 assert_eq!(d.quote_identifier("my_table"), "\"my_table\"");
203 }
204
205 #[test]
206 fn agnostic_qualifies_name() {
207 let d = AnsiDialect;
208 assert_eq!(d.qualify_name(Some("public"), "users"), "\"public\".\"users\"");
209 assert_eq!(d.qualify_name(None, "users"), "\"users\"");
210 }
211
212 #[test]
213 fn ansi_data_type_integer() {
214 assert_eq!(render_data_type_ansi(&DataType::int()), "INTEGER");
215 assert_eq!(render_data_type_ansi(&DataType::bigint()), "BIGINT");
216 assert_eq!(render_data_type_ansi(&DataType::smallint()), "SMALLINT");
217 }
218
219 #[test]
220 fn ansi_data_type_varchar() {
221 assert_eq!(render_data_type_ansi(&DataType::varchar(100)), "VARCHAR(100)");
222 assert_eq!(render_data_type_ansi(&DataType::text()), "TEXT");
223 }
224
225 #[test]
226 fn ansi_data_type_timestamp() {
227 assert_eq!(render_data_type_ansi(&DataType::timestamp()), "TIMESTAMP(6)");
228 assert_eq!(render_data_type_ansi(&DataType::date()), "DATE");
229 }
230}