Skip to content

Statement splitter breaks statements on blank lines, producing false syntax errors #784

Description

@edjubert

Describe the bug

The statement splitter treats a blank line as a statement boundary. Any blank line
inside a single statement causes that statement to be cut in two, and each half is
then reported as a syntax error by libpg_query.

Blank lines inside a statement are a common readability convention (separating join
blocks, separating a CTE list from the main query). On our codebase, this affects
466 of 1436 SQL files in one directory tree alone, which makes check unusable in
CI and very noisy in the editor.

To Reproduce

repro.sql:

SELECT
	t.a
FROM t

LEFT JOIN u ON u.a = t.a;
$ postgres-language-server check repro.sql
repro.sql:5:1 syntax ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  × Invalid statement: syntax error at or near "LEFT"

    3 │ FROM t
    4 │
  > 5 │ LEFT JOIN u ON u.a = t.a;
      │ ^^^^^^^^^^^^^^^^^^^^^^^^^

Removing the blank line on line 4 makes the diagnostic disappear.

Expected behavior

The statement is valid SQL and should parse cleanly. A blank line is not a statement
terminator in Postgres.

I understand the double-newline heuristic exists so the editor can recover from
incomplete statements while typing, which is the right tradeoff for the LSP. But it is
the wrong tradeoff for the CLI on committed files, where the input is expected to be
valid and complete.

Two options that would both work for us:

  1. Only fall back to the blank-line heuristic when the statement fails to parse without
    it, rather than splitting eagerly.
  2. Expose a configuration flag (or make it the default for the CLI, as opposed to the
    LSP) to split on ; only.

Related

This looks like the same family of bug as #372 / #380 (blank line between two CTEs) and
#780 (blank line after the final CTE, before the main statement) — both closed. This
report is a third trigger for the same underlying "blank line = statement boundary"
heuristic: a blank line inside a FROM clause, not adjacent to any CTE. Given three
separate triggers found so far, it might be worth addressing the heuristic itself (see
the two options above) rather than patching each shape individually.

System information

  • postgres-language-server 0.25.7
  • macOS (aarch64), release binary postgres-language-server_aarch64-apple-darwin

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions