From 4851ce16f08817c5f7de4bcdb12c0bcfd8025f2b Mon Sep 17 00:00:00 2001 From: Toby Mao Date: Thu, 24 Nov 2022 20:49:47 -0800 Subject: [PATCH] Like (#760) * added ability to parse LIKE in CREATE TABLE statement * fixed formatting * had to change formatting again * added EXCLUDING as well * refactor including/excluding Co-authored-by: Yuchao --- sqlglot/dialects/mysql.py | 1 + sqlglot/expressions.py | 4 ++++ sqlglot/generator.py | 6 ++++++ sqlglot/parser.py | 15 +++++++++++++++ tests/dialects/test_mysql.py | 2 ++ tests/dialects/test_postgres.py | 4 ++++ 6 files changed, 32 insertions(+) diff --git a/sqlglot/dialects/mysql.py b/sqlglot/dialects/mysql.py index 93a60f494a..7627b6e666 100644 --- a/sqlglot/dialects/mysql.py +++ b/sqlglot/dialects/mysql.py @@ -453,6 +453,7 @@ class Generator(generator.Generator): exp.CharacterSetProperty, exp.CollateProperty, exp.SchemaCommentProperty, + exp.LikeProperty, } WITH_PROPERTIES: t.Set[t.Type[exp.Property]] = set() diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py index 6a4c2d13d4..11893e8035 100644 --- a/sqlglot/expressions.py +++ b/sqlglot/expressions.py @@ -1075,6 +1075,10 @@ class DistStyleProperty(Property): arg_types = {"this": True} +class LikeProperty(Property): + arg_types = {"this": True, "expressions": False} + + class LocationProperty(Property): arg_types = {"this": True} diff --git a/sqlglot/generator.py b/sqlglot/generator.py index b411bdea84..81fa9db11b 100644 --- a/sqlglot/generator.py +++ b/sqlglot/generator.py @@ -94,6 +94,7 @@ class Generator: exp.DistStyleProperty, exp.DistKeyProperty, exp.SortKeyProperty, + exp.LikeProperty, } WITH_PROPERTIES = { @@ -568,6 +569,11 @@ def property_sql(self, expression): return f"{property_name}={self.sql(expression, 'this')}" + def likeproperty_sql(self, expression): + options = " ".join(f"{e.name} {self.sql(e, 'value')}" for e in expression.expressions) + options = f" {options}" if options else "" + return f"LIKE {self.sql(expression, 'this')}{options}" + def insert_sql(self, expression): overwrite = expression.args.get("overwrite") diff --git a/sqlglot/parser.py b/sqlglot/parser.py index be917e35b8..be9d85735d 100644 --- a/sqlglot/parser.py +++ b/sqlglot/parser.py @@ -470,6 +470,7 @@ class Parser(metaclass=_Parser): TokenType.DISTKEY: lambda self: self._parse_distkey(), TokenType.DISTSTYLE: lambda self: self._parse_property_assignment(exp.DistStyleProperty), TokenType.SORTKEY: lambda self: self._parse_sortkey(), + TokenType.LIKE: lambda self: self._parse_create_like(), TokenType.RETURNS: lambda self: self._parse_returns(), TokenType.COLLATE: lambda self: self._parse_property_assignment(exp.CollateProperty), TokenType.COMMENT: lambda self: self._parse_property_assignment(exp.SchemaCommentProperty), @@ -500,6 +501,7 @@ class Parser(metaclass=_Parser): ), TokenType.FOREIGN_KEY: lambda self: self._parse_foreign_key(), TokenType.UNIQUE: lambda self: self._parse_unique(), + TokenType.LIKE: lambda self: self._parse_create_like(), } NO_PAREN_FUNCTION_PARSERS = { @@ -882,6 +884,19 @@ def _parse_stored(self): def _parse_distkey(self): return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_var)) + def _parse_create_like(self): + table = self._parse_table(schema=True) + options = [] + while self._match_texts(("INCLUDING", "EXCLUDING")): + options.append( + self.expression( + exp.Property, + this=self._prev.text.upper(), + value=exp.Var(this=self._parse_id_var().this.upper()), + ) + ) + return self.expression(exp.LikeProperty, this=table, expressions=options) + def _parse_sortkey(self, compound=False): return self.expression( exp.SortKeyProperty, this=self._parse_wrapped_csv(self._parse_var), compound=compound diff --git a/tests/dialects/test_mysql.py b/tests/dialects/test_mysql.py index af98249058..79fe32a490 100644 --- a/tests/dialects/test_mysql.py +++ b/tests/dialects/test_mysql.py @@ -23,6 +23,8 @@ def test_identity(self): self.validate_identity("SELECT TRIM('bla' FROM ' XXX ')") self.validate_identity("@@GLOBAL.max_connections") + self.validate_identity("CREATE TABLE A LIKE B") + # SET Commands self.validate_identity("SET @var_name = expr") self.validate_identity("SET @name = 43") diff --git a/tests/dialects/test_postgres.py b/tests/dialects/test_postgres.py index c41fe01d80..ff16a96afd 100644 --- a/tests/dialects/test_postgres.py +++ b/tests/dialects/test_postgres.py @@ -98,6 +98,10 @@ def test_postgres(self): "spark": "CREATE TABLE x (a UUID, b BINARY)", }, ) + + self.validate_identity( + "CREATE TABLE A (LIKE B INCLUDING CONSTRAINT INCLUDING COMPRESSION EXCLUDING COMMENTS)" + ) self.validate_all( "SELECT SUM(x) OVER (PARTITION BY a ORDER BY d ROWS 1 PRECEDING)", write={