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::Paren(_) => expr,
115 Expression::In(_)
116 | Expression::Between(_)
117 | Expression::Is(_)
118 | Expression::IsNull(_)
119 | Expression::IsTrue(_)
120 | Expression::IsFalse(_)
121 | Expression::IsJson(_)
122 | Expression::Like(_)
123 | Expression::ILike(_)
124 | Expression::SimilarTo(_)
125 | Expression::Glob(_)
126 | Expression::RegexpLike(_)
127 | Expression::RegexpILike(_)
128 | Expression::MemberOf(_) => Expression::Paren(Box::new(Paren {
129 this: expr,
130 trailing_comments: Vec::new(),
131 })),
132 _ => expr,
133 }
134 };
135
136 let unwrap_in_array = |mut expressions: Vec<Expression>,
137 query: &Option<Expression>,
138 unnest: &Option<Box<Expression>>|
139 -> Vec<Expression> {
140 if query.is_none() && unnest.is_none() && expressions.len() == 1 {
141 if matches!(expressions[0], Expression::ArrayFunc(_)) {
142 if let Expression::ArrayFunc(arr) = expressions.remove(0) {
143 return arr.expressions;
144 }
145 }
146 }
147 expressions
148 };
149
150 match expr {
151 Expression::TryCast(c) => {
154 Ok(Expression::Cast(c))
157 }
158
159 Expression::SafeCast(c) => Ok(Expression::Cast(c)),
161
162 Expression::CountIf(f) => Ok(Expression::Function(Box::new(Function::new(
164 "countIf".to_string(),
165 vec![f.this],
166 )))),
167
168 Expression::Unnest(f) => Ok(Expression::Function(Box::new(Function::new(
170 "arrayJoin".to_string(),
171 vec![f.this],
172 )))),
173
174 Expression::Explode(f) => Ok(Expression::Function(Box::new(Function::new(
176 "arrayJoin".to_string(),
177 vec![f.this],
178 )))),
179
180 Expression::ExplodeOuter(f) => Ok(Expression::Function(Box::new(Function::new(
182 "arrayJoin".to_string(),
183 vec![f.this],
184 )))),
185
186 Expression::Rand(_) => Ok(Expression::Function(Box::new(Function::new(
188 "randCanonical".to_string(),
189 vec![],
190 )))),
191
192 Expression::Random(_) => Ok(Expression::Function(Box::new(Function::new(
194 "randCanonical".to_string(),
195 vec![],
196 )))),
197
198 Expression::StartsWith(f) => Ok(Expression::Function(Box::new(Function::new(
200 "startsWith".to_string(),
201 vec![f.this, f.expression],
202 )))),
203
204 Expression::EndsWith(f) => Ok(Expression::Function(Box::new(Function::new(
206 "endsWith".to_string(),
207 vec![f.this, f.expression],
208 )))),
209
210 Expression::In(in_expr) if in_expr.not => {
212 if in_expr.global {
213 return Ok(Expression::In(in_expr));
214 }
215 let In {
216 this,
217 expressions,
218 query,
219 unnest,
220 global,
221 is_field,
222 ..
223 } = *in_expr;
224 let expressions = unwrap_in_array(expressions, &query, &unnest);
225 let base = Expression::In(Box::new(In {
226 this: wrap_predicate_left(this),
227 expressions,
228 query,
229 not: false,
230 global,
231 unnest,
232 is_field,
233 }));
234 Ok(Expression::Not(Box::new(UnaryOp {
235 this: wrap_not_target(base),
236 inferred_type: None,
237 })))
238 }
239
240 Expression::IsNull(is_null) if is_null.not => {
242 let IsNull { this, .. } = *is_null;
243 let base = Expression::IsNull(Box::new(IsNull {
244 this: wrap_predicate_left(this),
245 not: false,
246 postfix_form: false,
247 }));
248 Ok(Expression::Not(Box::new(UnaryOp {
249 this: wrap_not_target(base),
250 inferred_type: None,
251 })))
252 }
253
254 Expression::In(mut in_expr) => {
255 in_expr.expressions =
256 unwrap_in_array(in_expr.expressions, &in_expr.query, &in_expr.unnest);
257 in_expr.this = wrap_predicate_left(in_expr.this);
258 Ok(Expression::In(in_expr))
259 }
260
261 Expression::IsNull(mut is_null) => {
262 is_null.this = wrap_predicate_left(is_null.this);
263 Ok(Expression::IsNull(is_null))
264 }
265
266 Expression::IfFunc(f) => {
268 let f = *f;
269 let has_aliased_arg = matches!(f.condition, Expression::Alias(_))
270 || matches!(f.true_value, Expression::Alias(_))
271 || matches!(f.false_value.as_ref(), Some(Expression::Alias(_)));
272 if has_aliased_arg {
273 return Ok(Expression::IfFunc(Box::new(f)));
274 }
275 Ok(Expression::Case(Box::new(Case {
276 operand: None,
277 whens: vec![(f.condition, f.true_value)],
278 else_: f.false_value,
279 comments: Vec::new(),
280 inferred_type: None,
281 })))
282 }
283
284 Expression::Is(mut is_expr) => {
285 is_expr.left = wrap_predicate_left(is_expr.left);
286 Ok(Expression::Is(is_expr))
287 }
288
289 Expression::Or(op) => {
290 let BinaryOp {
291 left,
292 right,
293 left_comments,
294 operator_comments,
295 trailing_comments,
296 ..
297 } = *op;
298 let left = if matches!(left, Expression::And(_)) {
299 Expression::Paren(Box::new(Paren {
300 this: left,
301 trailing_comments: Vec::new(),
302 }))
303 } else {
304 left
305 };
306 let right = if matches!(right, Expression::And(_)) {
307 Expression::Paren(Box::new(Paren {
308 this: right,
309 trailing_comments: Vec::new(),
310 }))
311 } else {
312 right
313 };
314 Ok(Expression::Or(Box::new(BinaryOp {
315 left,
316 right,
317 left_comments,
318 operator_comments,
319 trailing_comments,
320 inferred_type: None,
321 })))
322 }
323
324 Expression::Not(op) => {
325 let inner = wrap_not_target(op.this);
326 Ok(Expression::Not(Box::new(UnaryOp {
327 this: inner,
328 inferred_type: None,
329 })))
330 }
331
332 Expression::MapFunc(map) if map.curly_brace_syntax => {
333 let MapConstructor { keys, values, .. } = *map;
334 let mut args = Vec::with_capacity(keys.len() * 2);
335 for (key, value) in keys.into_iter().zip(values.into_iter()) {
336 args.push(key);
337 args.push(value);
338 }
339 Ok(Expression::Function(Box::new(Function::new(
340 "map".to_string(),
341 args,
342 ))))
343 }
344
345 Expression::Insert(mut insert) => {
346 for row in insert.values.iter_mut() {
347 for value in row.iter_mut() {
348 if !matches!(value, Expression::Paren(_)) {
349 let wrapped = Expression::Paren(Box::new(Paren {
350 this: value.clone(),
351 trailing_comments: Vec::new(),
352 }));
353 *value = wrapped;
354 }
355 }
356 }
357 Ok(Expression::Insert(insert))
358 }
359
360 Expression::Function(f) => self.transform_function(*f),
362
363 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
365
366 Expression::Cast(c) => self.transform_cast(*c),
368
369 Expression::Typeof(f) => Ok(Expression::Function(Box::new(Function::new(
371 "toTypeName".to_string(),
372 vec![f.this],
373 )))),
374
375 _ => Ok(expr),
377 }
378 }
379}
380
381#[cfg(feature = "transpile")]
382impl ClickHouseDialect {}
383
384#[cfg(feature = "transpile")]
385impl ClickHouseDialect {
386 fn transform_function(&self, f: Function) -> Result<Expression> {
387 let name_upper = f.name.to_uppercase();
388 match name_upper.as_str() {
389 "UTCTIMESTAMP" => Ok(Expression::UtcTimestamp(Box::new(
391 crate::expressions::UtcTimestamp { this: None },
392 ))),
393
394 "CURRENTDATABASE" | "CURRENT_DATABASE" => Ok(Expression::Function(Box::new(
395 Function::new("CURRENT_DATABASE".to_string(), f.args),
396 ))),
397 "CURRENTSCHEMAS" | "CURRENT_SCHEMAS" => Ok(Expression::Function(Box::new(
398 Function::new("CURRENT_SCHEMAS".to_string(), f.args),
399 ))),
400 "LEVENSHTEIN" | "LEVENSHTEINDISTANCE" | "EDITDISTANCE" => Ok(Expression::Function(
401 Box::new(Function::new("editDistance".to_string(), f.args)),
402 )),
403 "CHAR" | "CHR" => Ok(Expression::Function(Box::new(Function::new(
404 "CHAR".to_string(),
405 f.args,
406 )))),
407 "STR_TO_DATE" => Ok(Expression::Function(Box::new(Function::new(
408 "STR_TO_DATE".to_string(),
409 f.args,
410 )))),
411 "JSONEXTRACTSTRING" => Ok(Expression::Function(Box::new(Function::new(
412 "JSONExtractString".to_string(),
413 f.args,
414 )))),
415 "MATCH" => Ok(Expression::Function(Box::new(Function::new(
416 "match".to_string(),
417 f.args,
418 )))),
419 "LIKE" if f.args.len() == 2 => {
420 let left = f.args[0].clone();
421 let right = f.args[1].clone();
422 Ok(Expression::Like(Box::new(LikeOp::new(left, right))))
423 }
424 "NOTLIKE" if f.args.len() == 2 => {
425 let left = f.args[0].clone();
426 let right = f.args[1].clone();
427 let like = Expression::Like(Box::new(LikeOp::new(left, right)));
428 Ok(Expression::Not(Box::new(UnaryOp {
429 this: like,
430 inferred_type: None,
431 })))
432 }
433 "ILIKE" if f.args.len() == 2 => {
434 let left = f.args[0].clone();
435 let right = f.args[1].clone();
436 Ok(Expression::ILike(Box::new(LikeOp::new(left, right))))
437 }
438 "AND" if f.args.len() >= 2 => {
439 let mut iter = f.args.into_iter();
440 let mut expr = iter.next().unwrap();
441 for arg in iter {
442 expr = Expression::And(Box::new(BinaryOp::new(expr, arg)));
443 }
444 Ok(expr)
445 }
446 "OR" if f.args.len() >= 2 => {
447 let mut iter = f.args.into_iter();
448 let mut expr = iter.next().unwrap();
449 for arg in iter {
450 expr = Expression::Or(Box::new(BinaryOp::new(expr, arg)));
451 }
452 self.transform_expr(expr)
453 }
454 "XOR" if f.args.len() >= 2 => {
455 let mut iter = f.args.into_iter().map(Self::wrap_nested_xor_arg);
456 let mut expr = iter.next().unwrap();
457 for arg in iter {
458 expr = Expression::Function(Box::new(Function::new(
459 f.name.clone(),
460 vec![expr, arg],
461 )));
462 }
463 Ok(expr)
464 }
465 "TYPEOF" => Ok(Expression::Function(Box::new(Function::new(
467 "toTypeName".to_string(),
468 f.args,
469 )))),
470
471 "DATE_TRUNC" | "DATETRUNC" => Ok(Expression::Function(Box::new(Function::new(
473 "dateTrunc".to_string(),
474 f.args,
475 )))),
476 "TOSTARTOFDAY" if f.args.len() == 1 => {
477 Ok(Expression::Function(Box::new(Function::new(
478 "dateTrunc".to_string(),
479 vec![Expression::string("DAY"), f.args[0].clone()],
480 ))))
481 }
482
483 "SUBSTRING_INDEX" => Ok(Expression::Function(Box::new(Function::new(
485 f.name.clone(),
486 f.args,
487 )))),
488
489 "IS_NAN" | "ISNAN" => Ok(Expression::Function(Box::new(Function::new(
491 "isNaN".to_string(),
492 f.args,
493 )))),
494
495 _ => Ok(Expression::Function(Box::new(f))),
496 }
497 }
498
499 fn transform_aggregate_function(
500 &self,
501 f: Box<crate::expressions::AggregateFunction>,
502 ) -> Result<Expression> {
503 let name_upper = f.name.to_uppercase();
504 match name_upper.as_str() {
505 "COUNT_IF" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
507 "countIf".to_string(),
508 f.args,
509 )))),
510
511 "SUM_IF" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
513 "sumIf".to_string(),
514 f.args,
515 )))),
516
517 "AVG_IF" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
519 "avgIf".to_string(),
520 f.args,
521 )))),
522
523 "ANY_VALUE" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
525 "any".to_string(),
526 f.args,
527 )))),
528
529 "GROUP_CONCAT" if !f.args.is_empty() => {
531 let mut args = f.args;
532 let first = args.remove(0);
533 let separator = args.pop();
534 let group_array = Expression::Function(Box::new(Function::new(
535 "groupArray".to_string(),
536 vec![first],
537 )));
538 if let Some(sep) = separator {
539 Ok(Expression::Function(Box::new(Function::new(
540 "arrayStringConcat".to_string(),
541 vec![group_array, sep],
542 ))))
543 } else {
544 Ok(Expression::Function(Box::new(Function::new(
545 "arrayStringConcat".to_string(),
546 vec![group_array],
547 ))))
548 }
549 }
550
551 "STRING_AGG" if !f.args.is_empty() => {
553 let mut args = f.args;
554 let first = args.remove(0);
555 let separator = args.pop();
556 let group_array = Expression::Function(Box::new(Function::new(
557 "groupArray".to_string(),
558 vec![first],
559 )));
560 if let Some(sep) = separator {
561 Ok(Expression::Function(Box::new(Function::new(
562 "arrayStringConcat".to_string(),
563 vec![group_array, sep],
564 ))))
565 } else {
566 Ok(Expression::Function(Box::new(Function::new(
567 "arrayStringConcat".to_string(),
568 vec![group_array],
569 ))))
570 }
571 }
572
573 "LISTAGG" if !f.args.is_empty() => {
575 let mut args = f.args;
576 let first = args.remove(0);
577 let separator = args.pop();
578 let group_array = Expression::Function(Box::new(Function::new(
579 "groupArray".to_string(),
580 vec![first],
581 )));
582 if let Some(sep) = separator {
583 Ok(Expression::Function(Box::new(Function::new(
584 "arrayStringConcat".to_string(),
585 vec![group_array, sep],
586 ))))
587 } else {
588 Ok(Expression::Function(Box::new(Function::new(
589 "arrayStringConcat".to_string(),
590 vec![group_array],
591 ))))
592 }
593 }
594
595 "ARRAY_AGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
597 "groupArray".to_string(),
598 f.args,
599 )))),
600
601 "STDDEV" if !f.args.is_empty() => {
603 Ok(Expression::AggregateFunction(Box::new(AggregateFunction {
604 source_dialect: None,
605
606 name: "stddevSamp".to_string(),
607 args: f.args,
608 distinct: f.distinct,
609 filter: f.filter,
610 order_by: Vec::new(),
611 limit: None,
612 ignore_nulls: None,
613 inferred_type: None,
614 })))
615 }
616
617 "STDDEV_POP" if !f.args.is_empty() => {
619 Ok(Expression::AggregateFunction(Box::new(AggregateFunction {
620 source_dialect: None,
621
622 name: "stddevPop".to_string(),
623 args: f.args,
624 distinct: f.distinct,
625 filter: f.filter,
626 order_by: Vec::new(),
627 limit: None,
628 ignore_nulls: None,
629 inferred_type: None,
630 })))
631 }
632
633 "VARIANCE" if !f.args.is_empty() => {
635 Ok(Expression::AggregateFunction(Box::new(AggregateFunction {
636 source_dialect: None,
637
638 name: "varSamp".to_string(),
639 args: f.args,
640 distinct: f.distinct,
641 filter: f.filter,
642 order_by: Vec::new(),
643 limit: None,
644 ignore_nulls: None,
645 inferred_type: None,
646 })))
647 }
648
649 "VAR_POP" if !f.args.is_empty() => {
651 Ok(Expression::AggregateFunction(Box::new(AggregateFunction {
652 source_dialect: None,
653
654 name: "varPop".to_string(),
655 args: f.args,
656 distinct: f.distinct,
657 filter: f.filter,
658 order_by: Vec::new(),
659 limit: None,
660 ignore_nulls: None,
661 inferred_type: None,
662 })))
663 }
664
665 "MEDIAN" if !f.args.is_empty() => {
667 Ok(Expression::AggregateFunction(Box::new(AggregateFunction {
668 source_dialect: None,
669
670 name: "median".to_string(),
671 args: f.args,
672 distinct: f.distinct,
673 filter: f.filter,
674 order_by: Vec::new(),
675 limit: None,
676 ignore_nulls: None,
677 inferred_type: None,
678 })))
679 }
680
681 "APPROX_COUNT_DISTINCT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
683 Function::new("uniq".to_string(), f.args),
684 ))),
685
686 "APPROX_DISTINCT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
688 Function::new("uniq".to_string(), f.args),
689 ))),
690
691 _ => Ok(Expression::AggregateFunction(f)),
692 }
693 }
694
695 fn transform_cast(&self, c: Cast) -> Result<Expression> {
696 Ok(Expression::Cast(Box::new(c)))
697 }
698
699 fn wrap_nested_xor_arg(expr: Expression) -> Expression {
700 if matches!(&expr, Expression::Function(f) if f.name.eq_ignore_ascii_case("XOR")) {
701 Expression::Paren(Box::new(Paren {
702 this: expr,
703 trailing_comments: Vec::new(),
704 }))
705 } else {
706 expr
707 }
708 }
709}