Postgres Language Server

repository·main·Indexed 26 days ago

https://github.com/supabase-community/postgres-language-server

A collection of language tools and a Language Server Protocol (LSP) implementation for Postgres. It provides SQL autocompletion, linting, and type checking using the official libpg_query parser. The project includes a Rust-based core with crates like pgls_workspace and pgls_analyser, as well as WebAssembly bindings via @postgres-language-server/wasm for custom editor integrations and LSP JSON-RPC protocol support.

Tokens
74K
Snippets
203
Records
446
Agent score
89%

What's inside postgres-language-server

  1. Overview of Postgres Language Server features

    main

    The Postgres Language Server is a collection of language tools and a Language Server Protocol (LSP) implementation designed for Postgres. It is built using Postgres' own parser libpg_query to guarantee 100% syntax compatibility.

    The server uses a transport-agnostic Server-Client architecture, allowing features to be accessed via both the Language Server Protocol (LSP) and a Command Line Interface (CLI).

    Available features include:

    • Autocompletion & Hover
    • Syntax Diagnostics
    • Type Checking (leveraging EXPLAIN error insights)
    • Formatting
    • Migration Linting
    • Database Linting
    • PL/pgSQL Support
  2. Identify the entry points for postgres-language-server

    main

    The project provides two primary entry points for interacting with the Postgres language server functionality, both of which utilize the shared pgls_workspace API:

    1. Language Server (pgls_lsp): A server that listens for incoming LSP (Language Server Protocol) messages from an IDE or editor.
    2. Command-Line Interface (pgls_cli): A CLI tool used for direct commands like check. The published binary is named postgres-language-server (formerly postgrestools).
  3. Understand the core architecture of postgres-language-server

    main

    The postgres-language-server works by:

    1. Accepting input source code and splitting it into individual SQL statements.
    2. Parsing and analyzing each statement.
    3. Connecting to a Postgres database to maintain an in-memory schema cache (containing tables, columns, functions, and type information).
    4. Using the parsed results and the schema cache to answer queries about the SQL statements.

    To maintain performance, the engine uses a delta-based approach: when a file changes, it only re-parses and re-analyzes the affected statements.

  4. Design principles for the Postgres Tree-sitter grammar

    main
    The pgls_treesitter_grammar is not a standard syntax-highlighting grammar. It is specifically designed for Language Server Protocol (LSP) features like autocompletion and hover information. The grammar is optimized to provide specific intelligence while the user is actively typing SQL, even when the code is syntactically incomplete.
  5. Run diagnostics on files with postgres-language-server check

    main

    Run the language server's analysis on specific files or directories. You can use flags to target specific subsets of files based on Version Control System (VCS) status.

    Common usage patterns:

    • Check specific files: postgres-language-server check [PATH]...
    • Check staged files (local development): Use the --staged flag to lint only files prepared for commit.
    • Check changed files (CI environments): Use the --changed flag to lint files that differ from your defaultBranch.
    • Check piped input: Use --stdin-file-path=PATH to format code piped from stdin. The extension of the provided path determines how the code is checked.

    Example (piped input):

    echo 'let a;' | postgres-language-server check --stdin-file-path=test.sql
  6. Avoid using VACUUM FULL to prevent table locking

    main

    The banVacuumFull rule (Diagnostic Category: lint/safety/banVacuumFull) flags the use of VACUUM FULL in SQL code. VACUUM FULL rewrites the entire table and acquires an ACCESS EXCLUSIVE lock, which blocks all reads and writes for the duration of the operation. This can be extremely disruptive on large tables.

    To perform online table maintenance without blocking access, use regular VACUUM or pg_repack instead.

  7. Enable plpgsql_check for advanced PL/pgSQL diagnostics

    main

    By default, the Postgres Language Server uses libpg_query to check for syntax errors in PL/pgSQL function bodies. However, this method lacks location information and reports errors on the entire function body.

    To receive fine-grained, token-level error reporting and sophisticated static analysis, you should enable the plpgsql_check extension in your development database. The language server will automatically detect the extension and forward its reports as diagnostics.

    CREATE EXTENSION IF NOT EXISTS plpgsql_check;
  8. Avoid the `lint/safety/addingRequiredField` diagnostic

    main

    The lint/safety/addingRequiredField rule flags attempts to add a new column to an existing table that is marked as NOT NULL but lacks a DEFAULT value.

    Why this is a problem:

    • For populated tables, the operation will fail immediately because existing rows cannot satisfy the NOT NULL constraint.
    • Existing application code that does not know about the new column will fail during INSERT operations.

    Recommended Solutions:

    1. Make the column optional initially: Add the column without the NOT NULL constraint. Once all existing data is updated and application code is aware of the column, apply the NOT NULL constraint.
    2. Use a DEFAULT value (Postgres 11+): If you are using PostgreSQL version 11 or later, you can add the column with both a NOT NULL constraint and a non-volatile DEFAULT value. This allows Postgres to automatically populate existing rows.