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