[PATCH] Fix psql tab completion for REPACK boolean options

First seen: 2026-05-11 19:45:34+00:00 · Messages: 3 · Participants: 3

Latest Update

2026-05-14 · claude-opus-4-6

Technical Analysis: Fix psql Tab Completion for REPACK Boolean Options

Core Problem

The psql tab-completion system in PostgreSQL has a bug in how it matches parenthesized boolean options for the REPACK command. The issue lies in a misuse of the TailMatches() macro in src/bin/psql/tab-complete.in.c.

The Bug: Sequential vs. Alternative Matching

The TailMatches() macro in psql's tab-completion infrastructure supports two distinct matching semantics depending on syntax:

  1. Comma-separated arguments (TailMatches("A", "B", "C")) — matches a sequence of consecutive tokens. This means the parser expects to see token "A" followed by "B" followed by "C" in that exact order.

  2. Pipe-separated alternatives (TailMatches("A|B|C")) — matches any one of the listed tokens. This is a logical OR that triggers the completion when any single matching keyword is found.

The existing code used:

TailMatches("ANALYZE", "CONCURRENTLY", "VERBOSE")

This incorrectly requires all three keywords to appear in sequence (ANALYZE CONCURRENTLY VERBOSE), which is never valid REPACK syntax. REPACK's parenthesized options are individual boolean flags (e.g., REPACK (VERBOSE ...)), so the correct pattern is:

TailMatches("ANALYZE|CONCURRENTLY|VERBOSE")

This matches when any one of these keywords appears as the last token, then offers ON/OFF as completions — identical to how VACUUM's boolean options are handled.

Why It Matters

While this is a relatively minor UX bug (tab completion is a convenience feature), it demonstrates an important pattern in the tab-completion DSL. The TailMatches macro's overloaded semantics (comma = sequence, pipe = alternation) is a common source of errors when adding new command completions. The fix is a one-line change, but the pattern it corrects is architecturally significant for anyone maintaining tab-complete.in.c.

Proposed Solution

The patch changes the TailMatches call from comma-separated (sequential matching) to pipe-separated (alternative matching) syntax. This is a minimal, mechanical fix that aligns REPACK's completion behavior with the established pattern used by VACUUM.

Broader Implications

Fujii identified that CLUSTER and REINDEX commands have the same class of issue — their boolean options also lack ON/OFF completion suggestions. However, these are characterized as pre-existing omissions (improvements rather than regressions) and are deferred to v20 development rather than being backpatched together with this fix.

Backpatch Consideration

Álvaro Herrera noted this qualifies as a backpatchable bugfix since it corrects clearly incorrect behavior (the completion literally never works as written). However, its low criticality means backpatching is acceptable but not urgent — it's a tab-completion cosmetic issue with zero data integrity or correctness implications.

Design Pattern Lessons

The tab-complete.in.c file is one of the largest and most pattern-dense files in the PostgreSQL source tree. Its DSL (TailMatches, Matches, HeadMatches) with overloaded comma/pipe semantics requires careful attention:

This distinction is not immediately obvious from casual reading and is a recurring source of tab-completion bugs.