cockroachdb / cockroachdb/cockroach

v26.3: pg_dump aborts with "definition of view appears to be empty" on tables whose PL/pgSQL trigger body contains DML

Open
#174,537 2 comments 0 reactions 0 assignees View on GitHub
O-community T-sql-foundations X-blathers-triaged
Dominant language
Go
Stars
32.5k
Forks
4.1k
PR merge metrics
PR metrics pending

Description

## Summary

On CockroachDB v26.3.1, creating a trigger whose PL/pgSQL function body contains DML (e.g. `INSERT ... ON CONFLICT`) causes a bogus `_RETURN` entry to appear in `pg_rewrite` for the underlying **table**. PostgreSQL uses `_RETURN` rewrite rules to mark views, so PostgreSQL 18 `pg_dump` (with the new v26.3 `pg_dump_compatibility` support) misclassifies the table as a view and aborts:

```
pg_dump: error: definition of view "pos" appears to be empty (length zero)
```

This aborts the entire dump, not just the affected table.

## Reproduction

Server: `cockroachdb/cockroach:v26.3.1` (single-node, `--insecure`)
Client: `pg_dump (PostgreSQL) 18.6`

```sql
CREATE DATABASE repro;

CREATE TABLE repro.public.bal (id STRING PRIMARY KEY, n INT);
CREATE TABLE repro.public.pos (id STRING PRIMARY KEY, n INT);

CREATE FUNCTION repro.public.f_dml() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO bal (id, n) VALUES ((NEW).id, 1)
ON CONFLICT (id) DO UPDATE SET n = bal.n + 1;
RETURN NEW;
END
$$ LANGUAGE PLpgSQL;

CREATE TRIGGER pos_ai AFTER INSERT ON repro.public.pos
FOR EACH ROW EXECUTE FUNCTION repro.public.f_dml();
```

A `_RETURN` rewrite rule now exists for a plain table:

```sql
SELECT oid, rulename, ev_class::regclass::string AS ev_class, ev_type
FROM repro.public.pg_rewrite;
-- oid | rulename | ev_class | ev_type
-- 2920291571 | _RETURN | pos | 1
```

Then:

```bash
pg_dump "postgresql://root@localhost:26257/repro?sslmode=disable" --table=pos --schema-only
# NOTICE: setting pg_dump_compatibility = "cockroachdb" because application_name is "pg_dump"
# pg_dump: error: definition of view "pos" appears to be empty (length zero)
```

`pg_get_viewdef('pos'::regclass)` correctly returns NULL for the table, which is exactly what trips pg_dump's fatal check once the `_RETURN` rule makes it look like a view.

## Expected behavior

`pg_rewrite` should only expose `_RETURN` rules for actual views, and pg_dump should dump the table normally.

## Additional observations

- A trigger function whose body contains **no DML** (`BEGIN RETURN NEW; END`) does not produce the spurious `pg_rewrite` row, and pg_dump succeeds.
- The failure is identical with `pg_dump_compatibility=postgres`. With `=off`, pg_dump fails earlier with `schema with OID 101 does not exist` (possibly a separate catalog fixup gap).
- Related restore-side friction found in the same workflow: stock pg_dump plain output sets `check_function_bodies = false`, but CockroachDB still validates PL/pgSQL bodies at `CREATE FUNCTION` time. Since pg_dump emits `CREATE FUNCTION` before the tables the body references, restoring such a dump fails with `ERROR: relation "..." does not exist` unless the dump is reordered. Honoring deferred body validation would make stock pg_dump output restorable.

## Impact

Any schema using PL/pgSQL trigger functions with DML bodies (a common pattern for maintaining derived/balance tables) cannot be dumped at all with the documented v26.3 pg_dump support.

## Environment

- CockroachDB CCL v26.3.1 (aarch64, single-node local container)
- pg_dump (PostgreSQL) 18.6

Jira issue: CRDB-67763

Epic CRDB-65516

Contributor guide

Open the contributing guide

Research direction

Start by running the supplied SQL reproduction and inspecting pg_rewrite for the spurious _RETURN rule on the plain table. Trace the pg_dump_compatibility path involved in PostgreSQL 18 pg_dump, then verify that only actual views expose _RETURN rules and that schema-only pg_dump completes successfully.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, postgresql, sql
Domain
databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.