1use super::{DialectImpl, DialectType};
7#[cfg(feature = "transpile")]
8use crate::error::Result;
9#[cfg(feature = "transpile")]
10use crate::expressions::{
11 AggregateFunction, BinaryOp, Case, Cast, Expression, Function, In, IsNull, LikeOp,
12 MapConstructor, Paren, UnaryOp,
13};
14#[cfg(feature = "generate")]
15use crate::generator::GeneratorConfig;
16use crate::tokens::TokenizerConfig;
17
18pub struct ClickHouseDialect;
20
21impl DialectImpl for ClickHouseDialect {
22 fn dialect_type(&self) -> DialectType {
23 DialectType::ClickHouse
24 }
25
26 fn tokenizer_config(&self) -> TokenizerConfig {
27 let mut config = TokenizerConfig::default();
28 config.identifiers.insert('"', '"');
30 config.identifiers.insert('`', '`');
31 config.identifier_backslash_escapes = true;
32 config.nested_comments = true;
34 config.identifiers_can_start_with_digit = true;
36 config.string_escapes.push('\\');
38 config.hash_comments = true;
40 config.dollar_sign_is_identifier = true;
42 config.insert_format_raw_data = true;
44 config.hex_number_strings = true;
46 config.hex_string_is_integer_type = true;
47 config.numbers_can_be_underscore_separated = true;
49 config.recover_terminal_backslash_quote = true;
51 config.recover_unterminated_string = true;
53 config
54 }
55
56 #[cfg(feature = "generate")]
57
58 fn generator_config(&self) -> GeneratorConfig {
59 use crate::generator::{IdentifierQuoteStyle, NormalizeFunctions};
60 let mut complexity_guard = crate::guard::ComplexityGuardOptions::default();
61 complexity_guard.max_ast_depth = Some(4_096);
62 complexity_guard.max_function_call_depth = Some(512);
63
64 GeneratorConfig {
65 identifier_quote: '"',
66 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
67 dialect: Some(DialectType::ClickHouse),
68 complexity_guard,
69 uppercase_keywords: true,
71 normalize_functions: NormalizeFunctions::None,
73 case_sensitive_identifiers: true,
75 tablesample_keywords: "SAMPLE",
76 tablesample_requires_parens: false,
77 identifiers_can_start_with_digit: true,
78 array_bracket_only: true,
80 ..Default::default()
81 }
82 }
83
84 #[cfg(feature = "transpile")]
85
86 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
87 let wrap_predicate_left = |expr: Expression| -> Expression {
88 let needs_parens = matches!(
89 expr,
90 Expression::Add(_)
91 | Expression::Sub(_)
92 | Expression::Mul(_)
93 | Expression::Div(_)
94 | Expression::Mod(_)
95 | Expression::Concat(_)
96 | Expression::And(_)
97 | Expression::Or(_)
98 | Expression::Not(_)
99 | Expression::Case(_)
100 );
101
102 if needs_parens {
103 Expression::Paren(Box::new(Paren {
104 this: expr,
105 trailing_comments: Vec::new(),
106 }))
107 } else {
108 expr
109 }
110 };
111
112 let wrap_not_target = |expr: Expression| -> Expression {
113 match expr {
114 Expression::Like(_) | Expression::ILike(_) => expr,
117 Expression::Paren(_) => expr,
118 Expression::In(_)
119 | Expression::Between(_)
120 | Expression::Is(_)
121 | Expression::IsNull(_)
122 | Expression::IsTrue(_)
123 | Expression::IsFalse(_)
124 | Expression::IsJson(_)
125 | Expression::SimilarTo(_)
126 | Expression::Glob(_)
127 | Expression::RegexpLike(_)
128 | Expression::RegexpILike(_)
129 | Expression::MemberOf(_) => Expression::Paren(Box::new(Paren {
130 this: expr,
131 trailing_comments: Vec::new(),
132 })),
133 _ => expr,
134 }
135 };
136
137 let unwrap_in_array = |mut expressions: Vec<Expression>,
138 query: &Option<Expression>,
139 unnest: &Option<Box<Expression>>|
140 -> Vec<Expression> {
141 if query.is_none() && unnest.is_none() && expressions.len() == 1 {
142 if matches!(expressions[0], Expression::ArrayFunc(_)) {
143 if let Expression::ArrayFunc(arr) = expressions.remove(0) {
144 return arr.expressions;
145 }
146 }
147 }
148 expressions
149 };
150
151 match expr {
152 Expression::TryCast(c) => {
155 Ok(Expression::Cast(c))
158 }
159
160 Expression::SafeCast(c) => Ok(Expression::Cast(c)),
162
163 Expression::CountIf(f) => Ok(Expression::Function(Box::new(Function::new(
165 "countIf".to_string(),
166 vec![f.this],
167 )))),
168
169 Expression::Unnest(f) => Ok(Expression::Function(Box::new(Function::new(
171 "arrayJoin".to_string(),
172 vec![f.this],
173 )))),
174
175 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
177 "arrayJoin".to_string(),
178 vec![f.this],
179 )))),
180
181 Expression::ExplodeOuter(f) => Ok(Expression::Function(Box::new(Function::new(
183 "arrayJoin".to_string(),
184 vec![f.this],
185 )))),
186
187 Expression::Rand(_) => Ok(Expression::Function(Box::new(Function::new(
189 "randCanonical".to_string(),
190 vec![],
191 )))),
192
193 Expression::Random(_) => Ok(Expression::Function(Box::new(Function::new(
195 "randCanonical".to_string(),
196 vec![],
197 )))),
198
199 Expression::StartsWith(f) => Ok(Expression::Function(Box::new(Function::new(
201 "startsWith".to_string(),
202 vec![f.this, f.expression],
203 )))),
204
205 Expression::EndsWith(f) => Ok(Expression::Function(Box::new(Function::new(
207 "endsWith".to_string(),
208 vec![f.this, f.expression],
209 )))),
210
211 Expression::In(in_expr) if in_expr.not => {
213 if in_expr.global {
214 return Ok(Expression::In(in_expr));
215 }
216 let In {
217 this,
218 expressions,
219 query,
220 unnest,
221 global,
222 is_field,
223 ..
224 } = *in_expr;
225 let expressions = unwrap_in_array(expressions, &query, &unnest);
226 let base = Expression::In(Box::new(In {
227 this: wrap_predicate_left(this),
228 expressions,
229 query,
230 not: false,
231 global,
232 unnest,
233 is_field,
234 }));
235 Ok(Expression::Not(Box::new(UnaryOp {
236 this: wrap_not_target(base),
237 inferred_type: None,
238 })))
239 }
240
241 Expression::IsNull(is_null) if is_null.not => {
243 let IsNull { this, .. } = *is_null;
244 let base = Expression::IsNull(Box::new(IsNull {
245 this: wrap_predicate_left(this),
246 not: false,
247 postfix_form: false,
248 }));
249 Ok(Expression::Not(Box::new(UnaryOp {
250 this: wrap_not_target(base),
251 inferred_type: None,
252 })))
253 }
254
255 Expression::In(mut in_expr) => {
256 in_expr.expressions =
257 unwrap_in_array(in_expr.expressions, &in_expr.query, &in_expr.unnest);
258 in_expr.this = wrap_predicate_left(in_expr.this);
259 Ok(Expression::In(in_expr))
260 }
261
262 Expression::IsNull(mut is_null) => {
263 is_null.this = wrap_predicate_left(is_null.this);
264 Ok(Expression::IsNull(is_null))
265 }
266
267 Expression::IfFunc(f) => {
269 let f = *f;
270 let has_aliased_arg = matches!(f.condition, Expression::Alias(_))
271 || matches!(f.true_value, Expression::Alias(_))
272 || matches!(f.false_value.as_ref(), Some(Expression::Alias(_)));
273 if has_aliased_arg {
274 return Ok(Expression::IfFunc(Box::new(f)));
275 }
276 Ok(Expression::Case(Box::new(Case {
277 operand: None,
278 whens: vec![(f.condition, f.true_value)],
279 else_: f.false_value,
280 comments: Vec::new(),
281 inferred_type: None,
282 })))
283 }
284
285 Expression::Is(mut is_expr) => {
286 is_expr.left = wrap_predicate_left(is_expr.left);
287 Ok(Expression::Is(is_expr))
288 }
289
290 Expression::Or(op) => {
291 let BinaryOp {
292 left,
293 right,
294 left_comments,
295 operator_comments,
296 trailing_comments,
297 ..
298 } = *op;
299 let left = if matches!(left, Expression::And(_)) {
300 Expression::Paren(Box::new(Paren {
301 this: left,
302 trailing_comments: Vec::new(),
303 }))
304 } else {
305 left
306 };
307 let right = if matches!(right, Expression::And(_)) {
308 Expression::Paren(Box::new(Paren {
309 this: right,
310 trailing_comments: Vec::new(),
311 }))
312 } else {
313 right
314 };
315 Ok(Expression::Or(Box::new(BinaryOp {
316 left,
317 right,
318 left_comments,
319 operator_comments,
320 trailing_comments,
321 inferred_type: None,
322 })))
323 }
324
325 Expression::Not(op) => {
326 let inner = wrap_not_target(op.this);
327 Ok(Expression::Not(Box::new(UnaryOp {
328 this: inner,
329 inferred_type: None,
330 })))
331 }
332
333 Expression::MapFunc(map) if map.curly_brace_syntax => {
334 let MapConstructor { keys, values, .. } = *map;
335 let mut args = Vec::with_capacity(keys.len() * 2);
336 for (key, value) in keys.into_iter().zip(values.into_iter()) {
337 args.push(key);
338 args.push(value);
339 }
340 Ok(Expression::Function(Box::new(Function::new(
341 "map".to_string(),
342 args,
343 ))))
344 }
345
346 Expression::Insert(mut insert) => {
347 for row in insert.values.iter_mut() {
348 for value in row.iter_mut() {
349 if !matches!(value, Expression::Paren(_)) {
350 let wrapped = Expression::Paren(Box::new(Paren {
351 this: value.clone(),
352 trailing_comments: Vec::new(),
353 }));
354 *value = wrapped;
355 }
356 }
357 }
358 Ok(Expression::Insert(insert))
359 }
360
361 Expression::Function(f) => self.transform_function(*f),
363
364 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
366
367 Expression::Cast(c) => self.transform_cast(*c),
369
370 Expression::Typeof(f) => Ok(Expression::Function(Box::new(Function::new(
372 "toTypeName".to_string(),
373 vec![f.this],
374 )))),
375
376 _ => Ok(expr),
378 }
379 }
380}
381
382#[cfg(feature = "transpile")]
383impl ClickHouseDialect {}
384
385#[cfg(feature = "transpile")]
386impl ClickHouseDialect {
387 fn transform_function(&self, f: Function) -> Result<Expression> {
388 let name_upper = f.name.to_uppercase();
389 match name_upper.as_str() {
390 "UTCTIMESTAMP" => Ok(Expression::UtcTimestamp(Box::new(
392 crate::expressions::UtcTimestamp { this: None },
393 ))),
394
395 "CURRENTDATABASE" | "CURRENT_DATABASE" => Ok(Expression::Function(Box::new(
396 Function::new("CURRENT_DATABASE".to_string(), f.args),
397 ))),
398 "CURRENTSCHEMAS" | "CURRENT_SCHEMAS" => Ok(Expression::Function(Box::new(
399 Function::new("CURRENT_SCHEMAS".to_string(), f.args),
400 ))),
401 "LEVENSHTEIN" | "LEVENSHTEINDISTANCE" | "EDITDISTANCE" => Ok(Expression::Function(
402 Box::new(Function::new("editDistance".to_string(), f.args)),
403 )),
404 "CHAR" | "CHR" => Ok(Expression::Function(Box::new(Function::new(
405 "CHAR".to_string(),
406 f.args,
407 )))),
408 "STR_TO_DATE" => Ok(Expression::Function(Box::new(Function::new(
409 "STR_TO_DATE".to_string(),
410 f.args,
411 )))),
412 "JSONEXTRACTSTRING" => Ok(Expression::Function(Box::new(Function::new(
413 "JSONExtractString".to_string(),
414 f.args,
415 )))),
416 "MATCH" => Ok(Expression::Function(Box::new(Function::new(
417 "match".to_string(),
418 f.args,
419 )))),
420 "LIKE" if f.args.len() == 2 => {
421 let left = f.args[0].clone();
422 let right = f.args[1].clone();
423 Ok(Expression::Like(Box::new(LikeOp::new(left, right))))
424 }
425 "NOTLIKE" if f.args.len() == 2 => {
426 let left = f.args[0].clone();
427 let right = f.args[1].clone();
428 let like = Expression::Like(Box::new(LikeOp::new(left, right)));
429 Ok(Expression::Not(Box::new(UnaryOp {
430 this: like,
431 inferred_type: None,
432 })))
433 }
434 "ILIKE" if f.args.len() == 2 => {
435 let left = f.args[0].clone();
436 let right = f.args[1].clone();
437 Ok(Expression::ILike(Box::new(LikeOp::new(left, right))))
438 }
439 "AND" if f.args.len() >= 2 => {
440 let mut iter = f.args.into_iter();
441 let mut expr = iter.next().unwrap();
442 for arg in iter {
443 expr = Expression::And(Box::new(BinaryOp::new(expr, arg)));
444 }
445 Ok(expr)
446 }
447 "OR" if f.args.len() >= 2 => {
448 let mut iter = f.args.into_iter();
449 let mut expr = iter.next().unwrap();
450 for arg in iter {
451 expr = Expression::Or(Box::new(BinaryOp::new(expr, arg)));
452 }
453 self.transform_expr(expr)
454 }
455 "XOR" if f.args.len() >= 2 => {
456 let mut iter = f.args.into_iter().map(Self::wrap_nested_xor_arg);
457 let mut expr = iter.next().unwrap();
458 for arg in iter {
459 expr = Expression::Function(Box::new(Function::new(
460 f.name.clone(),
461 vec![expr, arg],
462 )));
463 }
464 Ok(expr)
465 }
466 "TYPEOF" => Ok(Expression::Function(Box::new(Function::new(
468 "toTypeName".to_string(),
469 f.args,
470 )))),
471
472 "DATE_TRUNC" | "DATETRUNC" => Ok(Expression::Function(Box::new(Function::new(
474 "dateTrunc".to_string(),
475 f.args,
476 )))),
477 "TOSTARTOFDAY" if f.args.len() == 1 => {
478 Ok(Expression::Function(Box::new(Function::new(
479 "dateTrunc".to_string(),
480 vec![Expression::string("DAY"), f.args[0].clone()],
481 ))))
482 }
483
484 "SUBSTRING_INDEX" => Ok(Expression::Function(Box::new(Function::new(
486 f.name.clone(),
487 f.args,
488 )))),
489
490 "IS_NAN" | "ISNAN" => Ok(Expression::Function(Box::new(Function::new(
492 "isNaN".to_string(),
493 f.args,
494 )))),
495
496 _ => Ok(Expression::Function(Box::new(f))),
497 }
498 }
499
500 fn transform_aggregate_function(
501 &self,
502 f: Box<crate::expressions::AggregateFunction>,
503 ) -> Result<Expression> {
504 let name_upper = f.name.to_uppercase();
505 match name_upper.as_str() {
506 "COUNT_IF" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
508 "countIf".to_string(),
509 f.args,
510 )))),
511
512 "SUM_IF" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
514 "sumIf".to_string(),
515 f.args,
516 )))),
517
518 "AVG_IF" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
520 "avgIf".to_string(),
521 f.args,
522 )))),
523
524 "ANY_VALUE" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
526 "any".to_string(),
527 f.args,
528 )))),
529
530 "GROUP_CONCAT" if !f.args.is_empty() => {
532 let mut args = f.args;
533 let first = args.remove(0);
534 let separator = args.pop();
535 let group_array = Expression::Function(Box::new(Function::new(
536 "groupArray".to_string(),
537 vec![first],
538 )));
539 if let Some(sep) = separator {
540 Ok(Expression::Function(Box::new(Function::new(
541 "arrayStringConcat".to_string(),
542 vec![group_array, sep],
543 ))))
544 } else {
545 Ok(Expression::Function(Box::new(Function::new(
546 "arrayStringConcat".to_string(),
547 vec![group_array],
548 ))))
549 }
550 }
551
552 "STRING_AGG" if !f.args.is_empty() => {
554 let mut args = f.args;
555 let first = args.remove(0);
556 let separator = args.pop();
557 let group_array = Expression::Function(Box::new(Function::new(
558 "groupArray".to_string(),
559 vec![first],
560 )));
561 if let Some(sep) = separator {
562 Ok(Expression::Function(Box::new(Function::new(
563 "arrayStringConcat".to_string(),
564 vec![group_array, sep],
565 ))))
566 } else {
567 Ok(Expression::Function(Box::new(Function::new(
568 "arrayStringConcat".to_string(),
569 vec![group_array],
570 ))))
571 }
572 }
573
574 "LISTAGG" if !f.args.is_empty() => {
576 let mut args = f.args;
577 let first = args.remove(0);
578 let separator = args.pop();
579 let group_array = Expression::Function(Box::new(Function::new(
580 "groupArray".to_string(),
581 vec![first],
582 )));
583 if let Some(sep) = separator {
584 Ok(Expression::Function(Box::new(Function::new(
585 "arrayStringConcat".to_string(),
586 vec![group_array, sep],
587 ))))
588 } else {
589 Ok(Expression::Function(Box::new(Function::new(
590 "arrayStringConcat".to_string(),
591 vec![group_array],
592 ))))
593 }
594 }
595
596 "ARRAY_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
598 "groupArray".to_string(),
599 f.args,
600 )))),
601
602 "STDDEV" if !f.args.is_empty() => {
604 Ok(Expression::AggregateFunction(Box::new(AggregateFunction {
605 source_dialect: None,
606
607 name: "stddevSamp".to_string(),
608 args: f.args,
609 distinct: f.distinct,
610 filter: f.filter,
611 order_by: Vec::new(),
612 limit: None,
613 ignore_nulls: None,
614 inferred_type: None,
615 })))
616 }
617
618 "STDDEV_POP" if !f.args.is_empty() => {
620 Ok(Expression::AggregateFunction(Box::new(AggregateFunction {
621 source_dialect: None,
622
623 name: "stddevPop".to_string(),
624 args: f.args,
625 distinct: f.distinct,
626 filter: f.filter,
627 order_by: Vec::new(),
628 limit: None,
629 ignore_nulls: None,
630 inferred_type: None,
631 })))
632 }
633
634 "VARIANCE" if !f.args.is_empty() => {
636 Ok(Expression::AggregateFunction(Box::new(AggregateFunction {
637 source_dialect: None,
638
639 name: "varSamp".to_string(),
640 args: f.args,
641 distinct: f.distinct,
642 filter: f.filter,
643 order_by: Vec::new(),
644 limit: None,
645 ignore_nulls: None,
646 inferred_type: None,
647 })))
648 }
649
650 "VAR_POP" if !f.args.is_empty() => {
652 Ok(Expression::AggregateFunction(Box::new(AggregateFunction {
653 source_dialect: None,
654
655 name: "varPop".to_string(),
656 args: f.args,
657 distinct: f.distinct,
658 filter: f.filter,
659 order_by: Vec::new(),
660 limit: None,
661 ignore_nulls: None,
662 inferred_type: None,
663 })))
664 }
665
666 "MEDIAN" if !f.args.is_empty() => {
668 Ok(Expression::AggregateFunction(Box::new(AggregateFunction {
669 source_dialect: None,
670
671 name: "median".to_string(),
672 args: f.args,
673 distinct: f.distinct,
674 filter: f.filter,
675 order_by: Vec::new(),
676 limit: None,
677 ignore_nulls: None,
678 inferred_type: None,
679 })))
680 }
681
682 "APPROX_COUNT_DISTINCT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
684 Function::new("uniq".to_string(), f.args),
685 ))),
686
687 "APPROX_DISTINCT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
689 Function::new("uniq".to_string(), f.args),
690 ))),
691
692 _ => Ok(Expression::AggregateFunction(f)),
693 }
694 }
695
696 fn transform_cast(&self, c: Cast) -> Result<Expression> {
697 Ok(Expression::Cast(Box::new(c)))
698 }
699
700 fn wrap_nested_xor_arg(expr: Expression) -> Expression {
701 if matches!(&expr, Expression::Function(f) if f.name.eq_ignore_ascii_case("XOR")) {
702 Expression::Paren(Box::new(Paren {
703 this: expr,
704 trailing_comments: Vec::new(),
705 }))
706 } else {
707 expr
708 }
709 }
710}