Repository: sqlfluff/sqlfluff

Issue:
Support alternative indentation of USING
Nice project. This is going to be really useful for us as we have a lot of BigQuery queries that other linters I've tried have struggled with.

However for JOINS, our preference is for this format:

```sql
SELECT
  a,
  b
FROM
  table1
JOIN
  table2
USING (a, b)
```

That is the `USING` is at the same indentation as the `JOIN`. To us it's another clause and so should be indented to the same level as the `SELECT`, `FROM`, and `JOIN`.

However sqlfluff doesn't like this so we need to disable L003, which is a shame as I'd like to have that enabled for other reasons.

Is there any possibility of either:
1. Adding an exception config to L003 to allow certain keywords (`USING` in our case, but probably also `ON`) to be automatically ignored, without adding a `-- noqa: L003` line to every instance of this or changing our preferred style?
2. Supporting this in a better way (so it would ideally actually check that `USING` is at the same level as `SELECT`, `FROM`, and `JOIN`).



Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e7b10f55..e01391e38 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Support for DETERMINISTIC user defined functions in BigQuery dialect [#1251](https://github.com/sqlfluff/sqlfluff/issues/1251)
 - Support more identifiers in BigQuery dialect [#1253](https://github.com/sqlfluff/sqlfluff/issues/1253)
 - Support function member field references in BigQuery dialect [#1255](https://github.com/sqlfluff/sqlfluff/issues/1255)
+- Support alternative indentation for USING and ON clauses [#1250](https://github.com/sqlfluff/sqlfluff/issues/1250)
 
 ## [0.6.2] - 2021-07-22
 ### Added
diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst
index 261257c10..d3e5240b2 100644
--- a/docs/source/configuration.rst
+++ b/docs/source/configuration.rst
@@ -41,6 +41,7 @@ For example
 
     [tool.sqlfluff.indentation]
     indented_joins = false
+    indented_using_on = true
     template_blocks_indent = false
 
     [tool.sqlfluff.templater]
diff --git a/docs/source/indentation.rst b/docs/source/indentation.rst
index 8d1cc0542..e2f3de32f 100644
--- a/docs/source/indentation.rst
+++ b/docs/source/indentation.rst
@@ -196,6 +196,18 @@ However if no value for :code:`indented_joins` is set, or if it is set to
    JOIN another_table
       USING(a)
 
+There is a similar :code:`indented_using_on` config (defaulted to :code:`true`)
+which can be set to :code:`false` to prevent the :code:`using` clause from
+being indented, in which case above SQL would become:
+
+.. code-block:: sql
+
+   SELECT
+      a, b, c
+   FROM my_table
+   JOIN another_table
+   USING(a)
+
 By default, *SQLFluff* aims to follow the indentation most common approach
 to indentation. However, if you have other versions of indentation which are
 supported by published style guides, then please submit an issue on github
diff --git a/src/sqlfluff/core/default_config.cfg b/src/sqlfluff/core/default_config.cfg
index 27050c1bc..fb514f5b2 100644
--- a/src/sqlfluff/core/default_config.cfg
+++ b/src/sqlfluff/core/default_config.cfg
@@ -17,6 +17,7 @@ sql_file_exts = .sql,.sql.j2,.dml,.ddl
 
 [sqlfluff:indentation]
 indented_joins = False
+indented_using_on = True
 template_blocks_indent = True
 
 [sqlfluff:templater]
diff --git a/src/sqlfluff/dialects/dialect_ansi.py b/src/sqlfluff/dialects/dialect_ansi.py
index e57225ae8..7c8cd596c 100644
--- a/src/sqlfluff/dialects/dialect_ansi.py
+++ b/src/sqlfluff/dialects/dialect_ansi.py
@@ -1183,6 +1183,7 @@ class JoinClauseSegment(BaseSegment):
         Indent,
         Sequence(
             Ref("FromExpressionElementSegment"),
+            Conditional(Dedent, indented_using_on=False),
             # NB: this is optional
             OneOf(
                 # ON clause
@@ -1209,6 +1210,7 @@ class JoinClauseSegment(BaseSegment):
                 # be a good idea.
                 optional=True,
             ),
+            Conditional(Indent, indented_using_on=False),
         ),
         Dedent,
     )
@@ -1242,7 +1244,7 @@ ansi_dialect.add(
 class FromClauseSegment(BaseSegment):
     """A `FROM` clause like in `SELECT`.
 
-    NOTE: thiis is a delimited set of table expressions, with a variable
+    NOTE: this is a delimited set of table expressions, with a variable
     number of optional join clauses with those table expressions. The
     delmited aspect is the higher of the two such that the following is
     valid (albeit unusual):


Test patch:
diff --git a/test/fixtures/rules/std_rule_cases/L003.yml b/test/fixtures/rules/std_rule_cases/L003.yml
index 7ccd63c5e..f87b2ba4c 100644
--- a/test/fixtures/rules/std_rule_cases/L003.yml
+++ b/test/fixtures/rules/std_rule_cases/L003.yml
@@ -115,6 +115,98 @@ test_fail_indented_joins_false_fix:
     indentation:
       indented_joins: false
 
+test_pass_indented_using_on_default:
+  # Configurable using_on indents work.
+  # 2.a) default
+  pass_str: |
+    SELECT a, b, c
+    FROM my_tbl
+    LEFT JOIN another_tbl
+        USING(a)
+
+test_pass_indented_using_on_true:
+  # 2.b) specific
+  pass_str: |
+    SELECT a, b, c
+    FROM my_tbl
+        LEFT JOIN another_tbl
+            USING(a)
+
+  configs:
+    indentation:
+      indented_joins: true
+      indented_using_on: true
+
+test_pass_indented_using_on_false:
+  # 2.c) specific False, but passing
+  pass_str: |
+    SELECT a, b, c
+    FROM my_tbl
+        LEFT JOIN another_tbl
+        USING(a)
+
+  configs:
+    indentation:
+      indented_joins: true
+      indented_using_on: false
+
+test_fail_indented_using_on_false:
+  # 2.d) specific False, but failing
+  fail_str: |
+    SELECT a, b, c
+    FROM my_tbl
+        LEFT JOIN another_tbl
+            USING(a)
+
+  fix_str: |
+    SELECT a, b, c
+    FROM my_tbl
+        LEFT JOIN another_tbl
+        USING(a)
+
+  configs:
+    indentation:
+      indented_joins: true
+      indented_using_on: false
+
+test_fail_indented_joins_using_on_false:
+  # 2.e) specific True, and failing
+  fail_str: |
+    SELECT a, b, c
+    FROM my_tbl
+        LEFT JOIN another_tbl
+        USING(a)
+
+  fix_str: |
+    SELECT a, b, c
+    FROM my_tbl
+        LEFT JOIN another_tbl
+            USING(a)
+
+  configs:
+    indentation:
+      indented_joins: true
+      indented_using_on: true
+
+test_fail_indented_joins_using_on_false:
+  # 2.f) specific false for both, and failing
+  fail_str: |
+    SELECT a, b, c
+    FROM my_tbl
+        LEFT JOIN another_tbl
+            USING(a)
+
+  fix_str: |
+    SELECT a, b, c
+    FROM my_tbl
+    LEFT JOIN another_tbl
+    USING(a)
+
+  configs:
+    indentation:
+      indented_joins: false
+      indented_using_on: false
+
 test_pass_indented_from_with_comment:
   pass_str: |
     SELECT *