Skip to content
Merged
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
63 changes: 61 additions & 2 deletions sqlglot/dialects/singlestore.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from sqlglot.dialects.mysql import _str_to_date
from sqlglot.expressions import DataType
from sqlglot.generator import ESCAPED_UNICODE_RE, unsupported_args
from sqlglot.helper import csv, seq_get, is_int
from sqlglot.helper import csv, seq_get, is_int, ensure_list
from sqlglot.parser import build_coalesce
from sqlglot.time import format_time
from sqlglot.trie import new_trie
Expand Down Expand Up @@ -457,6 +457,56 @@ def _parse_match_against(self) -> exp.MatchAgainst:

return self.expression(exp.MatchAgainst, this=this, expressions=expressions)

def _parse_alter(self) -> t.Union[exp.Alter, exp.Command]:
start = self._prev

if self._match_text_seq("DEFINER", advance=False):
definer = self._parse_assignment()
else:
definer = None

if self._match_text_seq("SCHEMA_BINDING", "=", "ON"):
schema_binding = True
elif self._match_text_seq("SCHEMA_BINDING", "=", "OFF"):
schema_binding = False
else:
schema_binding = None

alter_token = self._match_set(self.ALTERABLES) and self._prev
if not alter_token:
return self._parse_as_command(start)

exists = self._parse_exists()
only = self._match_text_seq("ONLY")
this = self._parse_table(schema=True)
cluster = self._parse_on_property() if self._match(TokenType.ON) else None

if self._next:
self._advance()

parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
if parser:
actions = ensure_list(parser(self))
not_valid = self._match_text_seq("NOT", "VALID")
options = self._parse_csv(self._parse_property)

if not self._curr and actions:
return self.expression(
exp.Alter,
this=this,
kind=alter_token.text.upper(),
exists=exists,
actions=actions,
only=only,
options=options,
cluster=cluster,
not_valid=not_valid,
definer=definer,
schema_binding=schema_binding,
)

return self._parse_as_command(start)

def _parse_alter_table_set(self) -> exp.AlterSet:
alter_set = self.expression(exp.AlterSet)

Expand Down Expand Up @@ -3596,8 +3646,17 @@ def alter_sql(self, expression: exp.Alter) -> str:
actions_sql = self.format_args(*actions_list).lstrip("\n")

kind = self.sql(expression, "kind")
definer = self.sql(expression, "definer")
definer = f" {definer}" if definer else ""
schema_binding = expression.args.get("schema_binding")
if schema_binding is True:
schema_binding = " SCHEMA_BINDING = ON"
elif schema_binding is False:
schema_binding = " SCHEMA_BINDING = OFF"
else:
schema_binding = ""

return f"ALTER {kind} {self.sql(expression, 'this')} {actions_sql}"
return f"ALTER{definer}{schema_binding} {kind} {self.sql(expression, 'this')} {actions_sql}"

def add_column_sql(self, expression: exp.Expression) -> str:
sql = self.sql(expression)
Expand Down
2 changes: 2 additions & 0 deletions sqlglot/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4856,6 +4856,8 @@ class Alter(Expression):
"options": False,
"cluster": False,
"not_valid": False,
"definer": False,
"schema_binding": False,
}

@property
Expand Down
82 changes: 82 additions & 0 deletions tests/dialects/test_singlestore.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ def setUp(self):
execute_query(
"""CREATE OR REPLACE PROCEDURE proc() RETURNS void AS BEGIN ECHO SELECT 1; END"""
)
execute_query("""DROP VIEW IF EXISTS users_view""")
execute_query("""CREATE VIEW users_view AS SELECT * FROM users""")

def validate_generation(
self,
Expand Down Expand Up @@ -5894,3 +5896,83 @@ def test_alter_database_parsing(self):
actions=[exp.AlterSet(expressions=[exp.Var(this="ASYNC REPLICATION")])],
),
)

def test_alter_view_parsing(self):
self.validate_parsing(
"ALTER VIEW users_view AS SELECT * FROM users",
exp.Alter(
this=exp.Table(this=exp.Identifier(this="users_view", quoted=False)),
kind="VIEW",
actions=[
exp.Select(
**{
"expressions": [exp.Star()],
"from": exp.From(
this=exp.Table(this=exp.Identifier(this="users", quoted=False))
),
}
)
],
),
)
self.validate_parsing(
"ALTER DEFINER = CURRENT_USER() VIEW users_view AS SELECT * FROM users",
exp.Alter(
this=exp.Table(this=exp.Identifier(this="users_view", quoted=False)),
kind="VIEW",
actions=[
exp.Select(
**{
"expressions": [exp.Star()],
"from": exp.From(
this=exp.Table(this=exp.Identifier(this="users", quoted=False))
),
}
)
],
definer=exp.EQ(
this=exp.Column(this=exp.Identifier(this="DEFINER", quoted=False)),
expression=exp.CurrentUser(),
),
),
)
self.validate_parsing(
"ALTER SCHEMA_BINDING = ON VIEW users_view AS SELECT * FROM users",
exp.Alter(
this=exp.Table(this=exp.Identifier(this="users_view", quoted=False)),
kind="VIEW",
actions=[
exp.Select(
**{
"expressions": [exp.Star()],
"from": exp.From(
this=exp.Table(this=exp.Identifier(this="users", quoted=False))
),
}
)
],
schema_binding=True,
),
)
self.validate_parsing(
"ALTER DEFINER = CURRENT_USER() SCHEMA_BINDING = ON VIEW users_view AS SELECT * FROM users",
exp.Alter(
this=exp.Table(this=exp.Identifier(this="users_view", quoted=False)),
kind="VIEW",
actions=[
exp.Select(
**{
"expressions": [exp.Star()],
"from": exp.From(
this=exp.Table(this=exp.Identifier(this="users", quoted=False))
),
}
)
],
definer=exp.EQ(
this=exp.Column(this=exp.Identifier(this="DEFINER", quoted=False)),
expression=exp.CurrentUser(),
),
schema_binding=True,
),
)