1use super::{DialectImpl, DialectType};
7use crate::error::Result;
8use crate::expressions::{
9 AggFunc, Case, Cast, DataType, Expression, Function, Limit, RegexpFunc, VarArgFunc,
10};
11use crate::generator::GeneratorConfig;
12use crate::tokens::TokenizerConfig;
13
14pub struct RedshiftDialect;
16
17impl DialectImpl for RedshiftDialect {
18 fn dialect_type(&self) -> DialectType {
19 DialectType::Redshift
20 }
21
22 fn tokenizer_config(&self) -> TokenizerConfig {
23 use crate::tokens::TokenType;
24 let mut config = TokenizerConfig::default();
25 config.identifiers.insert('"', '"');
27 config.nested_comments = false;
29 config.keywords.insert("MINUS".to_string(), TokenType::Except);
31 config
32 }
33
34 fn generator_config(&self) -> GeneratorConfig {
35 use crate::generator::IdentifierQuoteStyle;
36 GeneratorConfig {
37 identifier_quote: '"',
38 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
39 dialect: Some(DialectType::Redshift),
40 supports_column_join_marks: true,
41 locking_reads_supported: false,
42 tz_to_with_time_zone: true,
43 ..Default::default()
44 }
45 }
46
47 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
48 match expr {
49 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc { original_name: None,
51 expressions: vec![f.this, f.expression],
52 }))),
53
54 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc { original_name: None,
56 expressions: vec![f.this, f.expression],
57 }))),
58
59 Expression::TryCast(c) => Ok(Expression::TryCast(c)),
61
62 Expression::SafeCast(c) => Ok(Expression::TryCast(c)),
64
65 Expression::ILike(op) => Ok(Expression::ILike(op)),
67
68 Expression::CountIf(f) => {
70 let case_expr = Expression::Case(Box::new(Case {
71 operand: None,
72 whens: vec![(f.this.clone(), Expression::number(1))],
73 else_: Some(Expression::number(0)),
74 }));
75 Ok(Expression::Sum(Box::new(AggFunc { ignore_nulls: None, having_max: None,
76 this: case_expr,
77 distinct: f.distinct,
78 filter: f.filter,
79 order_by: Vec::new(),
80 name: None,
81 limit: None,
82 })))
83 }
84
85 Expression::Explode(_) => Ok(expr),
87
88 Expression::ExplodeOuter(_) => Ok(expr),
90
91 Expression::Unnest(_) => Ok(expr),
93
94 Expression::Rand(r) => {
96 let _ = r.seed;
97 Ok(Expression::Random(crate::expressions::Random))
98 }
99
100 Expression::Function(f) => self.transform_function(*f),
102
103 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
105
106 Expression::Cast(c) => self.transform_cast(*c),
108
109 Expression::Convert(c) => {
111 Ok(Expression::Cast(Box::new(Cast {
112 this: c.this,
113 to: c.to,
114 trailing_comments: Vec::new(),
115 double_colon_syntax: false,
116 format: None,
117 default: None,
118 })))
119 }
120
121 Expression::Select(mut select) => {
123 if let Some(top) = select.top.take() {
124 if !top.percent && !top.with_ties {
126 select.limit = Some(Limit {
128 this: top.this,
129 percent: false,
130 });
131 } else {
132 select.top = Some(top);
134 }
135 }
136 Ok(Expression::Select(select))
137 }
138
139 _ => Ok(expr),
141 }
142 }
143}
144
145impl RedshiftDialect {
146 fn transform_function(&self, f: Function) -> Result<Expression> {
147 let name_upper = f.name.to_uppercase();
148 match name_upper.as_str() {
149 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc { original_name: None,
151 expressions: f.args,
152 }))),
153
154 "NVL" if f.args.len() >= 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc { original_name: None,
156 expressions: f.args,
157 }))),
158
159 "ISNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc { original_name: None,
161 expressions: f.args,
162 }))),
163
164 "GETDATE" => Ok(Expression::Function(Box::new(Function::new(
166 "GETDATE".to_string(),
167 vec![],
168 )))),
169
170 "NOW" => Ok(Expression::Function(Box::new(Function::new(
172 "GETDATE".to_string(),
173 vec![],
174 )))),
175
176 "RAND" => Ok(Expression::Random(crate::expressions::Random)),
178
179 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
181 Function::new("LISTAGG".to_string(), f.args),
182 ))),
183
184 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
186 Function::new("LISTAGG".to_string(), f.args),
187 ))),
188
189 "LISTAGG" => Ok(Expression::Function(Box::new(f))),
191
192 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
194 "SUBSTRING".to_string(),
195 f.args,
196 )))),
197
198 "LEN" => Ok(Expression::Function(Box::new(f))),
200
201 "LENGTH" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
203 "LEN".to_string(),
204 f.args,
205 )))),
206
207 "CHARINDEX" => Ok(Expression::Function(Box::new(f))),
209
210 "POSITION" if f.args.len() == 2 => {
212 let mut args = f.args;
213 let substring = args.remove(0);
214 let string = args.remove(0);
215 Ok(Expression::Function(Box::new(Function::new(
217 "CHARINDEX".to_string(),
218 vec![substring, string],
219 ))))
220 }
221
222 "STRPOS" if f.args.len() == 2 => {
224 let args = f.args;
225 let string = args[0].clone();
227 let substring = args[1].clone();
228 Ok(Expression::Function(Box::new(Function::new(
229 "CHARINDEX".to_string(),
230 vec![substring, string],
231 ))))
232 }
233
234 "INSTR" if f.args.len() >= 2 => {
236 let mut args = f.args;
237 let string = args.remove(0);
238 let substring = args.remove(0);
239 Ok(Expression::Function(Box::new(Function::new(
241 "CHARINDEX".to_string(),
242 vec![substring, string],
243 ))))
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(
253 "CHARINDEX".to_string(),
254 vec![substring, string],
255 ))))
256 }
257
258 "ARRAY_LENGTH" => Ok(Expression::Function(Box::new(f))),
261
262 "SIZE" => Ok(Expression::Function(Box::new(f))),
264
265 "TO_DATE" => Ok(Expression::Function(Box::new(f))),
267
268 "TO_TIMESTAMP" => Ok(Expression::Function(Box::new(f))),
270
271 "DATE_FORMAT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
273 Function::new("TO_CHAR".to_string(), f.args),
274 ))),
275
276 "STRFTIME" if f.args.len() >= 2 => {
278 let mut args = f.args;
279 let format = args.remove(0);
280 let date = args.remove(0);
281 Ok(Expression::Function(Box::new(Function::new(
282 "TO_CHAR".to_string(),
283 vec![date, format],
284 ))))
285 }
286
287 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
289
290 "LEVENSHTEIN" => Ok(Expression::Function(Box::new(f))),
292
293 "JSON_EXTRACT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
295 Function::new("JSON_EXTRACT_PATH_TEXT".to_string(), f.args),
296 ))),
297
298 "JSON_EXTRACT_SCALAR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
300 Function::new("JSON_EXTRACT_PATH_TEXT".to_string(), f.args),
301 ))),
302
303 "GET_JSON_OBJECT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(
305 Function::new("JSON_EXTRACT_PATH_TEXT".to_string(), f.args),
306 ))),
307
308 "COLLECT_LIST" => Ok(Expression::Function(Box::new(f))),
310
311 "COLLECT_SET" => Ok(Expression::Function(Box::new(f))),
313
314 "RLIKE" if f.args.len() == 2 => {
316 let mut args = f.args;
318 let string = args.remove(0);
319 let pattern = args.remove(0);
320 Ok(Expression::RegexpLike(Box::new(RegexpFunc {
321 this: string,
322 pattern,
323 flags: None,
324 })))
325 }
326
327 "REGEXP" if f.args.len() == 2 => {
329 let mut args = f.args;
330 let string = args.remove(0);
331 let pattern = args.remove(0);
332 Ok(Expression::RegexpLike(Box::new(RegexpFunc {
333 this: string,
334 pattern,
335 flags: None,
336 })))
337 }
338
339 "REGEXP_LIKE" => Ok(Expression::Function(Box::new(f))),
341
342 "ADD_MONTHS" if f.args.len() == 2 => {
344 let mut args = f.args;
345 let date = args.remove(0);
346 let months = args.remove(0);
347 Ok(Expression::Function(Box::new(Function::new(
349 "DATEADD".to_string(),
350 vec![Expression::identifier("month"), months, date],
351 ))))
352 }
353
354 "DATEDIFF" => Ok(Expression::Function(Box::new(f))),
356
357 "DATE_DIFF" => Ok(Expression::Function(Box::new(Function::new(
359 "DATEDIFF".to_string(),
360 f.args,
361 )))),
362
363 "DATEADD" => Ok(Expression::Function(Box::new(f))),
365
366 "DATE_ADD" => Ok(Expression::Function(Box::new(Function::new(
368 "DATEADD".to_string(),
369 f.args,
370 )))),
371
372 "SPLIT_TO_ARRAY" => Ok(Expression::Function(Box::new(f))),
374
375 "STRING_TO_ARRAY" if f.args.len() >= 1 => Ok(Expression::Function(Box::new(
377 Function::new("SPLIT_TO_ARRAY".to_string(), f.args),
378 ))),
379
380 "SPLIT" if f.args.len() >= 1 => Ok(Expression::Function(Box::new(Function::new(
382 "SPLIT_TO_ARRAY".to_string(),
383 f.args,
384 )))),
385
386 "STRTOL" => Ok(Expression::Function(Box::new(f))),
388
389 "FROM_BASE" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
391 "STRTOL".to_string(),
392 f.args,
393 )))),
394
395 "CONVERT_TIMEZONE" if f.args.len() == 2 => {
397 let mut new_args = vec![Expression::string("UTC")];
398 new_args.extend(f.args);
399 Ok(Expression::Function(Box::new(Function::new(
400 "CONVERT_TIMEZONE".to_string(),
401 new_args,
402 ))))
403 }
404 "CONVERT_TIMEZONE" => Ok(Expression::Function(Box::new(f))),
406
407 "CONVERT" if f.args.len() == 2 => {
409 let type_expr = &f.args[0];
410 let value_expr = f.args[1].clone();
411
412 let type_name = match type_expr {
414 Expression::Column(c) => c.name.name.clone(),
415 Expression::Identifier(i) => i.name.clone(),
416 _ => return Ok(Expression::Function(Box::new(f))), };
418
419 let data_type = match type_name.to_uppercase().as_str() {
421 "INT" | "INTEGER" => DataType::Int { length: None, integer_spelling: false },
422 "BIGINT" => DataType::BigInt { length: None },
423 "SMALLINT" => DataType::SmallInt { length: None },
424 "TINYINT" => DataType::TinyInt { length: None },
425 "VARCHAR" => DataType::VarChar { length: None, parenthesized_length: false },
426 "CHAR" => DataType::Char { length: None },
427 "FLOAT" | "REAL" => DataType::Float { precision: None, scale: None, real_spelling: false },
428 "DOUBLE" => DataType::Double { precision: None, scale: None },
429 "BOOLEAN" | "BOOL" => DataType::Boolean,
430 "DATE" => DataType::Date,
431 "TIMESTAMP" => DataType::Timestamp { precision: None, timezone: false },
432 "TEXT" => DataType::Text,
433 "DECIMAL" | "NUMERIC" => DataType::Decimal { precision: None, scale: None },
434 _ => return Ok(Expression::Function(Box::new(f))), };
436
437 Ok(Expression::Cast(Box::new(Cast {
438 this: value_expr,
439 to: data_type,
440 trailing_comments: Vec::new(),
441 double_colon_syntax: false,
442 format: None,
443 default: None,
444 })))
445 }
446
447 _ => Ok(Expression::Function(Box::new(f))),
449 }
450 }
451
452 fn transform_aggregate_function(
453 &self,
454 f: Box<crate::expressions::AggregateFunction>,
455 ) -> Result<Expression> {
456 let name_upper = f.name.to_uppercase();
457 match name_upper.as_str() {
458 "COUNT_IF" if !f.args.is_empty() => {
460 let condition = f.args.into_iter().next().unwrap();
461 let case_expr = Expression::Case(Box::new(Case {
462 operand: None,
463 whens: vec![(condition, Expression::number(1))],
464 else_: Some(Expression::number(0)),
465 }));
466 Ok(Expression::Sum(Box::new(AggFunc { ignore_nulls: None, having_max: None,
467 this: case_expr,
468 distinct: f.distinct,
469 filter: f.filter,
470 order_by: Vec::new(),
471 name: None,
472 limit: None,
473 })))
474 }
475
476 "ANY_VALUE" => Ok(Expression::AggregateFunction(f)),
478
479 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
481 Function::new("LISTAGG".to_string(), f.args),
482 ))),
483
484 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
486 Function::new("LISTAGG".to_string(), f.args),
487 ))),
488
489 "LISTAGG" => Ok(Expression::AggregateFunction(f)),
491
492 "STDDEV" => Ok(Expression::AggregateFunction(f)),
494
495 "VARIANCE" => Ok(Expression::AggregateFunction(f)),
497
498 "MEDIAN" => Ok(Expression::AggregateFunction(f)),
500
501 _ => Ok(Expression::AggregateFunction(f)),
503 }
504 }
505
506 fn transform_cast(&self, c: Cast) -> Result<Expression> {
507 Ok(Expression::Cast(Box::new(c)))
509 }
510}