Repository: sqlfluff/sqlfluff

Issue:
Issue with indented_joins in 2.0.0a6
### Search before asking

- [X] I searched the [issues](https://github.com/sqlfluff/sqlfluff/issues) and found no similar issues.


### What Happened

Given this file:

`test.sql`
```sql
select *
from table_1
    inner join table_2
        on table_1.key = table_2.key
    inner join table_3
        on table_2.key = table_3.key
```

SQLFluff pushes the `on` clause out further than it should when `format` is run



Here's what the `format` command does if I take away the `indented_joins` config

```sql
select *
from table_1
inner join table_2
    on table_1.key = table_2.key
inner join table_3
    on table_2.key = table_3.key
```
It doesn't mess with the `on` clause 🤷🏻 

### Expected Behaviour

No weird indentation

### Observed Behaviour

`test.sql`
```sql
select *
from table_1
    inner join table_2
        on table_1.key = table_2.key
    inner join table_3
            on table_2.key = table_3.key
```

### How to reproduce

```sh
$ sqlfluff format test.sql
```

### Dialect

ANSI

### Version

2.0.0a6

### Configuration

`.sqlfluff`
```
[sqlfluff]
dialect = ansi

[sqlfluff:indentation]
indented_joins = True
```

### Are you willing to work on and submit a PR to address the issue?

- [ ] Yes I am willing to submit a PR!

### Code of Conduct

- [X] I agree to follow this project's [Code of Conduct](https://github.com/sqlfluff/sqlfluff/blob/main/CODE_OF_CONDUCT.md)


Discussion:
coveralls: ## Pull Request Test Coverage Report for [Build 4436946817](https://coveralls.io/builds/57927680)

* **0** of **0**   changed or added relevant lines in **0** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage remained the same at **100.0%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/57927680/badge)](https://coveralls.io/builds/57927680) |
| :-- | --: |
| Change from base [Build 4432106715](https://coveralls.io/builds/57907871): |  0.0% |
| Covered Lines: | 17445 |
| Relevant Lines: | 17445 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Patch:
diff --git a/src/sqlfluff/core/config.py b/src/sqlfluff/core/config.py
index 456e60508..06c175cd6 100644
--- a/src/sqlfluff/core/config.py
+++ b/src/sqlfluff/core/config.py
@@ -801,19 +801,25 @@ class FluffConfig:
             self._configs["core"]["recurse"] = True
 
         # Dialect and Template selection.
+        dialect: Optional[str] = self._configs["core"]["dialect"]
+        self._initialise_dialect(dialect, require_dialect)
+
+        self._configs["core"]["templater_obj"] = self.get_templater(
+            self._configs["core"]["templater"]
+        )
+
+    def _initialise_dialect(
+        self, dialect: Optional[str], require_dialect: bool = True
+    ) -> None:
         # NB: We import here to avoid a circular references.
         from sqlfluff.core.dialects import dialect_selector
 
-        dialect: Optional[str] = self._configs["core"]["dialect"]
         if dialect is not None:
             self._configs["core"]["dialect_obj"] = dialect_selector(
                 self._configs["core"]["dialect"]
             )
         elif require_dialect:
             self.verify_dialect_specified()
-        self._configs["core"]["templater_obj"] = self.get_templater(
-            self._configs["core"]["templater"]
-        )
 
     def verify_dialect_specified(self) -> None:
         """Check if the config specifies a dialect, raising an error if not."""
@@ -940,6 +946,7 @@ class FluffConfig:
         if exclude_rules:
             # Make a comma separated string to pass in as override
             overrides["exclude_rules"] = ",".join(exclude_rules)
+
         return cls(overrides=overrides, require_dialect=require_dialect)
 
     def get_templater(self, templater_name="jinja", **kwargs):
@@ -1094,6 +1101,9 @@ class FluffConfig:
         config_path = [elem.strip() for elem in config_line.split(":")]
         # Set the value
         self.set_value(config_path[:-1], config_path[-1])
+        # If the config is for dialect, initialise the dialect
+        if config_path[:-1] == ["dialect"]:
+            self._initialise_dialect(config_path[-1])
 
     def process_raw_file_for_config(self, raw_str: str):
         """Process a full raw file for inline config and update self."""
diff --git a/src/sqlfluff/core/dialects/__init__.py b/src/sqlfluff/core/dialects/__init__.py
index 886a9b50e..b02dc6249 100644
--- a/src/sqlfluff/core/dialects/__init__.py
+++ b/src/sqlfluff/core/dialects/__init__.py
@@ -59,6 +59,8 @@ def load_raw_dialect(label: str, base_module: str = "sqlfluff.dialects") -> Dial
     """Dynamically load a dialect."""
     if label in _legacy_dialects:
         raise SQLFluffUserError(_legacy_dialects[label])
+    elif label not in _dialect_lookup:
+        raise KeyError("Unknown dialect")
     module_name, name = _dialect_lookup[label]
     module = import_module(f"{base_module}.{module_name}")
     result: Dialect = getattr(module, name)
diff --git a/src/sqlfluff/dialects/dialect_ansi.py b/src/sqlfluff/dialects/dialect_ansi.py
index 240867e9e..e3ffa714c 100644
--- a/src/sqlfluff/dialects/dialect_ansi.py
+++ b/src/sqlfluff/dialects/dialect_ansi.py
@@ -1489,13 +1489,11 @@ class FromExpressionSegment(BaseSegment):
             Ref("MLTableExpressionSegment"),
             Ref("FromExpressionElementSegment"),
         ),
-        # TODO: Revisit this to make sure it's sensible.
-        Conditional(Dedent, indented_joins=False),
+        Dedent,
+        Conditional(Indent, indented_joins=True),
         AnyNumberOf(
             Sequence(
-                Conditional(Indent, indented_joins=True),
                 OneOf(Ref("JoinClauseSegment"), Ref("JoinLikeClauseGrammar")),
-                Conditional(Dedent, indented_joins=True),
             ),
             optional=True,
         ),


Test patch:
diff --git a/test/core/config_test.py b/test/core/config_test.py
index 84bc493e7..2ab615846 100644
--- a/test/core/config_test.py
+++ b/test/core/config_test.py
@@ -497,3 +497,26 @@ def test__config__warn_unknown_rule():
     assert ("The reference was found as a match for multiple rules: {") in caplog.text
     assert ("LT01") in caplog.text
     assert ("LT02") in caplog.text
+
+
+def test__process_inline_config():
+    """Test the processing of inline in-file configuration directives."""
+    cfg = FluffConfig(config_b)
+    assert cfg.get("rules") == "LT03"
+
+    cfg.process_inline_config("-- sqlfluff:rules:LT02")
+    assert cfg.get("rules") == "LT02"
+
+    assert cfg.get("tab_space_size", section="indentation") == 4
+    cfg.process_inline_config("-- sqlfluff:indentation:tab_space_size:20")
+    assert cfg.get("tab_space_size", section="indentation") == 20
+
+    assert cfg.get("dialect") == "ansi"
+    assert cfg.get("dialect_obj").name == "ansi"
+    cfg.process_inline_config("-- sqlfluff:dialect:postgres")
+    assert cfg.get("dialect") == "postgres"
+    assert cfg.get("dialect_obj").name == "postgres"
+
+    assert cfg.get("rulez") is None
+    cfg.process_inline_config("-- sqlfluff:rulez:LT06")
+    assert cfg.get("rulez") == "LT06"
diff --git a/test/dialects/ansi_test.py b/test/dialects/ansi_test.py
index 88842bf0c..80f49eceb 100644
--- a/test/dialects/ansi_test.py
+++ b/test/dialects/ansi_test.py
@@ -192,12 +192,12 @@ def test__dialect__ansi_is_whitespace():
 @pytest.mark.parametrize(
     "sql_string, indented_joins, meta_loc",
     [
-        ("select field_1 from my_table as alias_1", True, (1, 5, 8, 14, 15)),
+        ("select field_1 from my_table as alias_1", True, (1, 5, 8, 14, 15, 16, 17)),
         ("select field_1 from my_table as alias_1", False, (1, 5, 8, 14, 15)),
         (
             "select field_1 from my_table as alias_1 join foo using (field_1)",
             True,
-            (1, 5, 8, 15, 17, 21, 22, 24, 27, 29, 31, 32, 33, 34, 35),
+            (1, 5, 8, 15, 16, 18, 22, 23, 25, 28, 30, 32, 33, 34, 35),
         ),
         (
             "select field_1 from my_table as alias_1 join foo using (field_1)",
diff --git a/test/fixtures/dialects/mysql/explain.yml b/test/fixtures/dialects/mysql/explain.yml
index 248ce1740..48a53a002 100644
--- a/test/fixtures/dialects/mysql/explain.yml
+++ b/test/fixtures/dialects/mysql/explain.yml
@@ -3,7 +3,7 @@
 # computed by SQLFluff when running the tests. Please run
 # `python test/generate_parse_fixture_yml.py`  to generate them after adding or
 # altering SQL files.
-_hash: a1fbac192cf02d98f28a924f4b894fce63a8c73ecd867e5eea4d56c1fa6f49da
+_hash: 3628780103c71c5a4e04ea5423c51580c32bcd022b3659fce570c05bae3a63cd
 file:
 - statement:
     explain_statement:
@@ -19,11 +19,8 @@ file:
       keyword: explain
       update_statement:
         keyword: update
-        from_expression:
-          from_expression_element:
-            table_expression:
-              table_reference:
-                naked_identifier: tbl
+        table_reference:
+          naked_identifier: tbl
         set_clause_list:
           keyword: set
           set_clause:
diff --git a/test/fixtures/dialects/mysql/quoted_literal.yml b/test/fixtures/dialects/mysql/quoted_literal.yml
index d95d2b374..ef4ec1dc8 100644
--- a/test/fixtures/dialects/mysql/quoted_literal.yml
+++ b/test/fixtures/dialects/mysql/quoted_literal.yml
@@ -3,7 +3,7 @@
 # computed by SQLFluff when running the tests. Please run
 # `python test/generate_parse_fixture_yml.py`  to generate them after adding or
 # altering SQL files.
-_hash: 2f87d8252b0b31dabebfcb159b1a7833cc00684b7aaa53286c32683fcceaaba2
+_hash: ad88d0ef3cc10c070f32053dbaea0a7d788e8f01ef4ea30ac820784eb76cc4f6
 file:
 - statement:
     select_statement:
@@ -166,11 +166,8 @@ file:
 - statement:
     update_statement:
       keyword: UPDATE
-      from_expression:
-        from_expression_element:
-          table_expression:
-            table_reference:
-              naked_identifier: table1
+      table_reference:
+        naked_identifier: table1
       set_clause_list:
         keyword: SET
         set_clause:
@@ -183,11 +180,8 @@ file:
 - statement:
     update_statement:
       keyword: UPDATE
-      from_expression:
-        from_expression_element:
-          table_expression:
-            table_reference:
-              naked_identifier: table1
+      table_reference:
+        naked_identifier: table1
       set_clause_list:
         keyword: SET
         set_clause:
diff --git a/test/fixtures/dialects/mysql/update.yml b/test/fixtures/dialects/mysql/update.yml
index a159d69b1..4297a8c71 100644
--- a/test/fixtures/dialects/mysql/update.yml
+++ b/test/fixtures/dialects/mysql/update.yml
@@ -3,16 +3,13 @@
 # computed by SQLFluff when running the tests. Please run
 # `python test/generate_parse_fixture_yml.py`  to generate them after adding or
 # altering SQL files.
-_hash: e929b61b11d4ebbe7dcba4df45f5ee2d5e92b28ec812fd6032b7076f1ec4c3c2
+_hash: e97422c5a174d58b5638ee735094162724c01779876f33efb13089dcad90e6a2
 file:
 - statement:
     update_statement:
       keyword: UPDATE
-      from_expression:
-        from_expression_element:
-          table_expression:
-            table_reference:
-              naked_identifier: t1
+      table_reference:
+        naked_identifier: t1
       set_clause_list:
         keyword: SET
         set_clause:
@@ -29,11 +26,8 @@ file:
 - statement:
     update_statement:
       keyword: UPDATE
-      from_expression:
-        from_expression_element:
-          table_expression:
-            table_reference:
-              naked_identifier: t1
+      table_reference:
+        naked_identifier: t1
       set_clause_list:
       - keyword: SET
       - set_clause:
@@ -57,16 +51,13 @@ file:
 - statement_terminator: ;
 - statement:
     update_statement:
-      keyword: UPDATE
-      table_reference:
+    - keyword: UPDATE
+    - table_reference:
         naked_identifier: items
-      comma: ','
-      from_expression:
-        from_expression_element:
-          table_expression:
-            table_reference:
-              naked_identifier: month
-      set_clause_list:
+    - comma: ','
+    - table_reference:
+        naked_identifier: month
+    - set_clause_list:
         keyword: SET
         set_clause:
         - column_reference:
@@ -79,7 +70,7 @@ file:
           - naked_identifier: month
           - dot: .
           - naked_identifier: price
-      where_clause:
+    - where_clause:
         keyword: WHERE
         expression:
         - column_reference:
@@ -96,11 +87,8 @@ file:
 - statement:
     update_statement:
       keyword: UPDATE
-      from_expression:
-        from_expression_element:
-          table_expression:
-            table_reference:
-              naked_identifier: t
+      table_reference:
+        naked_identifier: t
       set_clause_list:
         keyword: SET
         set_clause:
@@ -123,11 +111,8 @@ file:
 - statement:
     update_statement:
       keyword: UPDATE
-      from_expression:
-        from_expression_element:
-          table_expression:
-            table_reference:
-              naked_identifier: items
+      table_reference:
+        naked_identifier: items
       set_clause_list:
         keyword: SET
         set_clause:
@@ -373,11 +358,8 @@ file:
     update_statement:
     - keyword: UPDATE
     - keyword: LOW_PRIORITY
-    - from_expression:
-        from_expression_element:
-          table_expression:
-            table_reference:
-              naked_identifier: foo
+    - table_reference:
+        naked_identifier: foo
     - set_clause_list:
         keyword: SET
         set_clause:
@@ -392,16 +374,13 @@ file:
 - statement_terminator: ;
 - statement:
     update_statement:
-      keyword: UPDATE
-      table_reference:
+    - keyword: UPDATE
+    - table_reference:
         naked_identifier: a
-      comma: ','
-      from_expression:
-        from_expression_element:
-          table_expression:
-            table_reference:
-              naked_identifier: b
-      set_clause_list:
+    - comma: ','
+    - table_reference:
+        naked_identifier: b
+    - set_clause_list:
         keyword: SET
         set_clause:
         - column_reference:
@@ -414,7 +393,7 @@ file:
           - naked_identifier: b
           - dot: .
           - naked_identifier: name
-      where_clause:
+    - where_clause:
         keyword: WHERE
         expression:
         - column_reference:
diff --git a/test/fixtures/dialects/mysql/variable_assignment.yml b/test/fixtures/dialects/mysql/variable_assignment.yml
index 2071e7365..4caa984aa 100644
--- a/test/fixtures/dialects/mysql/variable_assignment.yml
+++ b/test/fixtures/dialects/mysql/variable_assignment.yml
@@ -3,7 +3,7 @@
 # computed by SQLFluff when running the tests. Please run
 # `python test/generate_parse_fixture_yml.py`  to generate them after adding or
 # altering SQL files.
-_hash: afaf7d13bb288b44720e378bce9b97f290a3d003ca4bc17e02440b6b1438ba95
+_hash: bb42313b72d36da00df4839494e6e7357c200742df78c658ddbbbe051746a937
 file:
 - statement:
     select_statement:
@@ -48,11 +48,8 @@ file:
 - statement:
     update_statement:
       keyword: UPDATE
-      from_expression:
-        from_expression_element:
-          table_expression:
-            table_reference:
-              naked_identifier: t1
+      table_reference:
+        naked_identifier: t1
       set_clause_list:
         keyword: SET
         set_clause:
diff --git a/test/fixtures/rules/std_rule_cases/LT02-indent.yml b/test/fixtures/rules/std_rule_cases/LT02-indent.yml
index b1f1416d1..1c8cb0c6c 100644
--- a/test/fixtures/rules/std_rule_cases/LT02-indent.yml
+++ b/test/fixtures/rules/std_rule_cases/LT02-indent.yml
@@ -1825,3 +1825,16 @@ test_implicit_case_4542:
   configs:
     indentation:
       allow_implicit_indents: true
+
+test_indented_joins_4484:
+  # https://github.com/sqlfluff/sqlfluff/issues/4484
+  pass_str: |
+    select *
+    from table_1
+        inner join table_2
+            on table_1.key = table_2.key
+        inner join table_3
+            on table_2.key = table_3.key
+  configs:
+    indentation:
+      indented_joins: true