1use super::{DialectImpl, DialectType};
7use crate::error::Result;
8use crate::expressions::{
9 AggFunc, AggregateFunction, Case, Cast, DataType, Expression, Function, IntervalUnit,
10 IntervalUnitSpec, LikeOp, Literal, UnaryFunc, VarArgFunc,
11};
12#[cfg(feature = "generate")]
13use crate::generator::GeneratorConfig;
14use crate::tokens::TokenizerConfig;
15
16pub struct TrinoDialect;
18
19impl DialectImpl for TrinoDialect {
20 fn dialect_type(&self) -> DialectType {
21 DialectType::Trino
22 }
23
24 fn tokenizer_config(&self) -> TokenizerConfig {
25 let mut config = TokenizerConfig::default();
26 config.identifiers.insert('"', '"');
28 config.nested_comments = false;
30 config.keywords.remove("QUALIFY");
33 config
34 }
35
36 #[cfg(feature = "generate")]
37
38 fn generator_config(&self) -> GeneratorConfig {
39 use crate::generator::IdentifierQuoteStyle;
40 GeneratorConfig {
41 identifier_quote: '"',
42 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
43 dialect: Some(DialectType::Trino),
44 limit_only_literals: true,
45 tz_to_with_time_zone: true,
46 ..Default::default()
47 }
48 }
49
50 #[cfg(feature = "transpile")]
51
52 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
53 match expr {
54 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
56 original_name: None,
57 expressions: vec![f.this, f.expression],
58 inferred_type: None,
59 }))),
60
61 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
63 original_name: None,
64 expressions: vec![f.this, f.expression],
65 inferred_type: None,
66 }))),
67
68 Expression::Coalesce(mut f) => {
70 f.original_name = None;
71 Ok(Expression::Coalesce(f))
72 }
73
74 Expression::TryCast(c) => Ok(Expression::TryCast(c)),
76
77 Expression::SafeCast(c) => Ok(Expression::TryCast(c)),
79
80 Expression::ILike(op) => {
82 let lower_left = Expression::Lower(Box::new(UnaryFunc::new(op.left.clone())));
83 let lower_right = Expression::Lower(Box::new(UnaryFunc::new(op.right.clone())));
84 Ok(Expression::Like(Box::new(LikeOp {
85 left: lower_left,
86 right: lower_right,
87 escape: op.escape,
88 quantifier: op.quantifier.clone(),
89 inferred_type: None,
90 })))
91 }
92
93 Expression::CountIf(f) => Ok(Expression::CountIf(f)),
95
96 Expression::Explode(f) => Ok(Expression::Unnest(Box::new(
98 crate::expressions::UnnestFunc {
99 this: f.this,
100 expressions: Vec::new(),
101 with_ordinality: false,
102 alias: None,
103 offset_alias: None,
104 inferred_type: None,
105 },
106 ))),
107
108 Expression::ExplodeOuter(f) => Ok(Expression::Unnest(Box::new(
110 crate::expressions::UnnestFunc {
111 this: f.this,
112 expressions: Vec::new(),
113 with_ordinality: false,
114 alias: None,
115 offset_alias: None,
116 inferred_type: None,
117 },
118 ))),
119
120 Expression::Function(f) => self.transform_function(*f),
122
123 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
125
126 Expression::Cast(c) => self.transform_cast(*c),
128
129 Expression::Trim(mut f) => {
132 if !f.sql_standard_syntax && f.characters.is_some() {
133 f.sql_standard_syntax = true;
135 }
136 Ok(Expression::Trim(f))
137 }
138
139 Expression::ListAgg(mut f) => {
141 if f.separator.is_none() {
142 f.separator = Some(Expression::Literal(Box::new(Literal::String(
143 ",".to_string(),
144 ))));
145 }
146 Ok(Expression::ListAgg(f))
147 }
148
149 Expression::Interval(mut interval) => {
151 if interval.unit.is_none() {
152 if let Some(Expression::Literal(ref lit)) = interval.this {
153 if let Literal::String(ref s) = lit.as_ref() {
154 if let Some((value, unit)) = Self::parse_compound_interval(s) {
155 interval.this =
156 Some(Expression::Literal(Box::new(Literal::String(value))));
157 interval.unit = Some(unit);
158 }
159 }
160 }
161 }
162 Ok(Expression::Interval(interval))
163 }
164
165 _ => Ok(expr),
167 }
168 }
169}
170
171#[cfg(feature = "transpile")]
172impl TrinoDialect {
173 fn parse_compound_interval(s: &str) -> Option<(String, IntervalUnitSpec)> {
176 let s = s.trim();
177 let parts: Vec<&str> = s.split_whitespace().collect();
178 if parts.len() != 2 {
179 return None;
180 }
181 let value = parts[0].to_string();
182 let unit = match parts[1].to_uppercase().as_str() {
183 "YEAR" | "YEARS" => IntervalUnit::Year,
184 "MONTH" | "MONTHS" => IntervalUnit::Month,
185 "DAY" | "DAYS" => IntervalUnit::Day,
186 "HOUR" | "HOURS" => IntervalUnit::Hour,
187 "MINUTE" | "MINUTES" => IntervalUnit::Minute,
188 "SECOND" | "SECONDS" => IntervalUnit::Second,
189 "MILLISECOND" | "MILLISECONDS" => IntervalUnit::Millisecond,
190 "MICROSECOND" | "MICROSECONDS" => IntervalUnit::Microsecond,
191 _ => return None,
192 };
193 Some((
194 value,
195 IntervalUnitSpec::Simple {
196 unit,
197 use_plural: false,
198 },
199 ))
200 }
201
202 fn transform_function(&self, f: Function) -> Result<Expression> {
203 let name_upper = f.name.to_uppercase();
204 match name_upper.as_str() {
205 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
207 original_name: None,
208 expressions: f.args,
209 inferred_type: None,
210 }))),
211
212 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
214 original_name: None,
215 expressions: f.args,
216 inferred_type: None,
217 }))),
218
219 "ISNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
221 original_name: None,
222 expressions: f.args,
223 inferred_type: None,
224 }))),
225
226 "GETDATE" => Ok(Expression::CurrentTimestamp(
228 crate::expressions::CurrentTimestamp {
229 precision: None,
230 sysdate: false,
231 },
232 )),
233
234 "NOW" => Ok(Expression::CurrentTimestamp(
236 crate::expressions::CurrentTimestamp {
237 precision: None,
238 sysdate: false,
239 },
240 )),
241
242 "RAND" => Ok(Expression::Function(Box::new(Function::new(
244 "RANDOM".to_string(),
245 vec![],
246 )))),
247
248 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
250 Function::new("LISTAGG".to_string(), f.args),
251 ))),
252
253 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
255 Function::new("LISTAGG".to_string(), f.args),
256 ))),
257
258 "LISTAGG" => Ok(Expression::Function(Box::new(f))),
260
261 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
263 "SUBSTRING".to_string(),
264 f.args,
265 )))),
266
267 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
269 f.args.into_iter().next().unwrap(),
270 )))),
271
272 "CHARINDEX" if f.args.len() >= 2 => {
274 let mut args = f.args;
275 let substring = args.remove(0);
276 let string = args.remove(0);
277 Ok(Expression::Function(Box::new(Function::new(
278 "STRPOS".to_string(),
279 vec![string, substring],
280 ))))
281 }
282
283 "INSTR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
285 "STRPOS".to_string(),
286 f.args,
287 )))),
288
289 "LOCATE" if f.args.len() >= 2 => {
291 let mut args = f.args;
292 let substring = args.remove(0);
293 let string = args.remove(0);
294 Ok(Expression::Function(Box::new(Function::new(
295 "STRPOS".to_string(),
296 vec![string, substring],
297 ))))
298 }
299
300 "ARRAY_LENGTH" if f.args.len() == 1 => Ok(Expression::Function(Box::new(
302 Function::new("CARDINALITY".to_string(), f.args),
303 ))),
304
305 "SIZE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
307 "CARDINALITY".to_string(),
308 f.args,
309 )))),
310
311 "ARRAY_CONTAINS" if f.args.len() == 2 => Ok(Expression::Function(Box::new(
313 Function::new("CONTAINS".to_string(), f.args),
314 ))),
315
316 "TO_DATE" if !f.args.is_empty() => {
318 if f.args.len() == 1 {
319 Ok(Expression::Cast(Box::new(Cast {
320 this: f.args.into_iter().next().unwrap(),
321 to: DataType::Date,
322 trailing_comments: Vec::new(),
323 double_colon_syntax: false,
324 format: None,
325 default: None,
326 inferred_type: None,
327 })))
328 } else {
329 Ok(Expression::Function(Box::new(Function::new(
330 "DATE_PARSE".to_string(),
331 f.args,
332 ))))
333 }
334 }
335
336 "TO_TIMESTAMP" if !f.args.is_empty() => {
338 if f.args.len() == 1 {
339 Ok(Expression::Cast(Box::new(Cast {
340 this: f.args.into_iter().next().unwrap(),
341 to: DataType::Timestamp {
342 precision: None,
343 timezone: false,
344 },
345 trailing_comments: Vec::new(),
346 double_colon_syntax: false,
347 format: None,
348 default: None,
349 inferred_type: None,
350 })))
351 } else {
352 Ok(Expression::Function(Box::new(Function::new(
353 "DATE_PARSE".to_string(),
354 f.args,
355 ))))
356 }
357 }
358
359 "STRFTIME" if f.args.len() >= 2 => {
361 let mut args = f.args;
362 let format = args.remove(0);
363 let date = args.remove(0);
364 Ok(Expression::Function(Box::new(Function::new(
365 "DATE_FORMAT".to_string(),
366 vec![date, format],
367 ))))
368 }
369
370 "TO_CHAR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
372 "DATE_FORMAT".to_string(),
373 f.args,
374 )))),
375
376 "LEVENSHTEIN" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
378 Function::new("LEVENSHTEIN_DISTANCE".to_string(), f.args),
379 ))),
380
381 "GET_JSON_OBJECT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(
383 Function::new("JSON_EXTRACT_SCALAR".to_string(), f.args),
384 ))),
385
386 "COLLECT_LIST" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
388 Function::new("ARRAY_AGG".to_string(), f.args),
389 ))),
390
391 "COLLECT_SET" if !f.args.is_empty() => {
393 let array_agg =
394 Expression::Function(Box::new(Function::new("ARRAY_AGG".to_string(), f.args)));
395 Ok(Expression::Function(Box::new(Function::new(
396 "ARRAY_DISTINCT".to_string(),
397 vec![array_agg],
398 ))))
399 }
400
401 "RLIKE" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
403 "REGEXP_LIKE".to_string(),
404 f.args,
405 )))),
406
407 "REGEXP" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
409 "REGEXP_LIKE".to_string(),
410 f.args,
411 )))),
412
413 "ARRAY_SUM" if f.args.len() == 1 => {
416 Ok(Expression::Function(Box::new(f)))
420 }
421
422 _ => Ok(Expression::Function(Box::new(f))),
424 }
425 }
426
427 fn transform_aggregate_function(
428 &self,
429 f: Box<crate::expressions::AggregateFunction>,
430 ) -> Result<Expression> {
431 let name_upper = f.name.to_uppercase();
432 match name_upper.as_str() {
433 "COUNT_IF" if !f.args.is_empty() => {
435 let condition = f.args.into_iter().next().unwrap();
436 let case_expr = Expression::Case(Box::new(Case {
437 operand: None,
438 whens: vec![(condition, Expression::number(1))],
439 else_: Some(Expression::number(0)),
440 comments: Vec::new(),
441 inferred_type: None,
442 }));
443 Ok(Expression::Sum(Box::new(AggFunc {
444 ignore_nulls: None,
445 having_max: None,
446 this: case_expr,
447 distinct: f.distinct,
448 filter: f.filter,
449 order_by: Vec::new(),
450 name: None,
451 limit: None,
452 inferred_type: None,
453 })))
454 }
455
456 "ANY_VALUE" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
458 "ARBITRARY".to_string(),
459 f.args,
460 )))),
461
462 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
464 Function::new("LISTAGG".to_string(), f.args),
465 ))),
466
467 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
469 Function::new("LISTAGG".to_string(), f.args),
470 ))),
471
472 "VAR" if !f.args.is_empty() => {
474 Ok(Expression::AggregateFunction(Box::new(AggregateFunction {
475 name: "VAR_POP".to_string(),
476 args: f.args,
477 distinct: f.distinct,
478 filter: f.filter,
479 order_by: Vec::new(),
480 limit: None,
481 ignore_nulls: None,
482 inferred_type: None,
483 })))
484 }
485
486 "VARIANCE" if !f.args.is_empty() => {
488 Ok(Expression::AggregateFunction(Box::new(AggregateFunction {
489 name: "VAR_SAMP".to_string(),
490 args: f.args,
491 distinct: f.distinct,
492 filter: f.filter,
493 order_by: Vec::new(),
494 limit: None,
495 ignore_nulls: None,
496 inferred_type: None,
497 })))
498 }
499
500 _ => Ok(Expression::AggregateFunction(f)),
502 }
503 }
504
505 fn transform_cast(&self, c: Cast) -> Result<Expression> {
506 Ok(Expression::Cast(Box::new(c)))
508 }
509}