on_error table, saving error info to a table

First seen: 2024-02-03 06:22:34+00:00 · Messages: 28 · Participants: 6

Latest Update

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

Monthly Summary: ON_ERROR TABLE — Saving COPY FROM Errors to a Table (May 2026)

Overview

May 2026 saw the most active development period for this long-running patch (originally proposed Feb 2024), advancing from v9 through v13. The month brought the first independent testing, the first serious code review exposing real bugs, a significant policy reversal on trigger support, and multiple correctness fixes. Despite this progress, no committer has signed off on the patch.

Key Developments

Rebase and Snapshot Fix (v10, May 11)

jian he identified that the hand-built EState for error-table insertion never registered the active snapshot, creating a dangling pointer risk under concurrent activity. v10 adds proper RegisterSnapshot(GetActiveSnapshot()) calls, aligning with standard ExecutorStart/ExecutorEnd lifecycle management.

Major Policy Reversal: Triggers Now Allowed (v11, May 12)

The most consequential change this month was reversing the v8 blanket prohibition on triggers for the error table:

This re-opens the security surface flagged by Kirill Reshke in October 2025 (trigger-based privilege escalation). The motivation appears to be real-world use cases like audit triggers and error notification.

First Serious Code Review (Zsolt Parragi, mid-May)

Zsolt Parragi (Percona) provided the first in-depth code review, identifying multiple bugs:

  1. Use-after-close crash: error_rel was closed in BeginCopyFrom but referenced throughout COPY. Manifests as crash with debug_discard_caches=1. Fix: move table_close() to EndCopyFrom.
  2. Transition table crash: AFTER INSERT FOR EACH STATEMENT with transition tables crashed due to incorrect AfterTriggerEndQuery ordering between the two EStates. Fix: fire error-table's AfterTriggerEndQuery before target table's (following ExecForPortionOfLeftovers precedent).
  3. Incorrect num_errors count: When BEFORE ROW triggers return NULL (suppressing insert), the NOTICE still reports rows as "saved." Unresolved.
  4. Missing OidIsValid() guard on type lookup. Fixed.

Additional issues: redundant ACL check, redundant REJECT_LIMIT check, dead TODO comment, typos.

Documentation and Cleanup (v13, May 25)

v13 addressed Zsolt's review feedback without architectural changes:

Remaining Open Issues

  1. Security with triggers re-enabled: No mitigation proposed for trigger-based privilege escalation
  2. num_errors accuracy: Count doesn't account for trigger-suppressed rows
  3. No committer sign-off after 2+ years of iteration
  4. Built-in type compatibility risk: Changing copy_error_saving in future versions would break existing tables
  5. Rebase needed: v9 already had conflicts in nodeModifyTable.c; ongoing HEAD changes will require maintenance

Current Architecture (as of v13)

-- Built-in composite type (created during initdb)
CREATE TYPE copy_error_saving AS (
    userid oid, copy_tbl oid, filename text COLLATE "C",
    lineno bigint, line text COLLATE "C", colname text COLLATE "C",
    raw_field_value text COLLATE "C", err_message text COLLATE "C",
    err_detail text COLLATE "C", errorcode text COLLATE "C"
);

-- User creates typed table, runs COPY
CREATE TABLE my_errs OF copy_error_saving;
COPY t FROM '...' WITH (ON_ERROR table, ERROR_TABLE my_errs);

Error insertion reuses the executor's ExecInsert() via exported internals from nodeModifyTable.c. The error table must be a plain heap table (no partitions, no foreign tables, no FK constraints, no RLS, no rules, no column defaults). Triggers are now permitted.

History (1 prior analysis)
2026-06-01 · claude-opus-4-6

Round Update: Minor typo/wording feedback on v13 — no substantive progress

Zsolt Parragi's latest message is a final polish review of v13, containing only:

  1. Three typos identified:

    • Unnecessary word "row" in an errmsg() string
    • "should be not difficult" → "should not be difficult" in a TODO comment
    • "inseration" → "insertion" in documentation
  2. One documentation suggestion: Zsolt recommends explicitly documenting that a failure to insert into the error table (e.g., due to a constraint violation on the error table itself, or a trigger raising an exception) will cause the entire COPY statement to fail. This is a reasonable edge-case clarification but not a design change.

No new architectural discussion, no position shifts, no new patch version, no committer engagement. All previously identified open questions (security with triggers, num_errors accuracy, committer sign-off, built-in type compatibility risk) remain unaddressed.