1use super::{DialectImpl, DialectType};
8use crate::error::Result;
9use crate::expressions::{AggFunc, Case, Cast, Expression, Function, UnaryFunc, VarArgFunc};
10use crate::generator::GeneratorConfig;
11use crate::tokens::TokenizerConfig;
12
13pub struct TeradataDialect;
15
16impl DialectImpl for TeradataDialect {
17 fn dialect_type(&self) -> DialectType {
18 DialectType::Teradata
19 }
20
21 fn tokenizer_config(&self) -> TokenizerConfig {
22 let mut config = TokenizerConfig::default();
23 config.identifiers.insert('"', '"');
25 config.nested_comments = false;
27 config
29 .keywords
30 .insert("SEL".to_string(), crate::tokens::TokenType::Select);
31 config
32 .keywords
33 .insert("UPD".to_string(), crate::tokens::TokenType::Update);
34 config
35 .keywords
36 .insert("DEL".to_string(), crate::tokens::TokenType::Delete);
37 config
38 .keywords
39 .insert("INS".to_string(), crate::tokens::TokenType::Insert);
40 config
41 .keywords
42 .insert("SAMPLE".to_string(), crate::tokens::TokenType::Sample);
43 config
44 .keywords
45 .insert("LOCKING".to_string(), crate::tokens::TokenType::Lock);
46 config
47 .keywords
48 .insert("HELP".to_string(), crate::tokens::TokenType::Command);
49 config
50 .keywords
51 .insert("COLLECT".to_string(), crate::tokens::TokenType::Command);
52 config
53 .keywords
54 .insert("EQ".to_string(), crate::tokens::TokenType::Eq);
55 config
56 .keywords
57 .insert("NE".to_string(), crate::tokens::TokenType::Neq);
58 config
59 .keywords
60 .insert("GE".to_string(), crate::tokens::TokenType::Gte);
61 config
62 .keywords
63 .insert("GT".to_string(), crate::tokens::TokenType::Gt);
64 config
65 .keywords
66 .insert("LE".to_string(), crate::tokens::TokenType::Lte);
67 config
68 .keywords
69 .insert("LT".to_string(), crate::tokens::TokenType::Lt);
70 config
71 .keywords
72 .insert("MOD".to_string(), crate::tokens::TokenType::Mod);
73 config
74 .keywords
75 .insert("BYTEINT".to_string(), crate::tokens::TokenType::SmallInt);
76 config.keywords.insert(
77 "ST_GEOMETRY".to_string(),
78 crate::tokens::TokenType::Geometry,
79 );
80 config.single_tokens.remove(&'%');
82 config.hex_number_strings = true;
84 config
85 }
86
87 fn generator_config(&self) -> GeneratorConfig {
88 use crate::generator::IdentifierQuoteStyle;
89 GeneratorConfig {
90 identifier_quote: '"',
91 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
92 dialect: Some(DialectType::Teradata),
93 tablesample_keywords: "SAMPLE",
94 tablesample_requires_parens: false,
95 tz_to_with_time_zone: true,
96 ..Default::default()
97 }
98 }
99
100 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
101 match expr {
102 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
104 original_name: None,
105 expressions: vec![f.this, f.expression],
106 inferred_type: None,
107 }))),
108
109 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
111 original_name: None,
112 expressions: vec![f.this, f.expression],
113 inferred_type: None,
114 }))),
115
116 Expression::Coalesce(mut f) => {
118 f.original_name = None;
119 Ok(Expression::Coalesce(f))
120 }
121
122 Expression::TryCast(c) => Ok(Expression::TryCast(c)),
124
125 Expression::SafeCast(c) => Ok(Expression::TryCast(c)),
127
128 Expression::CountIf(f) => {
130 let case_expr = Expression::Case(Box::new(Case {
131 operand: None,
132 whens: vec![(f.this.clone(), Expression::number(1))],
133 else_: Some(Expression::number(0)),
134 comments: Vec::new(),
135 inferred_type: None,
136 }));
137 Ok(Expression::Sum(Box::new(AggFunc {
138 ignore_nulls: None,
139 having_max: None,
140 this: case_expr,
141 distinct: f.distinct,
142 filter: f.filter,
143 order_by: Vec::new(),
144 name: None,
145 limit: None,
146 inferred_type: None,
147 })))
148 }
149
150 Expression::Rand(r) => {
152 if r.lower.is_some() || r.upper.is_some() {
153 Ok(Expression::Rand(r))
155 } else {
156 Ok(Expression::Random(crate::expressions::Random))
157 }
158 }
159
160 Expression::Function(f) => self.transform_function(*f),
162
163 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
165
166 Expression::Cast(c) => self.transform_cast(*c),
168
169 _ => Ok(expr),
171 }
172 }
173}
174
175impl TeradataDialect {
176 fn transform_function(&self, f: Function) -> Result<Expression> {
177 let name_upper = f.name.to_uppercase();
178 match name_upper.as_str() {
179 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
181 original_name: None,
182 expressions: f.args,
183 inferred_type: None,
184 }))),
185
186 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
188 original_name: None,
189 expressions: f.args,
190 inferred_type: None,
191 }))),
192
193 "ISNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
195 original_name: None,
196 expressions: f.args,
197 inferred_type: None,
198 }))),
199
200 "NOW" => Ok(Expression::CurrentTimestamp(
202 crate::expressions::CurrentTimestamp {
203 precision: None,
204 sysdate: false,
205 },
206 )),
207
208 "GETDATE" => Ok(Expression::CurrentTimestamp(
210 crate::expressions::CurrentTimestamp {
211 precision: None,
212 sysdate: false,
213 },
214 )),
215
216 "RAND" => Ok(Expression::Random(crate::expressions::Random)),
218
219 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
221 f.args.into_iter().next().unwrap(),
222 )))),
223
224 "LENGTH" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
226 f.args.into_iter().next().unwrap(),
227 )))),
228
229 "CHARINDEX" if f.args.len() >= 2 => {
231 let mut args = f.args;
232 let substring = args.remove(0);
233 let string = args.remove(0);
234 Ok(Expression::Function(Box::new(Function::new(
235 "INSTR".to_string(),
236 vec![string, substring],
237 ))))
238 }
239
240 "STRPOS" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
242 "INSTR".to_string(),
243 f.args,
244 )))),
245
246 "LOCATE" if f.args.len() >= 2 => {
248 let mut args = f.args;
249 let substring = args.remove(0);
250 let string = args.remove(0);
251 Ok(Expression::Function(Box::new(Function::new(
252 "INSTR".to_string(),
253 vec![string, substring],
254 ))))
255 }
256
257 "ARRAY_LENGTH" if f.args.len() == 1 => Ok(Expression::Function(Box::new(
259 Function::new("CARDINALITY".to_string(), f.args),
260 ))),
261
262 "SIZE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
264 "CARDINALITY".to_string(),
265 f.args,
266 )))),
267
268 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
270 "SUBSTRING".to_string(),
271 f.args,
272 )))),
273
274 "DATE_FORMAT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
276 Function::new("TO_CHAR".to_string(), f.args),
277 ))),
278
279 "STRFTIME" if f.args.len() >= 2 => {
281 let mut args = f.args;
282 let format = args.remove(0);
283 let date = args.remove(0);
284 Ok(Expression::Function(Box::new(Function::new(
285 "TO_CHAR".to_string(),
286 vec![date, format],
287 ))))
288 }
289
290 "GREATEST" => Ok(Expression::Function(Box::new(f))),
292
293 "LEAST" => Ok(Expression::Function(Box::new(f))),
295
296 _ => Ok(Expression::Function(Box::new(f))),
298 }
299 }
300
301 fn transform_aggregate_function(
302 &self,
303 f: Box<crate::expressions::AggregateFunction>,
304 ) -> Result<Expression> {
305 let name_upper = f.name.to_uppercase();
306 match name_upper.as_str() {
307 "COUNT_IF" if !f.args.is_empty() => {
309 let condition = f.args.into_iter().next().unwrap();
310 let case_expr = Expression::Case(Box::new(Case {
311 operand: None,
312 whens: vec![(condition, Expression::number(1))],
313 else_: Some(Expression::number(0)),
314 comments: Vec::new(),
315 inferred_type: None,
316 }));
317 Ok(Expression::Sum(Box::new(AggFunc {
318 ignore_nulls: None,
319 having_max: None,
320 this: case_expr,
321 distinct: f.distinct,
322 filter: f.filter,
323 order_by: Vec::new(),
324 name: None,
325 limit: None,
326 inferred_type: None,
327 })))
328 }
329
330 "MAX_BY" => Ok(Expression::AggregateFunction(f)),
332
333 "MIN_BY" => Ok(Expression::AggregateFunction(f)),
335
336 _ => Ok(Expression::AggregateFunction(f)),
338 }
339 }
340
341 fn transform_cast(&self, c: Cast) -> Result<Expression> {
342 if let Some(format_expr) = &c.format {
345 let is_date = matches!(c.to, crate::expressions::DataType::Date);
346 let is_timestamp = matches!(c.to, crate::expressions::DataType::Timestamp { .. });
347
348 if is_date || is_timestamp {
349 let fmt_str = match format_expr.as_ref() {
351 Expression::Literal(crate::expressions::Literal::String(s)) => Some(s.clone()),
352 _ => None,
353 };
354
355 if let Some(teradata_fmt) = fmt_str {
356 let strftime_fmt = Self::teradata_to_strftime(&teradata_fmt);
358
359 if is_date {
360 return Ok(Expression::StrToDate(Box::new(
361 crate::expressions::StrToDate {
362 this: Box::new(c.this),
363 format: Some(strftime_fmt),
364 safe: None,
365 },
366 )));
367 } else {
368 return Ok(Expression::StrToTime(Box::new(
369 crate::expressions::StrToTime {
370 this: Box::new(c.this),
371 format: strftime_fmt,
372 zone: None,
373 safe: None,
374 target_type: None,
375 },
376 )));
377 }
378 }
379 }
380 }
381 Ok(Expression::Cast(Box::new(c)))
383 }
384
385 fn teradata_to_strftime(fmt: &str) -> String {
387 let mut result = fmt.to_string();
389 result = result.replace("YYYY", "%Y");
391 result = result.replace("Y4", "%Y");
392 result = result.replace("YY", "%y");
393 result = result.replace("MMMM", "%B");
394 result = result.replace("MMM", "%b");
395 result = result.replace("MM", "%m");
396 result = result.replace("M4", "%B");
397 result = result.replace("M3", "%b");
398 result = result.replace("EEEE", "%A");
399 result = result.replace("EEE", "%a");
400 result = result.replace("EE", "%a");
401 result = result.replace("E4", "%A");
402 result = result.replace("E3", "%a");
403 result = result.replace("DDD", "%j");
404 result = result.replace("DD", "%d");
405 result = result.replace("D3", "%j");
406 result = result.replace("HH24", "%H");
407 result = result.replace("HH", "%H");
408 result = result.replace("SSSSSS", "%f");
409 result = result.replace("SS", "%S");
410 result = result.replace("MI", "%M");
411 result
412 }
413}