internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: dynamiqs/dynamiqs

Issue:
Propagator solvers are cached on slighlty changing `delta_t`
Both the `sesolve` and `mesolve` propagator solvers are cached on the time step `delta_t` to take, which should be constant for linearly spaced `t_save`. Thus, the propagator should be computed only once. However, due to numerical imprecisions, the `delta_t` changes slightly even when `t_save` is linearly spaced, resulting in frequent recomputations of the same quantity.


Discussion:
For example for `t_save = np.linspace(0.0, 0.1, 11)`, adding a print statement in the base `Propagator` class we see the uneven spacing:
```
0.0
0.1
0.1
0.10000001
0.099999994
0.099999994
0.100000024
0.099999964
0.100000024
0.099999964
0.100000024
```

But the caching works well, if we add a print statement in `mesolve` propagator, we see that the value for a time spacing of `0.1` is correctly cached.
```
0.0
0.1
0.10000001
0.099999994
0.100000024
0.099999964
0.100000024
0.099999964
0.100000024
```

Resolving patch:
diff --git a/dynamiqs/solvers/propagator.py b/dynamiqs/solvers/propagator.py
--- a/dynamiqs/solvers/propagator.py
+++ b/dynamiqs/solvers/propagator.py
@@ -1,5 +1,8 @@
+from __future__ import annotations
+
 from abc import abstractmethod
 
+import numpy as np
 from torch import Tensor
 
 from .solver import AutogradSolver
@@ -7,6 +10,19 @@
 from .utils.utils import tqdm
 
 
+def round_truncate(x: np.float32 | np.float64) -> np.float32 | np.float64:
+    # round a strictly positive-valued float to remove numerical errors, and enable
+    # comparing floats for equality
+
+    # The mantissa of a float32 is stored using 23 bits. The following code rounds and
+    # truncates the float value to the 18 most significant bits of its mantissa. This
+    # removes any numerical error that may have accumulated in the 5 least significant
+    # bits of the mantissa.
+    leading = abs(int(np.log2(x)))
+    keep = leading + 18
+    return (x * 2**keep).round() / 2**keep
+
+
 class Propagator(AutogradSolver):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
@@ -21,7 +37,10 @@ def __init__(self, *args, **kwargs):
     def run_autograd(self):
         y, t1 = self.y0, 0.0
         for t2 in tqdm(self.t_stop.cpu().numpy(), disable=not self.options.verbose):
-            y = self.forward(t1, t2 - t1, y)
+            if t2 != 0.0:
+                # round time difference to avoid numerical errors when comparing floats
+                delta_t = round_truncate(t2 - t1)
+                y = self.forward(t1, delta_t, y)
             self.save(y)
             t1 = t2
 


Test patch:
Repository: tobymao/sqlglot

Issue:
add sqloxide benchmarks
From the README:

> It is currently the fastest Python SQL parser.

