Skip to content

Commit 19370d5

Browse files
authored
fix(postgres): Decouple UNIQUE from DEFAULT constraints (#3775)
1 parent 4bd598a commit 19370d5

File tree

5 files changed

+15
-3
lines changed

5 files changed

+15
-3
lines changed

sqlglot/dialects/postgres.py

+3
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,9 @@ def _parse_date_part(self) -> exp.Expression:
447447

448448
return self.expression(exp.Extract, this=part, expression=value)
449449

450+
def _parse_unique_key(self) -> t.Optional[exp.Expression]:
451+
return None
452+
450453
class Generator(generator.Generator):
451454
SINGLE_STRING_INTERVAL = True
452455
RENAME_TABLE_WITH_DB = False

sqlglot/expressions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1869,7 +1869,7 @@ class TitleColumnConstraint(ColumnConstraintKind):
18691869

18701870

18711871
class UniqueColumnConstraint(ColumnConstraintKind):
1872-
arg_types = {"this": False, "index_type": False, "on_conflict": False}
1872+
arg_types = {"this": False, "index_type": False, "on_conflict": False, "nulls": False}
18731873

18741874

18751875
class UppercaseColumnConstraint(ColumnConstraintKind):

sqlglot/generator.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,8 @@ def uniquecolumnconstraint_sql(self, expression: exp.UniqueColumnConstraint) ->
961961
index_type = f" USING {index_type}" if index_type else ""
962962
on_conflict = self.sql(expression, "on_conflict")
963963
on_conflict = f" {on_conflict}" if on_conflict else ""
964-
return f"UNIQUE{this}{index_type}{on_conflict}"
964+
nulls_sql = " NULLS NOT DISTINCT" if expression.args.get("nulls") else ""
965+
return f"UNIQUE{nulls_sql}{this}{index_type}{on_conflict}"
965966

966967
def createable_sql(self, expression: exp.Create, locations: t.DefaultDict) -> str:
967968
return self.sql(expression, "this")

sqlglot/parser.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -5179,11 +5179,15 @@ def _parse_unnamed_constraint(
51795179

51805180
return self.CONSTRAINT_PARSERS[constraint](self)
51815181

5182+
def _parse_unique_key(self) -> t.Optional[exp.Expression]:
5183+
return self._parse_id_var(any_token=False)
5184+
51825185
def _parse_unique(self) -> exp.UniqueColumnConstraint:
51835186
self._match_text_seq("KEY")
51845187
return self.expression(
51855188
exp.UniqueColumnConstraint,
5186-
this=self._parse_schema(self._parse_id_var(any_token=False)),
5189+
nulls=self._match_text_seq("NULLS", "NOT", "DISTINCT"),
5190+
this=self._parse_schema(self._parse_unique_key()),
51875191
index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
51885192
on_conflict=self._parse_on_conflict(),
51895193
)

tests/dialects/test_postgres.py

+4
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,10 @@ def test_ddl(self):
977977
},
978978
)
979979

980+
self.validate_identity("CREATE TABLE tbl (col INT UNIQUE NULLS NOT DISTINCT DEFAULT 9.99)")
981+
self.validate_identity("CREATE TABLE tbl (col UUID UNIQUE DEFAULT GEN_RANDOM_UUID())")
982+
self.validate_identity("CREATE TABLE tbl (col UUID, UNIQUE NULLS NOT DISTINCT (col))")
983+
980984
with self.assertRaises(ParseError):
981985
transpile("CREATE TABLE products (price DECIMAL CHECK price > 0)", read="postgres")
982986
with self.assertRaises(ParseError):

0 commit comments

Comments
 (0)