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