Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sqlglot/expressions/ddl.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ class AlterColumn(Expression):


class ModifyColumn(Expression):
arg_types = {"this": True, "rename_from": False}
arg_types = {"this": True, "rename_from": False, "exists": False}


class AlterIndex(Expression):
Expand Down
3 changes: 2 additions & 1 deletion sqlglot/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4229,7 +4229,8 @@ def modifycolumn_sql(self, expression: exp.ModifyColumn) -> str:
return f"CHANGE COLUMN {rename_from} {this}"
if not self.SUPPORTS_MODIFY_COLUMN:
self.unsupported("MODIFY COLUMN is not supported in this dialect")
return f"MODIFY COLUMN {this}"
exists = " IF EXISTS" if expression.args.get("exists") else ""
return f"MODIFY COLUMN{exists} {this}"

def alterindex_sql(self, expression: exp.AlterIndex) -> str:
this = self.sql(expression, "this")
Expand Down
1 change: 1 addition & 0 deletions sqlglot/generators/clickhouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ class ClickHouseGenerator(generator.Generator):
STRUCT_DELIMITER = ("(", ")")
NVL2_SUPPORTED = False
ALTER_SET_TYPE = "TYPE"
SUPPORTS_MODIFY_COLUMN = True
TABLESAMPLE_REQUIRES_PARENS = False
TABLESAMPLE_SIZE_IS_ROWS = False
TABLESAMPLE_KEYWORDS = "SAMPLE"
Expand Down
24 changes: 23 additions & 1 deletion sqlglot/parsers/clickhouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -911,7 +911,29 @@ def _parse_alter_table_replace(self) -> exp.Expr | None:
def _parse_alter_table_modify(self) -> exp.Expr | None:
if properties := self._parse_properties():
return self.expression(exp.AlterModifySqlSecurity(expressions=properties.expressions))
return None

# https://clickhouse.com/docs/sql-reference/statements/alter/column#modify-column
if not self._match(TokenType.COLUMN):
return None

exists = self._parse_exists()
column = self._parse_field(any_token=True)
if column is None:
return None

# REMOVE / MODIFY SETTING / RESET SETTING / ADD ENUM VALUES stay as Command
if (
self._match_texts(("REMOVE", "RESET"), advance=False)
or self._match_text_seq("MODIFY", "SETTING", advance=False)
or self._match_text_seq("ADD", "ENUM", advance=False)
):
return None

column_def = self._parse_column_def(column)
if not isinstance(column_def, exp.ColumnDef):
return None

return self.expression(exp.ModifyColumn(this=column_def, exists=exists or None))

def _parse_definer(self) -> exp.DefinerProperty | None:
self._match(TokenType.EQ)
Expand Down
19 changes: 19 additions & 0 deletions tests/dialects/test_clickhouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,25 @@ def test_clickhouse(self):
},
)

# Native ClickHouse MODIFY COLUMN form (type / default / codec / position)
modify = self.validate_identity("ALTER TABLE t MODIFY COLUMN c Int64").assert_is(exp.Alter)
self.assertIsInstance(modify.args["actions"][0], exp.ModifyColumn)
self.validate_identity("ALTER TABLE t MODIFY COLUMN c Int64 DEFAULT 0")
self.validate_identity("ALTER TABLE t MODIFY COLUMN IF EXISTS c Int64")
self.validate_identity("ALTER TABLE t MODIFY COLUMN c DEFAULT 0")
self.validate_identity("ALTER TABLE t MODIFY COLUMN c CODEC(ZSTD)")
self.validate_identity("ALTER TABLE t MODIFY COLUMN c Int64 FIRST")
self.validate_identity("ALTER TABLE t MODIFY COLUMN c Int64 AFTER b")
self.validate_identity("ALTER TABLE t MODIFY COLUMN c String MATERIALIZED toString(x)")
self.assertIsInstance(
parse_one(
"ALTER TABLE t MODIFY COLUMN c REMOVE DEFAULT",
read="clickhouse",
error_level=ErrorLevel.IGNORE,
),
exp.Command,
)

self.assertIsInstance(
parse_one("Tuple(select Int64)", into=exp.DataType, read="clickhouse"), exp.DataType
)
Expand Down
Loading