We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Problem with parsing Teradata COLLECT STATISTICS command
I have found a problem parsing the COLLECT STATISTICS command in Teradata.  
All variations of the COLLECT STATISTICS command fail

COLLECT STATISTICS ON TABLE1
INDEX(COL1);

COLLECT STATS
ON TABLE1
COLUMNS(COL1);

COLLECT STATS ON TABLE1
COLUMNS(COL1);

COLLECT STATS
COLUMNS(COL1)
ON TABLE1;

sqlglot Version: 17.4.1
Teradata version 17.10

Error message is 

File ~\AppData\Roaming\Python\Python311\site-packages\sqlglot\parser.py:946, in Parser._parse(self, parse_method, raw_tokens, sql)
    943     expressions.append(parse_method(self))
    945     if self._index < len(self._tokens):
--> 946         self.raise_error("Invalid expression / Unexpected token")
    948     self.check_errors()
    950 return expressions

File ~\AppData\Roaming\Python\Python311\site-packages\sqlglot\parser.py:987, in Parser.raise_error(self, message, token)
    975 error = ParseError.new(
    976     f"{message}. Line {token.line}, Col: {token.col}.\n"
    977     f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
   (...)
    983     end_context=end_context,
    984 )
    986 if self.error_level == ErrorLevel.IMMEDIATE:
--> 987     raise error
    989 self.errors.append(error)

or 

File ~\AppData\Roaming\Python\Python311\site-packages\sqlglot\parser.py:946, in Parser._parse(self, parse_method, raw_tokens, sql)
    943     expressions.append(parse_method(self))
    945     if self._index < len(self._tokens):
--> 946         self.raise_error("Invalid expression / Unexpected token")
    948     self.check_errors()
    950 return expressions

File ~\AppData\Roaming\Python\Python311\site-packages\sqlglot\parser.py:987, in Parser.raise_error(self, message, token)
    975 error = ParseError.new(
    976     f"{message}. Line {token.line}, Col: {token.col}.\n"
    977     f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
   (...)
    983     end_context=end_context,
    984 )
    986 if self.error_level == ErrorLevel.IMMEDIATE:
--> 987     raise error
    989 self.errors.append(error)

ParseError: Invalid expression / Unexpected token. Line 2, Col: 16.
  
