Repository: tobymao/sqlglot

Issue:
two-argument version of clickhouse's `countIf` function incorrectly fails to parse
This used to work:

```
In [3]: import sqlglot as sg

In [4]: sg.__version__
Out[4]: '20.7.1'

In [5]: sg.parse_one("select countIf(x, y)", read="clickhouse")
...
ParseError: The number of provided arguments (2) is greater than the maximum number of supported arguments (1). Line 1, Col: 20.
  select countIf(x, y)
```

ClickHouse CLI:

```
localhost :) select countIf(1, false), countIf(1, true);

SELECT
    countIf(1, false),
    countIf(1, true)

Query id: cd5dea26-fae2-4bdc-a18b-edbf5b910fda

┌─countIf(1, false)─┬─countIf(1, true)─┐
│                 0 │                1 │
└───────────────────┴──────────────────┘
```


Unfortunately the clickhouse docs on `countIf`'s signature are nonexistent, with only a single mention of the function in the `If` combinators section here https://clickhouse.com/docs/en/sql-reference/aggregate-functions/combinators#-if


Discussion:

Resolving patch:
diff --git a/sqlglot/dialects/clickhouse.py b/sqlglot/dialects/clickhouse.py
--- a/sqlglot/dialects/clickhouse.py
+++ b/sqlglot/dialects/clickhouse.py
@@ -23,16 +23,25 @@ def _lower_func(sql: str) -> str:
     return sql[:index].lower() + sql[index:]
 
 
-def _quantile_sql(self, e):
+def _quantile_sql(self: ClickHouse.Generator, e: exp.Quantile) -> str:
     quantile = e.args["quantile"]
     args = f"({self.sql(e, 'this')})"
+
     if isinstance(quantile, exp.Array):
         func = self.func("quantiles", *quantile)
     else:
         func = self.func("quantile", quantile)
+
     return func + args
 
 
+def _parse_count_if(args: t.List) -> exp.CountIf | exp.CombinedAggFunc:
+    if len(args) == 1:
+        return exp.CountIf(this=seq_get(args, 0))
+
+    return exp.CombinedAggFunc(this="countIf", expressions=args, parts=("count", "If"))
+
+
 class ClickHouse(Dialect):
     NORMALIZE_FUNCTIONS: bool | str = False
     NULL_ORDERING = "nulls_are_last"
@@ -92,6 +101,7 @@ class Parser(parser.Parser):
         FUNCTIONS = {
             **parser.Parser.FUNCTIONS,
             "ANY": exp.AnyValue.from_arg_list,
+            "COUNTIF": _parse_count_if,
             "DATE_ADD": lambda args: exp.DateAdd(
                 this=seq_get(args, 2), expression=seq_get(args, 1), unit=seq_get(args, 0)
             ),
@@ -542,6 +552,7 @@ class Generator(generator.Generator):
             exp.ArgMin: arg_max_or_min_no_count("argMin"),
             exp.Array: inline_array_sql,
             exp.CastToStrType: rename_func("CAST"),
+            exp.CountIf: rename_func("countIf"),
             exp.CurrentDate: lambda self, e: self.func("CURRENT_DATE"),
             exp.DateAdd: date_delta_sql("DATE_ADD"),
             exp.DateDiff: date_delta_sql("DATE_DIFF"),


Test patch:
diff --git a/tests/dialects/test_bigquery.py b/tests/dialects/test_bigquery.py
--- a/tests/dialects/test_bigquery.py
+++ b/tests/dialects/test_bigquery.py
@@ -292,8 +292,13 @@ def test_bigquery(self):
         )
         self.validate_all(
             "SELECT COUNTIF(x)",
+            read={
+                "clickhouse": "SELECT countIf(x)",
+                "duckdb": "SELECT COUNT_IF(x)",
+            },
             write={
                 "bigquery": "SELECT COUNTIF(x)",
+                "clickhouse": "SELECT countIf(x)",
                 "duckdb": "SELECT COUNT_IF(x)",
             },
         )
diff --git a/tests/dialects/test_clickhouse.py b/tests/dialects/test_clickhouse.py
--- a/tests/dialects/test_clickhouse.py
+++ b/tests/dialects/test_clickhouse.py
@@ -26,6 +26,7 @@ def test_clickhouse(self):
         self.assertEqual(expr.sql(dialect="clickhouse"), "COUNT(x)")
         self.assertIsNone(expr._meta)
 
+        self.validate_identity("countIf(x, y)")
         self.validate_identity("x = y")
         self.validate_identity("x <> y")
         self.validate_identity("SELECT * FROM (SELECT a FROM b SAMPLE 0.01)")