Repository: tobymao/sqlglot

Issue:
Error in parsing of `JOIN ... USING` expressions in Snowflake
In Snowflake (maybe in other dialects too), it is valid to specify the column name in `USING` expression  as `TABLE.COL_NAME` (in addition to the more commonly used format of `USING COL_NAME` without specifying a table).

For example, the following query is syntactically valid in Snowflake:
```sql
SELECT * 
FROM T1 
LEFT JOIN T2 USING(T1.a)
```

When trying to parse such query with sqlglot an exception is raised:
```
sqlglot.errors.ParseError: Expecting ). Line 3, Col: 22.
  SELECT * FROM T1 LEFT JOIN T2 USING(T1.a)
```

**Fully reproducible code snippet**
```python
sqlglot.parse(
    sql="""
        SELECT * 
        FROM T1 
        LEFT JOIN T2 USING(T1.a)
    """, 
    dialect=sqlglot.Dialects.SNOWFLAKE)
```

**Official Documentation**
https://docs.snowflake.com/en/sql-reference/constructs/join

Discussion:

Patch:
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
index d43a916e..3a0f529a 100644
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -3198,6 +3198,15 @@ class Parser(metaclass=_Parser):
             self._match_set(self.JOIN_KINDS) and self._prev,
         )
 
+    def _parse_using_identifiers(self) -> t.List[exp.Expression]:
+        def _parse_column_as_identifier() -> t.Optional[exp.Expression]:
+            this = self._parse_column()
+            if isinstance(this, exp.Column):
+                return this.this
+            return this
+
+        return self._parse_wrapped_csv(_parse_column_as_identifier, optional=True)
+
     def _parse_join(
         self, skip_join_token: bool = False, parse_bracket: bool = False
     ) -> t.Optional[exp.Join]:
@@ -3238,7 +3247,7 @@ class Parser(metaclass=_Parser):
         if self._match(TokenType.ON):
             kwargs["on"] = self._parse_assignment()
         elif self._match(TokenType.USING):
-            kwargs["using"] = self._parse_wrapped_id_vars()
+            kwargs["using"] = self._parse_using_identifiers()
         elif not isinstance(kwargs["this"], exp.Unnest) and not (
             kind and kind.token_type == TokenType.CROSS
         ):
@@ -3248,7 +3257,7 @@ class Parser(metaclass=_Parser):
             if joins and self._match(TokenType.ON):
                 kwargs["on"] = self._parse_assignment()
             elif joins and self._match(TokenType.USING):
-                kwargs["using"] = self._parse_wrapped_id_vars()
+                kwargs["using"] = self._parse_using_identifiers()
             else:
                 joins = None
                 self._retreat(index)


Test patch:
diff --git a/tests/dialects/test_snowflake.py b/tests/dialects/test_snowflake.py
index 16ef0196..a84d82a7 100644
--- a/tests/dialects/test_snowflake.py
+++ b/tests/dialects/test_snowflake.py
@@ -138,6 +138,10 @@ WHERE
         self.validate_identity(
             "SELECT * FROM DATA AS DATA_L ASOF JOIN DATA AS DATA_R MATCH_CONDITION (DATA_L.VAL > DATA_R.VAL) ON DATA_L.ID = DATA_R.ID"
         )
+        self.validate_identity(
+            "SELECT * FROM t1 INNER JOIN t2 USING (t1.col)",
+            "SELECT * FROM t1 INNER JOIN t2 USING (col)",
+        )
         self.validate_identity(
             "CURRENT_TIMESTAMP - INTERVAL '1 w' AND (1 = 1)",
             "CURRENT_TIMESTAMP() - INTERVAL '1 WEEK' AND (1 = 1)",