1use super::{DialectImpl, DialectType};
7use crate::error::Result;
8use crate::expressions::{AggFunc, BinaryOp, Case, Cast, CollationExpr, DataType, Expression, Function, Paren, VarArgFunc};
9use crate::generator::GeneratorConfig;
10use crate::tokens::TokenizerConfig;
11
12pub struct SingleStoreDialect;
14
15impl DialectImpl for SingleStoreDialect {
16 fn dialect_type(&self) -> DialectType {
17 DialectType::SingleStore
18 }
19
20 fn tokenizer_config(&self) -> TokenizerConfig {
21 let mut config = TokenizerConfig::default();
22 config.identifiers.insert('`', '`');
24 config.nested_comments = false;
25 config
26 }
27
28 fn generator_config(&self) -> GeneratorConfig {
29 use crate::generator::IdentifierQuoteStyle;
30 GeneratorConfig {
31 identifier_quote: '`',
32 identifier_quote_style: IdentifierQuoteStyle::BACKTICK,
33 dialect: Some(DialectType::SingleStore),
34 ..Default::default()
35 }
36 }
37
38 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
39 match expr {
40 Expression::Show(mut s) => {
42 if s.this == "INDEXES" || s.this == "KEYS" {
44 s.this = "INDEX".to_string();
45 }
46 Ok(Expression::Show(s))
47 }
48
49 Expression::Collation(c) => {
52 if let Expression::Cast(inner_cast) = &c.this {
53 let double_cast = Expression::Cast(Box::new(Cast {
55 this: c.this.clone(),
56 to: inner_cast.to.clone(),
57 trailing_comments: Vec::new(),
58 double_colon_syntax: false,
59 format: None,
60 default: None,
61 }));
62 Ok(Expression::Collation(Box::new(CollationExpr {
63 this: double_cast,
64 collation: c.collation.clone(),
65 quoted: c.quoted,
66 double_quoted: c.double_quoted,
67 })))
68 } else {
69 Ok(Expression::Collation(c))
70 }
71 }
72
73 Expression::IfNull(f) => Ok(Expression::IfNull(f)),
75
76 Expression::Nvl(f) => Ok(Expression::IfNull(f)),
78
79 Expression::TryCast(c) => Ok(Expression::TryCast(c)),
81
82 Expression::SafeCast(c) => Ok(Expression::TryCast(c)),
84
85 Expression::CountIf(f) => {
87 let case_expr = Expression::Case(Box::new(Case {
88 operand: None,
89 whens: vec![(f.this.clone(), Expression::number(1))],
90 else_: Some(Expression::number(0)),
91 }));
92 Ok(Expression::Sum(Box::new(AggFunc { ignore_nulls: None, having_max: None,
93 this: case_expr,
94 distinct: f.distinct,
95 filter: f.filter,
96 order_by: Vec::new(),
97 name: None,
98 limit: None,
99 })))
100 }
101
102 Expression::Rand(r) => Ok(Expression::Rand(r)),
104
105 Expression::Second(f) => {
107 let date = f.this;
108 let cast_to_time = Expression::Cast(Box::new(Cast {
110 this: date,
111 to: DataType::Time { precision: Some(6), timezone: false },
112 trailing_comments: Vec::new(),
113 double_colon_syntax: false,
114 format: None,
115 default: None,
116 }));
117 let date_format = Expression::Function(Box::new(Function::new(
118 "DATE_FORMAT".to_string(),
119 vec![cast_to_time, Expression::string("%s")],
120 )));
121 Ok(Expression::Cast(Box::new(Cast {
122 this: date_format,
123 to: DataType::Int { length: None, integer_spelling: false },
124 trailing_comments: Vec::new(),
125 double_colon_syntax: false,
126 format: None,
127 default: None,
128 })))
129 }
130
131 Expression::Hour(f) => {
133 let date = f.this;
134 let cast_to_time = Expression::Cast(Box::new(Cast {
136 this: date,
137 to: DataType::Time { precision: Some(6), timezone: false },
138 trailing_comments: Vec::new(),
139 double_colon_syntax: false,
140 format: None,
141 default: None,
142 }));
143 let date_format = Expression::Function(Box::new(Function::new(
144 "DATE_FORMAT".to_string(),
145 vec![cast_to_time, Expression::string("%k")],
146 )));
147 Ok(Expression::Cast(Box::new(Cast {
148 this: date_format,
149 to: DataType::Int { length: None, integer_spelling: false },
150 trailing_comments: Vec::new(),
151 double_colon_syntax: false,
152 format: None,
153 default: None,
154 })))
155 }
156
157 Expression::Minute(f) => {
159 let date = f.this;
160 let cast_to_time = Expression::Cast(Box::new(Cast {
162 this: date,
163 to: DataType::Time { precision: Some(6), timezone: false },
164 trailing_comments: Vec::new(),
165 double_colon_syntax: false,
166 format: None,
167 default: None,
168 }));
169 let date_format = Expression::Function(Box::new(Function::new(
170 "DATE_FORMAT".to_string(),
171 vec![cast_to_time, Expression::string("%i")],
172 )));
173 Ok(Expression::Cast(Box::new(Cast {
174 this: date_format,
175 to: DataType::Int { length: None, integer_spelling: false },
176 trailing_comments: Vec::new(),
177 double_colon_syntax: false,
178 format: None,
179 default: None,
180 })))
181 }
182
183 Expression::Function(f) => self.transform_function(*f),
185
186 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
188
189 Expression::Cast(c) => self.transform_cast(*c),
191
192 _ => Ok(expr),
194 }
195 }
196}
197
198impl SingleStoreDialect {
199 fn transform_function(&self, f: Function) -> Result<Expression> {
200 let name_upper = f.name.to_uppercase();
201 match name_upper.as_str() {
202 "NVL" if f.args.len() == 2 => Ok(Expression::Function(Box::new(Function::new(
204 "IFNULL".to_string(),
205 f.args,
206 )))),
207
208 "COALESCE" => Ok(Expression::Coalesce(Box::new(VarArgFunc { original_name: None,
210 expressions: f.args,
211 }))),
212
213 "NOW" => Ok(Expression::Function(Box::new(f))),
215
216 "GETDATE" => Ok(Expression::Function(Box::new(Function::new(
218 "NOW".to_string(),
219 f.args,
220 )))),
221
222 "GROUP_CONCAT" => Ok(Expression::Function(Box::new(f))),
224
225 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
227 "GROUP_CONCAT".to_string(),
228 f.args,
229 )))),
230
231 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
233 "GROUP_CONCAT".to_string(),
234 f.args,
235 )))),
236
237 "SUBSTR" => Ok(Expression::Function(Box::new(f))),
239
240 "SUBSTRING" => Ok(Expression::Function(Box::new(f))),
242
243 "LENGTH" => Ok(Expression::Function(Box::new(f))),
245
246 "LEN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
248 "LENGTH".to_string(),
249 f.args,
250 )))),
251
252 "CHARINDEX" if f.args.len() >= 2 => {
254 let mut args = f.args;
255 let substring = args.remove(0);
256 let string = args.remove(0);
257 Ok(Expression::Function(Box::new(Function::new(
258 "INSTR".to_string(),
259 vec![string, substring],
260 ))))
261 }
262
263 "STRPOS" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
265 "INSTR".to_string(),
266 f.args,
267 )))),
268
269 "LOCATE" => Ok(Expression::Function(Box::new(f))),
271
272 "INSTR" => Ok(Expression::Function(Box::new(f))),
274
275 "DATE_FORMAT" => Ok(Expression::Function(Box::new(f))),
277
278 "STRFTIME" if f.args.len() >= 2 => {
280 let mut args = f.args;
281 let format = args.remove(0);
282 let date = args.remove(0);
283 Ok(Expression::Function(Box::new(Function::new(
284 "DATE_FORMAT".to_string(),
285 vec![date, format],
286 ))))
287 }
288
289 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
291
292 "TO_DATE" => Ok(Expression::Function(Box::new(f))),
294
295 "TO_TIMESTAMP" => Ok(Expression::Function(Box::new(f))),
297
298 "JSON_EXTRACT_JSON" => Ok(Expression::Function(Box::new(f))),
300
301 "JSON_EXTRACT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
303 Function::new("JSON_EXTRACT_JSON".to_string(), f.args),
304 ))),
305
306 "GET_JSON_OBJECT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(
308 Function::new("JSON_EXTRACT_STRING".to_string(), f.args),
309 ))),
310
311 "REGEXP_LIKE" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
313 "RLIKE".to_string(),
314 f.args,
315 )))),
316
317 "RLIKE" => Ok(Expression::Function(Box::new(f))),
319
320 "TIME_BUCKET" => Ok(Expression::Function(Box::new(f))),
322
323 "DATE_BIN" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
325 "TIME_BUCKET".to_string(),
326 f.args,
327 )))),
328
329 "TIME_FORMAT" if f.args.len() == 2 => {
332 let mut args = f.args;
333 let date = args.remove(0);
334 let format = args.remove(0);
335 let cast_to_time = Expression::Cast(Box::new(Cast {
337 this: date,
338 to: DataType::Time { precision: Some(6), timezone: false },
339 trailing_comments: Vec::new(),
340 double_colon_syntax: false,
341 format: None,
342 default: None,
343 }));
344 Ok(Expression::Function(Box::new(Function::new(
345 "DATE_FORMAT".to_string(),
346 vec![cast_to_time, format],
347 ))))
348 }
349
350 "DAYNAME" if f.args.len() == 1 => {
352 let date = f.args.into_iter().next().unwrap();
353 Ok(Expression::Function(Box::new(Function::new(
354 "DATE_FORMAT".to_string(),
355 vec![date, Expression::string("%W")],
356 ))))
357 }
358
359 "MONTHNAME" if f.args.len() == 1 => {
361 let date = f.args.into_iter().next().unwrap();
362 Ok(Expression::Function(Box::new(Function::new(
363 "DATE_FORMAT".to_string(),
364 vec![date, Expression::string("%M")],
365 ))))
366 }
367
368 "HOUR" if f.args.len() == 1 => {
370 let date = f.args.into_iter().next().unwrap();
371 let cast_to_time = Expression::Cast(Box::new(Cast {
373 this: date,
374 to: DataType::Time { precision: Some(6), timezone: false },
375 trailing_comments: Vec::new(),
376 double_colon_syntax: false,
377 format: None,
378 default: None,
379 }));
380 let date_format = Expression::Function(Box::new(Function::new(
382 "DATE_FORMAT".to_string(),
383 vec![cast_to_time, Expression::string("%k")],
384 )));
385 Ok(Expression::Cast(Box::new(Cast {
387 this: date_format,
388 to: DataType::Int { length: None, integer_spelling: false },
389 trailing_comments: Vec::new(),
390 double_colon_syntax: false,
391 format: None,
392 default: None,
393 })))
394 }
395
396 "MINUTE" if f.args.len() == 1 => {
398 let date = f.args.into_iter().next().unwrap();
399 let cast_to_time = Expression::Cast(Box::new(Cast {
401 this: date,
402 to: DataType::Time { precision: Some(6), timezone: false },
403 trailing_comments: Vec::new(),
404 double_colon_syntax: false,
405 format: None,
406 default: None,
407 }));
408 let date_format = Expression::Function(Box::new(Function::new(
410 "DATE_FORMAT".to_string(),
411 vec![cast_to_time, Expression::string("%i")],
412 )));
413 Ok(Expression::Cast(Box::new(Cast {
415 this: date_format,
416 to: DataType::Int { length: None, integer_spelling: false },
417 trailing_comments: Vec::new(),
418 double_colon_syntax: false,
419 format: None,
420 default: None,
421 })))
422 }
423
424 "SECOND" if f.args.len() == 1 => {
426 let date = f.args.into_iter().next().unwrap();
427 let cast_to_time = Expression::Cast(Box::new(Cast {
429 this: date,
430 to: DataType::Time { precision: Some(6), timezone: false },
431 trailing_comments: Vec::new(),
432 double_colon_syntax: false,
433 format: None,
434 default: None,
435 }));
436 let date_format = Expression::Function(Box::new(Function::new(
438 "DATE_FORMAT".to_string(),
439 vec![cast_to_time, Expression::string("%s")],
440 )));
441 Ok(Expression::Cast(Box::new(Cast {
443 this: date_format,
444 to: DataType::Int { length: None, integer_spelling: false },
445 trailing_comments: Vec::new(),
446 double_colon_syntax: false,
447 format: None,
448 default: None,
449 })))
450 }
451
452 "MICROSECOND" if f.args.len() == 1 => {
454 let date = f.args.into_iter().next().unwrap();
455 let cast_to_time = Expression::Cast(Box::new(Cast {
457 this: date,
458 to: DataType::Time { precision: Some(6), timezone: false },
459 trailing_comments: Vec::new(),
460 double_colon_syntax: false,
461 format: None,
462 default: None,
463 }));
464 let date_format = Expression::Function(Box::new(Function::new(
466 "DATE_FORMAT".to_string(),
467 vec![cast_to_time, Expression::string("%f")],
468 )));
469 Ok(Expression::Cast(Box::new(Cast {
471 this: date_format,
472 to: DataType::Int { length: None, integer_spelling: false },
473 trailing_comments: Vec::new(),
474 double_colon_syntax: false,
475 format: None,
476 default: None,
477 })))
478 }
479
480 "WEEKDAY" if f.args.len() == 1 => {
482 let date = f.args.into_iter().next().unwrap();
483 let dayofweek = Expression::Function(Box::new(Function::new(
485 "DAYOFWEEK".to_string(),
486 vec![date],
487 )));
488 let add_five = Expression::Add(Box::new(BinaryOp::new(
490 dayofweek,
491 Expression::number(5),
492 )));
493 let add_five_paren = Expression::Paren(Box::new(Paren {
494 this: add_five,
495 trailing_comments: Vec::new(),
496 }));
497 Ok(Expression::Mod(Box::new(BinaryOp::new(
499 add_five_paren,
500 Expression::number(7),
501 ))))
502 }
503
504 _ => Ok(Expression::Function(Box::new(f))),
506 }
507 }
508
509 fn transform_aggregate_function(
510 &self,
511 f: Box<crate::expressions::AggregateFunction>,
512 ) -> Result<Expression> {
513 let name_upper = f.name.to_uppercase();
514 match name_upper.as_str() {
515 "COUNT_IF" if !f.args.is_empty() => {
517 let condition = f.args.into_iter().next().unwrap();
518 let case_expr = Expression::Case(Box::new(Case {
519 operand: None,
520 whens: vec![(condition, Expression::number(1))],
521 else_: Some(Expression::number(0)),
522 }));
523 Ok(Expression::Sum(Box::new(AggFunc { ignore_nulls: None, having_max: None,
524 this: case_expr,
525 distinct: f.distinct,
526 filter: f.filter,
527 order_by: Vec::new(),
528 name: None,
529 limit: None,
530 })))
531 }
532
533 "APPROX_COUNT_DISTINCT" => Ok(Expression::AggregateFunction(f)),
535
536 "HLL" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
538 "APPROX_COUNT_DISTINCT".to_string(),
539 f.args,
540 )))),
541
542 "VARIANCE" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
544 "VAR_SAMP".to_string(),
545 f.args,
546 )))),
547
548 "VAR_POP" => Ok(Expression::AggregateFunction(f)),
550
551 "VAR_SAMP" => Ok(Expression::AggregateFunction(f)),
553
554 _ => Ok(Expression::AggregateFunction(f)),
556 }
557 }
558
559 fn transform_cast(&self, c: Cast) -> Result<Expression> {
560 Ok(Expression::Cast(Box::new(c)))
562 }
563}