Skip to content

Commit 707d45e

Browse files
authored
fix(tsql): support default values on definitons and the OUTPUT/OUT/READ_ONLY syntax (#4704)
* fix(tsql): support default values on definitons and the OUTPUT/OUT/READ_ONLY syntax * PR feedback 1 * PR feedback 1 v2 * PR feedback 1 (removed test) * PR feedback 2 * PR feedback 2 (refactor)
1 parent c31947b commit 707d45e

File tree

4 files changed

+44
-2
lines changed

4 files changed

+44
-2
lines changed

sqlglot/dialects/tsql.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,8 @@ class Parser(parser.Parser):
598598
("ENCRYPTION", "RECOMPILE", "SCHEMABINDING", "NATIVE_COMPILATION", "EXECUTE"), tuple()
599599
)
600600

601+
COLUMN_DEFINITION_MODES = {"OUT", "OUTPUT", "READ_ONLY"}
602+
601603
RETURNS_TABLE_TOKENS = parser.Parser.ID_VAR_TOKENS - {
602604
TokenType.TABLE,
603605
*parser.Parser.TYPE_TOKENS,
@@ -736,6 +738,18 @@ def _parse_convert(
736738
convert.set("strict", strict)
737739
return convert
738740

741+
def _parse_column_def(
742+
self, this: t.Optional[exp.Expression], computed_column: bool = True
743+
) -> t.Optional[exp.Expression]:
744+
this = super()._parse_column_def(this=this, computed_column=computed_column)
745+
if not this:
746+
return None
747+
if self._match(TokenType.EQ):
748+
this.set("default", self._parse_disjunction())
749+
if self._match_texts(self.COLUMN_DEFINITION_MODES):
750+
this.set("output", self._prev.text)
751+
return this
752+
739753
def _parse_user_defined_function(
740754
self, kind: t.Optional[TokenType] = None
741755
) -> t.Optional[exp.Expression]:
@@ -1290,3 +1304,11 @@ def dpipe_sql(self, expression: exp.DPipe) -> str:
12901304

12911305
def isascii_sql(self, expression: exp.IsAscii) -> str:
12921306
return f"(PATINDEX(CONVERT(VARCHAR(MAX), 0x255b5e002d7f5d25) COLLATE Latin1_General_BIN, {self.sql(expression.this)}) = 0)"
1307+
1308+
def columndef_sql(self, expression: exp.ColumnDef, sep: str = " ") -> str:
1309+
this = super().columndef_sql(expression, sep)
1310+
default = self.sql(expression, "default")
1311+
default = f" = {default}" if default else ""
1312+
output = self.sql(expression, "output")
1313+
output = f" {output}" if output else ""
1314+
return f"{this}{default}{output}"

sqlglot/expressions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1675,6 +1675,8 @@ class ColumnDef(Expression):
16751675
"constraints": False,
16761676
"exists": False,
16771677
"position": False,
1678+
"default": False,
1679+
"output": False,
16781680
}
16791681

16801682
@property

sqlglot/parser.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5551,7 +5551,7 @@ def _parse_user_defined_function_expression(self) -> t.Optional[exp.Expression]:
55515551
return self._parse_statement()
55525552

55535553
def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
5554-
return self._parse_column_def(self._parse_id_var())
5554+
return self._parse_column_def(this=self._parse_id_var(), computed_column=False)
55555555

55565556
def _parse_user_defined_function(
55575557
self, kind: t.Optional[TokenType] = None
@@ -5638,11 +5638,16 @@ def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[e
56385638
def _parse_field_def(self) -> t.Optional[exp.Expression]:
56395639
return self._parse_column_def(self._parse_field(any_token=True))
56405640

5641-
def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5641+
def _parse_column_def(
5642+
self, this: t.Optional[exp.Expression], computed_column: bool = True
5643+
) -> t.Optional[exp.Expression]:
56425644
# column defs are not really columns, they're identifiers
56435645
if isinstance(this, exp.Column):
56445646
this = this.this
56455647

5648+
if not computed_column:
5649+
self._match(TokenType.ALIAS)
5650+
56465651
kind = self._parse_types(schema=True)
56475652

56485653
if self._match_text_seq("FOR", "ORDINALITY"):

tests/dialects/test_tsql.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,19 @@ def test_tsql(self):
456456
with self.assertRaises(ParseError):
457457
parse_one("SELECT begin", read="tsql")
458458

459+
self.validate_identity("CREATE PROCEDURE test(@v1 INTEGER = 1, @v2 CHAR(1) = 'c')")
460+
self.validate_identity("DECLARE @v1 AS INTEGER = 1, @v2 AS CHAR(1) = 'c')")
461+
462+
for output in ("OUT", "OUTPUT", "READ_ONLY"):
463+
self.validate_identity(
464+
f"CREATE PROCEDURE test(@v1 INTEGER = 1 {output}, @v2 CHAR(1) {output})"
465+
)
466+
467+
self.validate_identity(
468+
"CREATE PROCEDURE test(@v1 AS INTEGER = 1, @v2 AS CHAR(1) = 'c')",
469+
"CREATE PROCEDURE test(@v1 INTEGER = 1, @v2 CHAR(1) = 'c')",
470+
)
471+
459472
def test_option(self):
460473
possible_options = [
461474
"HASH GROUP",

0 commit comments

Comments
 (0)