refresh materialized view: concurrently + with no data

First seen: 2026-05-31 11:57:32+00:00 · Messages: 1 · Participants: 1

Latest Update

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

Technical Analysis: REFRESH MATERIALIZED VIEW CONCURRENTLY + WITH NO DATA Error Checking Location

Core Problem

The thread raises a question about PostgreSQL's internal architecture regarding where semantic validation of utility command options should occur — specifically whether conflicting options in REFRESH MATERIALIZED VIEW CONCURRENTLY ... WITH NO DATA should be detected at parse time (in gram.y) or deferred to execution time (in RefreshMatViewByOid()).

Currently, PostgreSQL allows the parser to accept the combination of CONCURRENTLY and WITH NO DATA without complaint, constructing a valid RefreshMatViewStmt node with both n->concurrent = true and n->skipData = true. The error is only raised later during execution in RefreshMatViewByOid() (in matview.c), which checks:

if (stmt->concurrent && stmt->skipData)
    ereport(ERROR,
            (errcode(ERRCODE_SYNTAX_ERROR),
             errmsg("REFRESH options CONCURRENTLY and WITH NO DATA cannot be used together")));

Why This Matters Architecturally

This question touches on a fundamental PostgreSQL design principle: the separation of concerns between parsing, analysis, rewriting, and execution phases.

The Case for Parser-Level Checking

The Case for Executor-Level Checking (Current Behavior)

PostgreSQL's Established Convention

The existing behavior is deliberate and consistent with PostgreSQL conventions. The project generally follows these principles:

  1. gram.y handles pure syntax — is the SQL grammatically valid?
  2. Parse analysis (analyze.c, parse_*.c) handles semantic validation that can be done without catalog access or with minimal catalog access
  3. Utility command execution handles option validation that is specific to the command's semantics

For utility statements specifically, many similar checks are deferred:

Technical Implications of Moving the Check

If one were to move this check to the parser, it would involve adding something like:

/* In gram.y, in the RefreshMatViewStmt production */
if (n->concurrent && n->skipData)
    ereport(ERROR,
            (errcode(ERRCODE_SYNTAX_ERROR),
             errmsg("REFRESH options CONCURRENTLY and WITH NO DATA cannot be used together")));

However, this would:

Conclusion

The current placement is an intentional architectural choice. PostgreSQL's utility command infrastructure consistently defers semantic validation of option combinations to the executor phase, keeping the parser focused on syntactic correctness. This is not a bug or oversight — it's a deliberate design pattern that prioritizes maintainability and consistency across the codebase.