tablecmds: clarify recurse vs recusing

First seen: 2026-01-19 07:14:48+00:00 · Messages: 9 · Participants: 4

Latest Update

2026-06-01 · claude-opus-4-6

Technical Analysis: tablecmds.c recurse vs recursing Parameter Naming Clarity

Core Problem

PostgreSQL's tablecmds.c is one of the largest and most complex files in the codebase, implementing all ALTER TABLE subcommands. Many of its internal functions accept two boolean parameters — recurse and recursing — whose names are visually similar but semantically distinct:

The confusion arises because:

  1. The names differ by only a suffix (-e vs -ing)
  2. There is virtually no documentation in tablecmds.c explaining these parameters
  3. All four boolean combinations are theoretically possible, making the state space non-obvious

Proposed Solutions

v1: Rename recurse to no_only (Rejected)

The original proposal renamed recurse to no_only to directly reflect its SQL-level meaning (the absence of the ONLY keyword). This was rejected by both Peter Eisentraut and Tom Lane because:

v2: Header comments + scattered references (Partially accepted)

The author pivoted to adding documentation. v2 added detailed descriptions in the header comments of ATController() and ATPrepCmd(), plus brief references in 16 other functions that take both parameters. Tom Lane objected to the "partial documentation" approach for other functions.

v3/v4: Focused header comment on ATPrepCmd() (Accepted approach)

Following Tom Lane's guidance, the final approach documents all arguments of ATPrepCmd() comprehensively in its header comment, and relies on developers extrapolating that understanding to other functions. This avoids:

A minor addition documents the previously-undocumented is_internal parameter of addFkConstraint(), squashed into the same commit.

Key Technical Insights

The Four-State Boolean Space

Ashutosh Bapat's analysis of the (recurse, recursing) combinations is architecturally revealing:

recurse recursing Meaning
true false Top-level call, will recurse to children (root of hierarchy)
false false Operating on a standalone table (no inheritance/partition context)
true true Mid-tree recursion: processing a non-leaf, non-root table that should continue recursing
false true Processing a child table but should NOT recurse further to its children

Tom Lane noted that the (false, true) case would arise if the inheritance tree were flattened into a list early on — but most code paths that flatten the tree don't use recurse/recursing parameters at all. This suggests potential for simplification via an enum, though no one pursued this.

Architectural Context

The recurse/recursing pattern is central to how PostgreSQL handles DDL propagation in inheritance hierarchies. When ALTER TABLE parent ALTER COLUMN ... is issued without ONLY:

  1. ATPrepCmd() is called with recurse=true, recursing=false
  2. It identifies child tables and calls itself (or the execution function) with recurse=true, recursing=true
  3. The recursing=true flag triggers different validation logic (e.g., inherited columns may have different constraints on what can be altered)

This two-boolean design is a pragmatic encoding of the call-stack context that avoids threading additional state through deeply nested function calls.

Design Philosophy Discussion

Tom Lane's position reveals a broader PostgreSQL development philosophy: documentation should be complete or absent — partial documentation of function parameters is worse than none because it creates a false sense of completeness and becomes a maintenance liability when signatures change. The preferred approach is to document one canonical location thoroughly and trust developers to read it.

Current Status

The patch (v5, rebased with no substantive changes from v4) is a pure comment addition to ATPrepCmd() documenting all its parameters. It remains uncommitted as of the last message (May 2026), with the author bumping it due to its continued utility while working on related inheritance/recursion patches.