1use super::{DialectImpl, DialectType};
6use crate::error::Result;
7use crate::expressions::{
8 AggFunc, BinaryFunc, BinaryOp, Case, Cast, CeilFunc, DataType, DateTimeField, DateTruncFunc,
9 Expression, ExtractFunc, Function, LikeOp, Literal, TrimFunc, TrimPosition, UnaryFunc,
10 VarArgFunc,
11};
12use crate::generator::GeneratorConfig;
13use crate::tokens::TokenizerConfig;
14
15pub struct SQLiteDialect;
17
18impl DialectImpl for SQLiteDialect {
19 fn dialect_type(&self) -> DialectType {
20 DialectType::SQLite
21 }
22
23 fn tokenizer_config(&self) -> TokenizerConfig {
24 let mut config = TokenizerConfig::default();
25 config.identifiers.insert('"', '"');
27 config.identifiers.insert('[', ']');
28 config.identifiers.insert('`', '`');
29 config.nested_comments = false;
31 config.hex_number_strings = true;
33 config
34 }
35
36 fn generator_config(&self) -> GeneratorConfig {
37 use crate::generator::IdentifierQuoteStyle;
38 GeneratorConfig {
39 identifier_quote: '"',
40 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
41 dialect: Some(DialectType::SQLite),
42 json_key_value_pair_sep: ",",
44 supports_table_alias_columns: false,
46 ..Default::default()
47 }
48 }
49
50 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
51 match expr {
52 Expression::Nvl(f) => Ok(Expression::IfNull(f)),
54
55 Expression::TryCast(c) => Ok(Expression::Cast(c)),
57
58 Expression::SafeCast(c) => Ok(Expression::Cast(c)),
60
61 Expression::Rand(r) => {
63 let _ = r.seed; Ok(Expression::Function(Box::new(Function::new(
66 "RANDOM".to_string(),
67 vec![],
68 ))))
69 }
70
71 Expression::Random(_) => Ok(Expression::Function(Box::new(Function::new(
73 "RANDOM".to_string(),
74 vec![],
75 )))),
76
77 Expression::ILike(op) => {
79 let lower_left = Expression::Lower(Box::new(UnaryFunc::new(op.left.clone())));
80 let lower_right = Expression::Lower(Box::new(UnaryFunc::new(op.right.clone())));
81 Ok(Expression::Like(Box::new(LikeOp {
82 left: lower_left,
83 right: lower_right,
84 escape: op.escape,
85 quantifier: op.quantifier.clone(),
86 inferred_type: None,
87 })))
88 }
89
90 Expression::CountIf(f) => {
92 let iif_expr = Expression::Function(Box::new(Function::new(
93 "IIF".to_string(),
94 vec![f.this.clone(), Expression::number(1), Expression::number(0)],
95 )));
96 Ok(Expression::Sum(Box::new(AggFunc {
97 ignore_nulls: None,
98 having_max: None,
99 this: iif_expr,
100 distinct: f.distinct,
101 filter: f.filter,
102 order_by: Vec::new(),
103 name: None,
104 limit: None,
105 inferred_type: None,
106 })))
107 }
108
109 Expression::Unnest(_) => Ok(expr),
111
112 Expression::Explode(_) => Ok(expr),
114
115 Expression::Concat(c) => {
117 Ok(Expression::Concat(c))
120 }
121
122 Expression::IfFunc(f) => {
124 let mut args = vec![f.condition, f.true_value];
125 if let Some(false_val) = f.false_value {
126 args.push(false_val);
127 }
128 Ok(Expression::Function(Box::new(Function::new(
129 "IIF".to_string(),
130 args,
131 ))))
132 }
133
134 Expression::Pragma(mut p) => {
136 if p.value.is_some() || p.args.len() == 1 {
137 p.use_assignment_syntax = true;
138 }
139 Ok(Expression::Pragma(p))
140 }
141
142 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Date(_)) => {
144 let Literal::Date(date) = lit.as_ref() else {
145 unreachable!()
146 };
147 Ok(Self::string_literal(date))
148 }
149
150 Expression::Least(f) => Ok(Self::function("MIN", f.expressions)),
152 Expression::Greatest(f) => Ok(Self::function("MAX", f.expressions)),
153
154 Expression::Extract(f) => Self::transform_extract(*f),
156
157 Expression::DateTrunc(f) => Self::transform_date_trunc(*f),
159
160 Expression::Substring(mut f) => {
162 f.from_for_syntax = false;
163 Ok(Expression::Substring(f))
164 }
165
166 Expression::Trim(f) => Ok(Self::transform_trim(*f)),
168
169 Expression::CreateTable(mut ct)
171 if ct
172 .name
173 .schema
174 .as_ref()
175 .is_some_and(|schema| schema.name.eq_ignore_ascii_case("public"))
176 && ct.name.catalog.is_none() =>
177 {
178 ct.name.schema = None;
179 Ok(Expression::CreateTable(ct))
180 }
181
182 Expression::Function(f) => self.transform_function(*f),
184
185 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
187
188 Expression::Cast(c) => self.transform_cast(*c),
190
191 Expression::Div(mut op) => {
193 let right_is_float = matches!(&op.right, Expression::Literal(lit) if matches!(lit.as_ref(), crate::expressions::Literal::Number(n) if n.contains('.')));
195 let right_is_float_cast = Self::is_float_cast(&op.right);
196 if !Self::is_float_cast(&op.left) && !right_is_float && !right_is_float_cast {
197 op.left = Expression::Cast(Box::new(crate::expressions::Cast {
198 this: op.left,
199 to: crate::expressions::DataType::Float {
200 precision: None,
201 scale: None,
202 real_spelling: true,
203 },
204 trailing_comments: Vec::new(),
205 double_colon_syntax: false,
206 format: None,
207 default: None,
208 inferred_type: None,
209 }));
210 }
211 Ok(Expression::Div(op))
212 }
213
214 _ => Ok(expr),
216 }
217 }
218}
219
220impl SQLiteDialect {
221 fn function(name: &str, args: Vec<Expression>) -> Expression {
222 Expression::Function(Box::new(Function::new(name.to_string(), args)))
223 }
224
225 fn string_literal(value: &str) -> Expression {
226 Expression::Literal(Box::new(Literal::String(value.to_string())))
227 }
228
229 fn strftime(format: &str, expr: Expression) -> Expression {
230 Expression::Function(Box::new(Function::new(
231 "STRFTIME".to_string(),
232 vec![Self::string_literal(format), expr],
233 )))
234 }
235
236 fn cast(expr: Expression, to: DataType) -> Expression {
237 Expression::Cast(Box::new(Cast {
238 this: expr,
239 to,
240 trailing_comments: Vec::new(),
241 double_colon_syntax: false,
242 format: None,
243 default: None,
244 inferred_type: None,
245 }))
246 }
247
248 fn sqlite_int_type() -> DataType {
249 DataType::Int {
250 length: None,
251 integer_spelling: true,
252 }
253 }
254
255 fn sqlite_real_type() -> DataType {
256 DataType::Float {
257 precision: None,
258 scale: None,
259 real_spelling: true,
260 }
261 }
262
263 fn transform_extract(f: ExtractFunc) -> Result<Expression> {
264 let strftime_format = match &f.field {
265 DateTimeField::Year => "%Y",
266 DateTimeField::Month => "%m",
267 DateTimeField::Day => "%d",
268 DateTimeField::Hour => "%H",
269 DateTimeField::Minute => "%M",
270 DateTimeField::Second => "%f",
271 DateTimeField::DayOfWeek => "%w",
272 DateTimeField::DayOfYear => "%j",
273 DateTimeField::Epoch => "%s",
274 _ => return Ok(Expression::Extract(Box::new(f))),
275 };
276 let target_type = if matches!(f.field, DateTimeField::Epoch | DateTimeField::Second) {
277 Self::sqlite_real_type()
278 } else {
279 Self::sqlite_int_type()
280 };
281 Ok(Self::cast(
282 Self::strftime(strftime_format, f.this),
283 target_type,
284 ))
285 }
286
287 fn transform_date_trunc(f: DateTruncFunc) -> Result<Expression> {
288 match &f.unit {
289 DateTimeField::Day => Ok(Self::function("DATE", vec![f.this])),
290 DateTimeField::Hour => Ok(Self::strftime("%Y-%m-%d %H:00:00", f.this)),
291 DateTimeField::Minute => Ok(Self::strftime("%Y-%m-%d %H:%M:00", f.this)),
292 DateTimeField::Second => Ok(Self::strftime("%Y-%m-%d %H:%M:%S", f.this)),
293 DateTimeField::Month => Ok(Self::strftime("%Y-%m-01", f.this)),
294 DateTimeField::Year => Ok(Self::strftime("%Y-01-01", f.this)),
295 _ => Ok(Expression::DateTrunc(Box::new(f))),
296 }
297 }
298
299 fn datetime_field_from_expr(expr: &Expression) -> Option<DateTimeField> {
300 let unit = match expr {
301 Expression::Literal(lit) => match lit.as_ref() {
302 Literal::String(s) => s.as_str(),
303 _ => return None,
304 },
305 Expression::Identifier(id) => id.name.as_str(),
306 Expression::Var(v) => v.this.as_str(),
307 Expression::Column(col) if col.table.is_none() => col.name.name.as_str(),
308 _ => return None,
309 };
310 match unit.to_ascii_lowercase().as_str() {
311 "year" | "yyyy" | "yy" => Some(DateTimeField::Year),
312 "month" | "mon" | "mm" => Some(DateTimeField::Month),
313 "day" | "dd" => Some(DateTimeField::Day),
314 "hour" | "hours" | "h" | "hh" | "hr" | "hrs" => Some(DateTimeField::Hour),
315 "minute" | "minutes" | "mi" | "min" | "mins" => Some(DateTimeField::Minute),
316 "second" | "seconds" | "s" | "sec" | "secs" | "ss" => Some(DateTimeField::Second),
317 "dow" | "dayofweek" | "dw" => Some(DateTimeField::DayOfWeek),
318 "doy" | "dayofyear" | "dy" => Some(DateTimeField::DayOfYear),
319 "epoch" => Some(DateTimeField::Epoch),
320 _ => None,
321 }
322 }
323
324 fn transform_trim(f: TrimFunc) -> Expression {
325 let function_name = match f.position {
326 TrimPosition::Leading => "LTRIM",
327 TrimPosition::Trailing => "RTRIM",
328 TrimPosition::Both => "TRIM",
329 };
330 let mut args = vec![f.this];
331 if let Some(characters) = f.characters {
332 args.push(characters);
333 }
334 Expression::Function(Box::new(Function::new(function_name.to_string(), args)))
335 }
336
337 fn is_float_cast(expr: &Expression) -> bool {
339 if let Expression::Cast(cast) = expr {
340 match &cast.to {
341 crate::expressions::DataType::Double { .. }
342 | crate::expressions::DataType::Float { .. } => true,
343 crate::expressions::DataType::Custom { name } => {
344 name.eq_ignore_ascii_case("REAL") || name.eq_ignore_ascii_case("DOUBLE")
345 }
346 _ => false,
347 }
348 } else {
349 false
350 }
351 }
352
353 fn transform_function(&self, f: Function) -> Result<Expression> {
354 let name_upper = f.name.to_uppercase();
355 match name_upper.as_str() {
356 "LIKE" if f.args.len() == 2 => {
358 let mut args = f.args;
359 let pattern = args.remove(0);
360 let string = args.remove(0);
361 Ok(Expression::Like(Box::new(LikeOp::new(string, pattern))))
363 }
364 "LIKE" if f.args.len() == 3 => {
366 let mut args = f.args;
367 let pattern = args.remove(0);
368 let string = args.remove(0);
369 let escape = args.remove(0);
370 Ok(Expression::Like(Box::new(LikeOp {
371 left: string,
372 right: pattern,
373 escape: Some(escape),
374 quantifier: None,
375 inferred_type: None,
376 })))
377 }
378 "GLOB" if f.args.len() == 2 => {
380 let mut args = f.args;
381 let pattern = args.remove(0);
382 let string = args.remove(0);
383 Ok(Expression::Glob(Box::new(BinaryOp::new(string, pattern))))
385 }
386 "NVL" if f.args.len() == 2 => {
388 let mut args = f.args;
389 let expr1 = args.remove(0);
390 let expr2 = args.remove(0);
391 Ok(Expression::IfNull(Box::new(BinaryFunc {
392 original_name: None,
393 this: expr1,
394 expression: expr2,
395 inferred_type: None,
396 })))
397 }
398
399 "COALESCE" => Ok(Expression::Coalesce(Box::new(VarArgFunc {
401 original_name: None,
402 expressions: f.args,
403 inferred_type: None,
404 }))),
405
406 "RAND" => Ok(Expression::Function(Box::new(Function::new(
408 "RANDOM".to_string(),
409 vec![],
410 )))),
411
412 "CHR" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
414 "CHAR".to_string(),
415 f.args,
416 )))),
417
418 "POSITION" if f.args.len() == 2 => {
420 let mut args = f.args;
421 let substring = args.remove(0);
422 let string = args.remove(0);
423 Ok(Expression::Function(Box::new(Function::new(
425 "INSTR".to_string(),
426 vec![string, substring],
427 ))))
428 }
429
430 "STRPOS" if f.args.len() == 2 => {
432 let mut args = f.args;
433 let string = args.remove(0);
434 let substring = args.remove(0);
435 Ok(Expression::Function(Box::new(Function::new(
437 "INSTR".to_string(),
438 vec![string, substring],
439 ))))
440 }
441
442 "CHARINDEX" if f.args.len() >= 2 => {
444 let mut args = f.args;
445 let substring = args.remove(0);
446 let string = args.remove(0);
447 Ok(Expression::Function(Box::new(Function::new(
449 "INSTR".to_string(),
450 vec![string, substring],
451 ))))
452 }
453
454 "LEVENSHTEIN" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
456 Function::new("EDITDIST3".to_string(), f.args),
457 ))),
458
459 "LEAST" if !f.args.is_empty() => Ok(Self::function("MIN", f.args)),
461 "GREATEST" if !f.args.is_empty() => Ok(Self::function("MAX", f.args)),
462 "JSON_BUILD_ARRAY" => Ok(Self::function("JSON_ARRAY", f.args)),
463 "JSON_BUILD_OBJECT" => Ok(Self::function("JSON_OBJECT", f.args)),
464 "JSON_AGG" | "JSONB_AGG" if f.args.len() == 1 => {
465 Ok(Self::function("JSON_GROUP_ARRAY", f.args))
466 }
467 "JSON_OBJECT_AGG" if f.args.len() == 2 => {
468 Ok(Self::function("JSON_GROUP_OBJECT", f.args))
469 }
470
471 "GETDATE" => Ok(Expression::CurrentTimestamp(
473 crate::expressions::CurrentTimestamp {
474 precision: None,
475 sysdate: false,
476 },
477 )),
478
479 "NOW" => Ok(Expression::CurrentTimestamp(
481 crate::expressions::CurrentTimestamp {
482 precision: None,
483 sysdate: false,
484 },
485 )),
486
487 "CEILING" if f.args.len() == 1 => Ok(Expression::Ceil(Box::new(CeilFunc {
489 this: f.args.into_iter().next().unwrap(),
490 decimals: None,
491 to: None,
492 }))),
493
494 "LEN" if f.args.len() == 1 => Ok(Expression::Length(Box::new(UnaryFunc::new(
496 f.args.into_iter().next().unwrap(),
497 )))),
498
499 "SUBSTRING" => Ok(Self::function("SUBSTRING", f.args)),
501
502 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
504 Function::new("GROUP_CONCAT".to_string(), f.args),
505 ))),
506
507 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
509 "GROUP_CONCAT".to_string(),
510 f.args,
511 )))),
512
513 "DATE_PART" if f.args.len() == 2 => {
514 let mut args = f.args;
515 let unit = args.remove(0);
516 let expr = args.remove(0);
517 if let Some(field) = Self::datetime_field_from_expr(&unit) {
518 Self::transform_extract(ExtractFunc { this: expr, field })
519 } else {
520 Ok(Self::function("DATE_PART", vec![unit, expr]))
521 }
522 }
523
524 "DATE_TRUNC" if f.args.len() == 2 => {
525 let mut args = f.args;
526 let unit = args.remove(0);
527 let expr = args.remove(0);
528 if let Some(unit) = Self::datetime_field_from_expr(&unit) {
529 Self::transform_date_trunc(DateTruncFunc { this: expr, unit })
530 } else {
531 Ok(Self::function("DATE_TRUNC", vec![unit, expr]))
532 }
533 }
534
535 "DATEDIFF" | "DATE_DIFF" if f.args.len() == 3 => {
537 let mut args = f.args;
538 let first = args.remove(0); let second = args.remove(0); let unit_expr = args.remove(0); let unit_str = match &unit_expr {
544 Expression::Literal(lit)
545 if matches!(lit.as_ref(), crate::expressions::Literal::String(_)) =>
546 {
547 let crate::expressions::Literal::String(s) = lit.as_ref() else {
548 unreachable!()
549 };
550 s.to_lowercase()
551 }
552 Expression::Identifier(id) => id.name.to_lowercase(),
553 Expression::Var(v) => v.this.to_lowercase(),
554 Expression::Column(col) if col.table.is_none() => col.name.name.to_lowercase(),
555 _ => "day".to_string(),
556 };
557
558 let jd_first = Expression::Function(Box::new(Function::new(
560 "JULIANDAY".to_string(),
561 vec![first],
562 )));
563 let jd_second = Expression::Function(Box::new(Function::new(
564 "JULIANDAY".to_string(),
565 vec![second],
566 )));
567 let diff = Expression::Sub(Box::new(BinaryOp::new(jd_first, jd_second)));
568 let paren_diff = Expression::Paren(Box::new(crate::expressions::Paren {
569 this: diff,
570 trailing_comments: Vec::new(),
571 }));
572
573 let adjusted = match unit_str.as_str() {
575 "hour" => Expression::Mul(Box::new(BinaryOp::new(
576 paren_diff,
577 Expression::Literal(Box::new(crate::expressions::Literal::Number(
578 "24.0".to_string(),
579 ))),
580 ))),
581 "minute" => Expression::Mul(Box::new(BinaryOp::new(
582 paren_diff,
583 Expression::Literal(Box::new(crate::expressions::Literal::Number(
584 "1440.0".to_string(),
585 ))),
586 ))),
587 "second" => Expression::Mul(Box::new(BinaryOp::new(
588 paren_diff,
589 Expression::Literal(Box::new(crate::expressions::Literal::Number(
590 "86400.0".to_string(),
591 ))),
592 ))),
593 "month" => Expression::Div(Box::new(BinaryOp::new(
594 paren_diff,
595 Expression::Literal(Box::new(crate::expressions::Literal::Number(
596 "30.0".to_string(),
597 ))),
598 ))),
599 "year" => Expression::Div(Box::new(BinaryOp::new(
600 paren_diff,
601 Expression::Literal(Box::new(crate::expressions::Literal::Number(
602 "365.0".to_string(),
603 ))),
604 ))),
605 _ => paren_diff, };
607
608 Ok(Expression::Cast(Box::new(Cast {
610 this: adjusted,
611 to: crate::expressions::DataType::Int {
612 length: None,
613 integer_spelling: true,
614 },
615 trailing_comments: Vec::new(),
616 double_colon_syntax: false,
617 format: None,
618 default: None,
619 inferred_type: None,
620 })))
621 }
622
623 "STRFTIME" if f.args.len() == 1 => {
625 let mut args = f.args;
626 args.push(Expression::CurrentTimestamp(
627 crate::expressions::CurrentTimestamp {
628 precision: None,
629 sysdate: false,
630 },
631 ));
632 Ok(Expression::Function(Box::new(Function::new(
633 "STRFTIME".to_string(),
634 args,
635 ))))
636 }
637
638 "CONCAT" if f.args.len() >= 2 => {
640 let mut args = f.args;
641 let mut result = args.remove(0);
642 for arg in args {
643 result = Expression::DPipe(Box::new(crate::expressions::DPipe {
644 this: Box::new(result),
645 expression: Box::new(arg),
646 safe: None,
647 }));
648 }
649 Ok(result)
650 }
651
652 "TRUNC" if f.args.len() > 1 => Ok(Expression::Function(Box::new(Function::new(
654 "TRUNC".to_string(),
655 vec![f.args[0].clone()],
656 )))),
657
658 _ => Ok(Expression::Function(Box::new(f))),
660 }
661 }
662
663 fn transform_aggregate_function(
664 &self,
665 f: Box<crate::expressions::AggregateFunction>,
666 ) -> Result<Expression> {
667 let name_upper = f.name.to_uppercase();
668 match name_upper.as_str() {
669 "COUNT_IF" if !f.args.is_empty() => {
671 let condition = f.args.into_iter().next().unwrap();
672 let case_expr = Expression::Case(Box::new(Case {
673 operand: None,
674 whens: vec![(condition, Expression::number(1))],
675 else_: Some(Expression::number(0)),
676 comments: Vec::new(),
677 inferred_type: None,
678 }));
679 Ok(Expression::Sum(Box::new(AggFunc {
680 ignore_nulls: None,
681 having_max: None,
682 this: case_expr,
683 distinct: f.distinct,
684 filter: f.filter,
685 order_by: Vec::new(),
686 name: None,
687 limit: None,
688 inferred_type: None,
689 })))
690 }
691
692 "ANY_VALUE" if !f.args.is_empty() => {
694 let arg = f.args.into_iter().next().unwrap();
695 Ok(Expression::Max(Box::new(AggFunc {
696 ignore_nulls: None,
697 having_max: None,
698 this: arg,
699 distinct: f.distinct,
700 filter: f.filter,
701 order_by: Vec::new(),
702 name: None,
703 limit: None,
704 inferred_type: None,
705 })))
706 }
707
708 "STRING_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
710 Function::new("GROUP_CONCAT".to_string(), f.args),
711 ))),
712
713 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
715 "GROUP_CONCAT".to_string(),
716 f.args,
717 )))),
718
719 "ARRAY_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
721 "GROUP_CONCAT".to_string(),
722 f.args,
723 )))),
724
725 "JSON_AGG" | "JSONB_AGG" if f.args.len() == 1 => {
726 Ok(Self::function("JSON_GROUP_ARRAY", f.args))
727 }
728
729 "JSON_OBJECT_AGG" if f.args.len() == 2 => {
730 Ok(Self::function("JSON_GROUP_OBJECT", f.args))
731 }
732
733 _ => Ok(Expression::AggregateFunction(f)),
735 }
736 }
737
738 fn transform_cast(&self, c: Cast) -> Result<Expression> {
739 Ok(Expression::Cast(Box::new(c)))
743 }
744}