From cf253dc9e0d6ab1591393dc67b5a8e79023d9e48 Mon Sep 17 00:00:00 2001 From: George Sittas Date: Mon, 9 Sep 2024 17:49:15 +0300 Subject: [PATCH] Fix(mysql): convert VARCHAR without size to TEXT for DDLs --- sqlglot/dialects/doris.py | 1 + sqlglot/dialects/mysql.py | 10 ++++++++++ sqlglot/dialects/starrocks.py | 1 + tests/dialects/test_mysql.py | 8 ++++++++ 4 files changed, 20 insertions(+) diff --git a/sqlglot/dialects/doris.py b/sqlglot/dialects/doris.py index 0891b495fa..05fb32ade8 100644 --- a/sqlglot/dialects/doris.py +++ b/sqlglot/dialects/doris.py @@ -40,6 +40,7 @@ class Parser(MySQL.Parser): class Generator(MySQL.Generator): LAST_DAY_SUPPORTS_DATE_PART = False + VARCHAR_REQUIRES_SIZE = False TYPE_MAPPING = { **MySQL.Generator.TYPE_MAPPING, diff --git a/sqlglot/dialects/mysql.py b/sqlglot/dialects/mysql.py index 2508596283..ff9042042b 100644 --- a/sqlglot/dialects/mysql.py +++ b/sqlglot/dialects/mysql.py @@ -690,6 +690,7 @@ class Generator(generator.Generator): PARSE_JSON_NAME: t.Optional[str] = None PAD_FILL_PATTERN_IS_REQUIRED = True WRAP_DERIVED_VALUES = False + VARCHAR_REQUIRES_SIZE = True TRANSFORMS = { **generator.Generator.TRANSFORMS, @@ -1117,10 +1118,19 @@ def extract_sql(self, expression: exp.Extract) -> str: return super().extract_sql(expression) def datatype_sql(self, expression: exp.DataType) -> str: + if ( + self.VARCHAR_REQUIRES_SIZE + and expression.is_type(exp.DataType.Type.VARCHAR) + and not expression.expressions + ): + # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT` + return "TEXT" + # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html result = super().datatype_sql(expression) if expression.this in self.UNSIGNED_TYPE_MAPPING: result = f"{result} UNSIGNED" + return result def jsonarraycontains_sql(self, expression: exp.JSONArrayContains) -> str: diff --git a/sqlglot/dialects/starrocks.py b/sqlglot/dialects/starrocks.py index f38c4e6d4a..d447f59797 100644 --- a/sqlglot/dialects/starrocks.py +++ b/sqlglot/dialects/starrocks.py @@ -73,6 +73,7 @@ def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]: class Generator(MySQL.Generator): EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False JSON_TYPE_REQUIRED_FOR_EXTRACTION = False + VARCHAR_REQUIRES_SIZE = False PARSE_JSON_NAME: t.Optional[str] = "PARSE_JSON" WITH_PROPERTIES_PREFIX = "PROPERTIES" diff --git a/tests/dialects/test_mysql.py b/tests/dialects/test_mysql.py index 2fd9ef07dc..2f1f7ba57b 100644 --- a/tests/dialects/test_mysql.py +++ b/tests/dialects/test_mysql.py @@ -81,6 +81,10 @@ def test_ddl(self): self.validate_identity( "CREATE OR REPLACE VIEW my_view AS SELECT column1 AS `boo`, column2 AS `foo` FROM my_table WHERE column3 = 'some_value' UNION SELECT q.* FROM fruits_table, JSON_TABLE(Fruits, '$[*]' COLUMNS(id VARCHAR(255) PATH '$.$id', value VARCHAR(255) PATH '$.value')) AS q", ) + self.validate_identity( + "CREATE TABLE t (name VARCHAR)", + "CREATE TABLE t (name TEXT)", + ) self.validate_identity( "ALTER TABLE t ADD KEY `i` (`c`)", "ALTER TABLE t ADD INDEX `i` (`c`)", @@ -175,6 +179,10 @@ def test_identity(self): self.validate_identity( "REPLACE INTO table SELECT id FROM table2 WHERE cnt > 100", check_command_warning=True ) + self.validate_identity( + "CAST(x AS VARCHAR)", + "CAST(x AS CHAR)", + ) self.validate_identity( """SELECT * FROM foo WHERE 3 MEMBER OF(info->'$.value')""", """SELECT * FROM foo WHERE 3 MEMBER OF(JSON_EXTRACT(info, '$.value'))""",