Skip to content
Merged
3 changes: 3 additions & 0 deletions sqlglot/generators/postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,9 @@ def datatype_sql(self, expression: exp.DataType) -> str:
return f"{self.expressions(expression, flat=True)}[{values}]"
return "ARRAY"

if expression.is_type(exp.DType.ENUM) and expression.expressions:
Comment thread
georgesittas marked this conversation as resolved.
Outdated
return f"ENUM ({self.expressions(expression, flat=True)})"

if expression.is_type(exp.DType.DOUBLE, exp.DType.FLOAT) and expression.expressions:
# Postgres doesn't support precision for REAL and DOUBLE PRECISION types
return f"FLOAT({self.expressions(expression, flat=True)})"
Expand Down
20 changes: 20 additions & 0 deletions sqlglot/parsers/postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,26 @@ class PostgresParser(parser.Parser):

ARG_MODE_TOKENS: t.ClassVar = {TokenType.IN, TokenType.OUT, TokenType.INOUT, TokenType.VARIADIC}

def _parse_create(self) -> exp.Create | exp.Command:
start = self._prev

if not self._match_text_seq("TYPE"):
return super()._parse_create()
Comment thread
georgesittas marked this conversation as resolved.
Outdated

this = self._parse_table_parts(schema=True)
if not this or not self._match(TokenType.ALIAS):
return self._parse_as_command(start)

if self._match(TokenType.ENUM, advance=False):
expression = self._parse_types()
Comment thread
georgesittas marked this conversation as resolved.
Outdated
else:
expression = self._parse_schema()

if not expression or self._curr:
return self._parse_as_command(start)
Comment thread
georgesittas marked this conversation as resolved.
Outdated

return self.expression(exp.Create(this=this, kind="TYPE", expression=expression))

def _parse_parameter_mode(self) -> TokenType | None:
"""
Parse PostgreSQL function parameter mode (IN, OUT, INOUT, VARIADIC).
Expand Down
33 changes: 33 additions & 0 deletions tests/dialects/test_postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,39 @@ def test_ddl(self):
exp.DataType
)

create_type = self.parse_one("CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy')")
Comment thread
georgesittas marked this conversation as resolved.
Outdated
self.assertIsInstance(create_type, exp.Create)
self.assertEqual(create_type.kind, "TYPE")
self.assertEqual(create_type.this, exp.to_table("mood"))
Comment thread
georgesittas marked this conversation as resolved.
Outdated

enum_type = create_type.expression
self.assertIsInstance(enum_type, exp.DataType)
self.assertTrue(enum_type.is_type(exp.DType.ENUM))
self.assertEqual([value.name for value in enum_type.expressions], ["sad", "ok", "happy"])
self.validate_identity("CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy')")

create_type = self.parse_one(
"CREATE TYPE inventory_item AS (name TEXT, supplier_id INT, price DECIMAL)"
)
self.assertIsInstance(create_type, exp.Create)
self.assertEqual(create_type.kind, "TYPE")

composite_type = create_type.expression
self.assertIsInstance(composite_type, exp.Schema)
columns = composite_type.expressions
self.assertEqual([column.this.name for column in columns], ["name", "supplier_id", "price"])
self.assertEqual(
[column.kind.this for column in columns],
[exp.DType.TEXT, exp.DType.INT, exp.DType.DECIMAL],
)
Comment thread
georgesittas marked this conversation as resolved.
Outdated
self.validate_identity(
"CREATE TYPE inventory_item AS (name TEXT, supplier_id INT, price DECIMAL)"
)

create_type = self.parse_one("CREATE TYPE public.mood AS ENUM ('sad', 'ok')")
self.assertEqual(create_type.this.sql(dialect="postgres"), "public.mood")
self.validate_identity("CREATE TYPE public.mood AS ENUM ('sad', 'ok')")

# Checks that OID is parsed into a DataType (ObjectIdentifier)
self.assertIsInstance(
self.parse_one("CREATE TABLE p.t (c oid)").find(exp.DataType), exp.ObjectIdentifier
Expand Down
Loading