Repository: tobymao/sqlglot

Issue:
`CREATE INDEX CONCURRENTLY` not parsed by postgres dialect
These all parse
```
sqlglot.parse_one("CREATE INDEX ix_table_id ON tbl USING btree (id);", read="postgres", dialect="postgres")
sqlglot.parse_one("CREATE INDEX IF NOT EXISTS ix_table_id ON tbl USING btree (id);", read="postgres", dialect="postgres")
sqlglot.parse_one("CREATE UNIQUE INDEX ix_table_id ON tbl USING btree (id);", read="postgres", dialect="postgres")
sqlglot.parse_one("CREATE UNIQUE INDEX IF NOT EXISTS ix_table_id ON tbl USING btree (id);", read="postgres", dialect="postgres")
```

These fail to parse (correctly)
```
sqlglot.parse_one("CREATE INDEX CONCURRENTLY ix_table_id ON tbl USING btree (id);", read="postgres", dialect="postgres")
sqlglot.parse_one("CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_table_id ON tbl USING btree (id);", read="postgres", dialect="postgres")
```

`'CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_table_id ON tbl USING btree (id)' contains unsupported syntax. Falling back to parsing as a 'Command'.`

From the documentation https://www.postgresql.org/docs/current/sql-createindex.html I belive it is just the `CONCURRENTLY` keyword that is an issue.

`CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON [ ONLY ] table_name [ USING method ]`


Discussion:

Patch:
diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py
index d905a2ba..8222bb5d 100644
--- a/sqlglot/expressions.py
+++ b/sqlglot/expressions.py
@@ -2015,6 +2015,7 @@ class Drop(Expression):
         "constraints": False,
         "purge": False,
         "cluster": False,
+        "concurrently": False,
     }
 
     @property
diff --git a/sqlglot/generator.py b/sqlglot/generator.py
index a19325d4..0dc4fa75 100644
--- a/sqlglot/generator.py
+++ b/sqlglot/generator.py
@@ -1290,6 +1290,7 @@ class Generator(metaclass=_Generator):
         kind = expression.args["kind"]
         kind = self.dialect.INVERSE_CREATABLE_KIND_MAPPING.get(kind) or kind
         exists_sql = " IF EXISTS " if expression.args.get("exists") else " "
+        concurrently_sql = " CONCURRENTLY" if expression.args.get("concurrently") else ""
         on_cluster = self.sql(expression, "cluster")
         on_cluster = f" {on_cluster}" if on_cluster else ""
         temporary = " TEMPORARY" if expression.args.get("temporary") else ""
@@ -1297,7 +1298,7 @@ class Generator(metaclass=_Generator):
         cascade = " CASCADE" if expression.args.get("cascade") else ""
         constraints = " CONSTRAINTS" if expression.args.get("constraints") else ""
         purge = " PURGE" if expression.args.get("purge") else ""
-        return f"DROP{temporary}{materialized} {kind}{exists_sql}{this}{on_cluster}{expressions}{cascade}{constraints}{purge}"
+        return f"DROP{temporary}{materialized} {kind}{concurrently_sql}{exists_sql}{this}{on_cluster}{expressions}{cascade}{constraints}{purge}"
 
     def set_operation(self, expression: exp.SetOperation) -> str:
         op_type = type(expression)
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
index 05e3e606..b0fc9d13 100644
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -1698,6 +1698,7 @@ class Parser(metaclass=_Parser):
         if not kind:
             return self._parse_as_command(start)
 
+        concurrently = self._match_text_seq("CONCURRENTLY")
         if_exists = exists or self._parse_exists()
         table = self._parse_table_parts(
             schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
@@ -1723,6 +1724,7 @@ class Parser(metaclass=_Parser):
             constraints=self._match_text_seq("CONSTRAINTS"),
             purge=self._match_text_seq("PURGE"),
             cluster=cluster,
+            concurrently=concurrently,
         )
 
     def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:


Test patch:
diff --git a/tests/dialects/test_postgres.py b/tests/dialects/test_postgres.py
index c628db46..daafe0c8 100644
--- a/tests/dialects/test_postgres.py
+++ b/tests/dialects/test_postgres.py
@@ -1023,6 +1023,10 @@ class TestPostgres(Validator):
         self.validate_identity(
             "CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_table_id ON tbl USING btree(id)"
         )
+        self.validate_identity("DROP INDEX ix_table_id")
+        self.validate_identity("DROP INDEX IF EXISTS ix_table_id")
+        self.validate_identity("DROP INDEX CONCURRENTLY ix_table_id")
+        self.validate_identity("DROP INDEX CONCURRENTLY IF EXISTS ix_table_id")
 
         self.validate_identity(
             """