COLLECT STATS ON TABLE1
COLUMNS(COL1);


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sqlglot/dialects/teradata.py`
Content:
```
1 from __future__ import annotations
2 
3 from sqlglot import exp, generator, parser, tokens, transforms
4 from sqlglot.dialects.dialect import Dialect, max_or_greatest, min_or_least
5 from sqlglot.tokens import TokenType
6 
7 
8 class Teradata(Dialect):
9     TIME_MAPPING = {
10         "Y": "%Y",
11         "YYYY": "%Y",
12         "YY": "%y",
13         "MMMM": "%B",
14         "MMM": "%b",
15         "DD": "%d",
16         "D": "%-d",
17         "HH": "%H",
18         "H": "%-H",
19         "MM": "%M",
20         "M": "%-M",
21         "SS": "%S",
22         "S": "%-S",
23         "SSSSSS": "%f",
24         "E": "%a",
25         "EE": "%a",
26         "EEE": "%a",
27         "EEEE": "%A",
28     }
29 
30     class Tokenizer(tokens.Tokenizer):
31         # https://docs.teradata.com/r/Teradata-Database-SQL-Functions-Operators-Expressions-and-Predicates/March-2017/Comparison-Operators-and-Functions/Comparison-Operators/ANSI-Compliance
32         KEYWORDS = {
33             **tokens.Tokenizer.KEYWORDS,
34             "^=": TokenType.NEQ,
35             "BYTEINT": TokenType.SMALLINT,
36             "GE": TokenType.GTE,
37             "GT": TokenType.GT,
38             "INS": TokenType.INSERT,
39             "LE": TokenType.LTE,
40             "LT": TokenType.LT,
41             "MOD": TokenType.MOD,
42             "NE": TokenType.NEQ,
43             "NOT=": TokenType.NEQ,
44             "SEL": TokenType.SELECT,
45             "ST_GEOMETRY": TokenType.GEOMETRY,
46             "TOP": TokenType.TOP,
47         }
48 
49         # Teradata does not support % as a modulo operator
50         SINGLE_TOKENS = {**tokens.Tokenizer.SINGLE_TOKENS}
51         SINGLE_TOKENS.pop("%")
52 
53     class Parser(parser.Parser):
54         CHARSET_TRANSLATORS = {
55             "GRAPHIC_TO_KANJISJIS",
56             "GRAPHIC_TO_LATIN",
57             "GRAPHIC_TO_UNICODE",
58             "GRAPHIC_TO_UNICODE_PadSpace",
59             "KANJI1_KanjiEBCDIC_TO_UNICODE",
60             "KANJI1_KanjiEUC_TO_UNICODE",
61             "KANJI1_KANJISJIS_TO_UNICODE",
62             "KANJI1_SBC_TO_UNICODE",
63             "KANJISJIS_TO_GRAPHIC",
64             "KANJISJIS_TO_LATIN",
65             "KANJISJIS_TO_UNICODE",
66             "LATIN_TO_GRAPHIC",
67             "LATIN_TO_KANJISJIS",
68             "LATIN_TO_UNICODE",
69             "LOCALE_TO_UNICODE",
70             "UNICODE_TO_GRAPHIC",
71             "UNICODE_TO_GRAPHIC_PadGraphic",
72             "UNICODE_TO_GRAPHIC_VarGraphic",
73             "UNICODE_TO_KANJI1_KanjiEBCDIC",
74             "UNICODE_TO_KANJI1_KanjiEUC",
75             "UNICODE_TO_KANJI1_KANJISJIS",
76             "UNICODE_TO_KANJI1_SBC",
77             "UNICODE_TO_KANJISJIS",
78             "UNICODE_TO_LATIN",
79             "UNICODE_TO_LOCALE",
80             "UNICODE_TO_UNICODE_FoldSpace",
81             "UNICODE_TO_UNICODE_Fullwidth",
82             "UNICODE_TO_UNICODE_Halfwidth",
83             "UNICODE_TO_UNICODE_NFC",
84             "UNICODE_TO_UNICODE_NFD",
85             "UNICODE_TO_UNICODE_NFKC",
86             "UNICODE_TO_UNICODE_NFKD",
87         }
88 
89         FUNC_TOKENS = {*parser.Parser.FUNC_TOKENS}
90         FUNC_TOKENS.remove(TokenType.REPLACE)
91 
92         STATEMENT_PARSERS = {
93             **parser.Parser.STATEMENT_PARSERS,
94             TokenType.REPLACE: lambda self: self._parse_create(),
95         }
96 
97         FUNCTION_PARSERS = {
98             **parser.Parser.FUNCTION_PARSERS,
99             "RANGE_N": lambda self: self._parse_rangen(),
100             "TRANSLATE": lambda self: self._parse_translate(self.STRICT_CAST),
101         }
102 
103         def _parse_translate(self, strict: bool) -> exp.Expression:
104             this = self._parse_conjunction()
105 
106             if not self._match(TokenType.USING):
107                 self.raise_error("Expected USING in TRANSLATE")
108 
109             if self._match_texts(self.CHARSET_TRANSLATORS):
110                 charset_split = self._prev.text.split("_TO_")
111                 to = self.expression(exp.CharacterSet, this=charset_split[1])
112             else:
113                 self.raise_error("Expected a character set translator after USING in TRANSLATE")
114 
115             return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to)
116 
117         # FROM before SET in Teradata UPDATE syntax
118         # https://docs.teradata.com/r/Enterprise_IntelliFlex_VMware/Teradata-VantageTM-SQL-Data-Manipulation-Language-17.20/Statement-Syntax/UPDATE/UPDATE-Syntax-Basic-Form-FROM-Clause
119         def _parse_update(self) -> exp.Update:
120             return self.expression(
121                 exp.Update,
122                 **{  # type: ignore
123                     "this": self._parse_table(alias_tokens=self.UPDATE_ALIAS_TOKENS),
124                     "from": self._parse_from(joins=True),
125                     "expressions": self._match(TokenType.SET)
126                     and self._parse_csv(self._parse_equality),
127                     "where": self._parse_where(),
128                 },
129             )
130 
131         def _parse_rangen(self):
132             this = self._parse_id_var()
133             self._match(TokenType.BETWEEN)
134 
135             expressions = self._parse_csv(self._parse_conjunction)
136             each = self._match_text_seq("EACH") and self._parse_conjunction()
137 
138             return self.expression(exp.RangeN, this=this, expressions=expressions, each=each)
139 
140     class Generator(generator.Generator):
141         JOIN_HINTS = False
142         TABLE_HINTS = False
143         QUERY_HINTS = False
144 
145         TYPE_MAPPING = {
146             **generator.Generator.TYPE_MAPPING,
147             exp.DataType.Type.GEOMETRY: "ST_GEOMETRY",
148         }
149 
150         PROPERTIES_LOCATION = {
151             **generator.Generator.PROPERTIES_LOCATION,
152             exp.OnCommitProperty: exp.Properties.Location.POST_INDEX,
153             exp.PartitionedByProperty: exp.Properties.Location.POST_EXPRESSION,
154             exp.StabilityProperty: exp.Properties.Location.POST_CREATE,
155         }
156 
157         TRANSFORMS = {
158             **generator.Generator.TRANSFORMS,
159             exp.Max: max_or_greatest,
160             exp.Min: min_or_least,
161             exp.Select: transforms.preprocess([transforms.eliminate_distinct_on]),
162             exp.StrToDate: lambda self, e: f"CAST({self.sql(e, 'this')} AS DATE FORMAT {self.format_time(e)})",
163             exp.ToChar: lambda self, e: self.function_fallback_sql(e),
164         }
165 
166         def partitionedbyproperty_sql(self, expression: exp.PartitionedByProperty) -> str:
167             return f"PARTITION BY {self.sql(expression, 'this')}"
168 
169         # FROM before SET in Teradata UPDATE syntax
170         # https://docs.teradata.com/r/Enterprise_IntelliFlex_VMware/Teradata-VantageTM-SQL-Data-Manipulation-Language-17.20/Statement-Syntax/UPDATE/UPDATE-Syntax-Basic-Form-FROM-Clause
171         def update_sql(self, expression: exp.Update) -> str:
172             this = self.sql(expression, "this")
173             from_sql = self.sql(expression, "from")
174             set_sql = self.expressions(expression, flat=True)
175             where_sql = self.sql(expression, "where")
176             sql = f"UPDATE {this}{from_sql} SET {set_sql}{where_sql}"
177             return self.prepend_ctes(expression, sql)
178 
179         def mod_sql(self, expression: exp.Mod) -> str:
180             return self.binary(expression, "MOD")
181 
182         def datatype_sql(self, expression: exp.DataType) -> str:
183             type_sql = super().datatype_sql(expression)
184             prefix_sql = expression.args.get("prefix")
185             return f"SYSUDTLIB.{type_sql}" if prefix_sql else type_sql
186 
187         def rangen_sql(self, expression: exp.RangeN) -> str:
188             this = self.sql(expression, "this")
189             expressions_sql = self.expressions(expression)
190             each_sql = self.sql(expression, "each")
191             each_sql = f" EACH {each_sql}" if each_sql else ""
192 
193             return f"RANGE_N({this} BETWEEN {expressions_sql}{each_sql})"
194 
195         def createable_sql(
196             self,
197             expression: exp.Create,
198             locations: dict[exp.Properties.Location, list[exp.Property]],
199         ) -> str:
200             kind = self.sql(expression, "kind").upper()
201             if kind == "TABLE" and locations.get(exp.Properties.Location.POST_NAME):
202                 this_name = self.sql(expression.this, "this")
203                 this_properties = self.properties(
204                     exp.Properties(expressions=locations[exp.Properties.Location.POST_NAME]),
205                     wrapped=False,
206                     prefix=",",
207                 )
208                 this_schema = self.schema_columns_sql(expression.this)
209                 return f"{this_name}{this_properties}{self.sep()}{this_schema}"
210             return super().createable_sql(expression, locations)
211
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/sqlglot/dialects/teradata.py b/sqlglot/dialects/teradata.py
--- a/sqlglot/dialects/teradata.py
+++ b/sqlglot/dialects/teradata.py
@@ -33,8 +33,11 @@
             **tokens.Tokenizer.KEYWORDS,
             "^=": TokenType.NEQ,
             "BYTEINT": TokenType.SMALLINT,
+            "COLLECT STATS": TokenType.COMMAND,
+            "COLLECT STATISTICS": TokenType.COMMAND,
             "GE": TokenType.GTE,
             "GT": TokenType.GT,
+            "HELP": TokenType.COMMAND,
             "INS": TokenType.INSERT,
             "LE": TokenType.LTE,
             "LT": TokenType.LT,

{"golden_diff": "diff --git a/sqlglot/dialects/teradata.py b/sqlglot/dialects/teradata.py\n--- a/sqlglot/dialects/teradata.py\n+++ b/sqlglot/dialects/teradata.py\n@@ -33,8 +33,11 @@\n             **tokens.Tokenizer.KEYWORDS,\n             \"^=\": TokenType.NEQ,\n             \"BYTEINT\": TokenType.SMALLINT,\n+            \"COLLECT STATS\": TokenType.COMMAND,\n+            \"COLLECT STATISTICS\": TokenType.COMMAND,\n             \"GE\": TokenType.GTE,\n             \"GT\": TokenType.GT,\n+            \"HELP\": TokenType.COMMAND,\n             \"INS\": TokenType.INSERT,\n             \"LE\": TokenType.LTE,\n             \"LT\": TokenType.LT,\n", "issue": "Problem with parsing Teradata COLLECT STATISTICS command\nI have found a problem parsing the COLLECT STATISTICS command in Teradata.  \r\nAll variations of the COLLECT STATISTICS command fail\r\n\r\nCOLLECT STATISTICS ON TABLE1\r\nINDEX(COL1);\r\n\r\nCOLLECT STATS\r\nON TABLE1\r\nCOLUMNS(COL1);\r\n\r\nCOLLECT STATS ON TABLE1\r\nCOLUMNS(COL1);\r\n\r\nCOLLECT STATS\r\nCOLUMNS(COL1)\r\nON TABLE1;\r\n\r\nsqlglot Version: 17.4.1\r\nTeradata version 17.10\r\n\r\nError message is \r\n\r\nFile ~\\AppData\\Roaming\\Python\\Python311\\site-packages\\sqlglot\\parser.py:946, in Parser._parse(self, parse_method, raw_tokens, sql)\r\n    943     expressions.append(parse_method(self))\r\n    945     if self._index < len(self._tokens):\r\n--> 946         self.raise_error(\"Invalid expression / Unexpected token\")\r\n    948     self.check_errors()\r\n    950 return expressions\r\n\r\nFile ~\\AppData\\Roaming\\Python\\Python311\\site-packages\\sqlglot\\parser.py:987, in Parser.raise_error(self, message, token)\r\n    975 error = ParseError.new(\r\n    976     f\"{message}. Line {token.line}, Col: {token.col}.\\n\"\r\n    977     f\"  {start_context}\\033[4m{highlight}\\033[0m{end_context}\",\r\n   (...)\r\n    983     end_context=end_context,\r\n    984 )\r\n    986 if self.error_level == ErrorLevel.IMMEDIATE:\r\n--> 987     raise error\r\n    989 self.errors.append(error)\r\n\r\nor \r\n\r\nFile ~\\AppData\\Roaming\\Python\\Python311\\site-packages\\sqlglot\\parser.py:946, in Parser._parse(self, parse_method, raw_tokens, sql)\r\n    943     expressions.append(parse_method(self))\r\n    945     if self._index < len(self._tokens):\r\n--> 946         self.raise_error(\"Invalid expression / Unexpected token\")\r\n    948     self.check_errors()\r\n    950 return expressions\r\n\r\nFile ~\\AppData\\Roaming\\Python\\Python311\\site-packages\\sqlglot\\parser.py:987, in Parser.raise_error(self, message, token)\r\n    975 error = ParseError.new(\r\n    976     f\"{message}. Line {token.line}, Col: {token.col}.\\n\"\r\n    977     f\"  {start_context}\\033[4m{highlight}\\033[0m{end_context}\",\r\n   (...)\r\n    983     end_context=end_context,\r\n    984 )\r\n    986 if self.error_level == ErrorLevel.IMMEDIATE:\r\n--> 987     raise error\r\n    989 self.errors.append(error)\r\n\r\nParseError: Invalid expression / Unexpected token. Line 2, Col: 16.\r\n  \r\nCOLLECT STATS ON TABLE1\r\nCOLUMNS(COL1);\r\n\n", "before_files": [{"content": "from __future__ import annotations\n\nfrom sqlglot import exp, generator, parser, tokens, transforms\nfrom sqlglot.dialects.dialect import Dialect, max_or_greatest, min_or_least\nfrom sqlglot.tokens import TokenType\n\n\nclass Teradata(Dialect):\n    TIME_MAPPING = {\n        \"Y\": \"%Y\",\n        \"YYYY\": \"%Y\",\n        \"YY\": \"%y\",\n        \"MMMM\": \"%B\",\n        \"MMM\": \"%b\",\n        \"DD\": \"%d\",\n        \"D\": \"%-d\",\n        \"HH\": \"%H\",\n        \"H\": \"%-H\",\n        \"MM\": \"%M\",\n        \"M\": \"%-M\",\n        \"SS\": \"%S\",\n        \"S\": \"%-S\",\n        \"SSSSSS\": \"%f\",\n        \"E\": \"%a\",\n        \"EE\": \"%a\",\n        \"EEE\": \"%a\",\n        \"EEEE\": \"%A\",\n    }\n\n    class Tokenizer(tokens.Tokenizer):\n        # https://docs.teradata.com/r/Teradata-Database-SQL-Functions-Operators-Expressions-and-Predicates/March-2017/Comparison-Operators-and-Functions/Comparison-Operators/ANSI-Compliance\n        KEYWORDS = {\n            **tokens.Tokenizer.KEYWORDS,\n            \"^=\": TokenType.NEQ,\n            \"BYTEINT\": TokenType.SMALLINT,\n            \"GE\": TokenType.GTE,\n            \"GT\": TokenType.GT,\n            \"INS\": TokenType.INSERT,\n            \"LE\": TokenType.LTE,\n            \"LT\": TokenType.LT,\n            \"MOD\": TokenType.MOD,\n            \"NE\": TokenType.NEQ,\n            \"NOT=\": TokenType.NEQ,\n            \"SEL\": TokenType.SELECT,\n            \"ST_GEOMETRY\": TokenType.GEOMETRY,\n            \"TOP\": TokenType.TOP,\n        }\n\n        # Teradata does not support % as a modulo operator\n        SINGLE_TOKENS = {**tokens.Tokenizer.SINGLE_TOKENS}\n        SINGLE_TOKENS.pop(\"%\")\n\n    class Parser(parser.Parser):\n        CHARSET_TRANSLATORS = {\n            \"GRAPHIC_TO_KANJISJIS\",\n            \"GRAPHIC_TO_LATIN\",\n            \"GRAPHIC_TO_UNICODE\",\n            \"GRAPHIC_TO_UNICODE_PadSpace\",\n            \"KANJI1_KanjiEBCDIC_TO_UNICODE\",\n            \"KANJI1_KanjiEUC_TO_UNICODE\",\n            \"KANJI1_KANJISJIS_TO_UNICODE\",\n            \"KANJI1_SBC_TO_UNICODE\",\n            \"KANJISJIS_TO_GRAPHIC\",\n            \"KANJISJIS_TO_LATIN\",\n            \"KANJISJIS_TO_UNICODE\",\n            \"LATIN_TO_GRAPHIC\",\n            \"LATIN_TO_KANJISJIS\",\n            \"LATIN_TO_UNICODE\",\n            \"LOCALE_TO_UNICODE\",\n            \"UNICODE_TO_GRAPHIC\",\n            \"UNICODE_TO_GRAPHIC_PadGraphic\",\n            \"UNICODE_TO_GRAPHIC_VarGraphic\",\n            \"UNICODE_TO_KANJI1_KanjiEBCDIC\",\n            \"UNICODE_TO_KANJI1_KanjiEUC\",\n            \"UNICODE_TO_KANJI1_KANJISJIS\",\n            \"UNICODE_TO_KANJI1_SBC\",\n            \"UNICODE_TO_KANJISJIS\",\n            \"UNICODE_TO_LATIN\",\n            \"UNICODE_TO_LOCALE\",\n            \"UNICODE_TO_UNICODE_FoldSpace\",\n            \"UNICODE_TO_UNICODE_Fullwidth\",\n            \"UNICODE_TO_UNICODE_Halfwidth\",\n            \"UNICODE_TO_UNICODE_NFC\",\n            \"UNICODE_TO_UNICODE_NFD\",\n            \"UNICODE_TO_UNICODE_NFKC\",\n            \"UNICODE_TO_UNICODE_NFKD\",\n        }\n\n        FUNC_TOKENS = {*parser.Parser.FUNC_TOKENS}\n        FUNC_TOKENS.remove(TokenType.REPLACE)\n\n        STATEMENT_PARSERS = {\n            **parser.Parser.STATEMENT_PARSERS,\n            TokenType.REPLACE: lambda self: self._parse_create(),\n        }\n\n        FUNCTION_PARSERS = {\n            **parser.Parser.FUNCTION_PARSERS,\n            \"RANGE_N\": lambda self: self._parse_rangen(),\n            \"TRANSLATE\": lambda self: self._parse_translate(self.STRICT_CAST),\n        }\n\n        def _parse_translate(self, strict: bool) -> exp.Expression:\n            this = self._parse_conjunction()\n\n            if not self._match(TokenType.USING):\n                self.raise_error(\"Expected USING in TRANSLATE\")\n\n            if self._match_texts(self.CHARSET_TRANSLATORS):\n                charset_split = self._prev.text.split(\"_TO_\")\n                to = self.expression(exp.CharacterSet, this=charset_split[1])\n            else:\n                self.raise_error(\"Expected a character set translator after USING in TRANSLATE\")\n\n            return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to)\n\n        # FROM before SET in Teradata UPDATE syntax\n        # https://docs.teradata.com/r/Enterprise_IntelliFlex_VMware/Teradata-VantageTM-SQL-Data-Manipulation-Language-17.20/Statement-Syntax/UPDATE/UPDATE-Syntax-Basic-Form-FROM-Clause\n        def _parse_update(self) -> exp.Update:\n            return self.expression(\n                exp.Update,\n                **{  # type: ignore\n                    \"this\": self._parse_table(alias_tokens=self.UPDATE_ALIAS_TOKENS),\n                    \"from\": self._parse_from(joins=True),\n                    \"expressions\": self._match(TokenType.SET)\n                    and self._parse_csv(self._parse_equality),\n                    \"where\": self._parse_where(),\n                },\n            )\n\n        def _parse_rangen(self):\n            this = self._parse_id_var()\n            self._match(TokenType.BETWEEN)\n\n            expressions = self._parse_csv(self._parse_conjunction)\n            each = self._match_text_seq(\"EACH\") and self._parse_conjunction()\n\n            return self.expression(exp.RangeN, this=this, expressions=expressions, each=each)\n\n    class Generator(generator.Generator):\n        JOIN_HINTS = False\n        TABLE_HINTS = False\n        QUERY_HINTS = False\n\n        TYPE_MAPPING = {\n            **generator.Generator.TYPE_MAPPING,\n            exp.DataType.Type.GEOMETRY: \"ST_GEOMETRY\",\n        }\n\n        PROPERTIES_LOCATION = {\n            **generator.Generator.PROPERTIES_LOCATION,\n            exp.OnCommitProperty: exp.Properties.Location.POST_INDEX,\n            exp.PartitionedByProperty: exp.Properties.Location.POST_EXPRESSION,\n            exp.StabilityProperty: exp.Properties.Location.POST_CREATE,\n        }\n\n        TRANSFORMS = {\n            **generator.Generator.TRANSFORMS,\n            exp.Max: max_or_greatest,\n            exp.Min: min_or_least,\n            exp.Select: transforms.preprocess([transforms.eliminate_distinct_on]),\n            exp.StrToDate: lambda self, e: f\"CAST({self.sql(e, 'this')} AS DATE FORMAT {self.format_time(e)})\",\n            exp.ToChar: lambda self, e: self.function_fallback_sql(e),\n        }\n\n        def partitionedbyproperty_sql(self, expression: exp.PartitionedByProperty) -> str:\n            return f\"PARTITION BY {self.sql(expression, 'this')}\"\n\n        # FROM before SET in Teradata UPDATE syntax\n        # https://docs.teradata.com/r/Enterprise_IntelliFlex_VMware/Teradata-VantageTM-SQL-Data-Manipulation-Language-17.20/Statement-Syntax/UPDATE/UPDATE-Syntax-Basic-Form-FROM-Clause\n        def update_sql(self, expression: exp.Update) -> str:\n            this = self.sql(expression, \"this\")\n            from_sql = self.sql(expression, \"from\")\n            set_sql = self.expressions(expression, flat=True)\n            where_sql = self.sql(expression, \"where\")\n            sql = f\"UPDATE {this}{from_sql} SET {set_sql}{where_sql}\"\n            return self.prepend_ctes(expression, sql)\n\n        def mod_sql(self, expression: exp.Mod) -> str:\n            return self.binary(expression, \"MOD\")\n\n        def datatype_sql(self, expression: exp.DataType) -> str:\n            type_sql = super().datatype_sql(expression)\n            prefix_sql = expression.args.get(\"prefix\")\n            return f\"SYSUDTLIB.{type_sql}\" if prefix_sql else type_sql\n\n        def rangen_sql(self, expression: exp.RangeN) -> str:\n            this = self.sql(expression, \"this\")\n            expressions_sql = self.expressions(expression)\n            each_sql = self.sql(expression, \"each\")\n            each_sql = f\" EACH {each_sql}\" if each_sql else \"\"\n\n            return f\"RANGE_N({this} BETWEEN {expressions_sql}{each_sql})\"\n\n        def createable_sql(\n            self,\n            expression: exp.Create,\n            locations: dict[exp.Properties.Location, list[exp.Property]],\n        ) -> str:\n            kind = self.sql(expression, \"kind\").upper()\n            if kind == \"TABLE\" and locations.get(exp.Properties.Location.POST_NAME):\n                this_name = self.sql(expression.this, \"this\")\n                this_properties = self.properties(\n                    exp.Properties(expressions=locations[exp.Properties.Location.POST_NAME]),\n                    wrapped=False,\n                    prefix=\",\",\n                )\n                this_schema = self.schema_columns_sql(expression.this)\n                return f\"{this_name}{this_properties}{self.sep()}{this_schema}\"\n            return super().createable_sql(expression, locations)\n", "path": "sqlglot/dialects/teradata.py"}], "after_files": [{"content": "from __future__ import annotations\n\nfrom sqlglot import exp, generator, parser, tokens, transforms\nfrom sqlglot.dialects.dialect import Dialect, max_or_greatest, min_or_least\nfrom sqlglot.tokens import TokenType\n\n\nclass Teradata(Dialect):\n    TIME_MAPPING = {\n        \"Y\": \"%Y\",\n        \"YYYY\": \"%Y\",\n        \"YY\": \"%y\",\n        \"MMMM\": \"%B\",\n        \"MMM\": \"%b\",\n        \"DD\": \"%d\",\n        \"D\": \"%-d\",\n        \"HH\": \"%H\",\n        \"H\": \"%-H\",\n        \"MM\": \"%M\",\n        \"M\": \"%-M\",\n        \"SS\": \"%S\",\n        \"S\": \"%-S\",\n        \"SSSSSS\": \"%f\",\n        \"E\": \"%a\",\n        \"EE\": \"%a\",\n        \"EEE\": \"%a\",\n        \"EEEE\": \"%A\",\n    }\n\n    class Tokenizer(tokens.Tokenizer):\n        # https://docs.teradata.com/r/Teradata-Database-SQL-Functions-Operators-Expressions-and-Predicates/March-2017/Comparison-Operators-and-Functions/Comparison-Operators/ANSI-Compliance\n        KEYWORDS = {\n            **tokens.Tokenizer.KEYWORDS,\n            \"^=\": TokenType.NEQ,\n            \"BYTEINT\": TokenType.SMALLINT,\n            \"COLLECT STATS\": TokenType.COMMAND,\n            \"COLLECT STATISTICS\": TokenType.COMMAND,\n            \"GE\": TokenType.GTE,\n            \"GT\": TokenType.GT,\n            \"HELP\": TokenType.COMMAND,\n            \"INS\": TokenType.INSERT,\n            \"LE\": TokenType.LTE,\n            \"LT\": TokenType.LT,\n            \"MOD\": TokenType.MOD,\n            \"NE\": TokenType.NEQ,\n            \"NOT=\": TokenType.NEQ,\n            \"SEL\": TokenType.SELECT,\n            \"ST_GEOMETRY\": TokenType.GEOMETRY,\n            \"TOP\": TokenType.TOP,\n        }\n\n        # Teradata does not support % as a modulo operator\n        SINGLE_TOKENS = {**tokens.Tokenizer.SINGLE_TOKENS}\n        SINGLE_TOKENS.pop(\"%\")\n\n    class Parser(parser.Parser):\n        CHARSET_TRANSLATORS = {\n            \"GRAPHIC_TO_KANJISJIS\",\n            \"GRAPHIC_TO_LATIN\",\n            \"GRAPHIC_TO_UNICODE\",\n            \"GRAPHIC_TO_UNICODE_PadSpace\",\n            \"KANJI1_KanjiEBCDIC_TO_UNICODE\",\n            \"KANJI1_KanjiEUC_TO_UNICODE\",\n            \"KANJI1_KANJISJIS_TO_UNICODE\",\n            \"KANJI1_SBC_TO_UNICODE\",\n            \"KANJISJIS_TO_GRAPHIC\",\n            \"KANJISJIS_TO_LATIN\",\n            \"KANJISJIS_TO_UNICODE\",\n            \"LATIN_TO_GRAPHIC\",\n            \"LATIN_TO_KANJISJIS\",\n            \"LATIN_TO_UNICODE\",\n            \"LOCALE_TO_UNICODE\",\n            \"UNICODE_TO_GRAPHIC\",\n            \"UNICODE_TO_GRAPHIC_PadGraphic\",\n            \"UNICODE_TO_GRAPHIC_VarGraphic\",\n            \"UNICODE_TO_KANJI1_KanjiEBCDIC\",\n            \"UNICODE_TO_KANJI1_KanjiEUC\",\n            \"UNICODE_TO_KANJI1_KANJISJIS\",\n            \"UNICODE_TO_KANJI1_SBC\",\n            \"UNICODE_TO_KANJISJIS\",\n            \"UNICODE_TO_LATIN\",\n            \"UNICODE_TO_LOCALE\",\n            \"UNICODE_TO_UNICODE_FoldSpace\",\n            \"UNICODE_TO_UNICODE_Fullwidth\",\n            \"UNICODE_TO_UNICODE_Halfwidth\",\n            \"UNICODE_TO_UNICODE_NFC\",\n            \"UNICODE_TO_UNICODE_NFD\",\n            \"UNICODE_TO_UNICODE_NFKC\",\n            \"UNICODE_TO_UNICODE_NFKD\",\n        }\n\n        FUNC_TOKENS = {*parser.Parser.FUNC_TOKENS}\n        FUNC_TOKENS.remove(TokenType.REPLACE)\n\n        STATEMENT_PARSERS = {\n            **parser.Parser.STATEMENT_PARSERS,\n            TokenType.REPLACE: lambda self: self._parse_create(),\n        }\n\n        FUNCTION_PARSERS = {\n            **parser.Parser.FUNCTION_PARSERS,\n            \"RANGE_N\": lambda self: self._parse_rangen(),\n            \"TRANSLATE\": lambda self: self._parse_translate(self.STRICT_CAST),\n        }\n\n        def _parse_translate(self, strict: bool) -> exp.Expression:\n            this = self._parse_conjunction()\n\n            if not self._match(TokenType.USING):\n                self.raise_error(\"Expected USING in TRANSLATE\")\n\n            if self._match_texts(self.CHARSET_TRANSLATORS):\n                charset_split = self._prev.text.split(\"_TO_\")\n                to = self.expression(exp.CharacterSet, this=charset_split[1])\n            else:\n                self.raise_error(\"Expected a character set translator after USING in TRANSLATE\")\n\n            return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to)\n\n        # FROM before SET in Teradata UPDATE syntax\n        # https://docs.teradata.com/r/Enterprise_IntelliFlex_VMware/Teradata-VantageTM-SQL-Data-Manipulation-Language-17.20/Statement-Syntax/UPDATE/UPDATE-Syntax-Basic-Form-FROM-Clause\n        def _parse_update(self) -> exp.Update:\n            return self.expression(\n                exp.Update,\n                **{  # type: ignore\n                    \"this\": self._parse_table(alias_tokens=self.UPDATE_ALIAS_TOKENS),\n                    \"from\": self._parse_from(joins=True),\n                    \"expressions\": self._match(TokenType.SET)\n                    and self._parse_csv(self._parse_equality),\n                    \"where\": self._parse_where(),\n                },\n            )\n\n        def _parse_rangen(self):\n            this = self._parse_id_var()\n            self._match(TokenType.BETWEEN)\n\n            expressions = self._parse_csv(self._parse_conjunction)\n            each = self._match_text_seq(\"EACH\") and self._parse_conjunction()\n\n            return self.expression(exp.RangeN, this=this, expressions=expressions, each=each)\n\n    class Generator(generator.Generator):\n        JOIN_HINTS = False\n        TABLE_HINTS = False\n        QUERY_HINTS = False\n\n        TYPE_MAPPING = {\n            **generator.Generator.TYPE_MAPPING,\n            exp.DataType.Type.GEOMETRY: \"ST_GEOMETRY\",\n        }\n\n        PROPERTIES_LOCATION = {\n            **generator.Generator.PROPERTIES_LOCATION,\n            exp.OnCommitProperty: exp.Properties.Location.POST_INDEX,\n            exp.PartitionedByProperty: exp.Properties.Location.POST_EXPRESSION,\n            exp.StabilityProperty: exp.Properties.Location.POST_CREATE,\n        }\n\n        TRANSFORMS = {\n            **generator.Generator.TRANSFORMS,\n            exp.Max: max_or_greatest,\n            exp.Min: min_or_least,\n            exp.Select: transforms.preprocess([transforms.eliminate_distinct_on]),\n            exp.StrToDate: lambda self, e: f\"CAST({self.sql(e, 'this')} AS DATE FORMAT {self.format_time(e)})\",\n            exp.ToChar: lambda self, e: self.function_fallback_sql(e),\n        }\n\n        def partitionedbyproperty_sql(self, expression: exp.PartitionedByProperty) -> str:\n            return f\"PARTITION BY {self.sql(expression, 'this')}\"\n\n        # FROM before SET in Teradata UPDATE syntax\n        # https://docs.teradata.com/r/Enterprise_IntelliFlex_VMware/Teradata-VantageTM-SQL-Data-Manipulation-Language-17.20/Statement-Syntax/UPDATE/UPDATE-Syntax-Basic-Form-FROM-Clause\n        def update_sql(self, expression: exp.Update) -> str:\n            this = self.sql(expression, \"this\")\n            from_sql = self.sql(expression, \"from\")\n            set_sql = self.expressions(expression, flat=True)\n            where_sql = self.sql(expression, \"where\")\n            sql = f\"UPDATE {this}{from_sql} SET {set_sql}{where_sql}\"\n            return self.prepend_ctes(expression, sql)\n\n        def mod_sql(self, expression: exp.Mod) -> str:\n            return self.binary(expression, \"MOD\")\n\n        def datatype_sql(self, expression: exp.DataType) -> str:\n            type_sql = super().datatype_sql(expression)\n            prefix_sql = expression.args.get(\"prefix\")\n            return f\"SYSUDTLIB.{type_sql}\" if prefix_sql else type_sql\n\n        def rangen_sql(self, expression: exp.RangeN) -> str:\n            this = self.sql(expression, \"this\")\n            expressions_sql = self.expressions(expression)\n            each_sql = self.sql(expression, \"each\")\n            each_sql = f\" EACH {each_sql}\" if each_sql else \"\"\n\n            return f\"RANGE_N({this} BETWEEN {expressions_sql}{each_sql})\"\n\n        def createable_sql(\n            self,\n            expression: exp.Create,\n            locations: dict[exp.Properties.Location, list[exp.Property]],\n        ) -> str:\n            kind = self.sql(expression, \"kind\").upper()\n            if kind == \"TABLE\" and locations.get(exp.Properties.Location.POST_NAME):\n                this_name = self.sql(expression.this, \"this\")\n                this_properties = self.properties(\n                    exp.Properties(expressions=locations[exp.Properties.Location.POST_NAME]),\n                    wrapped=False,\n                    prefix=\",\",\n                )\n                this_schema = self.schema_columns_sql(expression.this)\n                return f\"{this_name}{this_properties}{self.sep()}{this_schema}\"\n            return super().createable_sql(expression, locations)\n", "path": "sqlglot/dialects/teradata.py"}]}