Repository: tobymao/sqlglot

Issue:
[sqlite dialect] Parser doesn't recognize optional order parameter for PKEY column-constraint
sqlite's `CREATE TABLE` statement accepts an optional order parameter for `PRIMARY KEY` column-constraints. `sqlglot` does not yet handle this parameter:

```python
create_table_sql = "CREATE TABLE foo (id INTEGER PRIMARY KEY ASC);"
sqlglot.parse_one(create_table_sql, read="sqlite")
```

```shell
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/sqlglot/sqlglot/__init__.py", line 82, in parse_one
    result = dialect.parse(sql, **opts)
  File "/sqlglot/sqlglot/dialects/dialect.py", line 150, in parse
    return self.parser(**opts).parse(self.tokenizer.tokenize(sql), sql)
  File "/sqlglot/sqlglot/parser.py", line 604, in parse
    return self._parse(
  File "/sqlglot/sqlglot/parser.py", line 637, in _parse
    expressions.append(parse_method(self))
  File "/sqlglot/sqlglot/parser.py", line 728, in _parse_statement
    return self.STATEMENT_PARSERS[self._prev.token_type](self)
  File "/sqlglot/sqlglot/parser.py", line 391, in <lambda>
    TokenType.CREATE: lambda self: self._parse_create(),
  File "/sqlglot/sqlglot/parser.py", line 801, in _parse_create
    this = self._parse_table(schema=True)
  File "/sqlglot/sqlglot/parser.py", line 1417, in _parse_table
    return self._parse_schema(this=this)
  File "/sqlglot/sqlglot/parser.py", line 2140, in _parse_schema
    self._match_r_paren()
  File "/sqlglot/sqlglot/parser.py", line 2759, in _match_r_paren
    self.raise_error("Expecting )")
  File "/sqlglot/sqlglot/parser.py", line 665, in raise_error
    raise error
sqlglot.errors.ParseError: Expecting ). Line 1, Col: 42.
  CREATE TABLE foo (id INTEGER PRIMARY KEY ASC);
```


Discussion:

Resolving patch:
diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py
--- a/sqlglot/expressions.py
+++ b/sqlglot/expressions.py
@@ -767,7 +767,7 @@ class NotNullColumnConstraint(ColumnConstraintKind):
 
 
 class PrimaryKeyColumnConstraint(ColumnConstraintKind):
-    pass
+    arg_types = {"desc": False}
 
 
 class UniqueColumnConstraint(ColumnConstraintKind):
diff --git a/sqlglot/generator.py b/sqlglot/generator.py
--- a/sqlglot/generator.py
+++ b/sqlglot/generator.py
@@ -387,8 +387,11 @@ def generatedasidentitycolumnconstraint_sql(self, expression):
     def notnullcolumnconstraint_sql(self, _):
         return "NOT NULL"
 
-    def primarykeycolumnconstraint_sql(self, _):
-        return "PRIMARY KEY"
+    def primarykeycolumnconstraint_sql(self, expression):
+        desc = expression.args.get("desc")
+        if desc is not None:
+            return f"PRIMARY KEY{' DESC' if desc else ' ASC'}"
+        return f"PRIMARY KEY"
 
     def uniquecolumnconstraint_sql(self, _):
         return "UNIQUE"
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -2050,7 +2050,10 @@ def _parse_column_constraint(self):
         elif self._match(TokenType.SCHEMA_COMMENT):
             kind = self.expression(exp.CommentColumnConstraint, this=self._parse_string())
         elif self._match(TokenType.PRIMARY_KEY):
-            kind = exp.PrimaryKeyColumnConstraint()
+            desc = None
+            if self._match(TokenType.ASC) or self._match(TokenType.DESC):
+                desc = self._prev.token_type == TokenType.DESC
+            kind = exp.PrimaryKeyColumnConstraint(desc=desc)
         elif self._match(TokenType.UNIQUE):
             kind = exp.UniqueColumnConstraint()
         elif self._match(TokenType.GENERATED):


Test patch:
diff --git a/tests/dialects/test_sqlite.py b/tests/dialects/test_sqlite.py
--- a/tests/dialects/test_sqlite.py
+++ b/tests/dialects/test_sqlite.py
@@ -5,6 +5,10 @@ class TestSQLite(Validator):
     dialect = "sqlite"
 
     def test_ddl(self):
+        self.validate_all(
+            "CREATE TABLE foo (id INTEGER PRIMARY KEY ASC)",
+            write={"sqlite": "CREATE TABLE foo (id INTEGER PRIMARY KEY ASC)"},
+        )
         self.validate_all(
             """
             CREATE TABLE "Track"
diff --git a/tests/fixtures/identity.sql b/tests/fixtures/identity.sql
--- a/tests/fixtures/identity.sql
+++ b/tests/fixtures/identity.sql
@@ -441,6 +441,7 @@ SELECT student, score FROM tests CROSS JOIN UNNEST(scores) AS t(a, b)
 SELECT student, score FROM tests CROSS JOIN UNNEST(scores) WITH ORDINALITY AS t(a, b)
 SELECT student, score FROM tests CROSS JOIN UNNEST(x.scores) AS t(score)
 SELECT student, score FROM tests CROSS JOIN UNNEST(ARRAY(x.scores)) AS t(score)
+CREATE TABLE foo (id INT PRIMARY KEY ASC)
 CREATE TABLE a.b AS SELECT 1
 CREATE TABLE a.b AS SELECT a FROM a.c
 CREATE TABLE IF NOT EXISTS x AS SELECT a FROM d