Repository: tobymao/sqlglot

Issue:
Snowflake: ALTER TABLE SET COMMENT is incorrectly rendered as SET TAG
eg:
```
sqlglot.parse_one("ALTER TABLE ingredients SET comment = 'pineapple'", read="snowflake").sql(dialect="snowflake")
```
produces:
```
"ALTER TABLE ingredients SET TAG comment = 'pineapple'"
```

sqlglot 16.4.2



Discussion:

Patch:
diff --git a/sqlglot/dialects/snowflake.py b/sqlglot/dialects/snowflake.py
index 1f620dfc..a902f503 100644
--- a/sqlglot/dialects/snowflake.py
+++ b/sqlglot/dialects/snowflake.py
@@ -258,15 +258,15 @@ class Snowflake(Dialect):
 
         ALTER_PARSERS = {
             **parser.Parser.ALTER_PARSERS,
-            "UNSET": lambda self: self._parse_alter_table_set_tag(unset=True),
-            "SET": lambda self: self._parse_alter_table_set_tag(),
+            "SET": lambda self: self._parse_set(tag=self._match_text_seq("TAG")),
+            "UNSET": lambda self: self.expression(
+                exp.Set,
+                tag=self._match_text_seq("TAG"),
+                expressions=self._parse_csv(self._parse_id_var),
+                unset=True,
+            ),
         }
 
-        def _parse_alter_table_set_tag(self, unset: bool = False) -> exp.Expression:
-            self._match_text_seq("TAG")
-            parser = t.cast(t.Callable, self._parse_id_var if unset else self._parse_conjunction)
-            return self.expression(exp.SetTag, expressions=self._parse_csv(parser), unset=unset)
-
     class Tokenizer(tokens.Tokenizer):
         QUOTES = ["'", "$$"]
         STRING_ESCAPES = ["\\", "'"]
@@ -380,10 +380,6 @@ class Snowflake(Dialect):
                 self.unsupported("INTERSECT with All is not supported in Snowflake")
             return super().intersect_op(expression)
 
-        def settag_sql(self, expression: exp.SetTag) -> str:
-            action = "UNSET" if expression.args.get("unset") else "SET"
-            return f"{action} TAG {self.expressions(expression)}"
-
         def describe_sql(self, expression: exp.Describe) -> str:
             # Default to table if kind is unknown
             kind_value = expression.args.get("kind") or "TABLE"
diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py
index 1c0af58a..7e53d697 100644
--- a/sqlglot/expressions.py
+++ b/sqlglot/expressions.py
@@ -1013,7 +1013,7 @@ class Pragma(Expression):
 
 
 class Set(Expression):
-    arg_types = {"expressions": False}
+    arg_types = {"expressions": False, "unset": False, "tag": False}
 
 
 class SetItem(Expression):
@@ -1168,10 +1168,6 @@ class RenameTable(Expression):
     pass
 
 
-class SetTag(Expression):
-    arg_types = {"expressions": True, "unset": False}
-
-
 class Comment(Expression):
     arg_types = {"this": True, "kind": True, "expression": True, "exists": False}
 
diff --git a/sqlglot/generator.py b/sqlglot/generator.py
index 81e0ac3a..0030c8b3 100644
--- a/sqlglot/generator.py
+++ b/sqlglot/generator.py
@@ -1408,7 +1408,8 @@ class Generator:
         expressions = (
             f" {self.expressions(expression, flat=True)}" if expression.expressions else ""
         )
-        return f"SET{expressions}"
+        tag = " TAG" if expression.args.get("tag") else ""
+        return f"{'UNSET' if expression.args.get('unset') else 'SET'}{tag}{expressions}"
 
     def pragma_sql(self, expression: exp.Pragma) -> str:
         return f"PRAGMA {self.sql(expression, 'this')}"
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
index e16a88e5..089ea67d 100644
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -4394,8 +4394,8 @@ class Parser(metaclass=_Parser):
 
         if self._next:
             self._advance()
-        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
 
+        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
         if parser:
             actions = ensure_list(parser(self))
 
@@ -4516,9 +4516,11 @@ class Parser(metaclass=_Parser):
         parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
         return parser(self) if parser else self._parse_set_item_assignment(kind=None)
 
-    def _parse_set(self) -> exp.Set | exp.Command:
+    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
         index = self._index
-        set_ = self.expression(exp.Set, expressions=self._parse_csv(self._parse_set_item))
+        set_ = self.expression(
+            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
+        )
 
         if self._curr:
             self._retreat(index)


Test patch:
diff --git a/tests/dialects/test_snowflake.py b/tests/dialects/test_snowflake.py
index 48bb2f7f..0c735925 100644
--- a/tests/dialects/test_snowflake.py
+++ b/tests/dialects/test_snowflake.py
@@ -23,6 +23,9 @@ class TestSnowflake(Validator):
         self.validate_identity("CREATE TABLE foo (bar FLOAT AUTOINCREMENT START 0 INCREMENT 1)")
         self.validate_identity("ALTER TABLE IF EXISTS foo SET TAG a = 'a', b = 'b', c = 'c'")
         self.validate_identity("ALTER TABLE foo UNSET TAG a, b, c")
+        self.validate_identity("ALTER TABLE foo SET COMMENT = 'bar'")
+        self.validate_identity("ALTER TABLE foo SET CHANGE_TRACKING = FALSE")
+        self.validate_identity("ALTER TABLE foo UNSET DATA_RETENTION_TIME_IN_DAYS, CHANGE_TRACKING")
         self.validate_identity("COMMENT IF EXISTS ON TABLE foo IS 'bar'")
         self.validate_identity("SELECT CONVERT_TIMEZONE('UTC', 'America/Los_Angeles', col)")
         self.validate_identity(