I have [python bindings to sqlparser-rs](https://github.com/wseaton/sqloxide), would you be open to adding these to the benchmark suite? I went ahead and added your library to [my benchmarks](https://github.com/wseaton/sqloxide#benchmarks) and it indeed compares favorably to the other pure-python implementations. 

Not to take away from your awesome project, it does a lot of other cool things that simple bindings cannot!


Discussion:

Resolving patch:
diff --git a/benchmarks/bench.py b/benchmarks/bench.py
--- a/benchmarks/bench.py
+++ b/benchmarks/bench.py
@@ -3,6 +3,7 @@
 import moz_sql_parser
 import sqlglot
 import sqlparse
+import sqloxide
 
 long = """
 SELECT
@@ -64,7 +65,10 @@ def sqlparse_parse(sql):
 def moz_sql_parser_parse(sql):
     moz_sql_parser.parse(sql)
 
+def sqloxide_parse(sql):
+    sqloxide.parse_sql(sql, dialect='ansi')
 
-for lib in ['sqlglot_parse', 'sqlparse_parse', 'moz_sql_parser_parse']:
+
+for lib in ['sqlglot_parse', 'sqlparse_parse', 'moz_sql_parser_parse', 'sqloxide_parse']:
     for name, sql in {'short': short, 'long': long, 'crazy': crazy}.items():
         print(f"{lib} {name}", np.mean(timeit.repeat(lambda: globals()[lib](sql), number=1)))


Test patch:
Repository: tobymao/sqlglot

Issue:
Arguments to lambda functions wrapped in brackets even with only one argument
```python
sql = """
transform(array('a','b','c'), X -> upper(X))
"""

import sqlglot
sqlglot.transpile(sql)
```
```
> ["TRANSFORM(ARRAY('a', 'b', 'c'), (X) -> UPPER(X))"]
```

I discovered this as it was breaking some pyspark queries. Minimal pyspark example below:
```python
from pyspark.context import SparkContext
from pyspark.sql import SparkSession
sc = SparkContext.getOrCreate()
spark = SparkSession(sc)
from pyspark.sql import Row
data_list = [
    {"array_col": ['a', 'b']},

        ]

df = spark.createDataFrame(Row(**x) for x in data_list)
df.createOrReplaceTempView("df")

import sqlglot 
sql = "select transform(array_col, x -> x) as transformed from df"
spark.sql(sql).toPandas()

sql = sqlglot.transpile(sql, read='spark', write='spark')
spark.sql(sql).toPandas()
```

Will submit a PR to:
- distinguish between `x -> f(x)` and `(x,y,z) -> f(x,y,z)` syntax
- add a new test 
- update `identity.sql` accordingly


Discussion:

Resolving patch:
diff --git a/sqlglot/generator.py b/sqlglot/generator.py
--- a/sqlglot/generator.py
+++ b/sqlglot/generator.py
@@ -423,9 +423,9 @@ def join_sql(self, expression):
         return f"{expression_sql}{op_sql} {this_sql}{on_sql}"
 
     def lambda_sql(self, expression):
-        return self.no_identify(
-            lambda: f"({self.expressions(expression, flat=True)}) -> {self.sql(expression, 'this')}"
-        )
+        args = self.expressions(expression, flat=True)
+        args = f"({args})" if len(args) > 1 else args
+        return self.no_identify(lambda: f"{args} -> {self.sql(expression, 'this')}")
 
     def lateral_sql(self, expression):
         this = self.sql(expression, "this")


Test patch:
diff --git a/tests/fixtures/identity.sql b/tests/fixtures/identity.sql
--- a/tests/fixtures/identity.sql
+++ b/tests/fixtures/identity.sql
@@ -59,7 +59,7 @@ INTERVAL '1' day
 INTERVAL '1' month
 INTERVAL 2 months
 QUANTILE(x, 0.5)
-REGEXP_REPLACE('new york', '(\w)(\w*)', (x) -> UPPER(x[1]) || LOWER(x[2]))
+REGEXP_REPLACE('new york', '(\w)(\w*)', x -> UPPER(x[1]) || LOWER(x[2]))
 REPLACE(1)
 DATE(x) = DATE(y)
 x[y - 1]
@@ -91,11 +91,11 @@ SELECT t.count
 SELECT DISTINCT x FROM test
 SELECT DISTINCT x, y FROM test
 SELECT GREATEST((3 + 1), LEAST(3, 4))
-SELECT TRANSFORM(a, (b) -> b) AS x
+SELECT TRANSFORM(a, b -> b) AS x
 SELECT AGGREGATE(a, (a, b) -> a + b) AS x
-SELECT X((a, b) -> a + b, (z) -> z) AS x
-SELECT X((a) -> "a" + ("z" - 1))
-SELECT EXISTS(ARRAY(2, 3), (x) -> x % 2 = 0)
+SELECT X((a, b) -> a + b, z -> z) AS x
+SELECT X(a -> "a" + ("z" - 1))
+SELECT EXISTS(ARRAY(2, 3), x -> x % 2 = 0)
 SELECT test.* FROM test
 SELECT a AS b FROM test
 SELECT "a"."b" FROM "a"
Repository: tobymao/sqlglot

Issue:
Add support for DATE_TRUNC, TIME_TRUNC, DATETIME_TRUNC, TIMESTAMP_TRUNC
Would be great when this is supported. And other date/time functions.

https://blog.coupler.io/bigquery-datetime-bigquery-timestamp-functions/


Discussion:
could you be more specific in what you’re looking for?
Here a few examples:

```
SELECT
  TIMESTAMP_TRUNC(COALESCE(time_field, CURRENT_TIMESTAMP()), DAY) AS time_value,
FROM
  `table`
```

```
SELECT
  DISTINCT TIMESTAMP_TRUNC(time_field, MONTH) AS time_value,
FROM
  `table`
```

```
SELECT
  TIMESTAMP(DATE_TRUNC(DATE(time_field), MONTH)) AS time_value,
FROM
  `table`
```

```
SELECT
  COUNT(
    DISTINCT CASE
      WHEN DATE_TRUNC(DATE(time_field), isoweek) = DATE_TRUNC(DATE(time_field2), isoweek) THEN report_id
      ELSE NULL
    END
  ) AS time_value,
FROM
  `table`
```


and also this is not working (TIMESTAMP(DATE)):

```
SELECT
  TIMESTAMP(DATE(time_field)) AS time_snapshot
FROM
  `table`
```

Resolving patch:
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -56,7 +56,6 @@ class Parser:
 
     NESTED_TYPE_TOKENS = {
         TokenType.ARRAY,
-        TokenType.DATE,
         TokenType.MAP,
     }
 
@@ -122,6 +121,9 @@ class Parser:
         TokenType.VAR,
         TokenType.LEFT,
         TokenType.RIGHT,
+        TokenType.DATE,
+        TokenType.TIMESTAMP,
+        TokenType.TIMESTAMPTZ,
         *CASTS,
         *NESTED_TYPE_TOKENS,
         *SUBQUERY_PREDICATES,
@@ -1201,7 +1203,7 @@ def _parse_types(self):
                 self._parse_types if nested else self._parse_number
             )
 
-            if nested and not expressions:
+            if not expressions:
                 self._retreat(index)
                 return None
 


Test patch:
diff --git a/tests/fixtures/identity.sql b/tests/fixtures/identity.sql
--- a/tests/fixtures/identity.sql
+++ b/tests/fixtures/identity.sql
@@ -76,6 +76,10 @@ REGEXP_SPLIT('new york', '.')
 SPLIT('new york', '.')
 REPLACE(1)
 DATE(x) = DATE(y)
+TIMESTAMP(DATE(x))
+TIMESTAMP_TRUNC(COALESCE(time_field, CURRENT_TIMESTAMP()), DAY)
+TIMESTAMP_TRUNC(COALESCE(time_field, CURRENT_TIMESTAMP()), DAY)
+COUNT(DISTINCT CASE WHEN DATE_TRUNC(DATE(time_field), isoweek) = DATE_TRUNC(DATE(time_field2), isoweek) THEN report_id ELSE NULL END)
 x[y - 1]
 CASE WHEN SUM(x) > 3 THEN 1 END OVER(PARTITION BY x)
 SUM(ROW() OVER(PARTITION BY x))
@@ -116,6 +120,8 @@ SELECT 1 AS number FROM test
 SELECT t.count
 SELECT DISTINCT x FROM test
 SELECT DISTINCT x, y FROM test
+SELECT DISTINCT TIMESTAMP_TRUNC(time_field, MONTH) AS time_value FROM "table"
+SELECT TIMESTAMP(DATE_TRUNC(DATE(time_field), MONTH)) AS time_value FROM "table"
 SELECT GREATEST((3 + 1), LEAST(3, 4))
 SELECT TRANSFORM(a, b -> b) AS x
 SELECT AGGREGATE(a, (a, b) -> a + b) AS x
Repository: tobymao/sqlglot

Issue:
Support for multiple comma-separated fields in IN expression
Snowflake, Spark, and potentially other dialects support statements with row-constructors in the IN expression such as

```sql
SELECT a FROM b
WHERE (c, d) IN (SELECT e, f FROM g)
```

which is currently misparsed (multiple errors thrown). This syntax is equivalent to

```sql
SELECT a FROM b
WHERE c IN (SELECT d FROM e)
AND f IN (SELECT g FROM e)
```

Here's the link to documentation: https://docs.snowflake.com/en/sql-reference/functions/in.html#parameters

Is it possible to support such syntax? I tried to look into adding this myself, but not sure how.


Discussion:

Resolving patch:
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -1364,10 +1364,16 @@ def _parse_primary(self):
             return self.PRIMARY_PARSERS[self._prev.token_type](self, self._prev)
 
         if self._match(TokenType.L_PAREN):
-            this = self._parse_conjunction() or self._parse_with()
+            expressions = self._parse_csv(self._parse_conjunction) or [
+                self._parse_with()
+            ]
+            this = list_get(expressions, 0)
+
             self._match_r_paren()
             if self._return_subquery and isinstance(this, exp.Subqueryable):
                 return self._parse_subquery(this)
+            if len(expressions) > 1:
+                return self.expression(exp.Tuple, expressions=expressions)
             return self.expression(exp.Paren, this=this)
 
         return None


Test patch:
diff --git a/tests/fixtures/identity.sql b/tests/fixtures/identity.sql
--- a/tests/fixtures/identity.sql
+++ b/tests/fixtures/identity.sql
@@ -204,6 +204,7 @@ SELECT a FROM test WHERE EXISTS(SELECT * FROM x UNION SELECT * FROM Y) OR TRUE
 SELECT a FROM test WHERE TRUE OR NOT EXISTS(SELECT * FROM x)
 SELECT a AS any, b AS some, c AS all, d AS exists FROM test WHERE a = ANY (SELECT 1)
 SELECT a FROM test WHERE a > ALL (SELECT 1)
+SELECT a FROM test WHERE (a, b) IN (SELECT 1, 2)
 SELECT a FROM test ORDER BY a
 SELECT a FROM test ORDER BY a, b
 SELECT x FROM tests ORDER BY a DESC, b DESC, c
Repository: tobymao/sqlglot

Issue:
[Postgres 14.4] Parser does not recognize interval type when using cast() function
Example (valid sql):

```
select cast('1 day' as interval)
```
Result:
```
ParseError: Expected TYPE after CAST. Line 1, Col: 24.
  select cast('1 day' as interval)
```


Discussion:

Resolving patch:
diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py
--- a/sqlglot/expressions.py
+++ b/sqlglot/expressions.py
@@ -1654,6 +1654,7 @@ class Type(AutoName):
         DECIMAL = auto()
         BOOLEAN = auto()
         JSON = auto()
+        INTERVAL = auto()
         TIMESTAMP = auto()
         TIMESTAMPTZ = auto()
         DATE = auto()
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -78,6 +78,7 @@ class Parser:
         TokenType.TEXT,
         TokenType.BINARY,
         TokenType.JSON,
+        TokenType.INTERVAL,
         TokenType.TIMESTAMP,
         TokenType.TIMESTAMPTZ,
         TokenType.DATETIME,


Test patch:
diff --git a/tests/dialects/test_dialect.py b/tests/dialects/test_dialect.py
--- a/tests/dialects/test_dialect.py
+++ b/tests/dialects/test_dialect.py
@@ -164,6 +164,12 @@ def test_cast(self):
                 "starrocks": "CAST(a AS DOUBLE)",
             },
         )
+        self.validate_all(
+            "CAST('1 DAY' AS INTERVAL)",
+            write={
+                "postgres": "CAST('1 DAY' AS INTERVAL)",
+            },
+        )
         self.validate_all(
             "CAST(a AS TIMESTAMP)", write={"starrocks": "CAST(a AS DATETIME)"}
         )
Repository: tobymao/sqlglot

Issue:
[Postgres 14.4] Parser does not support subquery after lateral keyword
Example (valid sql):
```
select art from table1 inner join lateral (select art from table2) table2 on table2.art=table2.art
```
Result:
```
ParseError: Expected table name. Line 1, Col: 35.
  select art from table1 inner join lateral (select art from table2) table2 on table2.art=table2.art;

Required keyword: 'this' missing for <class 'sqlglot.expressions.Table'>. Line 1, Col: 35.
  select art from table1 inner join lateral (select art from table2) table2 on table2.art=table2.art;

Expected VIEW after LATERAL. Line 1, Col: 43.
  select art from table1 inner join lateral (select art from table2) table2 on table2.art=table2.art;

... and 2 more
```


Discussion:

Resolving patch:
diff --git a/sqlglot/generator.py b/sqlglot/generator.py
--- a/sqlglot/generator.py
+++ b/sqlglot/generator.py
@@ -630,6 +630,8 @@ def lambda_sql(self, expression):
 
     def lateral_sql(self, expression):
         this = self.sql(expression, "this")
+        if isinstance(expression.this, exp.Subquery):
+            return f"LATERAL{self.sep()}{this}"
         op_sql = self.seg(
             f"LATERAL VIEW{' OUTER' if expression.args.get('outer') else ''}"
         )
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -1070,8 +1070,12 @@ def _parse_lateral(self):
         if not self._match(TokenType.LATERAL):
             return None
 
-        if not self._match(TokenType.VIEW):
-            self.raise_error("Expected VIEW after LATERAL")
+        subquery = self._parse_select(table=True)
+
+        if subquery:
+            return self.expression(exp.Lateral, this=subquery)
+        elif not self._match(TokenType.VIEW):
+            self.raise_error("Expected subquery or VIEW after LATERAL")
 
         outer = self._match(TokenType.OUTER)
 
@@ -1105,7 +1109,7 @@ def _parse_join(self):
         if not self._match(TokenType.JOIN):
             return None
 
-        kwargs = {"this": self._parse_table()}
+        kwargs = {"this": self._parse_lateral() or self._parse_table()}
 
         if side:
             kwargs["side"] = side.text


Test patch:
diff --git a/tests/dialects/test_dialect.py b/tests/dialects/test_dialect.py
--- a/tests/dialects/test_dialect.py
+++ b/tests/dialects/test_dialect.py
@@ -629,6 +629,14 @@ def test_cross_join(self):
             },
         )
 
+    def test_lateral_subquery(self):
+        self.validate_identity(
+            "SELECT art FROM tbl1 INNER JOIN LATERAL (SELECT art FROM tbl2) AS tbl2 ON tbl1.art = tbl2.art"
+        )
+        self.validate_identity(
+            "SELECT * FROM tbl AS t LEFT JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) AS t ON TRUE"
+        )
+
     def test_set_operators(self):
         self.validate_all(
             "SELECT * FROM a UNION SELECT * FROM b",
Repository: tobymao/sqlglot

Issue:
[Postgres] Parser does not support operators inside extract() function
Example (valid sql):
```
select extract(week from current_date + 2);
```

Result:
```
ParseError: Expecting ). Line 1, Col: 39.
  select extract(week from current_date + 2);

Invalid expression / Unexpected token. Line 1, Col: 42.
  select extract(week from current_date + 2);
```

The addition operator can be substituted for other operators, yielding the same exception.


Discussion:
This has been documented [here](https://github.com/tobymao/sqlglot/discussions/436) as well. I will open a PR to fix it later if yuchaofan13 hasn't done so already.

Resolving patch:
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -1904,7 +1904,7 @@ def _parse_extract(self):
         if not self._match(TokenType.FROM):
             self.raise_error("Expected FROM after EXTRACT", self._prev)
 
-        return self.expression(exp.Extract, this=this, expression=self._parse_type())
+        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
 
     def _parse_cast(self, strict):
         this = self._parse_conjunction()


Test patch:
diff --git a/tests/test_transpile.py b/tests/test_transpile.py
--- a/tests/test_transpile.py
+++ b/tests/test_transpile.py
@@ -108,6 +108,13 @@ def test_extract(self):
             "extract(month from '2021-01-31'::timestamp without time zone)",
             "EXTRACT(month FROM CAST('2021-01-31' AS TIMESTAMP))",
         )
+        self.validate(
+            "extract(week from current_date + 2)", "EXTRACT(week FROM CURRENT_DATE + 2)"
+        )
+        self.validate(
+            "EXTRACT(minute FROM datetime1 - datetime2)",
+            "EXTRACT(minute FROM datetime1 - datetime2)",
+        )
 
     def test_if(self):
         self.validate(
Repository: tobymao/sqlglot

Issue:
[Postgres] Parser does not support string concatenation operator inside substring function
Example (valid sql):
```
select substring(2022::char(4) || lpad(3::char(2), 2, '0') from 3 for 4)
```
Result:
```
ParseError: Expecting ). Line 1, Col: 31.
  select substring(2022::char(4)||lpad(3::char(2), 2, '0') from 3 for 4)

Expected table name. Line 1, Col: 63.
  select substring(2022::char(4)||lpad(3::char(2), 2, '0') from 3 for 4)

Required keyword: 'this' missing for <class 'sqlglot.expressions.Table'>. Line 1, Col: 63.
  select substring(2022::char(4)||lpad(3::char(2), 2, '0') from 3 for 4)
```

And it seems like https://github.com/tobymao/sqlglot/issues/421 is still an issue here (I'm using sqlglot 6.0.7).


Discussion:

Resolving patch:
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -1936,12 +1936,12 @@ def _parse_substring(self):
         # Postgres supports the form: substring(string [from int] [for int])
         # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
 
-        args = self._parse_csv(self._parse_term)
+        args = self._parse_csv(self._parse_bitwise)
 
         if self._match(TokenType.FROM):
-            args.append(self._parse_term())
+            args.append(self._parse_bitwise())
             if self._match(TokenType.FOR):
-                args.append(self._parse_term())
+                args.append(self._parse_bitwise())
 
         this = exp.Substring.from_arg_list(args)
         self.validate_expression(this, args)


Test patch:
diff --git a/tests/dialects/test_postgres.py b/tests/dialects/test_postgres.py
--- a/tests/dialects/test_postgres.py
+++ b/tests/dialects/test_postgres.py
@@ -72,6 +72,9 @@ def test_postgres(self):
         self.validate_identity(
             "SELECT * FROM x WHERE SUBSTRING('Thomas' FROM '%#\"o_a#\"_' FOR '#') IN ('mas')"
         )
+        self.validate_identity(
+            "SELECT SUBSTRING('bla' + 'foo' || 'bar' FROM 3 - 1 + 5 FOR 4 + SOME_FUNC(arg1, arg2))"
+        )
         self.validate_identity("SELECT TRIM(' X' FROM ' XXX ')")
         self.validate_identity(
             "SELECT TRIM(LEADING 'bla' FROM ' XXX ' COLLATE utf8_bin)"
@@ -128,6 +131,12 @@ def test_postgres(self):
                 "spark": "SELECT * FROM x WHERE SUBSTRING(col1, 3 + LENGTH(col1) - 10, 10) IN (col2)",
             },
         )
+        self.validate_all(
+            "SELECT SUBSTRING(CAST(2022 AS CHAR(4)) || LPAD(CAST(3 AS CHAR(2)), 2, '0') FROM 3 FOR 4)",
+            read={
+                "postgres": "SELECT SUBSTRING(2022::CHAR(4) || LPAD(3::CHAR(2), 2, '0') FROM 3 FOR 4)",
+            },
+        )
         self.validate_all(
             "SELECT TRIM(BOTH ' XXX ')",
             write={
Repository: tobymao/sqlglot

Issue:
cast to map with clickhouse dialect ignores case
Yet another clickhouse case sensitivity bug :)


ClickHouse CLI:

```
albatross :) select cast(map('a', 1, 'b', 2) as Map(String, Int8));

SELECT CAST(map('a', 1, 'b', 2), 'Map(String, Int8)')

Query id: bab188fb-69f7-4c0f-9bde-ac524a08f6e8

┌─CAST(map('a', 1, 'b', 2), 'Map(String, Int8)')─┐
│ {'a':1,'b':2}                                  │
└────────────────────────────────────────────────┘

1 row in set. Elapsed: 0.001 sec.
```

sqlglot:

```
In [7]: sg.parse_one("cast(map('a', 1, 'b', 2) as Map(String, Int8))", read="clickhouse").sql(dialect="clickhouse")
Out[7]: "CAST(map('a', 1, 'b', 2) AS MAP(TEXT, TINYINT))"
```

Perhaps there's a way to disable all case transformations for the clickhouse dialect.


Discussion:
Seems to be happening with other types as well:

```
In [2]: sg.parse_one("cast([] as Array(Nullable(Int8)))", read="clickhouse").sql(dialect="clickhouse")
Out[2]: 'CAST([] AS ARRAY(Nullable(TINYINT)))'
```

Resolving patch:
diff --git a/sqlglot/dialects/clickhouse.py b/sqlglot/dialects/clickhouse.py
--- a/sqlglot/dialects/clickhouse.py
+++ b/sqlglot/dialects/clickhouse.py
@@ -51,6 +51,9 @@ class Generator(Generator):
             **Generator.TYPE_MAPPING,
             exp.DataType.Type.NULLABLE: "Nullable",
             exp.DataType.Type.DATETIME: "DateTime64",
+            exp.DataType.Type.MAP: "Map",
+            exp.DataType.Type.ARRAY: "Array",
+            exp.DataType.Type.STRUCT: "Tuple",
         }
 
         TRANSFORMS = {


Test patch:
diff --git a/tests/dialects/test_dialect.py b/tests/dialects/test_dialect.py
--- a/tests/dialects/test_dialect.py
+++ b/tests/dialects/test_dialect.py
@@ -81,6 +81,24 @@ def test_cast(self):
                 "starrocks": "CAST(a AS STRING)",
             },
         )
+        self.validate_all(
+            "CAST(MAP('a', '1') AS MAP(TEXT, TEXT))",
+            write={
+                "clickhouse": "CAST(map('a', '1') AS Map(TEXT, TEXT))",
+            },
+        )
+        self.validate_all(
+            "CAST(ARRAY(1, 2) AS ARRAY<TINYINT>)",
+            write={
+                "clickhouse": "CAST([1, 2] AS Array(TINYINT))",
+            },
+        )
+        self.validate_all(
+            "CAST((1, 2) AS STRUCT<a: TINYINT, b: TINYINT>)",
+            write={
+                "clickhouse": "CAST((1, 2) AS Tuple(a TINYINT, b TINYINT))",
+            },
+        )
         self.validate_all(
             "CAST(a AS DATETIME)",
             write={