From 84ae5c05439cbf791cd353f4a03c8930f78047ad Mon Sep 17 00:00:00 2001 From: Eugene Date: Sun, 20 Sep 2026 15:33:38 +0300 Subject: [PATCH 1/4] Restore from stdin without dropping the progress view A dump arriving on stdin can't be preflighted, so there are no denominators - and until now that sent the whole run to passthrough, handing the user back the firehose the tool exists to swallow. But denominators are the only thing missing: every completion event carries its own object description, and toc.SectionOf maps that to a phase exactly the way the plan would have. So a nil plan now means countless, not passthrough. The aggregator counts phases from the event's description, skips the cap it has no total for, and flags the snapshot; the frame and the summary swap the three bars for three object counts and leave the cleanup row, working line and error panel exactly as they were. Plain mode needed its own rule - its milestones are deciles, and with zero totals it would have printed one line and then gone quiet for the rest of the restore - so it paces on the object count instead. `--replay -` feeds the same view a plan-less log, which is how countless mode can be seen and tested without a stdin restore and a database. Two documented env vars were missing while I was in here. ELE_LOG names the raw log (unset keeps the timestamped default), and ELE_PASSTHROUGH is the one way back to raw pg_restore: argv verbatim, no log, its own exit code. Both live in engine/env.go with ELE_STRICT_EXIT, which was already implemented but read inline. --- cmd/ele/main.go | 3 +- internal/aggregator/aggregator.go | 85 ++++++++++++++++--------- internal/aggregator/aggregator_test.go | 70 +++++++++++++++++++- internal/aggregator/snapshot.go | 6 ++ internal/engine/engine.go | 35 +++++++--- internal/engine/env.go | 34 ++++++++++ internal/engine/env_test.go | 51 +++++++++++++++ internal/engine/replay.go | 17 ++++- internal/engine/replay_test.go | 28 ++++++++ internal/render/frame.go | 46 +++++++++++++- internal/render/plain.go | 45 +++++++++++-- internal/render/render_test.go | 88 ++++++++++++++++++++++++++ internal/render/summary.go | 6 +- 13 files changed, 461 insertions(+), 53 deletions(-) create mode 100644 internal/engine/env.go create mode 100644 internal/engine/env_test.go diff --git a/cmd/ele/main.go b/cmd/ele/main.go index de3abcd..dee7cc4 100644 --- a/cmd/ele/main.go +++ b/cmd/ele/main.go @@ -72,7 +72,8 @@ func printUsage(w io.Writer) { " ele --plan print the parsed restore plan and exit\n"+ " ele --replay dry-run: replay a captured stderr log through the\n"+ " live view\n"+ - " ( is a dump or a saved pg_restore -l listing)\n") + " ( is a dump or a saved pg_restore -l listing;\n"+ + " '-' replays with no plan, as a stdin restore runs)\n") } func preflightOnly(out io.Writer, dumpPath string) error { diff --git a/internal/aggregator/aggregator.go b/internal/aggregator/aggregator.go index f2cfdc2..0e337d0 100644 --- a/internal/aggregator/aggregator.go +++ b/internal/aggregator/aggregator.go @@ -26,6 +26,11 @@ type Aggregator struct { cfg Config now func() time.Time // injectable clock for item timing + // countless: no plan, so no denominators. Phases are still counted - the + // event's own description gives the section - they just have no total to + // count against. This is the stdin restore, where preflight is impossible. + countless bool + // phase denominators, from the plan total map[toc.Section]int // phase progress @@ -70,31 +75,35 @@ type inflightItem struct { start time.Time } -// New builds an Aggregator for a restore plan and config. +// New builds an Aggregator for a restore plan and config. A nil plan is the +// countless restore: everything still aggregates, only the denominators are +// missing. func New(plan *toc.RestorePlan, cfg Config) *Aggregator { - pre, data, post, _ := plan.PhaseCounts() - bytesTotal, byteSized := plan.DataBytes(), false - // DataBytes is only meaningful when preflight sized every data file; the - // caller signals that via a nonzero total together with ByteSized. Here we - // treat any positive total as byte-capable and let the renderer decide. - if bytesTotal > 0 { - byteSized = true - } - return &Aggregator{ - plan: plan, - cfg: cfg, - now: time.Now, - total: map[toc.Section]int{ - toc.PreData: pre, toc.Data: data, toc.PostData: post, - }, + a := &Aggregator{ + plan: plan, + cfg: cfg, + now: time.Now, + countless: plan == nil, + total: map[toc.Section]int{}, done: map[toc.Section]int{}, sectionDone: map[toc.Section]bool{}, doneIDs: map[int]bool{}, - bytesTotal: bytesTotal, - byteSized: byteSized, inflight: map[int]*inflightItem{}, groups: map[string]*errorGroup{}, } + if plan == nil { + return a + } + + pre, data, post, _ := plan.PhaseCounts() + a.total = map[toc.Section]int{toc.PreData: pre, toc.Data: data, toc.PostData: post} + // DataBytes is only meaningful when preflight sized every data file; the + // caller signals that via a nonzero total together with ByteSized. Here we + // treat any positive total as byte-capable and let the renderer decide. + if bytesTotal := plan.DataBytes(); bytesTotal > 0 { + a.bytesTotal, a.byteSized = bytesTotal, true + } + return a } // Feed folds one event into the running state. @@ -102,7 +111,7 @@ func (a *Aggregator) Feed(ev parser.Event) { switch ev.Kind { case parser.KindProcessingItem: a.parallel = true - a.completeID(ev.DumpID) + a.completeID(ev.DumpID, ev.Desc) case parser.KindLaunchItem: a.parallel = true @@ -116,7 +125,7 @@ func (a *Aggregator) Feed(ev parser.Event) { }) delete(a.inflight, ev.DumpID) } - a.completeID(ev.DumpID) + a.completeID(ev.DumpID, ev.Desc) case parser.KindCreating: if !a.parallel { @@ -152,20 +161,35 @@ func (a *Aggregator) Feed(ev parser.Event) { } // completeID marks the entry with the given dump id done, once. Its phase and -// byte size come from the plan. Ids not in the plan are ignored. -func (a *Aggregator) completeID(id int) { +// byte size come from the plan; ids the plan doesn't know are ignored, since a +// real plan is the authority on what this restore contains. +// +// Countless mode has no plan to consult, so the event's own description carries +// the phase instead - toc.SectionOf maps it exactly the way the plan would have. +// Sizes stay unknown either way: only preflight can stat a data file. +func (a *Aggregator) completeID(id int, desc string) { if a.doneIDs[id] { return } - e, ok := a.plan.Get(id) - if !ok { + if a.plan != nil { + e, ok := a.plan.Get(id) + if !ok { + return + } + a.doneIDs[id] = true + a.incPhase(e.Section) + if e.Section == toc.Data && e.HasBytes { + a.bytesDone += e.Bytes + } + return + } + + s := toc.SectionOf(desc) + if s == toc.SectionUnknown { return } a.doneIDs[id] = true - a.incPhase(e.Section) - if e.Section == toc.Data && e.HasBytes { - a.bytesDone += e.Bytes - } + a.incPhase(s) } // completeSerial advances a phase in serial mode, where events carry no dump id @@ -204,10 +228,11 @@ func (a *Aggregator) setCurrent(desc, name string) { // incPhase increments a phase's done count, capped at its total so a stray // double-count can never push a bar past 100%. The first real completion also -// ends the DROP wave. +// ends the DROP wave. Countless mode has no total to cap against - and nothing +// to overflow, since it draws counts rather than bars. func (a *Aggregator) incPhase(s toc.Section) { a.dropWaveOver = true - if a.done[s] < a.total[s] { + if a.countless || a.done[s] < a.total[s] { a.done[s]++ } } diff --git a/internal/aggregator/aggregator_test.go b/internal/aggregator/aggregator_test.go index 321812f..9b245fe 100644 --- a/internal/aggregator/aggregator_test.go +++ b/internal/aggregator/aggregator_test.go @@ -29,6 +29,18 @@ func loadPlan(t *testing.T) *toc.RestorePlan { // replay drives a captured stderr fixture (from the parser package's testdata) // through parser then aggregator, exactly as the runner will wire them. func replay(t *testing.T, fixture string, cfg Config) *Aggregator { + t.Helper() + return feed(t, New(loadPlan(t), cfg), fixture) +} + +// replayCountless drives the same fixture with no plan - the stdin restore, +// where preflight is impossible and only numerators exist. +func replayCountless(t *testing.T, fixture string, cfg Config) *Aggregator { + t.Helper() + return feed(t, New(nil, cfg), fixture) +} + +func feed(t *testing.T, agg *Aggregator, fixture string) *Aggregator { t.Helper() f, err := os.Open(filepath.Join("..", "parser", "testdata", fixture)) if err != nil { @@ -36,7 +48,6 @@ func replay(t *testing.T, fixture string, cfg Config) *Aggregator { } defer f.Close() - agg := New(loadPlan(t), cfg) p := parser.New() sc := bufio.NewScanner(f) sc.Buffer(make([]byte, 0, 64*1024), 4*1024*1024) @@ -321,3 +332,60 @@ func TestClassifyBenign(t *testing.T) { t.Error("unique violation must be real") } } + +// TestCountlessSerial is the stdin restore: no plan, so no denominators, but +// every phase still counts and the error groups are unchanged. Counts come from +// each event's own object description rather than a TOC lookup. +func TestCountlessSerial(t *testing.T) { + cfg := Config{Clean: true, NoOwner: true} + s := replayCountless(t, "clean-serial.stderr", cfg).Snapshot() + planned := replay(t, "clean-serial.stderr", cfg).Snapshot() + + if !s.Countless { + t.Error("Countless = false, want true for a nil plan") + } + for _, p := range []PhaseProgress{s.Pre, s.Data, s.Post} { + if p.Total != 0 { + t.Errorf("%s total = %d, want 0 (no plan to count against)", p.Section, p.Total) + } + if p.Done == 0 { + t.Errorf("%s made no progress", p.Section) + } + } + if s.ByteSized { + t.Error("ByteSized = true; only preflight can size data files") + } + + // The planned run caps each phase at its denominator, so countless counting + // can match it but never fall behind it. + if s.Pre.Done < planned.Pre.Done || s.Data.Done < planned.Data.Done || s.Post.Done < planned.Post.Done { + t.Errorf("countless %d/%d/%d behind planned %d/%d/%d", + s.Pre.Done, s.Data.Done, s.Post.Done, + planned.Pre.Done, planned.Data.Done, planned.Post.Done) + } + + // Error classification never depended on the plan. + if s.ErrTotal != planned.ErrTotal || s.ErrBenign != planned.ErrBenign || s.ErrReal != planned.ErrReal { + t.Errorf("errors = %d/%d/%d, want the planned run's %d/%d/%d", + s.ErrTotal, s.ErrBenign, s.ErrReal, + planned.ErrTotal, planned.ErrBenign, planned.ErrReal) + } +} + +// TestCountlessParallel confirms the -j path counts too: item events carry the +// object description alongside the dump id, so a missing plan costs only the +// denominators - in-flight tracking and timings are unaffected. +func TestCountlessParallel(t *testing.T) { + agg := replayCountless(t, "clean-j4.stderr", Config{Clean: true, NoOwner: true}) + s := agg.Snapshot() + + if s.Data.Done == 0 || s.Post.Done == 0 { + t.Errorf("data %d, post %d: want both counted", s.Data.Done, s.Post.Done) + } + if len(s.InFlight) != 0 { + t.Errorf("in-flight not drained: %+v", s.InFlight) + } + if len(s.Slowest) == 0 { + t.Error("no item timings; launching/finished pairs should still time") + } +} diff --git a/internal/aggregator/snapshot.go b/internal/aggregator/snapshot.go index d67d162..ce57fe0 100644 --- a/internal/aggregator/snapshot.go +++ b/internal/aggregator/snapshot.go @@ -59,6 +59,11 @@ type Snapshot struct { Data PhaseProgress Post PhaseProgress + // Countless: the restore ran without a plan (a dump on stdin), so every + // Total is 0 and the phases carry counts only. The renderer drops the bars + // rather than drawing three empty tracks. + Countless bool + ByteSized bool BytesDone int64 BytesTotal int64 @@ -101,6 +106,7 @@ func (a *Aggregator) Snapshot() Snapshot { Pre: a.phase(toc.PreData), Data: a.phase(toc.Data), Post: a.phase(toc.PostData), + Countless: a.countless, ByteSized: a.byteSized, BytesDone: a.bytesDone, BytesTotal: a.bytesTotal, diff --git a/internal/engine/engine.go b/internal/engine/engine.go index 5bf5f1e..e0329b3 100644 --- a/internal/engine/engine.go +++ b/internal/engine/engine.go @@ -36,6 +36,12 @@ var spinner = []rune("⣾⣽⣻⢿⡿⣟⣯⣷") // code ele should exit with. stdout receives the child's stdout untouched; // stderrFile is the terminal channel for the status block and summary. func Run(ctx context.Context, args []string, stdout io.Writer, stderrFile *os.File) (int, error) { + // ELE_PASSTHROUGH is the opt-out: the user wants pg_restore exactly as it + // comes, so it wins over every mode below. + if passthroughRequested() { + return passthrough(ctx, args, stdout, stderrFile) + } + f := detectFlags(args) // Not a restore-to-database (no -d): ele adds nothing, so pass through. @@ -47,18 +53,21 @@ func Run(ctx context.Context, args []string, stdout io.Writer, stderrFile *os.Fi _, err := os.Stat(p) return err == nil }) + // No plan (a dump arriving on stdin, or a preflight that failed) means no + // denominators - but the aggregation, the working line and the error panel + // don't need them. Run countless rather than drop the user back into the + // firehose; only ELE_PASSTHROUGH does that. plan := preflightPlan(ctx, dumpPath, stderrFile) + title := f.dbName if plan == nil { - // No plan means no denominators; fall back to a transparent run rather - // than draw meaningless bars. - fmt.Fprintln(stderrFile, "ele: no restore plan available; passing through") - return passthrough(ctx, args, stdout, stderrFile) + fmt.Fprintln(stderrFile, "ele: "+countlessReason(dumpPath)+"; progress runs without totals") + title += " (no totals)" } - logPath := "ele-" + time.Now().Format("20060102-150405") + ".log" + logPath := logDestination(time.Now()) logf, err := os.Create(logPath) if err != nil { - return 1, fmt.Errorf("creating log: %w", err) + return 1, fmt.Errorf("creating log %s: %w", logPath, err) } defer logf.Close() @@ -68,7 +77,7 @@ func Run(ctx context.Context, args []string, stdout io.Writer, stderrFile *os.Fi start := time.Now() live, stopTicker := startRenderer(stderrFile, agg, &mu, start, render.Opts{ - Title: f.dbName, + Title: title, LogPath: logPath, Styles: render.NewStyles(stderrFile), }) @@ -180,6 +189,16 @@ func blockSize(stderrFile *os.File) (width, maxLines int) { return w, 0 } +// countlessReason names why this run has no denominators, for the note printed +// above the block. A missing dump path is the stdin case the contract calls out; +// anything else means preflight itself failed, and it already said how. +func countlessReason(dumpPath string) string { + if dumpPath == "" { + return "no dump to preflight (restoring from stdin)" + } + return "preflight produced no plan" +} + // preflightPlan runs preflight, returning nil (with a note) when it can't. func preflightPlan(ctx context.Context, dumpPath string, stderrFile *os.File) *toc.RestorePlan { if dumpPath == "" { @@ -198,7 +217,7 @@ func preflightPlan(ctx context.Context, dumpPath string, stderrFile *os.File) *t // hack. A signal death or any real error keeps a failing code. func exitCode(result *runner.Result, snap aggregator.Snapshot, stderrFile *os.File) int { code := result.ExitCode - if code != 0 && !result.Signaled && snap.ErrReal == 0 && os.Getenv("ELE_STRICT_EXIT") == "" { + if code != 0 && !result.Signaled && snap.ErrReal == 0 && !strictExit() { fmt.Fprintf(stderrFile, "\nele: pg_restore exited %d but all errors were benign; normalizing to 0\n", code) return 0 } diff --git a/internal/engine/env.go b/internal/engine/env.go new file mode 100644 index 0000000..dd3c17c --- /dev/null +++ b/internal/engine/env.go @@ -0,0 +1,34 @@ +package engine + +import ( + "os" + "time" +) + +// ele has no flags of its own - pg_restore owns the whole argv - so every knob +// is an environment variable. These three are the engine's; the renderer reads +// ELE_PLAIN / NO_COLOR / CI / CLAUDECODE in internal/render, and --replay reads +// ELE_REPLAY_SECONDS. Unset and empty always mean the same thing. +const ( + envLog = "ELE_LOG" + envPassthrough = "ELE_PASSTHROUGH" + envStrictExit = "ELE_STRICT_EXIT" +) + +// logDestination is where the raw pg_restore stderr gets teed: ELE_LOG when it +// names a path, else a timestamped file in the working directory. +func logDestination(now time.Time) string { + if p := os.Getenv(envLog); p != "" { + return p + } + return "ele-" + now.Format("20060102-150405") + ".log" +} + +// passthroughRequested reports whether ELE_PASSTHROUGH asks for the raw +// firehose - pg_restore's own stderr and exit code, no aggregation. It is the +// only way back to unwrapped output; the degraded modes never give it. +func passthroughRequested() bool { return os.Getenv(envPassthrough) != "" } + +// strictExit reports whether ELE_STRICT_EXIT asks for pg_restore's raw exit +// code, leaving a benign-only failure nonzero. +func strictExit() bool { return os.Getenv(envStrictExit) != "" } diff --git a/internal/engine/env_test.go b/internal/engine/env_test.go new file mode 100644 index 0000000..cba26bb --- /dev/null +++ b/internal/engine/env_test.go @@ -0,0 +1,51 @@ +package engine + +import ( + "strings" + "testing" + "time" +) + +func TestLogDestination(t *testing.T) { + at := time.Date(2026, 7, 22, 16, 18, 15, 0, time.UTC) + + t.Run("default is timestamped in the cwd", func(t *testing.T) { + t.Setenv(envLog, "") + if got := logDestination(at); got != "ele-20260722-161815.log" { + t.Errorf("logDestination = %q, want the timestamped default", got) + } + }) + + t.Run("ELE_LOG names the path", func(t *testing.T) { + t.Setenv(envLog, "/tmp/restore.log") + if got := logDestination(at); got != "/tmp/restore.log" { + t.Errorf("logDestination = %q, want /tmp/restore.log", got) + } + }) + + // Empty has to behave as unset, the way every other var here does. + t.Run("empty falls back to the default", func(t *testing.T) { + t.Setenv(envLog, "") + if got := logDestination(at); !strings.HasPrefix(got, "ele-") { + t.Errorf("logDestination = %q, want the default", got) + } + }) +} + +func TestEnvFlags(t *testing.T) { + t.Run("unset", func(t *testing.T) { + t.Setenv(envPassthrough, "") + t.Setenv(envStrictExit, "") + if passthroughRequested() || strictExit() { + t.Error("flags set with empty environment") + } + }) + + t.Run("set", func(t *testing.T) { + t.Setenv(envPassthrough, "1") + t.Setenv(envStrictExit, "1") + if !passthroughRequested() || !strictExit() { + t.Error("flags not picked up") + } + }) +} diff --git a/internal/engine/replay.go b/internal/engine/replay.go index 1f46c3e..283101e 100644 --- a/internal/engine/replay.go +++ b/internal/engine/replay.go @@ -24,7 +24,8 @@ const replaySeconds = 12 // Replay reruns a captured pg_restore stderr log through the full pipeline // without touching a database - a safe dry-run of the live view. planSource is -// either a real dump (preflighted) or a saved `pg_restore -l` listing file; +// a real dump (preflighted), a saved `pg_restore -l` listing file, or "-" for +// the countless view a planless restore gets; // logPath is the captured stderr. On a TTY it drives the live block paced over // replaySeconds, then prints the summary; otherwise it prints milestones and the // summary. The exit code reflects the log's verdict: real errors -> 1, else 0. @@ -43,9 +44,14 @@ func Replay(ctx context.Context, planSource, logPath string, stdout io.Writer, s p := parser.New() var mu sync.Mutex + title := "(replay) " + logPath + if plan == nil { + title += " (no totals)" + } + start := time.Now() live, stopTicker := startRenderer(stderrFile, agg, &mu, start, render.Opts{ - Title: "(replay) " + logPath, + Title: title, LogPath: logPath, Styles: render.NewStyles(stderrFile), }) @@ -112,8 +118,13 @@ func replayPacing(live bool, lines int) time.Duration { } // loadPlan builds a RestorePlan from a dump or a saved `pg_restore -l` listing. -// preflight.Run handles the detection for both. +// preflight.Run handles the detection for both. "-" means no plan at all: the +// countless replay, which is how the denominator-free view a stdin restore gets +// can be seen and tested without a stdin restore. func loadPlan(ctx context.Context, source string) (*toc.RestorePlan, error) { + if source == "-" { + return nil, nil + } res, err := preflight.Run(ctx, source) if err != nil { return nil, err diff --git a/internal/engine/replay_test.go b/internal/engine/replay_test.go index 3ca58b8..9d62cc7 100644 --- a/internal/engine/replay_test.go +++ b/internal/engine/replay_test.go @@ -74,3 +74,31 @@ func TestLoadPlanListing(t *testing.T) { t.Errorf("phase counts = %d/%d/%d, want 15/7/11", pre, data, post) } } + +// TestReplayCountless is the offline view of a stdin restore: "-" for the plan +// means no denominators at all. The same log still yields counts, the same +// benign verdict, and exit 0 - only the bars are gone. +func TestReplayCountless(t *testing.T) { + out, code := runReplay(t, "-", logFixture) + if code != 0 { + t.Errorf("exit = %d, want 0 (all errors benign)", code) + } + for _, want := range []string{"success", "21 benign", "objects"} { + if !strings.Contains(out, want) { + t.Errorf("countless summary missing %q:\n%s", want, out) + } + } + for _, unwanted := range []string{"15/15", "7/7", "11/11"} { + if strings.Contains(out, unwanted) { + t.Errorf("countless summary shows the planned fraction %q:\n%s", unwanted, out) + } + } +} + +// A nil plan is the contract loadPlan owes Replay for "-", not an error. +func TestLoadPlanCountless(t *testing.T) { + plan, err := loadPlan(context.Background(), "-") + if err != nil || plan != nil { + t.Errorf("loadPlan(\"-\") = %v, %v; want nil, nil", plan, err) + } +} diff --git a/internal/render/frame.go b/internal/render/frame.go index a409f8e..abf4cc8 100644 --- a/internal/render/frame.go +++ b/internal/render/frame.go @@ -94,9 +94,9 @@ func Frame(s aggregator.Snapshot, opt Opts) []string { if cl := cleanupLine(st, s, opt.Spinner); cl != "" { add(" %-10s %s", "cleanup", cl) } - add(" %s", phaseBar(st, "pre-data", fillPre, s.Pre, "")) - add(" %s", phaseBar(st, "data", fillData, s.Data, dataNote(s))) - add(" %s", phaseBar(st, "post-data", fillPost, s.Post, "")) + for _, row := range phaseRows(st, s) { + add(" %s", row) + } // The working line sits below all three bars: under -j, data and post-data // items run concurrently, so it reflects current activity across the restore. // Its spinner and live timer are what tell a long single item apart from a hang. @@ -140,6 +140,46 @@ func groupLimit(maxLines, used int) int { return min(maxGroups, max(maxLines-used-1, 0)) // -1 reserves the "… N more" row } +// phaseRows renders the three phase rows: bars when preflight supplied +// denominators, bare counts when it couldn't (countless mode). Frame and +// Summary share it so the block appears to freeze in place at the end of a run +// rather than change shape. +func phaseRows(st *Styles, s aggregator.Snapshot) []string { + if s.Countless { + return []string{ + phaseCount(st, "pre-data", s.Pre), + phaseCount(st, "data", s.Data), + phaseCount(st, "post-data", s.Post), + } + } + return []string{ + phaseBar(st, "pre-data", fillPre, s.Pre, ""), + phaseBar(st, "data", fillData, s.Data, dataNote(s)), + phaseBar(st, "post-data", fillPost, s.Post, ""), + } +} + +// phaseCount renders a phase with no denominator to draw against: the running +// object count where the bar would be, and nothing that implies a fraction. The +// count sits in the bar's own column so the three rows stay aligned with each +// other and with the cleanup row above them. +func phaseCount(st *Styles, name string, p aggregator.PhaseProgress) string { + count := fmt.Sprintf("%d %s", p.Done, objectWord(p.Done)) + line := fmt.Sprintf("%-10s %s", name, count) + if !p.Complete { + return line + } + pad := max(barWidth-ansi.StringWidth(count), 1) + return line + strings.Repeat(" ", pad) + " " + st.done.Render("done") +} + +func objectWord(n int) string { + if n == 1 { + return "object" + } + return "objects" +} + // phaseBar renders "name ▓▓▓░░░ done/total pct" with an optional trailing // note. fill is the phase's filled-cell glyph; the empty track is uniform. A // complete phase reads 100% and "done" even if pg_restore skipped some entries - diff --git a/internal/render/plain.go b/internal/render/plain.go index f57203a..812b4f1 100644 --- a/internal/render/plain.go +++ b/internal/render/plain.go @@ -3,6 +3,7 @@ package render import ( "fmt" "io" + "strconv" "time" "github.com/amberpixels/ele/internal/aggregator" @@ -10,9 +11,19 @@ import ( ) // PlainProgress emits a one-line status to w at meaningful milestones - each -// phase completion and every 10% within a phase. It is the degraded-mode +// phase completion and every 10% within a phase, or, with no denominators to +// measure against, every countlessStep objects. It is the degraded-mode // substitute for the live repaint block (non-TTY, CI, NO_COLOR, ELE_PLAIN), // never the raw firehose. Feed it snapshots on a ticker. +// countlessStep and countlessInterval pace the line when there are no +// denominators to hit deciles against: a milestone is every N objects, or every +// N seconds, whichever lands first. Without them a countless restore would +// print one line at the start and then nothing for the rest of the run. +const ( + countlessStep = 50 + countlessInterval = 15 * time.Second +) + type PlainProgress struct { w io.Writer st *Styles @@ -21,6 +32,11 @@ type PlainProgress struct { preDone bool dataDecile int postDecile int + + // countless pacing: the object count and the elapsed reading at the last + // emitted line. + lastCount int + lastEmit time.Duration } // NewPlainProgress returns an emitter writing to w. @@ -34,6 +50,18 @@ func (p *PlainProgress) Update(s aggregator.Snapshot, elapsed time.Duration) { milestone := !p.started p.started = true + if s.Countless { + done := s.Pre.Done + s.Data.Done + s.Post.Done + if done-p.lastCount >= countlessStep || elapsed-p.lastEmit >= countlessInterval { + milestone = true + } + if milestone { + p.lastCount, p.lastEmit = done, elapsed + p.emit(s, elapsed) + } + return + } + if s.Pre.Total > 0 && s.Pre.Done == s.Pre.Total && !p.preDone { p.preDone = true milestone = true @@ -57,9 +85,9 @@ func (p *PlainProgress) emit(s aggregator.Snapshot, elapsed time.Duration) { realStyle = p.st.real } fmt.Fprintf(p.w, "ele · pre %s · data %s · post %s · %d err · %s", - frac(s.Pre.Done, s.Pre.Total), - fracPct(s.Data.Done, s.Data.Total), - fracPct(s.Post.Done, s.Post.Total), + countOr(s.Countless, s.Pre.Done, frac(s.Pre.Done, s.Pre.Total)), + countOr(s.Countless, s.Data.Done, fracPct(s.Data.Done, s.Data.Total)), + countOr(s.Countless, s.Post.Done, fracPct(s.Post.Done, s.Post.Total)), s.ErrTotal, realStyle.Render(fmt.Sprintf("%d real", s.ErrReal)), ) @@ -87,6 +115,15 @@ func decile(done, total int) int { return done * 10 / total } +// countOr is the bare count in countless mode, where "0/0 0%" would be a lie +// dressed as a fraction, and the given fraction otherwise. +func countOr(countless bool, done int, fraction string) string { + if countless { + return strconv.Itoa(done) + } + return fraction +} + func frac(done, total int) string { return fmt.Sprintf("%d/%d", done, total) } func fracPct(done, total int) string { diff --git a/internal/render/render_test.go b/internal/render/render_test.go index 8794128..7bc6fd7 100644 --- a/internal/render/render_test.go +++ b/internal/render/render_test.go @@ -342,3 +342,91 @@ func TestLiveClose(t *testing.T) { t.Error("Close should restore the cursor") } } + +// countlessSample is the stdin restore: counts, no denominators, same errors. +func countlessSample() aggregator.Snapshot { + s := sample() + s.Countless = true + s.Pre = aggregator.PhaseProgress{Done: 1009, Complete: true} + s.Data = aggregator.PhaseProgress{Done: 166} + s.Post = aggregator.PhaseProgress{Done: 4} + return s +} + +// TestFrameCountless: with no plan there is nothing to draw a bar against, so +// the rows carry counts and nothing that implies a fraction. Everything that +// never needed denominators - the working line, the log line, the error panel - +// stays exactly as it was. +func TestFrameCountless(t *testing.T) { + s := countlessSample() + s.Working = []aggregator.WorkItem{{Desc: "TABLE DATA", Name: "activity_logs"}} + out := joined(Frame(s, Opts{Title: "throwaway", LogPath: "run.log", Spinner: '⣾'})) + + for _, want := range []string{ + "pre-data 1009 objects", "data 166 objects", "post-data 4 objects", + "done", // pre-data finished, and says so without a bar + "activity_logs", // working line intact + "run.log", + "1909 total", "0 real", + } { + if !strings.Contains(out, want) { + t.Errorf("countless frame missing %q:\n%s", want, out) + } + } + for _, unwanted := range []string{"░", "█", "▓", "▒", "%", "/1009"} { + if strings.Contains(out, unwanted) { + t.Errorf("countless frame still shows %q (no denominators exist):\n%s", unwanted, out) + } + } +} + +// The summary mirrors the live block, so it drops the bars too. +func TestSummaryCountless(t *testing.T) { + var buf bytes.Buffer + Summary(&buf, countlessSample(), "run.log", time.Minute, 100) + out := buf.String() + + if !strings.Contains(out, "data 166 objects") { + t.Errorf("countless summary missing the data count:\n%s", out) + } + if strings.Contains(out, "░") || strings.Contains(out, "166/") { + t.Errorf("countless summary still shows a bar or a fraction:\n%s", out) + } + if !strings.Contains(out, "success") { + t.Errorf("countless summary missing the verdict:\n%s", out) + } +} + +// TestPlainProgressCountless: deciles can't fire without totals, so the plain +// line paces on the object count instead. The old rule would have emitted once +// and then gone silent for the whole restore. +func TestPlainProgressCountless(t *testing.T) { + var buf bytes.Buffer + pp := NewPlainProgress(&buf) + + snap := func(pre, data int) aggregator.Snapshot { + return aggregator.Snapshot{ + Countless: true, + Pre: aggregator.PhaseProgress{Done: pre}, + Data: aggregator.PhaseProgress{Done: data}, + } + } + + pp.Update(snap(0, 0), 0) // first tick -> emits + pp.Update(snap(20, 0), time.Second) // under the step, under the interval + pp.Update(snap(60, 0), 2*time.Second) // 60 objects on -> emits + pp.Update(snap(70, 0), 3*time.Second) // only 10 since the last line + pp.Update(snap(70, 0), 20*time.Second) // quiet, but the interval elapsed -> emits + pp.Update(snap(70, 5), 21*time.Second) // nothing new to say + + out := buf.String() + if n := strings.Count(out, "\n"); n != 3 { + t.Errorf("emitted %d lines, want 3:\n%s", n, out) + } + if !strings.Contains(out, "pre 70 · data 0") { + t.Errorf("counts not reported bare:\n%s", out) + } + if strings.Contains(out, "0/0") { + t.Errorf("plain line invented a denominator:\n%s", out) + } +} diff --git a/internal/render/summary.go b/internal/render/summary.go index d464e5c..a2a3354 100644 --- a/internal/render/summary.go +++ b/internal/render/summary.go @@ -26,9 +26,9 @@ func Summary(w io.Writer, s aggregator.Snapshot, logPath string, elapsed time.Du if cl := cleanupLine(st, s, 0); cl != "" { fmt.Fprintf(w, " %-10s %s\n", "cleanup", cl) } - fmt.Fprintf(w, " %s\n", phaseBar(st, "pre-data", fillPre, s.Pre, "")) - fmt.Fprintf(w, " %s\n", phaseBar(st, "data", fillData, s.Data, dataNote(s))) - fmt.Fprintf(w, " %s\n", phaseBar(st, "post-data", fillPost, s.Post, "")) + for _, row := range phaseRows(st, s) { + fmt.Fprintf(w, " %s\n", row) + } if logPath != "" { fmt.Fprintf(w, "\n raw log %s\n", st.dim.Render(logPath)) From 662d78b119a2ff80c1e75aaef1d62d67d385314f Mon Sep 17 00:00:00 2001 From: Eugene Date: Sun, 20 Sep 2026 15:33:50 +0300 Subject: [PATCH 2/4] Generate the parser's message table from pg_dump's catalogs The wordings the parser matched on were hand-copied, which made every new PostgreSQL major a silent downgrade: a reworded message stops matching, the line becomes Unknown, and the bars quietly stall until somebody notices. tools/pgmsg closes that. It pulls the msgid set of pg_dump's message catalog at REL_13 through REL_18, snapshots each one under tools/pgmsg/testdata, and emits internal/parser/messages_gen.go. Regenerating is deterministic - sorted, no timestamps - so rerunning against the same tags is a no-op, and `just gen-messages--check` proves it offline from the snapshots. The source is a committed .po rather than pg_dump.pot: the .pot template is a build artifact and is 404 at every release tag on the mirror, while the .po translations carry the identical msgid set. Two languages are unioned per tag, since one translation can lag upstream but two are unlikely to lag the same message. What the generator owns is wording and version coverage; what stays hand-written is meaning. gettext carries no semantics, so the msgid -> event bindings live in the generator's own source and are checked against upstream on every run: absent from every tag is an error, absent from some is recorded as a narrower range. `Command was: %s` is already that case - standalone in 17 and 18, folded into the query-error message in 13. The envelope stays hand-written too, because it isn't pg_dump's: the `pg_restore:` prefix, the error:/warning:/detail: tags from common/logging.c, and the from-TOC-entry context line. The golden suite is the equivalence proof - it replays all three fixtures through the rewritten classify unchanged. --- internal/parser/messages.go | 49 +++ internal/parser/messages_gen.go | 39 ++ internal/parser/parser.go | 92 ++-- internal/parser/parser_test.go | 39 ++ justfile | 17 + tools/pgmsg/bindings.go | 41 ++ tools/pgmsg/main.go | 373 ++++++++++++++++ tools/pgmsg/testdata/REL_13_STABLE.txt | 510 +++++++++++++++++++++ tools/pgmsg/testdata/REL_14_STABLE.txt | 524 ++++++++++++++++++++++ tools/pgmsg/testdata/REL_15_STABLE.txt | 505 +++++++++++++++++++++ tools/pgmsg/testdata/REL_16_STABLE.txt | 537 +++++++++++++++++++++++ tools/pgmsg/testdata/REL_17_STABLE.txt | 572 ++++++++++++++++++++++++ tools/pgmsg/testdata/REL_18_STABLE.txt | 585 +++++++++++++++++++++++++ 13 files changed, 3837 insertions(+), 46 deletions(-) create mode 100644 internal/parser/messages.go create mode 100644 internal/parser/messages_gen.go create mode 100644 tools/pgmsg/bindings.go create mode 100644 tools/pgmsg/main.go create mode 100644 tools/pgmsg/testdata/REL_13_STABLE.txt create mode 100644 tools/pgmsg/testdata/REL_14_STABLE.txt create mode 100644 tools/pgmsg/testdata/REL_15_STABLE.txt create mode 100644 tools/pgmsg/testdata/REL_16_STABLE.txt create mode 100644 tools/pgmsg/testdata/REL_17_STABLE.txt create mode 100644 tools/pgmsg/testdata/REL_18_STABLE.txt diff --git a/internal/parser/messages.go b/internal/parser/messages.go new file mode 100644 index 0000000..4e23f79 --- /dev/null +++ b/internal/parser/messages.go @@ -0,0 +1,49 @@ +package parser + +import "strings" + +// A message body is matched against a table generated from pg_dump's own +// gettext catalogs - see tools/pgmsg and messages_gen.go. This file is the +// hand-written half of that split: what a matched message means, and which +// Event fields its arguments fill. Wording lives upstream; meaning lives here. + +// shape is how a message's format arguments are read back out of the printed +// line. Each shape is named for the Event fields it fills. +type shape uint8 + +const ( + shapeNone shape = iota // no arguments worth keeping + shapeTOCEntry // a TOC listing line; sets the error-context dump id + shapeDescTag // " " -> Desc, Tag + shapeDescName // " " -> Desc, Name + shapeDescQuoted // ` ""` -> Desc, Name + shapeQuotedName // `""` -> Name + shapeItem // " " -> DumpID, Desc, Tag +) + +// message is one row of the generated table: the text pg_restore prints before +// its first argument, and what that message means. +type message struct { + literal string + exact bool // the whole message is literal - it takes no arguments + kind Kind + shape shape +} + +// matchMessage finds the message whose literal opens body and returns it with +// the remainder: the arguments pg_restore filled in. The table is ordered +// longest-literal-first, so the first hit is the most specific one. +func matchMessage(body string) (message, string, bool) { + for _, m := range messages { + if m.exact { + if body == m.literal { + return m, "", true + } + continue + } + if strings.HasPrefix(body, m.literal) { + return m, body[len(m.literal):], true + } + } + return message{}, "", false +} diff --git a/internal/parser/messages_gen.go b/internal/parser/messages_gen.go new file mode 100644 index 0000000..2a76c7b --- /dev/null +++ b/internal/parser/messages_gen.go @@ -0,0 +1,39 @@ +// Code generated by tools/pgmsg. DO NOT EDIT. +// +// Source: src/bin/pg_dump/po/{de,fr}.po at REL_13_STABLE .. REL_18_STABLE +// (github.com/postgres/postgres). Regenerate with `just gen-messages`. + +package parser + +// messages is what pg_restore prints, mapped to what it means. Ordered +// longest-literal-first, so the first match is the most specific one. +var messages = []message{ + // "connecting to database for restore" (13-18) + {literal: "connecting to database for restore", exact: true, kind: KindInfo, shape: shapeNone}, + // "entering main parallel loop" (13-18) + {literal: "entering main parallel loop", exact: true, kind: KindInfo, shape: shapeNone}, + // "finished main parallel loop" (13-18) + {literal: "finished main parallel loop", exact: true, kind: KindInfo, shape: shapeNone}, + // "processing data for table \"%s.%s\"" (13-18) + {literal: "processing data for table ", exact: false, kind: KindProcessingData, shape: shapeQuotedName}, + // "while PROCESSING TOC:" (13-18) + {literal: "while PROCESSING TOC:", exact: true, kind: KindInfo, shape: shapeNone}, + // "while INITIALIZING:" (13-18) + {literal: "while INITIALIZING:", exact: true, kind: KindInfo, shape: shapeNone}, + // "while FINALIZING:" (13-18) + {literal: "while FINALIZING:", exact: true, kind: KindInfo, shape: shapeNone}, + // "processing item %d %s %s" (13-18) + {literal: "processing item ", exact: false, kind: KindProcessingItem, shape: shapeItem}, + // "from TOC entry %d; %u %u %s %s %s" (13-18) + {literal: "from TOC entry ", exact: false, kind: KindUnknown, shape: shapeTOCEntry}, + // "launching item %d %s %s" (13-18) + {literal: "launching item ", exact: false, kind: KindLaunchItem, shape: shapeItem}, + // "finished item %d %s %s" (13-18) + {literal: "finished item ", exact: false, kind: KindFinishItem, shape: shapeItem}, + // "executing %s %s" (13-18), "executing %s" (13-18) + {literal: "executing ", exact: false, kind: KindExecuting, shape: shapeDescName}, + // "creating %s \"%s.%s\"" (13-18), "creating %s \"%s\"" (13-18) + {literal: "creating ", exact: false, kind: KindCreating, shape: shapeDescQuoted}, + // "dropping %s %s" (13-18) + {literal: "dropping ", exact: false, kind: KindDropping, shape: shapeDescTag}, +} diff --git a/internal/parser/parser.go b/internal/parser/parser.go index 0ce6652..fab93f6 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -4,6 +4,10 @@ // locking, which doubles, splits, or drops that prefix mid-line. Lines it can't // classify become KindUnknown rather than errors, so wording drift across // PostgreSQL versions never breaks the pipeline. +// +// The wordings it matches on are not hand-written: messages_gen.go is generated +// from pg_dump's own gettext catalogs across the supported releases (see +// tools/pgmsg), and messages.go binds each one to the Event it means. package parser import ( @@ -71,62 +75,58 @@ func (p *Parser) flushErr() []Event { return []Event{ev} } -// classify maps a de-prefixed body to an Event. raw is the original line, kept -// for the KindUnknown fallback. ok is false only for context-only lines that -// produce no event (e.g. "from TOC entry", "while PROCESSING TOC:"). +// classify maps a de-prefixed body to an Event, matching it against the +// generated message table (messages_gen.go). raw is the original line, kept for +// the KindUnknown fallback. ok is false only for context-only lines that produce +// no event of their own (the "from TOC entry" line). func (p *Parser) classify(body, raw string) (Event, bool) { - switch { - case body == "connecting to database for restore", - body == "entering main parallel loop", - body == "finished main parallel loop", - body == "while PROCESSING TOC:": - return Event{Kind: KindInfo, Raw: body}, true - - case strings.HasPrefix(body, "from TOC entry "): - // The remainder is a TOC listing line; reuse the toc parser for its id. - if e, ok := toc.ParseListingLine(strings.TrimPrefix(body, "from TOC entry ")); ok { + // Severity tags are part of the envelope - they come from + // src/common/logging.c, not pg_dump's message catalog - so they're matched + // here rather than in the generated table. + if msg, ok := cut(body, "error: "); ok { + ev := Event{Kind: KindError, Message: msg, DumpID: p.pendingCtxID} + p.pendingCtxID = 0 + return ev, true + } + if msg, ok := cut(body, "warning: "); ok { + return Event{Kind: KindWarning, Message: msg}, true + } + + m, args, ok := matchMessage(body) + if !ok { + return Event{Kind: KindUnknown, Raw: raw}, true + } + + switch m.shape { + case shapeTOCEntry: + // Error context, not an event of its own: the remainder is a TOC + // listing line, so reuse the toc parser for its id. + if e, ok := toc.ParseListingLine(args); ok { p.pendingCtxID = e.DumpID } return Event{}, false - case strings.HasPrefix(body, "dropping "): - desc, tag := splitDescTag(strings.TrimPrefix(body, "dropping ")) - return Event{Kind: KindDropping, Desc: desc, Tag: tag}, true + case shapeDescTag: + desc, tag := splitDescTag(args) + return Event{Kind: m.kind, Desc: desc, Tag: tag}, true - case strings.HasPrefix(body, "creating "): - desc, name := splitDescQuoted(strings.TrimPrefix(body, "creating ")) - return Event{Kind: KindCreating, Desc: desc, Name: name}, true + case shapeDescName: + desc, name := splitDescTag(args) + return Event{Kind: m.kind, Desc: desc, Name: name}, true - case strings.HasPrefix(body, "processing data for table "): - return Event{Kind: KindProcessingData, Name: unquote(strings.TrimPrefix(body, "processing data for table "))}, true + case shapeDescQuoted: + desc, name := splitDescQuoted(args) + return Event{Kind: m.kind, Desc: desc, Name: name}, true - case strings.HasPrefix(body, "processing item "): - id, desc, tag := splitItem(strings.TrimPrefix(body, "processing item ")) - return Event{Kind: KindProcessingItem, DumpID: id, Desc: desc, Tag: tag}, true + case shapeQuotedName: + return Event{Kind: m.kind, Name: unquote(args)}, true - case strings.HasPrefix(body, "launching item "): - id, desc, tag := splitItem(strings.TrimPrefix(body, "launching item ")) - return Event{Kind: KindLaunchItem, DumpID: id, Desc: desc, Tag: tag}, true + case shapeItem: + id, desc, tag := splitItem(args) + return Event{Kind: m.kind, DumpID: id, Desc: desc, Tag: tag}, true - case strings.HasPrefix(body, "finished item "): - id, desc, tag := splitItem(strings.TrimPrefix(body, "finished item ")) - return Event{Kind: KindFinishItem, DumpID: id, Desc: desc, Tag: tag}, true - - case strings.HasPrefix(body, "executing "): - desc, name := splitDescTag(strings.TrimPrefix(body, "executing ")) - return Event{Kind: KindExecuting, Desc: desc, Name: name}, true - - case strings.HasPrefix(body, "error: "): - msg := strings.TrimPrefix(body, "error: ") - ev := Event{Kind: KindError, Message: msg, DumpID: p.pendingCtxID} - p.pendingCtxID = 0 - return ev, true - - case strings.HasPrefix(body, "warning: "): - return Event{Kind: KindWarning, Message: strings.TrimPrefix(body, "warning: ")}, true - - default: - return Event{Kind: KindUnknown, Raw: raw}, true + default: // shapeNone: the message is its own meaning + return Event{Kind: m.kind, Raw: body}, true } } diff --git a/internal/parser/parser_test.go b/internal/parser/parser_test.go index b2780fd..5870cb9 100644 --- a/internal/parser/parser_test.go +++ b/internal/parser/parser_test.go @@ -194,3 +194,42 @@ func TestParallelInterleaving(t *testing.T) { t.Errorf("parsed %d errors, pg_restore reported %d", got, want) } } + +// TestMessageTableOrder guards the invariant matchMessage depends on and the +// generator provides: longest literal first, so a specific message can never be +// shadowed by a shorter one that happens to share its opening words. +func TestMessageTableOrder(t *testing.T) { + for i := 1; i < len(messages); i++ { + if len(messages[i-1].literal) < len(messages[i].literal) { + t.Fatalf("table out of order at %d: %q before %q - regenerate with `just gen-messages`", + i, messages[i-1].literal, messages[i].literal) + } + } + + // Every literal has to be reachable: a literal that another entry already + // matches in full would be dead weight in the scan. + for i, m := range messages { + if got, _, ok := matchMessage(m.literal); ok && got.literal != m.literal { + t.Errorf("entry %d (%q) is shadowed by %q", i, m.literal, got.literal) + } + } +} + +// TestMessageTableCovers pins the kinds the table is expected to carry, so a +// regeneration that silently dropped a binding fails here rather than showing +// up as a stalled progress bar during a restore. +func TestMessageTableCovers(t *testing.T) { + want := []Kind{ + KindInfo, KindDropping, KindCreating, KindProcessingData, + KindProcessingItem, KindLaunchItem, KindFinishItem, KindExecuting, + } + have := map[Kind]bool{} + for _, m := range messages { + have[m.kind] = true + } + for _, k := range want { + if !have[k] { + t.Errorf("no message maps to %s", k) + } + } +} diff --git a/justfile b/justfile index 5053950..9601ccb 100644 --- a/justfile +++ b/justfile @@ -91,6 +91,23 @@ _golangci-install: test *ARGS: go test {{ARGS}} ./... +# --- Codegen --- +# +# The parser's message table comes from PostgreSQL's own pg_dump catalogs, so a +# new major is a data change: run `gen-messages` when one ships, read the drift +# summary it prints, and commit what moved. + +# Regenerate the message table from upstream release tags - fetches over the network +[group('gen')] +gen-messages: + go run ./tools/pgmsg + +# Regenerate from the committed msgid snapshots; fails if anything moved - immutable +[group('gen')] +gen-messages--check: + go run ./tools/pgmsg -offline + git diff --exit-code internal/parser/messages_gen.go tools/pgmsg/testdata + # --- CI & release --- # Everything CI runs, in CI's order (build, vet, test) - immutable diff --git a/tools/pgmsg/bindings.go b/tools/pgmsg/bindings.go new file mode 100644 index 0000000..a3aea04 --- /dev/null +++ b/tools/pgmsg/bindings.go @@ -0,0 +1,41 @@ +package main + +// binding is one pg_dump message the parser acts on: the upstream msgid, the +// event it means, and how its arguments are read back out of the printed line. +// +// This table is hand-maintained on purpose. A gettext catalog carries wording, +// never meaning, so no generator can decide that "launching item %d %s %s" is +// the start of a parallel item. What the generator does instead is prove every +// line below still exists upstream, and emit the literal text to match on. +type binding struct { + msgid string + kind string // parser.Kind constant + shape string // parser shape constant: which fields the arguments fill +} + +// bindings covers exactly what parser.classify matches on a message body. +// The envelope around it - the "pg_restore:" prefix, the error:/warning:/detail: +// severity tags, the "Command was:" continuation - comes from +// src/common/logging.c rather than pg_dump's catalog, and stays hand-written in +// the parser. +var bindings = []binding{ + {"connecting to database for restore", "KindInfo", "shapeNone"}, + {"entering main parallel loop", "KindInfo", "shapeNone"}, + {"finished main parallel loop", "KindInfo", "shapeNone"}, + {"while INITIALIZING:", "KindInfo", "shapeNone"}, + {"while PROCESSING TOC:", "KindInfo", "shapeNone"}, + {"while FINALIZING:", "KindInfo", "shapeNone"}, + + // Context for the error that follows it; sets parser state, emits nothing. + {"from TOC entry %d; %u %u %s %s %s", "KindUnknown", "shapeTOCEntry"}, + + {"dropping %s %s", "KindDropping", "shapeDescTag"}, + {"creating %s \"%s.%s\"", "KindCreating", "shapeDescQuoted"}, + {"creating %s \"%s\"", "KindCreating", "shapeDescQuoted"}, + {"processing data for table \"%s.%s\"", "KindProcessingData", "shapeQuotedName"}, + {"processing item %d %s %s", "KindProcessingItem", "shapeItem"}, + {"launching item %d %s %s", "KindLaunchItem", "shapeItem"}, + {"finished item %d %s %s", "KindFinishItem", "shapeItem"}, + {"executing %s %s", "KindExecuting", "shapeDescName"}, + {"executing %s", "KindExecuting", "shapeDescName"}, +} diff --git a/tools/pgmsg/main.go b/tools/pgmsg/main.go new file mode 100644 index 0000000..0f602e9 --- /dev/null +++ b/tools/pgmsg/main.go @@ -0,0 +1,373 @@ +// Command pgmsg regenerates the parser's message table from PostgreSQL's own +// message catalogs, so a new major release is a data change rather than a +// guessing game about which wording moved. +// +// It pulls the msgid set of src/bin/pg_dump/po/.po at each supported +// release tag from the GitHub mirror, snapshots it under testdata/, checks the +// hand-maintained bindings (bindings.go) still exist upstream, and writes +// internal/parser/messages_gen.go. +// +// go run ./tools/pgmsg # fetch, snapshot, generate +// go run ./tools/pgmsg -offline # generate from the committed snapshots +// +// The .po files are the source rather than pg_dump.pot: the .pot template is a +// build artifact and is not committed upstream (404 at every release tag), +// while the .po translations carry the identical msgid set. Two languages are +// unioned per tag, since one translation can lag upstream but two are unlikely +// to lag the same message. +package main + +import ( + "flag" + "fmt" + "go/format" + "io" + "log" + "net/http" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "time" +) + +const poURL = "https://raw.githubusercontent.com/postgres/postgres/%s/src/bin/pg_dump/po/%s.po" + +func main() { + log.SetFlags(0) + log.SetPrefix("pgmsg: ") + + tags := flag.String("tags", "REL_13_STABLE,REL_14_STABLE,REL_15_STABLE,REL_16_STABLE,REL_17_STABLE,REL_18_STABLE", + "release tags to read, oldest first") + langs := flag.String("langs", "de,fr", "translations to union per tag") + snapshots := flag.String("snapshots", filepath.Join("tools", "pgmsg", "testdata"), "where msgid snapshots live") + out := flag.String("out", filepath.Join("internal", "parser", "messages_gen.go"), "generated file") + offline := flag.Bool("offline", false, "read the committed snapshots instead of fetching") + flag.Parse() + + tagList := split(*tags) + langList := split(*langs) + if len(tagList) == 0 || len(langList) == 0 { + log.Fatal("need at least one tag and one language") + } + + catalogs, err := load(tagList, langList, *snapshots, *offline) + if err != nil { + log.Fatal(err) + } + reportDrift(tagList, catalogs) + + entries, err := resolve(tagList, catalogs) + if err != nil { + log.Fatal(err) + } + if err := write(*out, entries, tagList, langList); err != nil { + log.Fatal(err) + } + log.Printf("wrote %s: %d message(s) from %d binding(s)", *out, len(entries), len(bindings)) +} + +// --- catalogs ------------------------------------------------------------- + +// load returns the msgid set per tag, fetching and snapshotting it unless the +// committed snapshots were asked for. +func load(tags, langs []string, dir string, offline bool) (map[string]map[string]bool, error) { + catalogs := map[string]map[string]bool{} + for _, tag := range tags { + if offline { + set, err := readSnapshot(filepath.Join(dir, tag+".txt")) + if err != nil { + return nil, err + } + catalogs[tag] = set + continue + } + + set := map[string]bool{} + for _, lang := range langs { + body, err := fetch(fmt.Sprintf(poURL, tag, lang)) + if err != nil { + return nil, fmt.Errorf("%s/%s.po: %w", tag, lang, err) + } + for _, id := range msgids(body) { + set[id] = true + } + } + if len(set) == 0 { + return nil, fmt.Errorf("%s: no msgids found", tag) + } + if err := writeSnapshot(filepath.Join(dir, tag+".txt"), tag, langs, set); err != nil { + return nil, err + } + catalogs[tag] = set + log.Printf("%s: %d msgids", tag, len(set)) + } + return catalogs, nil +} + +func fetch(url string) (string, error) { + client := &http.Client{Timeout: 60 * time.Second} + resp, err := client.Get(url) + if err != nil { + return "", err + } + defer func() { _ = resp.Body.Close() }() + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("GET %s: %s", url, resp.Status) + } + b, err := io.ReadAll(resp.Body) + return string(b), err +} + +// msgids extracts every msgid from a .po file. gettext wraps long strings over +// several lines (`msgid ""` followed by quoted fragments), so a msgid is read +// until the first line that isn't another fragment. +func msgids(po string) []string { + var out []string + lines := strings.Split(po, "\n") + for i := 0; i < len(lines); i++ { + line := strings.TrimSpace(lines[i]) + if !strings.HasPrefix(line, "msgid ") { + continue + } + var b strings.Builder + b.WriteString(unquotePO(strings.TrimPrefix(line, "msgid "))) + for i+1 < len(lines) { + next := strings.TrimSpace(lines[i+1]) + if !strings.HasPrefix(next, `"`) { + break + } + b.WriteString(unquotePO(next)) + i++ + } + if s := b.String(); s != "" { + out = append(out, s) + } + } + return out +} + +// unquotePO resolves one quoted .po fragment, including the C escapes gettext +// uses. Anything that isn't a quoted fragment yields nothing. +func unquotePO(s string) string { + s = strings.TrimSpace(s) + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return "" + } + return strings.NewReplacer(`\"`, `"`, `\\`, `\`, `\n`, "\n", `\t`, "\t").Replace(s[1 : len(s)-1]) +} + +// --- snapshots ------------------------------------------------------------ + +// writeSnapshot records a tag's msgid set, one strconv-quoted msgid per line so +// multi-line messages stay on one line and the file diffs cleanly. Sorted, with +// no timestamp, so regenerating an unchanged tag is a no-op. +func writeSnapshot(path, tag string, langs []string, set map[string]bool) error { + var b strings.Builder + fmt.Fprintf(&b, "# msgid set of src/bin/pg_dump/po/{%s}.po at %s\n", strings.Join(langs, ","), tag) + fmt.Fprintf(&b, "# generated by tools/pgmsg; one Go-quoted msgid per line\n") + for _, id := range sorted(set) { + b.WriteString(strconv.Quote(id) + "\n") + } + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + return err + } + return os.WriteFile(path, []byte(b.String()), 0o644) +} + +func readSnapshot(path string) (map[string]bool, error) { + b, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("reading snapshot (run without -offline to create it): %w", err) + } + set := map[string]bool{} + for _, line := range strings.Split(string(b), "\n") { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + id, err := strconv.Unquote(line) + if err != nil { + return nil, fmt.Errorf("%s: %w", path, err) + } + set[id] = true + } + return set, nil +} + +// reportDrift prints how the catalog moved between adjacent releases - the +// cheap early warning that a new major reworded something. +func reportDrift(tags []string, catalogs map[string]map[string]bool) { + for i := 1; i < len(tags); i++ { + prev, cur := catalogs[tags[i-1]], catalogs[tags[i]] + added, removed := 0, 0 + for id := range cur { + if !prev[id] { + added++ + } + } + for id := range prev { + if !cur[id] { + removed++ + } + } + log.Printf("%s -> %s: +%d -%d msgids", tags[i-1], tags[i], added, removed) + } +} + +// --- resolution ----------------------------------------------------------- + +// entry is one row of the generated table: the literal text to match, what it +// means, and the msgids (with their release ranges) that produced it. +type entry struct { + literal string + exact bool + kind string + shape string + sources []string // "msgid" (range), for the row's comment +} + +// resolve checks every binding against the catalogs and folds the bindings that +// share a literal into one row. A binding no release carries is an error: it +// means the parser is matching on wording that no longer exists. +func resolve(tags []string, catalogs map[string]map[string]bool) ([]entry, error) { + byLiteral := map[string]*entry{} + var order []string + var missing []string + + for _, b := range bindings { + var found []string + for _, tag := range tags { + if catalogs[tag][b.msgid] { + found = append(found, tag) + } + } + if len(found) == 0 { + missing = append(missing, b.msgid) + continue + } + + lit, exact := literal(b.msgid) + e := byLiteral[lit] + if e == nil { + e = &entry{literal: lit, exact: exact, kind: b.kind, shape: b.shape} + byLiteral[lit] = e + order = append(order, lit) + } + if e.kind != b.kind || e.shape != b.shape { + return nil, fmt.Errorf("%q: two bindings share a literal but disagree (%s/%s vs %s/%s)", + lit, e.kind, e.shape, b.kind, b.shape) + } + e.sources = append(e.sources, fmt.Sprintf("%s (%s)", strconv.Quote(b.msgid), versions(found))) + } + + if len(missing) > 0 { + return nil, fmt.Errorf("binding(s) absent from every release - upstream reworded them:\n %s", + strings.Join(missing, "\n ")) + } + + // Longest literal first: the most specific match wins, whatever order the + // bindings happen to be written in. + sort.SliceStable(order, func(i, j int) bool { + if len(order[i]) != len(order[j]) { + return len(order[i]) > len(order[j]) + } + return order[i] < order[j] + }) + out := make([]entry, 0, len(order)) + for _, lit := range order { + out = append(out, *byLiteral[lit]) + } + return out, nil +} + +// literal is the text pg_restore prints verbatim: everything before the first +// format verb. A msgid with no verb is matched exactly rather than by prefix. +// +// A quote right before the verb belongs to the argument, not to the literal: +// postgres quotes every identifier, and the parser's unquote is what reads that +// back. Leaving it in the literal would also make the match intolerant of a +// release that stopped quoting there. +func literal(msgid string) (lit string, exact bool) { + if i := strings.IndexByte(msgid, '%'); i >= 0 { + return strings.TrimSuffix(msgid[:i], `"`), false + } + return msgid, true +} + +// versions renders the majors a msgid was found in, compressing runs: "13-18", +// "17-18", "13, 16-18". +func versions(tags []string) string { + var majors []string + for _, t := range tags { + majors = append(majors, strings.TrimSuffix(strings.TrimPrefix(t, "REL_"), "_STABLE")) + } + var parts []string + for i := 0; i < len(majors); { + j := i + for j+1 < len(majors) && consecutive(majors[j], majors[j+1]) { + j++ + } + if i == j { + parts = append(parts, majors[i]) + } else { + parts = append(parts, majors[i]+"-"+majors[j]) + } + i = j + 1 + } + return strings.Join(parts, ", ") +} + +func consecutive(a, b string) bool { + x, err1 := strconv.Atoi(a) + y, err2 := strconv.Atoi(b) + return err1 == nil && err2 == nil && y == x+1 +} + +// --- output --------------------------------------------------------------- + +func write(path string, entries []entry, tags, langs []string) error { + var b strings.Builder + b.WriteString("// Code generated by tools/pgmsg. DO NOT EDIT.\n//\n") + fmt.Fprintf(&b, "// Source: src/bin/pg_dump/po/{%s}.po at %s .. %s\n", + strings.Join(langs, ","), tags[0], tags[len(tags)-1]) + b.WriteString("// (github.com/postgres/postgres). Regenerate with `just gen-messages`.\n\n") + b.WriteString("package parser\n\n") + b.WriteString("// messages is what pg_restore prints, mapped to what it means. Ordered\n") + b.WriteString("// longest-literal-first, so the first match is the most specific one.\n") + b.WriteString("var messages = []message{\n") + for _, e := range entries { + fmt.Fprintf(&b, "\t// %s\n", strings.Join(e.sources, ", ")) + fmt.Fprintf(&b, "\t{literal: %s, exact: %t, kind: %s, shape: %s},\n", + strconv.Quote(e.literal), e.exact, e.kind, e.shape) + } + b.WriteString("}\n") + + src, err := format.Source([]byte(b.String())) + if err != nil { + return fmt.Errorf("formatting generated source: %w", err) + } + return os.WriteFile(path, src, 0o644) +} + +// --- helpers -------------------------------------------------------------- + +func split(s string) []string { + var out []string + for _, p := range strings.Split(s, ",") { + if p = strings.TrimSpace(p); p != "" { + out = append(out, p) + } + } + return out +} + +func sorted(set map[string]bool) []string { + out := make([]string, 0, len(set)) + for k := range set { + out = append(out, k) + } + sort.Strings(out) + return out +} diff --git a/tools/pgmsg/testdata/REL_13_STABLE.txt b/tools/pgmsg/testdata/REL_13_STABLE.txt new file mode 100644 index 0000000..6f389b0 --- /dev/null +++ b/tools/pgmsg/testdata/REL_13_STABLE.txt @@ -0,0 +1,510 @@ +# msgid set of src/bin/pg_dump/po/{de,fr}.po at REL_13_STABLE +# generated by tools/pgmsg; one Go-quoted msgid per line +"\nConnection options:\n" +"\nGeneral options:\n" +"\nIf -f/--file is not used, then the SQL script will be written to the standard\noutput.\n\n" +"\nIf no database name is supplied, then the PGDATABASE environment\nvariable value is used.\n\n" +"\nIf no input file name is supplied, then standard input is used.\n\n" +"\nOptions controlling the output content:\n" +"\nOptions controlling the restore:\n" +"\nThe options -I, -n, -N, -P, -t, -T, and --section can be combined and specified\nmultiple times to select multiple objects.\n" +" %s" +" %s [OPTION]...\n" +" %s [OPTION]... [DBNAME]\n" +" %s [OPTION]... [FILE]\n" +" --binary-upgrade for use by upgrade utilities only\n" +" --column-inserts dump data as INSERT commands with column names\n" +" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n" +" --disable-triggers disable triggers during data-only restore\n" +" --enable-row-security enable row security\n" +" --enable-row-security enable row security (dump only content user has\n access to)\n" +" --exclude-database=PATTERN exclude databases whose name matches PATTERN\n" +" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n" +" --extra-float-digits=NUM override default setting for extra_float_digits\n" +" --if-exists use IF EXISTS when dropping objects\n" +" --include-foreign-data=PATTERN\n include data of foreign tables on foreign\n servers matching PATTERN\n" +" --inserts dump data as INSERT commands, rather than COPY\n" +" --load-via-partition-root load partitions via the root table\n" +" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n" +" --no-comments do not dump comments\n" +" --no-comments do not restore comments\n" +" --no-data-for-failed-tables do not restore data of tables that could not be\n created\n" +" --no-publications do not dump publications\n" +" --no-publications do not restore publications\n" +" --no-role-passwords do not dump passwords for roles\n" +" --no-security-labels do not dump security label assignments\n" +" --no-security-labels do not restore security labels\n" +" --no-subscriptions do not dump subscriptions\n" +" --no-subscriptions do not restore subscriptions\n" +" --no-sync do not wait for changes to be written safely to disk\n" +" --no-synchronized-snapshots do not use synchronized snapshots in parallel jobs\n" +" --no-tablespaces do not dump tablespace assignments\n" +" --no-tablespaces do not restore tablespace assignments\n" +" --no-unlogged-table-data do not dump unlogged table data\n" +" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n" +" --quote-all-identifiers quote all identifiers, even if not key words\n" +" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n" +" --role=ROLENAME do SET ROLE before dump\n" +" --role=ROLENAME do SET ROLE before restore\n" +" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n" +" --section=SECTION dump named section (pre-data, data, or post-data)\n" +" --section=SECTION restore named section (pre-data, data, or post-data)\n" +" --serializable-deferrable wait until the dump can run without anomalies\n" +" --snapshot=SNAPSHOT use given snapshot for the dump\n" +" --strict-names require table and/or schema include patterns to\n match at least one entity each\n" +" --use-set-session-authorization\n use SET SESSION AUTHORIZATION commands instead of\n ALTER OWNER commands to set ownership\n" +" -1, --single-transaction restore as a single transaction\n" +" -?, --help show this help, then exit\n" +" -?, --help show this help, then exit\n" +" -B, --no-blobs exclude large objects in dump\n" +" -C, --create create the target database\n" +" -C, --create include commands to create database in dump\n" +" -E, --encoding=ENCODING dump the data in encoding ENCODING\n" +" -F, --format=c|d|t backup file format (should be automatic)\n" +" -F, --format=c|d|t|p output file format (custom, directory, tar,\n plain text (default))\n" +" -I, --index=NAME restore named index\n" +" -L, --use-list=FILENAME use table of contents from this file for\n selecting/ordering output\n" +" -N, --exclude-schema=NAME do not restore objects in this schema\n" +" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n" +" -O, --no-owner skip restoration of object ownership\n" +" -O, --no-owner skip restoration of object ownership in\n plain-text format\n" +" -P, --function=NAME(args) restore named function\n" +" -S, --superuser=NAME superuser user name to use for disabling triggers\n" +" -S, --superuser=NAME superuser user name to use in plain-text format\n" +" -S, --superuser=NAME superuser user name to use in the dump\n" +" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n" +" -T, --trigger=NAME restore named trigger\n" +" -U, --username=NAME connect as specified database user\n" +" -V, --version output version information, then exit\n" +" -V, --version output version information, then exit\n" +" -W, --password force password prompt (should happen automatically)\n" +" -Z, --compress=0-9 compression level for compressed formats\n" +" -a, --data-only dump only the data, not the schema\n" +" -a, --data-only restore only the data, no schema\n" +" -b, --blobs include large objects in dump\n" +" -c, --clean clean (drop) database objects before recreating\n" +" -c, --clean clean (drop) databases before recreating\n" +" -d, --dbname=CONNSTR connect using connection string\n" +" -d, --dbname=DBNAME database to dump\n" +" -d, --dbname=NAME connect to database name\n" +" -e, --exit-on-error exit on error, default is to continue\n" +" -f, --file=FILENAME output file name\n" +" -f, --file=FILENAME output file or directory name\n" +" -f, --file=FILENAME output file name (- for stdout)\n" +" -g, --globals-only dump only global objects, no databases\n" +" -h, --host=HOSTNAME database server host or socket directory\n" +" -j, --jobs=NUM use this many parallel jobs to dump\n" +" -j, --jobs=NUM use this many parallel jobs to restore\n" +" -l, --database=DBNAME alternative default database\n" +" -l, --list print summarized TOC of the archive\n" +" -n, --schema=NAME restore only objects in this schema\n" +" -n, --schema=PATTERN dump the specified schema(s) only\n" +" -p, --port=PORT database server port number\n" +" -r, --roles-only dump only roles, no databases or tablespaces\n" +" -s, --schema-only dump only the schema, no data\n" +" -s, --schema-only restore only the schema, no data\n" +" -t, --table=NAME restore named relation (table, view, etc.)\n" +" -t, --table=PATTERN dump the specified table(s) only\n" +" -t, --tablespaces-only dump only tablespaces, no databases or roles\n" +" -v, --verbose verbose mode\n" +" -v, --verbose verbose mode\n" +" -w, --no-password never prompt for password\n" +" -x, --no-privileges do not dump privileges (grant/revoke)\n" +" -x, --no-privileges skip restoration of access privileges (grant/revoke)\n" +"%s" +"%s dumps a database as a text file or to other formats.\n\n" +"%s extracts a PostgreSQL database cluster into an SQL script file.\n\n" +"%s home page: <%s>\n" +"%s restores a PostgreSQL database from an archive created by pg_dump.\n\n" +"%s: %sCommand was: %s" +"(The system catalogs might be corrupted.)" +"COPY failed for table \"%s\": %s" +"Consider using a full dump instead of a --data-only dump to avoid this problem." +"Dumping the contents of table \"%s\" failed: PQgetCopyData() failed." +"Dumping the contents of table \"%s\" failed: PQgetResult() failed." +"Error message from server: %s" +"Exported snapshots are not supported by this server version." +"Password: " +"Report bugs to <%s>.\n" +"Synchronized snapshots are not supported by this server version.\nRun with --no-synchronized-snapshots instead if you do not need\nsynchronized snapshots." +"Synchronized snapshots on standby servers are not supported by this server version.\nRun with --no-synchronized-snapshots instead if you do not need\nsynchronized snapshots." +"The command was: %s" +"The program \"%s\" is needed by %s but was not found in the\nsame directory as \"%s\".\nCheck your installation." +"The program \"%s\" was found by \"%s\"\nbut was not the same version as %s.\nCheck your installation." +"Try \"%s --help\" for more information.\n" +"Usage:\n" +"WITH OIDS is not supported anymore (table \"%s\")" +"WSAStartup failed: %d" +"You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints." +"a worker process died unexpectedly" +"aborting because of server version mismatch" +"actual file length (%s) does not match expected (%s)" +"aggregate function %s could not be dumped correctly for this database version; ignored" +"already connected to a database" +"archive is compressed, but this installation does not support compression -- no data will be available" +"archive items not in correct section order" +"archive was made on a machine with larger integers, some operations might fail" +"bad dumpId" +"bad table dumpId for TABLE DATA item" +"bogus transform definition, at least one of trffromsql and trftosql should be nonzero" +"bogus value in pg_cast.castfunc or pg_cast.castmethod field" +"bogus value in pg_cast.castmethod field" +"bogus value in pg_transform.trffromsql field" +"bogus value in pg_transform.trftosql field" +"bogus value in proargmodes array" +"can only reopen input archives" +"cannot duplicate null pointer (internal error)\n" +"cannot restore from compressed archive (compression not supported in this installation)" +"cannot specify both --single-transaction and multiple jobs" +"child process exited with exit code %d" +"child process exited with unrecognized status %d" +"child process was terminated by exception 0x%X" +"child process was terminated by signal %d: %s" +"command not executable" +"command not found" +"compression is not supported by tar archive format" +"compression level must be in range 0..9" +"compressor active" +"connecting to database for restore" +"connecting to new database \"%s\"" +"connection to database \"%s\" failed: %s" +"corrupt tar header found in %s (expected %d, computed %d) file position %s" +"could not change directory to \"%s\": %m" +"could not close TOC file: %m" +"could not close archive file: %m" +"could not close blob data file: %m" +"could not close blobs TOC file: %m" +"could not close compression library: %s" +"could not close compression stream: %s" +"could not close data file \"%s\": %m" +"could not close data file: %m" +"could not close directory \"%s\": %m" +"could not close input file: %m" +"could not close large object TOC file \"%s\": %m" +"could not close output file: %m" +"could not close tar member: %m" +"could not close temporary file: %m" +"could not commit database transaction" +"could not compress data: %s" +"could not connect to database" +"could not connect to database \"%s\"" +"could not connect to database \"%s\": %s" +"could not connect to databases \"postgres\" or \"template1\"\nPlease specify an alternative database." +"could not create communication channels: %m" +"could not create directory \"%s\": %m" +"could not create large object %u: %s" +"could not create worker process: %m" +"could not determine seek position in archive file: %m" +"could not execute query" +"could not find a \"%s\" to execute" +"could not find block ID %d in archive -- possibly corrupt archive" +"could not find block ID %d in archive -- possibly due to out-of-order restore request, which cannot be handled due to non-seekable input file" +"could not find entry for ID %d" +"could not find file \"%s\" in archive" +"could not find function definition for function with OID %u" +"could not find header for file \"%s\" in tar archive" +"could not find operator with OID %s" +"could not find parent extension for %s %s" +"could not find referenced extension %u" +"could not find where to insert IF EXISTS in statement \"%s\"" +"could not generate restrict key" +"could not generate temporary file name: %m" +"could not get server version" +"could not get server_version from libpq" +"could not identify current directory: %m" +"could not identify dependency loop" +"could not initialize compression library: %s" +"could not obtain lock on relation \"%s\"\nThis usually means that someone requested an ACCESS EXCLUSIVE lock on the table after the pg_dump parent process had gotten the initial ACCESS SHARE lock on the table." +"could not open TOC file \"%s\" for input: %m" +"could not open TOC file \"%s\" for output: %m" +"could not open TOC file \"%s\": %m" +"could not open TOC file for input: %m" +"could not open TOC file for output: %m" +"could not open input file \"%s\": %m" +"could not open input file: %m" +"could not open large object %u: %s" +"could not open large object TOC file \"%s\" for input: %m" +"could not open output file \"%s\": %m" +"could not open output file: %m" +"could not open temporary file" +"could not parse ACL list (%s) for tablespace \"%s\"" +"could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)" +"could not parse default ACL list (%s)" +"could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)" +"could not parse numeric array \"%s\": invalid character in number" +"could not parse numeric array \"%s\": too many numbers" +"could not parse proallargtypes array" +"could not parse proargmodes array" +"could not parse proargnames array" +"could not parse proconfig array" +"could not parse reloptions array" +"could not parse result of current_schemas()" +"could not parse server version \"%s\"" +"could not parse subpublications array" +"could not re-open the output file \"%s\": %m" +"could not read binary \"%s\"" +"could not read directory \"%s\": %m" +"could not read from input file: %m" +"could not read from input file: %s" +"could not read from input file: end of file" +"could not read input file: %m" +"could not read symbolic link \"%s\": %m" +"could not resolve dependency loop among these items:" +"could not set default_table_access_method: %s" +"could not set default_tablespace to %s: %s" +"could not set search_path to \"%s\": %s" +"could not set seek position in archive file: %m" +"could not set session user to \"%s\": %s" +"could not start database transaction" +"could not uncompress data: %s" +"could not write to blobs TOC file" +"could not write to large object (result: %lu, expected: %lu)" +"could not write to output file: %s" +"could not write to the communication channel: %m" +"creating %s \"%s\"" +"creating %s \"%s.%s\"" +"data block %d has wrong seek position" +"definition of view \"%s\" appears to be empty (length zero)" +"did not find magic string in file header" +"direct database connections are not supported in pre-1.3 archives" +"directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)" +"directory name too long: \"%s\"" +"disabling triggers for %s" +"don't know how to set owner for object type \"%s\"" +"dropping %s %s" +"dumping contents of table \"%s.%s\"" +"dumping database \"%s\"" +"enabling triggers for %s" +"entering main parallel loop" +"entry ID %d out of range -- perhaps a corrupt TOC" +"error during file seek: %m" +"error reading large object %u: %s" +"error reading large object TOC file \"%s\"" +"error returned by PQputCopyData: %s" +"error returned by PQputCopyEnd: %s" +"error: " +"errors ignored on restore: %d" +"excluding database \"%s\"" +"executing %s" +"executing %s %s" +"expected %d check constraint on table \"%s\" but found %d" +"expected format (%d) differs from format found in file (%d)" +"extra_float_digits must be in range -15..3" +"failed sanity check, parent OID %u of table \"%s\" (OID %u) not found" +"failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found" +"failed sanity check, parent table with OID %u of sequence with OID %u not found" +"failed sanity check, table OID %u appearing in pg_partitioned_table not found" +"fatal: " +"file name too long: \"%s\"" +"file offset in dump file is too large" +"finding check constraints for table \"%s.%s\"" +"finding default expressions of table \"%s.%s\"" +"finding extension tables" +"finding inheritance relationships" +"finding the columns and types of table \"%s.%s\"" +"finished item %d %s %s" +"finished main parallel loop" +"flagging indexes in partitioned tables" +"flagging inherited columns in subtables" +"found orphaned pg_auth_members entry for role %s" +"found unexpected block ID (%d) when reading data -- expected %d" +"from TOC entry %d; %u %u %s %s %s" +"function \"%s\" not found" +"identifying extension members" +"implied data-only restore" +"incomplete tar header found (%lu byte)" +"index \"%s\" not found" +"input file appears to be a text format dump. Please use psql." +"input file does not appear to be a valid archive" +"input file does not appear to be a valid archive (too short?)" +"input file is too short (read %lu, expected 5)" +"internal error -- WriteData cannot be called outside the context of a DataDumper routine" +"invalid ENCODING item: %s" +"invalid OID for large object" +"invalid OID for large object (%u)" +"invalid STDSTRINGS item: %s" +"invalid adnum value %d for table \"%s\"" +"invalid argument string (%s) for trigger \"%s\" on table \"%s\"" +"invalid binary \"%s\"" +"invalid client encoding \"%s\" specified" +"invalid column number %d for table \"%s\"" +"invalid column numbering in table \"%s\"" +"invalid compression code: %d" +"invalid creation date in header" +"invalid dependency %d" +"invalid dumpId %d" +"invalid line in large object TOC file \"%s\": \"%s\"" +"invalid message received from worker: \"%s\"" +"invalid number of parallel jobs" +"invalid number of parents %d for table \"%s\"" +"invalid output format \"%s\" specified" +"invalid restrict key" +"invalid type \"%c\" of access method \"%s\"" +"large-object output not supported in chosen format" +"last built-in OID is %u" +"launching item %d %s %s" +"line ignored: %s" +"maximum number of parallel jobs is %d" +"missing index for constraint \"%s\"" +"no matching foreign servers were found for pattern \"%s\"" +"no matching schemas were found" +"no matching schemas were found for pattern \"%s\"" +"no matching tables were found" +"no matching tables were found for pattern \"%s\"" +"no output directory specified" +"no referenced object %u %u" +"no referencing object %u %u" +"not built with zlib support" +"one of -d/--dbname and -f/--file must be specified" +"option --exclude-database cannot be used together with -g/--globals-only, -r/--roles-only, or -t/--tablespaces-only" +"option --if-exists requires option -c/--clean" +"option --include-foreign-data is not supported with parallel backup" +"option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts" +"option --restrict-key can only be used with --format=plain" +"options -C/--create and -1/--single-transaction cannot be used together" +"options -c/--clean and -a/--data-only cannot be used together" +"options -d/--dbname and --restrict-key cannot be used together" +"options -d/--dbname and -f/--file cannot be used together" +"options -g/--globals-only and -r/--roles-only cannot be used together" +"options -g/--globals-only and -t/--tablespaces-only cannot be used together" +"options -r/--roles-only and -t/--tablespaces-only cannot be used together" +"options -s/--schema-only and --include-foreign-data cannot be used together" +"options -s/--schema-only and -a/--data-only cannot be used together" +"out of memory" +"out of memory\n" +"out of on_exit_nicely slots" +"owner of aggregate function \"%s\" appears to be invalid" +"owner of data type \"%s\" appears to be invalid" +"owner of function \"%s\" appears to be invalid" +"owner of operator \"%s\" appears to be invalid" +"owner of operator class \"%s\" appears to be invalid" +"owner of operator family \"%s\" appears to be invalid" +"owner of publication \"%s\" appears to be invalid" +"owner of schema \"%s\" appears to be invalid" +"owner of subscription \"%s\" appears to be invalid" +"owner of table \"%s\" appears to be invalid" +"parallel backup only supported by the directory format" +"parallel restore from non-seekable file is not supported" +"parallel restore from standard input is not supported" +"parallel restore is not supported with archives made by pre-8.0 pg_dump" +"parallel restore is not supported with this archive file format" +"pclose failed: %m" +"pg_dump failed on database \"%s\", exiting" +"pgpipe: could not accept connection: error code %d" +"pgpipe: could not bind: error code %d" +"pgpipe: could not connect socket: error code %d" +"pgpipe: could not create second socket: error code %d" +"pgpipe: could not create socket: error code %d" +"pgpipe: could not listen: error code %d" +"pgpipe: getsockname() failed: error code %d" +"processing %s" +"processing data for table \"%s.%s\"" +"processing item %d %s %s" +"processing missed item %d %s %s" +"query failed: %s" +"query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)" +"query returned %d row instead of one: %s" +"query to get data of sequence \"%s\" returned %d row (expected 1)" +"query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned" +"query to obtain definition of view \"%s\" returned more than one definition" +"query to obtain definition of view \"%s\" returned no data" +"query was: %s" +"reading column info for interesting tables" +"reading constraints" +"reading default privileges" +"reading dependency data" +"reading event triggers" +"reading extended statistics" +"reading extensions" +"reading foreign key constraints for table \"%s.%s\"" +"reading indexes" +"reading indexes for table \"%s.%s\"" +"reading large objects" +"reading partitioning data" +"reading policies" +"reading procedural languages" +"reading publication membership" +"reading publications" +"reading rewrite rules" +"reading row-level security policies" +"reading schemas" +"reading subscriptions" +"reading table inheritance information" +"reading transforms" +"reading triggers" +"reading triggers for table \"%s.%s\"" +"reading type casts" +"reading user-defined access methods" +"reading user-defined aggregate functions" +"reading user-defined collations" +"reading user-defined conversions" +"reading user-defined foreign servers" +"reading user-defined foreign-data wrappers" +"reading user-defined functions" +"reading user-defined operator classes" +"reading user-defined operator families" +"reading user-defined operators" +"reading user-defined tables" +"reading user-defined text search configurations" +"reading user-defined text search dictionaries" +"reading user-defined text search parsers" +"reading user-defined text search templates" +"reading user-defined types" +"reconnection to database \"%s\" failed: %s" +"requested compression not available in this installation -- archive will be uncompressed" +"restored %d large object" +"restoring data out of order is not supported in this archive format: \"%s\" is required, but comes before \"%s\" in the archive file." +"restoring large object with OID %u" +"restoring tables WITH OIDS is not supported anymore" +"role name starting with \"pg_\" skipped (%s)" +"rows-per-insert must be in range %d..%d" +"running \"%s\"" +"sanity check on integer size (%lu) failed" +"saving database definition" +"saving encoding = %s" +"saving large objects" +"saving search_path = %s" +"saving standard_conforming_strings = %s" +"schema \"%s\" not found" +"schema with OID %u does not exist" +"select() failed: %m" +"server version: %s; %s version: %s" +"skipping item %d %s %s" +"subscriptions not dumped because current user is not a superuser" +"table \"%s\" could not be created, will not restore its data" +"table \"%s\" not found" +"there are circular foreign-key constraints on this table:" +"this format cannot be read" +"too many command-line arguments (first is \"%s\")" +"trigger \"%s\" not found" +"typtype of data type \"%s\" appears to be invalid" +"unexpected COPY statement syntax: \"%s\"" +"unexpected data offset flag %d" +"unexpected extra results during COPY of table \"%s\"" +"unexpected policy command type: %c" +"unexpected section code %d" +"unexpected tgtype value: %d" +"unrecognized aggfinalmodify value for aggregate \"%s\"" +"unrecognized aggmfinalmodify value for aggregate \"%s\"" +"unrecognized archive format \"%s\"; please specify \"c\", \"d\", or \"t\"" +"unrecognized collation provider: %s" +"unrecognized command received from master: \"%s\"" +"unrecognized constraint type: %c" +"unrecognized data block type %d while restoring archive" +"unrecognized data block type (%d) while searching archive" +"unrecognized encoding \"%s\"" +"unrecognized file format \"%d\"" +"unrecognized object type in default privileges: %d" +"unrecognized proparallel value for function \"%s\"" +"unrecognized provolatile value for function \"%s\"" +"unrecognized section name: \"%s\"" +"unrecognized sequence type: %s" +"unsupported version (%d.%d) in file header" +"warning from original dump file: %s" +"warning: " +"while FINALIZING:" +"while INITIALIZING:" +"while PROCESSING TOC:" +"worker process failed: exit code %d" +"wrong number of fields retrieved from table \"%s\"" +"wrote %lu byte of large object data (result = %lu)" diff --git a/tools/pgmsg/testdata/REL_14_STABLE.txt b/tools/pgmsg/testdata/REL_14_STABLE.txt new file mode 100644 index 0000000..2cc301c --- /dev/null +++ b/tools/pgmsg/testdata/REL_14_STABLE.txt @@ -0,0 +1,524 @@ +# msgid set of src/bin/pg_dump/po/{de,fr}.po at REL_14_STABLE +# generated by tools/pgmsg; one Go-quoted msgid per line +"\nConnection options:\n" +"\nGeneral options:\n" +"\nIf -f/--file is not used, then the SQL script will be written to the standard\noutput.\n\n" +"\nIf no database name is supplied, then the PGDATABASE environment\nvariable value is used.\n\n" +"\nIf no input file name is supplied, then standard input is used.\n\n" +"\nOptions controlling the output content:\n" +"\nOptions controlling the restore:\n" +"\nThe options -I, -n, -N, -P, -t, -T, and --section can be combined and specified\nmultiple times to select multiple objects.\n" +" %s" +" %s [OPTION]...\n" +" %s [OPTION]... [DBNAME]\n" +" %s [OPTION]... [FILE]\n" +" --binary-upgrade for use by upgrade utilities only\n" +" --column-inserts dump data as INSERT commands with column names\n" +" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n" +" --disable-triggers disable triggers during data-only restore\n" +" --enable-row-security enable row security\n" +" --enable-row-security enable row security (dump only content user has\n access to)\n" +" --exclude-database=PATTERN exclude databases whose name matches PATTERN\n" +" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n" +" --extra-float-digits=NUM override default setting for extra_float_digits\n" +" --if-exists use IF EXISTS when dropping objects\n" +" --include-foreign-data=PATTERN\n include data of foreign tables on foreign\n servers matching PATTERN\n" +" --inserts dump data as INSERT commands, rather than COPY\n" +" --load-via-partition-root load partitions via the root table\n" +" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n" +" --no-comments do not dump comments\n" +" --no-comments do not restore comments\n" +" --no-data-for-failed-tables do not restore data of tables that could not be\n created\n" +" --no-publications do not dump publications\n" +" --no-publications do not restore publications\n" +" --no-role-passwords do not dump passwords for roles\n" +" --no-security-labels do not dump security label assignments\n" +" --no-security-labels do not restore security labels\n" +" --no-subscriptions do not dump subscriptions\n" +" --no-subscriptions do not restore subscriptions\n" +" --no-sync do not wait for changes to be written safely to disk\n" +" --no-synchronized-snapshots do not use synchronized snapshots in parallel jobs\n" +" --no-tablespaces do not dump tablespace assignments\n" +" --no-tablespaces do not restore tablespace assignments\n" +" --no-toast-compression do not dump TOAST compression methods\n" +" --no-unlogged-table-data do not dump unlogged table data\n" +" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n" +" --quote-all-identifiers quote all identifiers, even if not key words\n" +" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n" +" --role=ROLENAME do SET ROLE before dump\n" +" --role=ROLENAME do SET ROLE before restore\n" +" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n" +" --section=SECTION dump named section (pre-data, data, or post-data)\n" +" --section=SECTION restore named section (pre-data, data, or post-data)\n" +" --serializable-deferrable wait until the dump can run without anomalies\n" +" --snapshot=SNAPSHOT use given snapshot for the dump\n" +" --strict-names require table and/or schema include patterns to\n match at least one entity each\n" +" --use-set-session-authorization\n use SET SESSION AUTHORIZATION commands instead of\n ALTER OWNER commands to set ownership\n" +" -1, --single-transaction restore as a single transaction\n" +" -?, --help show this help, then exit\n" +" -?, --help show this help, then exit\n" +" -B, --no-blobs exclude large objects in dump\n" +" -C, --create create the target database\n" +" -C, --create include commands to create database in dump\n" +" -E, --encoding=ENCODING dump the data in encoding ENCODING\n" +" -F, --format=c|d|t backup file format (should be automatic)\n" +" -F, --format=c|d|t|p output file format (custom, directory, tar,\n plain text (default))\n" +" -I, --index=NAME restore named index\n" +" -L, --use-list=FILENAME use table of contents from this file for\n selecting/ordering output\n" +" -N, --exclude-schema=NAME do not restore objects in this schema\n" +" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n" +" -O, --no-owner skip restoration of object ownership\n" +" -O, --no-owner skip restoration of object ownership in\n plain-text format\n" +" -P, --function=NAME(args) restore named function\n" +" -S, --superuser=NAME superuser user name to use for disabling triggers\n" +" -S, --superuser=NAME superuser user name to use in plain-text format\n" +" -S, --superuser=NAME superuser user name to use in the dump\n" +" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n" +" -T, --trigger=NAME restore named trigger\n" +" -U, --username=NAME connect as specified database user\n" +" -V, --version output version information, then exit\n" +" -V, --version output version information, then exit\n" +" -W, --password force password prompt (should happen automatically)\n" +" -Z, --compress=0-9 compression level for compressed formats\n" +" -a, --data-only dump only the data, not the schema\n" +" -a, --data-only restore only the data, no schema\n" +" -b, --blobs include large objects in dump\n" +" -c, --clean clean (drop) database objects before recreating\n" +" -c, --clean clean (drop) databases before recreating\n" +" -d, --dbname=CONNSTR connect using connection string\n" +" -d, --dbname=DBNAME database to dump\n" +" -d, --dbname=NAME connect to database name\n" +" -e, --exit-on-error exit on error, default is to continue\n" +" -e, --extension=PATTERN dump the specified extension(s) only\n" +" -f, --file=FILENAME output file name\n" +" -f, --file=FILENAME output file or directory name\n" +" -f, --file=FILENAME output file name (- for stdout)\n" +" -g, --globals-only dump only global objects, no databases\n" +" -h, --host=HOSTNAME database server host or socket directory\n" +" -j, --jobs=NUM use this many parallel jobs to dump\n" +" -j, --jobs=NUM use this many parallel jobs to restore\n" +" -l, --database=DBNAME alternative default database\n" +" -l, --list print summarized TOC of the archive\n" +" -n, --schema=NAME restore only objects in this schema\n" +" -n, --schema=PATTERN dump the specified schema(s) only\n" +" -p, --port=PORT database server port number\n" +" -r, --roles-only dump only roles, no databases or tablespaces\n" +" -s, --schema-only dump only the schema, no data\n" +" -s, --schema-only restore only the schema, no data\n" +" -t, --table=NAME restore named relation (table, view, etc.)\n" +" -t, --table=PATTERN dump the specified table(s) only\n" +" -t, --tablespaces-only dump only tablespaces, no databases or roles\n" +" -v, --verbose verbose mode\n" +" -v, --verbose verbose mode\n" +" -w, --no-password never prompt for password\n" +" -x, --no-privileges do not dump privileges (grant/revoke)\n" +" -x, --no-privileges skip restoration of access privileges (grant/revoke)\n" +"%s" +"%s dumps a database as a text file or to other formats.\n\n" +"%s extracts a PostgreSQL database cluster into an SQL script file.\n\n" +"%s home page: <%s>\n" +"%s restores a PostgreSQL database from an archive created by pg_dump.\n\n" +"%s() failed: %m" +"%s() failed: error code %d" +"%s: %sCommand was: %s" +"(The system catalogs might be corrupted.)" +"COPY failed for table \"%s\": %s" +"Consider using a full dump instead of a --data-only dump to avoid this problem." +"Dumping the contents of table \"%s\" failed: PQgetCopyData() failed." +"Dumping the contents of table \"%s\" failed: PQgetResult() failed." +"Error message from server: %s" +"Exported snapshots are not supported by this server version." +"Password: " +"Report bugs to <%s>.\n" +"Synchronized snapshots are not supported by this server version.\nRun with --no-synchronized-snapshots instead if you do not need\nsynchronized snapshots." +"Synchronized snapshots on standby servers are not supported by this server version.\nRun with --no-synchronized-snapshots instead if you do not need\nsynchronized snapshots." +"The command was: %s" +"The program \"%s\" is needed by %s but was not found in the\nsame directory as \"%s\".\nCheck your installation." +"The program \"%s\" was found by \"%s\"\nbut was not the same version as %s.\nCheck your installation." +"Try \"%s --help\" for more information.\n" +"Usage:\n" +"WITH OIDS is not supported anymore (table \"%s\")" +"You are currently not connected to a database." +"You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints." +"a worker process died unexpectedly" +"aborting because of server version mismatch" +"actual file length (%s) does not match expected (%s)" +"already connected to a database" +"archive is compressed, but this installation does not support compression -- no data will be available" +"archive items not in correct section order" +"archive was made on a machine with larger integers, some operations might fail" +"bad dumpId" +"bad table dumpId for TABLE DATA item" +"bogus transform definition, at least one of trffromsql and trftosql should be nonzero" +"bogus value in pg_cast.castfunc or pg_cast.castmethod field" +"bogus value in pg_cast.castmethod field" +"bogus value in pg_transform.trffromsql field" +"bogus value in pg_transform.trftosql field" +"bogus value in proargmodes array" +"can only reopen input archives" +"cannot duplicate null pointer (internal error)\n" +"cannot restore from compressed archive (compression not supported in this installation)" +"cannot specify both --single-transaction and multiple jobs" +"child process exited with exit code %d" +"child process exited with unrecognized status %d" +"child process was terminated by exception 0x%X" +"child process was terminated by signal %d: %s" +"command not executable" +"command not found" +"compression is not supported by tar archive format" +"compression level must be in range 0..9" +"compressor active" +"connecting to database for restore" +"connecting to new database \"%s\"" +"corrupt tar header found in %s (expected %d, computed %d) file position %s" +"could not change directory to \"%s\": %m" +"could not close TOC file: %m" +"could not close archive file: %m" +"could not close blob data file: %m" +"could not close blobs TOC file: %m" +"could not close compression library: %s" +"could not close compression stream: %s" +"could not close data file \"%s\": %m" +"could not close data file: %m" +"could not close directory \"%s\": %m" +"could not close input file: %m" +"could not close large object TOC file \"%s\": %m" +"could not close output file: %m" +"could not close tar member: %m" +"could not close temporary file: %m" +"could not commit database transaction" +"could not compress data: %s" +"could not connect to database" +"could not connect to database \"%s\"" +"could not connect to databases \"postgres\" or \"template1\"\nPlease specify an alternative database." +"could not create communication channels: %m" +"could not create directory \"%s\": %m" +"could not create large object %u: %s" +"could not create worker process: %m" +"could not create worker thread: %m" +"could not determine seek position in archive file: %m" +"could not execute query" +"could not find a \"%s\" to execute" +"could not find block ID %d in archive -- possibly corrupt archive" +"could not find block ID %d in archive -- possibly due to out-of-order restore request, which cannot be handled due to non-seekable input file" +"could not find entry for ID %d" +"could not find file \"%s\" in archive" +"could not find function definition for function with OID %u" +"could not find header for file \"%s\" in tar archive" +"could not find operator with OID %s" +"could not find parent extension for %s %s" +"could not find referenced extension %u" +"could not find where to insert IF EXISTS in statement \"%s\"" +"could not generate restrict key" +"could not generate temporary file name: %m" +"could not get server version" +"could not get server_version from libpq" +"could not identify current directory: %m" +"could not identify dependency loop" +"could not initialize compression library: %s" +"could not obtain lock on relation \"%s\"\nThis usually means that someone requested an ACCESS EXCLUSIVE lock on the table after the pg_dump parent process had gotten the initial ACCESS SHARE lock on the table." +"could not open TOC file \"%s\" for input: %m" +"could not open TOC file \"%s\" for output: %m" +"could not open TOC file \"%s\": %m" +"could not open TOC file for input: %m" +"could not open TOC file for output: %m" +"could not open input file \"%s\": %m" +"could not open input file: %m" +"could not open large object %u: %s" +"could not open large object TOC file \"%s\" for input: %m" +"could not open output file \"%s\": %m" +"could not open output file: %m" +"could not open temporary file" +"could not parse ACL list (%s) for tablespace \"%s\"" +"could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)" +"could not parse default ACL list (%s)" +"could not parse extension condition array" +"could not parse extension configuration array" +"could not parse index statistic columns" +"could not parse index statistic values" +"could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)" +"could not parse numeric array \"%s\": invalid character in number" +"could not parse numeric array \"%s\": too many numbers" +"could not parse proallargtypes array" +"could not parse proargmodes array" +"could not parse proargnames array" +"could not parse proconfig array" +"could not parse reloptions array" +"could not parse result of current_schemas()" +"could not parse server version \"%s\"" +"could not parse subpublications array" +"could not re-open the output file \"%s\": %m" +"could not read binary \"%s\"" +"could not read directory \"%s\": %m" +"could not read from input file: %m" +"could not read from input file: %s" +"could not read from input file: end of file" +"could not read input file: %m" +"could not read symbolic link \"%s\": %m" +"could not resolve dependency loop among these items:" +"could not set default_table_access_method: %s" +"could not set default_tablespace to %s: %s" +"could not set search_path to \"%s\": %s" +"could not set seek position in archive file: %m" +"could not set session user to \"%s\": %s" +"could not start database transaction" +"could not uncompress data: %s" +"could not write to blobs TOC file" +"could not write to large object: %s" +"could not write to output file: %s" +"could not write to the communication channel: %m" +"creating %s \"%s\"" +"creating %s \"%s.%s\"" +"cross-database references are not implemented: %s" +"data block %d has wrong seek position" +"definition of view \"%s\" appears to be empty (length zero)" +"did not find magic string in file header" +"direct database connections are not supported in pre-1.3 archives" +"directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)" +"directory name too long: \"%s\"" +"disabling triggers for %s" +"don't know how to set owner for object type \"%s\"" +"dropping %s %s" +"dumping contents of table \"%s.%s\"" +"dumping database \"%s\"" +"enabling triggers for %s" +"entering main parallel loop" +"entry ID %d out of range -- perhaps a corrupt TOC" +"error during file seek: %m" +"error reading large object %u: %s" +"error reading large object TOC file \"%s\"" +"error returned by PQputCopyData: %s" +"error returned by PQputCopyEnd: %s" +"error: " +"errors ignored on restore: %d" +"excluding database \"%s\"" +"executing %s" +"executing %s %s" +"expected %d check constraint on table \"%s\" but found %d" +"expected format (%d) differs from format found in file (%d)" +"extra_float_digits must be in range -15..3" +"failed sanity check, parent OID %u of table \"%s\" (OID %u) not found" +"failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found" +"failed sanity check, parent table with OID %u of sequence with OID %u not found" +"failed sanity check, table OID %u appearing in pg_partitioned_table not found" +"fatal: " +"file name too long: \"%s\"" +"file offset in dump file is too large" +"finding check constraints for table \"%s.%s\"" +"finding default expressions of table \"%s.%s\"" +"finding extension tables" +"finding inheritance relationships" +"finding the columns and types of table \"%s.%s\"" +"finished item %d %s %s" +"finished main parallel loop" +"flagging indexes in partitioned tables" +"flagging inherited columns in subtables" +"found orphaned pg_auth_members entry for role %s" +"found unexpected block ID (%d) when reading data -- expected %d" +"from TOC entry %d; %u %u %s %s %s" +"function \"%s\" not found" +"identifying extension members" +"implied data-only restore" +"improper qualified name (too many dotted names): %s" +"improper relation name (too many dotted names): %s" +"incomplete tar header found (%lu byte)" +"index \"%s\" not found" +"input file appears to be a text format dump. Please use psql." +"input file does not appear to be a valid archive" +"input file does not appear to be a valid archive (too short?)" +"input file is too short (read %lu, expected 5)" +"internal error -- WriteData cannot be called outside the context of a DataDumper routine" +"invalid ENCODING item: %s" +"invalid OID for large object" +"invalid OID for large object (%u)" +"invalid STDSTRINGS item: %s" +"invalid adnum value %d for table \"%s\"" +"invalid argument string (%s) for trigger \"%s\" on table \"%s\"" +"invalid binary \"%s\"" +"invalid client encoding \"%s\" specified" +"invalid column number %d for table \"%s\"" +"invalid column numbering in table \"%s\"" +"invalid compression code: %d" +"invalid creation date in header" +"invalid dependency %d" +"invalid dumpId %d" +"invalid line in large object TOC file \"%s\": \"%s\"" +"invalid memory allocation request size %zu * %zu\n" +"invalid memory allocation request size %zu + %zu\n" +"invalid message received from worker: \"%s\"" +"invalid number of parallel jobs" +"invalid number of parents %d for table \"%s\"" +"invalid output format \"%s\" specified" +"invalid restrict key" +"invalid type \"%c\" of access method \"%s\"" +"large-object output not supported in chosen format" +"last built-in OID is %u" +"launching item %d %s %s" +"line ignored: %s" +"maximum number of parallel jobs is %d" +"mismatched number of columns and values for index statistics" +"mismatched number of configurations and conditions for extension" +"missing index for constraint \"%s\"" +"no matching extensions were found" +"no matching extensions were found for pattern \"%s\"" +"no matching foreign servers were found for pattern \"%s\"" +"no matching schemas were found" +"no matching schemas were found for pattern \"%s\"" +"no matching tables were found" +"no matching tables were found for pattern \"%s\"" +"no output directory specified" +"no referenced object %u %u" +"no referencing object %u %u" +"not built with zlib support" +"one of -d/--dbname and -f/--file must be specified" +"option --exclude-database cannot be used together with -g/--globals-only, -r/--roles-only, or -t/--tablespaces-only" +"option --if-exists requires option -c/--clean" +"option --include-foreign-data is not supported with parallel backup" +"option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts" +"option --restrict-key can only be used with --format=plain" +"options -C/--create and -1/--single-transaction cannot be used together" +"options -c/--clean and -a/--data-only cannot be used together" +"options -d/--dbname and --restrict-key cannot be used together" +"options -d/--dbname and -f/--file cannot be used together" +"options -g/--globals-only and -r/--roles-only cannot be used together" +"options -g/--globals-only and -t/--tablespaces-only cannot be used together" +"options -r/--roles-only and -t/--tablespaces-only cannot be used together" +"options -s/--schema-only and --include-foreign-data cannot be used together" +"options -s/--schema-only and -a/--data-only cannot be used together" +"out of memory" +"out of memory\n" +"out of on_exit_nicely slots" +"owner of aggregate function \"%s\" appears to be invalid" +"owner of data type \"%s\" appears to be invalid" +"owner of function \"%s\" appears to be invalid" +"owner of operator \"%s\" appears to be invalid" +"owner of operator class \"%s\" appears to be invalid" +"owner of operator family \"%s\" appears to be invalid" +"owner of publication \"%s\" appears to be invalid" +"owner of schema \"%s\" appears to be invalid" +"owner of subscription \"%s\" appears to be invalid" +"owner of table \"%s\" appears to be invalid" +"parallel backup only supported by the directory format" +"parallel restore from non-seekable file is not supported" +"parallel restore from standard input is not supported" +"parallel restore is not supported with archives made by pre-8.0 pg_dump" +"parallel restore is not supported with this archive file format" +"pg_dump failed on database \"%s\", exiting" +"pgpipe: %s() failed: error code %d" +"pgpipe: could not accept connection: error code %d" +"pgpipe: could not bind: error code %d" +"pgpipe: could not connect socket: error code %d" +"pgpipe: could not create second socket: error code %d" +"pgpipe: could not create socket: error code %d" +"pgpipe: could not listen: error code %d" +"postfix operators are not supported anymore (operator \"%s\")" +"processing %s" +"processing data for table \"%s.%s\"" +"processing item %d %s %s" +"processing missed item %d %s %s" +"query failed: %s" +"query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)" +"query returned %d row instead of one: %s" +"query to get data of sequence \"%s\" returned %d row (expected 1)" +"query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned" +"query to obtain definition of view \"%s\" returned more than one definition" +"query to obtain definition of view \"%s\" returned no data" +"query was: %s" +"reading column info for interesting tables" +"reading constraints" +"reading default privileges" +"reading dependency data" +"reading event triggers" +"reading extended statistics" +"reading extensions" +"reading foreign key constraints for table \"%s.%s\"" +"reading indexes" +"reading indexes for table \"%s.%s\"" +"reading large objects" +"reading partitioning data" +"reading policies" +"reading procedural languages" +"reading publication membership" +"reading publications" +"reading rewrite rules" +"reading row-level security policies" +"reading schemas" +"reading subscriptions" +"reading table inheritance information" +"reading transforms" +"reading triggers" +"reading triggers for table \"%s.%s\"" +"reading type casts" +"reading user-defined access methods" +"reading user-defined aggregate functions" +"reading user-defined collations" +"reading user-defined conversions" +"reading user-defined foreign servers" +"reading user-defined foreign-data wrappers" +"reading user-defined functions" +"reading user-defined operator classes" +"reading user-defined operator families" +"reading user-defined operators" +"reading user-defined tables" +"reading user-defined text search configurations" +"reading user-defined text search dictionaries" +"reading user-defined text search parsers" +"reading user-defined text search templates" +"reading user-defined types" +"reconnection failed: %s" +"requested compression not available in this installation -- archive will be uncompressed" +"restored %d large object" +"restoring data out of order is not supported in this archive format: \"%s\" is required, but comes before \"%s\" in the archive file." +"restoring large object with OID %u" +"restoring tables WITH OIDS is not supported anymore" +"role name starting with \"pg_\" skipped (%s)" +"rows-per-insert must be in range %d..%d" +"running \"%s\"" +"sanity check on integer size (%lu) failed" +"saving database definition" +"saving encoding = %s" +"saving large objects" +"saving search_path = %s" +"saving standard_conforming_strings = %s" +"schema \"%s\" not found" +"schema with OID %u does not exist" +"server version: %s; %s version: %s" +"skipping item %d %s %s" +"subscriptions not dumped because current user is not a superuser" +"table \"%s\" could not be created, will not restore its data" +"table \"%s\" not found" +"there are circular foreign-key constraints on this table:" +"this format cannot be read" +"too many command-line arguments (first is \"%s\")" +"trigger \"%s\" not found" +"typtype of data type \"%s\" appears to be invalid" +"unexpected COPY statement syntax: \"%s\"" +"unexpected data offset flag %d" +"unexpected extra results during COPY of table \"%s\"" +"unexpected policy command type: %c" +"unexpected section code %d" +"unexpected tgtype value: %d" +"unrecognized aggfinalmodify value for aggregate \"%s\"" +"unrecognized aggmfinalmodify value for aggregate \"%s\"" +"unrecognized archive format \"%s\"; please specify \"c\", \"d\", or \"t\"" +"unrecognized collation provider: %s" +"unrecognized command received from leader: \"%s\"" +"unrecognized constraint type: %c" +"unrecognized data block type %d while restoring archive" +"unrecognized data block type (%d) while searching archive" +"unrecognized encoding \"%s\"" +"unrecognized file format \"%d\"" +"unrecognized object type in default privileges: %d" +"unrecognized proparallel value for function \"%s\"" +"unrecognized provolatile value for function \"%s\"" +"unrecognized section name: \"%s\"" +"unrecognized sequence type: %s" +"unsupported version (%d.%d) in file header" +"warning from original dump file: %s" +"warning: " +"while FINALIZING:" +"while INITIALIZING:" +"while PROCESSING TOC:" +"worker process failed: exit code %d" +"wrong number of fields retrieved from table \"%s\"" +"wrote %zu byte of large object data (result = %d)" diff --git a/tools/pgmsg/testdata/REL_15_STABLE.txt b/tools/pgmsg/testdata/REL_15_STABLE.txt new file mode 100644 index 0000000..20bd19e --- /dev/null +++ b/tools/pgmsg/testdata/REL_15_STABLE.txt @@ -0,0 +1,505 @@ +# msgid set of src/bin/pg_dump/po/{de,fr}.po at REL_15_STABLE +# generated by tools/pgmsg; one Go-quoted msgid per line +"\nConnection options:\n" +"\nGeneral options:\n" +"\nIf -f/--file is not used, then the SQL script will be written to the standard\noutput.\n\n" +"\nIf no database name is supplied, then the PGDATABASE environment\nvariable value is used.\n\n" +"\nIf no input file name is supplied, then standard input is used.\n\n" +"\nOptions controlling the output content:\n" +"\nOptions controlling the restore:\n" +"\nThe options -I, -n, -N, -P, -t, -T, and --section can be combined and specified\nmultiple times to select multiple objects.\n" +" %s [OPTION]...\n" +" %s [OPTION]... [DBNAME]\n" +" %s [OPTION]... [FILE]\n" +" --binary-upgrade for use by upgrade utilities only\n" +" --column-inserts dump data as INSERT commands with column names\n" +" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n" +" --disable-triggers disable triggers during data-only restore\n" +" --enable-row-security enable row security\n" +" --enable-row-security enable row security (dump only content user has\n access to)\n" +" --exclude-database=PATTERN exclude databases whose name matches PATTERN\n" +" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n" +" --extra-float-digits=NUM override default setting for extra_float_digits\n" +" --if-exists use IF EXISTS when dropping objects\n" +" --include-foreign-data=PATTERN\n include data of foreign tables on foreign\n servers matching PATTERN\n" +" --inserts dump data as INSERT commands, rather than COPY\n" +" --load-via-partition-root load partitions via the root table\n" +" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n" +" --no-comments do not dump comments\n" +" --no-comments do not restore comments\n" +" --no-data-for-failed-tables do not restore data of tables that could not be\n created\n" +" --no-publications do not dump publications\n" +" --no-publications do not restore publications\n" +" --no-role-passwords do not dump passwords for roles\n" +" --no-security-labels do not dump security label assignments\n" +" --no-security-labels do not restore security labels\n" +" --no-subscriptions do not dump subscriptions\n" +" --no-subscriptions do not restore subscriptions\n" +" --no-sync do not wait for changes to be written safely to disk\n" +" --no-table-access-method do not dump table access methods\n" +" --no-table-access-method do not restore table access methods\n" +" --no-tablespaces do not dump tablespace assignments\n" +" --no-tablespaces do not restore tablespace assignments\n" +" --no-toast-compression do not dump TOAST compression methods\n" +" --no-unlogged-table-data do not dump unlogged table data\n" +" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n" +" --quote-all-identifiers quote all identifiers, even if not key words\n" +" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n" +" --role=ROLENAME do SET ROLE before dump\n" +" --role=ROLENAME do SET ROLE before restore\n" +" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n" +" --section=SECTION dump named section (pre-data, data, or post-data)\n" +" --section=SECTION restore named section (pre-data, data, or post-data)\n" +" --serializable-deferrable wait until the dump can run without anomalies\n" +" --snapshot=SNAPSHOT use given snapshot for the dump\n" +" --strict-names require table and/or schema include patterns to\n match at least one entity each\n" +" --use-set-session-authorization\n use SET SESSION AUTHORIZATION commands instead of\n ALTER OWNER commands to set ownership\n" +" -1, --single-transaction restore as a single transaction\n" +" -?, --help show this help, then exit\n" +" -?, --help show this help, then exit\n" +" -B, --no-blobs exclude large objects in dump\n" +" -C, --create create the target database\n" +" -C, --create include commands to create database in dump\n" +" -E, --encoding=ENCODING dump the data in encoding ENCODING\n" +" -F, --format=c|d|t backup file format (should be automatic)\n" +" -F, --format=c|d|t|p output file format (custom, directory, tar,\n plain text (default))\n" +" -I, --index=NAME restore named index\n" +" -L, --use-list=FILENAME use table of contents from this file for\n selecting/ordering output\n" +" -N, --exclude-schema=NAME do not restore objects in this schema\n" +" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n" +" -O, --no-owner skip restoration of object ownership\n" +" -O, --no-owner skip restoration of object ownership in\n plain-text format\n" +" -P, --function=NAME(args) restore named function\n" +" -S, --superuser=NAME superuser user name to use for disabling triggers\n" +" -S, --superuser=NAME superuser user name to use in plain-text format\n" +" -S, --superuser=NAME superuser user name to use in the dump\n" +" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n" +" -T, --trigger=NAME restore named trigger\n" +" -U, --username=NAME connect as specified database user\n" +" -V, --version output version information, then exit\n" +" -V, --version output version information, then exit\n" +" -W, --password force password prompt (should happen automatically)\n" +" -Z, --compress=0-9 compression level for compressed formats\n" +" -a, --data-only dump only the data, not the schema\n" +" -a, --data-only restore only the data, no schema\n" +" -b, --blobs include large objects in dump\n" +" -c, --clean clean (drop) database objects before recreating\n" +" -c, --clean clean (drop) databases before recreating\n" +" -d, --dbname=CONNSTR connect using connection string\n" +" -d, --dbname=DBNAME database to dump\n" +" -d, --dbname=NAME connect to database name\n" +" -e, --exit-on-error exit on error, default is to continue\n" +" -e, --extension=PATTERN dump the specified extension(s) only\n" +" -f, --file=FILENAME output file name\n" +" -f, --file=FILENAME output file or directory name\n" +" -f, --file=FILENAME output file name (- for stdout)\n" +" -g, --globals-only dump only global objects, no databases\n" +" -h, --host=HOSTNAME database server host or socket directory\n" +" -j, --jobs=NUM use this many parallel jobs to dump\n" +" -j, --jobs=NUM use this many parallel jobs to restore\n" +" -l, --database=DBNAME alternative default database\n" +" -l, --list print summarized TOC of the archive\n" +" -n, --schema=NAME restore only objects in this schema\n" +" -n, --schema=PATTERN dump the specified schema(s) only\n" +" -p, --port=PORT database server port number\n" +" -r, --roles-only dump only roles, no databases or tablespaces\n" +" -s, --schema-only dump only the schema, no data\n" +" -s, --schema-only restore only the schema, no data\n" +" -t, --table=NAME restore named relation (table, view, etc.)\n" +" -t, --table=PATTERN dump the specified table(s) only\n" +" -t, --tablespaces-only dump only tablespaces, no databases or roles\n" +" -v, --verbose verbose mode\n" +" -v, --verbose verbose mode\n" +" -w, --no-password never prompt for password\n" +" -x, --no-privileges do not dump privileges (grant/revoke)\n" +" -x, --no-privileges skip restoration of access privileges (grant/revoke)\n" +"%s" +"%s dumps a database as a text file or to other formats.\n\n" +"%s extracts a PostgreSQL database cluster into an SQL script file.\n\n" +"%s home page: <%s>\n" +"%s must be in range %d..%d" +"%s restores a PostgreSQL database from an archive created by pg_dump.\n\n" +"%s() failed: %m" +"%s() failed: error code %d" +"%s: %sCommand was: %s" +"COPY failed for table \"%s\": %s" +"Command was: %s" +"Consider using a full dump instead of a --data-only dump to avoid this problem." +"Dumping the contents of table \"%s\" failed: PQgetCopyData() failed." +"Dumping the contents of table \"%s\" failed: PQgetResult() failed." +"Error message from server: %s" +"Password: " +"Query was: %s" +"Report bugs to <%s>.\n" +"The system catalogs might be corrupted." +"Try \"%s --help\" for more information." +"Usage:\n" +"WITH OIDS is not supported anymore (table \"%s\")" +"You are currently not connected to a database." +"You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints." +"a worker process died unexpectedly" +"aborting because of server version mismatch" +"actual file length (%lld) does not match expected (%lld)" +"already connected to a database" +"archive is compressed, but this installation does not support compression -- no data will be available" +"archive items not in correct section order" +"archive was made on a machine with larger integers, some operations might fail" +"bad dumpId" +"bad table dumpId for TABLE DATA item" +"bogus transform definition, at least one of trffromsql and trftosql should be nonzero" +"bogus value in pg_cast.castfunc or pg_cast.castmethod field" +"bogus value in pg_cast.castmethod field" +"bogus value in pg_transform.trffromsql field" +"bogus value in pg_transform.trftosql field" +"can only reopen input archives" +"cannot duplicate null pointer (internal error)\n" +"cannot restore from compressed archive (compression not supported in this installation)" +"cannot specify both --single-transaction and multiple jobs" +"child process exited with exit code %d" +"child process exited with unrecognized status %d" +"child process was terminated by exception 0x%X" +"child process was terminated by signal %d: %s" +"command not executable" +"command not found" +"compression is not supported by tar archive format" +"compressor active" +"connecting to database for restore" +"connecting to new database \"%s\"" +"corrupt tar header found in %s (expected %d, computed %d) file position %llu" +"could not change directory to \"%s\": %m" +"could not close TOC file: %m" +"could not close archive file: %m" +"could not close blob data file: %m" +"could not close blobs TOC file: %m" +"could not close compression library: %s" +"could not close compression stream: %s" +"could not close data file \"%s\": %m" +"could not close data file: %m" +"could not close directory \"%s\": %m" +"could not close input file: %m" +"could not close large object TOC file \"%s\": %m" +"could not close output file: %m" +"could not close temporary file: %m" +"could not commit database transaction" +"could not compress data: %s" +"could not connect to database" +"could not connect to database \"%s\"" +"could not connect to databases \"postgres\" or \"template1\"\nPlease specify an alternative database." +"could not create communication channels: %m" +"could not create directory \"%s\": %m" +"could not create large object %u: %s" +"could not create worker process: %m" +"could not create worker thread: %m" +"could not determine seek position in archive file: %m" +"could not execute query" +"could not find a \"%s\" to execute" +"could not find block ID %d in archive -- possibly corrupt archive" +"could not find block ID %d in archive -- possibly due to out-of-order restore request, which cannot be handled due to non-seekable input file" +"could not find entry for ID %d" +"could not find file \"%s\" in archive" +"could not find function definition for function with OID %u" +"could not find header for file \"%s\" in tar archive" +"could not find operator with OID %s" +"could not find parent extension for %s %s" +"could not find referenced extension %u" +"could not find where to insert IF EXISTS in statement \"%s\"" +"could not generate restrict key" +"could not generate temporary file name: %m" +"could not get server version" +"could not get server_version from libpq" +"could not identify current directory: %m" +"could not identify dependency loop" +"could not initialize compression library: %s" +"could not obtain lock on relation \"%s\"\nThis usually means that someone requested an ACCESS EXCLUSIVE lock on the table after the pg_dump parent process had gotten the initial ACCESS SHARE lock on the table." +"could not open TOC file \"%s\" for input: %m" +"could not open TOC file \"%s\" for output: %m" +"could not open TOC file \"%s\": %m" +"could not open TOC file for input: %m" +"could not open TOC file for output: %m" +"could not open input file \"%s\": %m" +"could not open input file: %m" +"could not open large object %u: %s" +"could not open large object TOC file \"%s\" for input: %m" +"could not open output file \"%s\": %m" +"could not open output file: %m" +"could not parse %s array" +"could not parse ACL list (%s) for parameter \"%s\"" +"could not parse ACL list (%s) for tablespace \"%s\"" +"could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)" +"could not parse default ACL list (%s)" +"could not parse index statistic columns" +"could not parse index statistic values" +"could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)" +"could not parse numeric array \"%s\": invalid character in number" +"could not parse numeric array \"%s\": too many numbers" +"could not parse result of current_schemas()" +"could not parse server version \"%s\"" +"could not re-open the output file \"%s\": %m" +"could not read binary \"%s\"" +"could not read directory \"%s\": %m" +"could not read from input file: %m" +"could not read from input file: %s" +"could not read from input file: end of file" +"could not read input file: %m" +"could not read symbolic link \"%s\": %m" +"could not resolve dependency loop among these items:" +"could not set default_table_access_method: %s" +"could not set default_tablespace to %s: %s" +"could not set search_path to \"%s\": %s" +"could not set seek position in archive file: %m" +"could not set session user to \"%s\": %s" +"could not start database transaction" +"could not uncompress data: %s" +"could not write to blobs TOC file" +"could not write to large object: %s" +"could not write to output file: %s" +"could not write to the communication channel: %m" +"creating %s \"%s\"" +"creating %s \"%s.%s\"" +"cross-database references are not implemented: %s" +"data block %d has wrong seek position" +"definition of view \"%s\" appears to be empty (length zero)" +"detail: " +"did not find magic string in file header" +"direct database connections are not supported in pre-1.3 archives" +"directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)" +"directory name too long: \"%s\"" +"disabling triggers for %s" +"don't know how to set owner for object type \"%s\"" +"dropping %s %s" +"dumping contents of table \"%s.%s\"" +"dumping database \"%s\"" +"enabling triggers for %s" +"entering main parallel loop" +"entry ID %d out of range -- perhaps a corrupt TOC" +"error during file seek: %m" +"error reading large object %u: %s" +"error reading large object TOC file \"%s\"" +"error returned by PQputCopyData: %s" +"error returned by PQputCopyEnd: %s" +"error: " +"errors ignored on restore: %d" +"excluding database \"%s\"" +"executing %s" +"executing %s %s" +"expected %d check constraint on table \"%s\" but found %d" +"expected format (%d) differs from format found in file (%d)" +"failed sanity check, parent OID %u of table \"%s\" (OID %u) not found" +"failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found" +"failed sanity check, parent table with OID %u of sequence with OID %u not found" +"failed sanity check, table OID %u appearing in pg_partitioned_table not found" +"file name too long: \"%s\"" +"file offset in dump file is too large" +"finding extension tables" +"finding inheritance relationships" +"finding table check constraints" +"finding table default expressions" +"finished item %d %s %s" +"finished main parallel loop" +"flagging indexes in partitioned tables" +"flagging inherited columns in subtables" +"found orphaned pg_auth_members entry for role %s" +"found unexpected block ID (%d) when reading data -- expected %d" +"from TOC entry %d; %u %u %s %s %s" +"function \"%s\" not found" +"hint: " +"identifying extension members" +"implied data-only restore" +"improper qualified name (too many dotted names): %s" +"improper relation name (too many dotted names): %s" +"incomplete tar header found (%lu byte)" +"index \"%s\" not found" +"input file appears to be a text format dump. Please use psql." +"input file does not appear to be a valid archive" +"input file does not appear to be a valid archive (too short?)" +"input file is too short (read %lu, expected 5)" +"internal error -- WriteData cannot be called outside the context of a DataDumper routine" +"invalid ENCODING item: %s" +"invalid OID for large object" +"invalid OID for large object (%u)" +"invalid STDSTRINGS item: %s" +"invalid adnum value %d for table \"%s\"" +"invalid argument string (%s) for trigger \"%s\" on table \"%s\"" +"invalid binary \"%s\"" +"invalid client encoding \"%s\" specified" +"invalid collation \"%s\"" +"invalid column number %d for table \"%s\"" +"invalid column numbering in table \"%s\"" +"invalid compression code: %d" +"invalid creation date in header" +"invalid dependency %d" +"invalid dumpId %d" +"invalid line in large object TOC file \"%s\": \"%s\"" +"invalid memory allocation request size %zu * %zu\n" +"invalid memory allocation request size %zu + %zu\n" +"invalid message received from worker: \"%s\"" +"invalid number of parents %d for table \"%s\"" +"invalid output format \"%s\" specified" +"invalid restrict key" +"invalid type \"%c\" of access method \"%s\"" +"invalid value \"%s\" for option %s" +"large-object output not supported in chosen format" +"last built-in OID is %u" +"launching item %d %s %s" +"line ignored: %s" +"mismatched number of columns and values for index statistics" +"mismatched number of configurations and conditions for extension" +"missing index for constraint \"%s\"" +"no matching extensions were found" +"no matching extensions were found for pattern \"%s\"" +"no matching foreign servers were found for pattern \"%s\"" +"no matching schemas were found" +"no matching schemas were found for pattern \"%s\"" +"no matching tables were found" +"no matching tables were found for pattern \"%s\"" +"no output directory specified" +"no referenced object %u %u" +"no referencing object %u %u" +"not built with zlib support" +"one of -d/--dbname and -f/--file must be specified" +"option --exclude-database cannot be used together with -g/--globals-only, -r/--roles-only, or -t/--tablespaces-only" +"option --if-exists requires option -c/--clean" +"option --include-foreign-data is not supported with parallel backup" +"option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts" +"option --restrict-key can only be used with --format=plain" +"options -C/--create and -1/--single-transaction cannot be used together" +"options -c/--clean and -a/--data-only cannot be used together" +"options -d/--dbname and --restrict-key cannot be used together" +"options -d/--dbname and -f/--file cannot be used together" +"options -g/--globals-only and -r/--roles-only cannot be used together" +"options -g/--globals-only and -t/--tablespaces-only cannot be used together" +"options -r/--roles-only and -t/--tablespaces-only cannot be used together" +"options -s/--schema-only and --include-foreign-data cannot be used together" +"options -s/--schema-only and -a/--data-only cannot be used together" +"out of memory" +"out of memory\n" +"out of on_exit_nicely slots" +"parallel backup only supported by the directory format" +"parallel dumps from standby servers are not supported by this server version" +"parallel restore from non-seekable file is not supported" +"parallel restore from standard input is not supported" +"parallel restore is not supported with archives made by pre-8.0 pg_dump" +"parallel restore is not supported with this archive file format" +"pg_dump failed on database \"%s\", exiting" +"pgpipe: %s() failed: error code %d" +"pgpipe: could not accept connection: error code %d" +"pgpipe: could not bind: error code %d" +"pgpipe: could not connect socket: error code %d" +"pgpipe: could not create second socket: error code %d" +"pgpipe: could not create socket: error code %d" +"pgpipe: could not listen: error code %d" +"postfix operators are not supported anymore (operator \"%s\")" +"processing %s" +"processing data for table \"%s.%s\"" +"processing item %d %s %s" +"processing missed item %d %s %s" +"program \"%s\" is needed by %s but was not found in the same directory as \"%s\"" +"program \"%s\" was found by \"%s\" but was not the same version as %s" +"query failed: %s" +"query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)" +"query returned %d row instead of one: %s" +"query to get data of sequence \"%s\" returned %d row (expected 1)" +"query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned" +"query to obtain definition of view \"%s\" returned more than one definition" +"query to obtain definition of view \"%s\" returned no data" +"reading column info for interesting tables" +"reading constraints" +"reading default privileges" +"reading dependency data" +"reading event triggers" +"reading extended statistics" +"reading extensions" +"reading indexes" +"reading large objects" +"reading partitioning data" +"reading policies" +"reading procedural languages" +"reading publication membership of schemas" +"reading publication membership of tables" +"reading publications" +"reading rewrite rules" +"reading row-level security policies" +"reading schemas" +"reading subscriptions" +"reading table inheritance information" +"reading transforms" +"reading triggers" +"reading type casts" +"reading user-defined access methods" +"reading user-defined aggregate functions" +"reading user-defined collations" +"reading user-defined conversions" +"reading user-defined foreign servers" +"reading user-defined foreign-data wrappers" +"reading user-defined functions" +"reading user-defined operator classes" +"reading user-defined operator families" +"reading user-defined operators" +"reading user-defined tables" +"reading user-defined text search configurations" +"reading user-defined text search dictionaries" +"reading user-defined text search parsers" +"reading user-defined text search templates" +"reading user-defined types" +"reconnection failed: %s" +"requested compression not available in this installation -- archive will be uncompressed" +"restored %d large object" +"restoring data out of order is not supported in this archive format: \"%s\" is required, but comes before \"%s\" in the archive file." +"restoring large object with OID %u" +"restoring tables WITH OIDS is not supported anymore" +"role name starting with \"pg_\" skipped (%s)" +"role with OID %u does not exist" +"running \"%s\"" +"sanity check on integer size (%lu) failed" +"saving database definition" +"saving encoding = %s" +"saving large objects" +"saving search_path = %s" +"saving standard_conforming_strings = %s" +"schema \"%s\" not found" +"schema with OID %u does not exist" +"server version: %s; %s version: %s" +"skipping item %d %s %s" +"subscriptions not dumped because current user is not a superuser" +"table \"%s\" could not be created, will not restore its data" +"table \"%s\" not found" +"there are circular foreign-key constraints on this table:" +"this format cannot be read" +"too many command-line arguments (first is \"%s\")" +"trigger \"%s\" not found" +"typtype of data type \"%s\" appears to be invalid" +"unexpected COPY statement syntax: \"%s\"" +"unexpected column data for table \"%s\"" +"unexpected data offset flag %d" +"unexpected extra results during COPY of table \"%s\"" +"unexpected index data for table \"%s\"" +"unexpected policy command type: %c" +"unexpected section code %d" +"unexpected tgtype value: %d" +"unrecognized aggfinalmodify value for aggregate \"%s\"" +"unrecognized aggmfinalmodify value for aggregate \"%s\"" +"unrecognized archive format \"%s\"; please specify \"c\", \"d\", or \"t\"" +"unrecognized collation provider: %s" +"unrecognized command received from leader: \"%s\"" +"unrecognized constraint type: %c" +"unrecognized data block type %d while restoring archive" +"unrecognized data block type (%d) while searching archive" +"unrecognized encoding \"%s\"" +"unrecognized file format \"%d\"" +"unrecognized locale provider: %s" +"unrecognized object type in default privileges: %d" +"unrecognized proparallel value for function \"%s\"" +"unrecognized provolatile value for function \"%s\"" +"unrecognized section name: \"%s\"" +"unrecognized sequence type: %s" +"unrecognized table OID %u" +"unsupported pg_init_privs entry: %u %u %d" +"unsupported version (%d.%d) in file header" +"warning from original dump file: %s" +"warning: " +"while FINALIZING:" +"while INITIALIZING:" +"while PROCESSING TOC:" +"worker process failed: exit code %d" +"wrong number of fields retrieved from table \"%s\"" +"wrote %zu byte of large object data (result = %d)" diff --git a/tools/pgmsg/testdata/REL_16_STABLE.txt b/tools/pgmsg/testdata/REL_16_STABLE.txt new file mode 100644 index 0000000..773b6b3 --- /dev/null +++ b/tools/pgmsg/testdata/REL_16_STABLE.txt @@ -0,0 +1,537 @@ +# msgid set of src/bin/pg_dump/po/{de,fr}.po at REL_16_STABLE +# generated by tools/pgmsg; one Go-quoted msgid per line +"\nConnection options:\n" +"\nGeneral options:\n" +"\nIf -f/--file is not used, then the SQL script will be written to the standard\noutput.\n\n" +"\nIf no database name is supplied, then the PGDATABASE environment\nvariable value is used.\n\n" +"\nIf no input file name is supplied, then standard input is used.\n\n" +"\nOptions controlling the output content:\n" +"\nOptions controlling the restore:\n" +"\nThe options -I, -n, -N, -P, -t, -T, and --section can be combined and specified\nmultiple times to select multiple objects.\n" +" %s [OPTION]...\n" +" %s [OPTION]... [DBNAME]\n" +" %s [OPTION]... [FILE]\n" +" --binary-upgrade for use by upgrade utilities only\n" +" --blobs (same as --large-objects, deprecated)\n" +" --column-inserts dump data as INSERT commands with column names\n" +" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n" +" --disable-triggers disable triggers during data-only restore\n" +" --enable-row-security enable row security\n" +" --enable-row-security enable row security (dump only content user has\n access to)\n" +" --exclude-database=PATTERN exclude databases whose name matches PATTERN\n" +" --exclude-table-and-children=PATTERN\n do NOT dump the specified table(s), including\n child and partition tables\n" +" --exclude-table-data-and-children=PATTERN\n do NOT dump data for the specified table(s),\n including child and partition tables\n" +" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n" +" --extra-float-digits=NUM override default setting for extra_float_digits\n" +" --if-exists use IF EXISTS when dropping objects\n" +" --include-foreign-data=PATTERN\n include data of foreign tables on foreign\n servers matching PATTERN\n" +" --inserts dump data as INSERT commands, rather than COPY\n" +" --load-via-partition-root load partitions via the root table\n" +" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n" +" --no-blobs (same as --no-large-objects, deprecated)\n" +" --no-comments do not dump comments\n" +" --no-comments do not restore comments\n" +" --no-data-for-failed-tables do not restore data of tables that could not be\n created\n" +" --no-publications do not dump publications\n" +" --no-publications do not restore publications\n" +" --no-role-passwords do not dump passwords for roles\n" +" --no-security-labels do not dump security label assignments\n" +" --no-security-labels do not restore security labels\n" +" --no-subscriptions do not dump subscriptions\n" +" --no-subscriptions do not restore subscriptions\n" +" --no-sync do not wait for changes to be written safely to disk\n" +" --no-table-access-method do not dump table access methods\n" +" --no-table-access-method do not restore table access methods\n" +" --no-tablespaces do not dump tablespace assignments\n" +" --no-tablespaces do not restore tablespace assignments\n" +" --no-toast-compression do not dump TOAST compression methods\n" +" --no-unlogged-table-data do not dump unlogged table data\n" +" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n" +" --quote-all-identifiers quote all identifiers, even if not key words\n" +" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n" +" --role=ROLENAME do SET ROLE before dump\n" +" --role=ROLENAME do SET ROLE before restore\n" +" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n" +" --section=SECTION dump named section (pre-data, data, or post-data)\n" +" --section=SECTION restore named section (pre-data, data, or post-data)\n" +" --serializable-deferrable wait until the dump can run without anomalies\n" +" --snapshot=SNAPSHOT use given snapshot for the dump\n" +" --strict-names require table and/or schema include patterns to\n match at least one entity each\n" +" --table-and-children=PATTERN dump only the specified table(s), including\n child and partition tables\n" +" --use-set-session-authorization\n use SET SESSION AUTHORIZATION commands instead of\n ALTER OWNER commands to set ownership\n" +" -1, --single-transaction restore as a single transaction\n" +" -?, --help show this help, then exit\n" +" -?, --help show this help, then exit\n" +" -B, --no-large-objects exclude large objects in dump\n" +" -C, --create create the target database\n" +" -C, --create include commands to create database in dump\n" +" -E, --encoding=ENCODING dump the data in encoding ENCODING\n" +" -F, --format=c|d|t backup file format (should be automatic)\n" +" -F, --format=c|d|t|p output file format (custom, directory, tar,\n plain text (default))\n" +" -I, --index=NAME restore named index\n" +" -L, --use-list=FILENAME use table of contents from this file for\n selecting/ordering output\n" +" -N, --exclude-schema=NAME do not restore objects in this schema\n" +" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n" +" -O, --no-owner skip restoration of object ownership\n" +" -O, --no-owner skip restoration of object ownership in\n plain-text format\n" +" -P, --function=NAME(args) restore named function\n" +" -S, --superuser=NAME superuser user name to use for disabling triggers\n" +" -S, --superuser=NAME superuser user name to use in plain-text format\n" +" -S, --superuser=NAME superuser user name to use in the dump\n" +" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n" +" -T, --trigger=NAME restore named trigger\n" +" -U, --username=NAME connect as specified database user\n" +" -V, --version output version information, then exit\n" +" -V, --version output version information, then exit\n" +" -W, --password force password prompt (should happen automatically)\n" +" -Z, --compress=METHOD[:DETAIL]\n compress as specified\n" +" -a, --data-only dump only the data, not the schema\n" +" -a, --data-only restore only the data, no schema\n" +" -b, --large-objects include large objects in dump\n" +" -c, --clean clean (drop) database objects before recreating\n" +" -c, --clean clean (drop) databases before recreating\n" +" -d, --dbname=CONNSTR connect using connection string\n" +" -d, --dbname=DBNAME database to dump\n" +" -d, --dbname=NAME connect to database name\n" +" -e, --exit-on-error exit on error, default is to continue\n" +" -e, --extension=PATTERN dump the specified extension(s) only\n" +" -f, --file=FILENAME output file name\n" +" -f, --file=FILENAME output file or directory name\n" +" -f, --file=FILENAME output file name (- for stdout)\n" +" -g, --globals-only dump only global objects, no databases\n" +" -h, --host=HOSTNAME database server host or socket directory\n" +" -j, --jobs=NUM use this many parallel jobs to dump\n" +" -j, --jobs=NUM use this many parallel jobs to restore\n" +" -l, --database=DBNAME alternative default database\n" +" -l, --list print summarized TOC of the archive\n" +" -n, --schema=NAME restore only objects in this schema\n" +" -n, --schema=PATTERN dump the specified schema(s) only\n" +" -p, --port=PORT database server port number\n" +" -r, --roles-only dump only roles, no databases or tablespaces\n" +" -s, --schema-only dump only the schema, no data\n" +" -s, --schema-only restore only the schema, no data\n" +" -t, --table=NAME restore named relation (table, view, etc.)\n" +" -t, --table=PATTERN dump only the specified table(s)\n" +" -t, --tablespaces-only dump only tablespaces, no databases or roles\n" +" -v, --verbose verbose mode\n" +" -v, --verbose verbose mode\n" +" -w, --no-password never prompt for password\n" +" -x, --no-privileges do not dump privileges (grant/revoke)\n" +" -x, --no-privileges skip restoration of access privileges (grant/revoke)\n" +"%s" +"%s dumps a database as a text file or to other formats.\n\n" +"%s extracts a PostgreSQL database cluster into an SQL script file.\n\n" +"%s home page: <%s>\n" +"%s must be in range %d..%d" +"%s restores a PostgreSQL database from an archive created by pg_dump.\n\n" +"%s() failed: %m" +"%s() failed: error code %d" +"%s: %sCommand was: %s" +"COPY failed for table \"%s\": %s" +"Command was: %s" +"Consider using a full dump instead of a --data-only dump to avoid this problem." +"Dumping the contents of table \"%s\" failed: PQgetCopyData() failed." +"Dumping the contents of table \"%s\" failed: PQgetResult() failed." +"Error message from server: %s" +"Password: " +"Query was: %s" +"Report bugs to <%s>.\n" +"The system catalogs might be corrupted." +"This grant will be dumped without GRANTED BY." +"Try \"%s --help\" for more information." +"Usage:\n" +"WITH OIDS is not supported anymore (table \"%s\")" +"You are currently not connected to a database." +"You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints." +"a worker process died unexpectedly" +"aborting because of server version mismatch" +"actual file length (%lld) does not match expected (%lld)" +"already connected to a database" +"archive is compressed, but this installation does not support compression (%s) -- no data will be available" +"archive items not in correct section order" +"archive was made on a machine with larger integers, some operations might fail" +"bad dumpId" +"bad table dumpId for TABLE DATA item" +"bogus transform definition, at least one of trffromsql and trftosql should be nonzero" +"bogus value in pg_cast.castfunc or pg_cast.castmethod field" +"bogus value in pg_cast.castmethod field" +"bogus value in pg_transform.trffromsql field" +"bogus value in pg_transform.trftosql field" +"can only reopen input archives" +"cannot duplicate null pointer (internal error)\n" +"cannot restore from compressed archive (%s)" +"cannot specify both --single-transaction and multiple jobs" +"child process exited with exit code %d" +"child process exited with unrecognized status %d" +"child process was terminated by exception 0x%X" +"child process was terminated by signal %d: %s" +"command not executable" +"command not found" +"compression algorithm \"%s\" does not accept a compression level" +"compression algorithm \"%s\" does not accept a worker count" +"compression algorithm \"%s\" does not support long-distance mode" +"compression algorithm \"%s\" expects a compression level between %d and %d (default at %d)" +"compression is not supported by tar archive format" +"compression option \"%s\" is not currently supported by pg_dump" +"compression option \"%s\" requires a value" +"compressor active" +"connecting to database for restore" +"connecting to new database \"%s\"" +"corrupt tar header found in %s (expected %d, computed %d) file position %llu" +"could not close LO data file: %m" +"could not close LOs TOC file: %m" +"could not close TOC file: %m" +"could not close archive file: %m" +"could not close compression library: %s" +"could not close compression stream: %s" +"could not close data file \"%s\": %m" +"could not close data file: %m" +"could not close directory \"%s\": %m" +"could not close file: %m" +"could not close input file: %m" +"could not close large object TOC file \"%s\": %m" +"could not close output file: %m" +"could not close temporary file: %m" +"could not commit database transaction" +"could not compress data: %s" +"could not connect to database" +"could not connect to database \"%s\"" +"could not connect to databases \"postgres\" or \"template1\"\nPlease specify an alternative database." +"could not create LZ4 decompression context: %s" +"could not create communication channels: %m" +"could not create directory \"%s\": %m" +"could not create large object %u: %s" +"could not create worker process: %m" +"could not create worker thread: %m" +"could not decompress data: %s" +"could not decompress: %s" +"could not determine seek position in archive file: %m" +"could not end compression: %s" +"could not end decompression: %s" +"could not execute query" +"could not find a \"%s\" to execute" +"could not find a legal dump ordering for memberships in role \"%s\"" +"could not find block ID %d in archive -- possibly corrupt archive" +"could not find block ID %d in archive -- possibly due to out-of-order restore request, which cannot be handled due to non-seekable input file" +"could not find entry for ID %d" +"could not find file \"%s\" in archive" +"could not find function definition for function with OID %u" +"could not find header for file \"%s\" in tar archive" +"could not find operator with OID %s" +"could not find parent extension for %s %s" +"could not find referenced extension %u" +"could not find where to insert IF EXISTS in statement \"%s\"" +"could not free LZ4 decompression context: %s" +"could not generate restrict key" +"could not generate temporary file name: %m" +"could not get server version" +"could not get server_version from libpq" +"could not identify dependency loop" +"could not initialize LZ4 compression: %s" +"could not initialize compression library" +"could not initialize compression library: %s" +"could not obtain lock on relation \"%s\"\nThis usually means that someone requested an ACCESS EXCLUSIVE lock on the table after the pg_dump parent process had gotten the initial ACCESS SHARE lock on the table." +"could not open TOC file \"%s\" for input: %m" +"could not open TOC file \"%s\" for output: %m" +"could not open TOC file \"%s\": %m" +"could not open TOC file for input: %m" +"could not open TOC file for output: %m" +"could not open input file \"%s\": %m" +"could not open input file: %m" +"could not open large object %u: %s" +"could not open large object TOC file \"%s\" for input: %m" +"could not open output file \"%s\": %m" +"could not open output file: %m" +"could not open stdout for appending: %m" +"could not parse %s array" +"could not parse ACL list (%s) for parameter \"%s\"" +"could not parse ACL list (%s) for tablespace \"%s\"" +"could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)" +"could not parse default ACL list (%s)" +"could not parse index statistic columns" +"could not parse index statistic values" +"could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)" +"could not parse numeric array \"%s\": invalid character in number" +"could not parse numeric array \"%s\": too many numbers" +"could not parse result of current_schemas()" +"could not parse server version \"%s\"" +"could not re-open the output file \"%s\": %m" +"could not read binary \"%s\": %m" +"could not read directory \"%s\": %m" +"could not read from input file: %m" +"could not read from input file: %s" +"could not read from input file: end of file" +"could not read input file: %m" +"could not resolve dependency loop among these items:" +"could not resolve path \"%s\" to absolute form: %m" +"could not set compression parameter \"%s\": %s" +"could not set default_table_access_method: %s" +"could not set default_tablespace to %s: %s" +"could not set search_path to \"%s\": %s" +"could not set seek position in archive file: %m" +"could not set session user to \"%s\": %s" +"could not start database transaction" +"could not uncompress data: %s" +"could not write to file: %m" +"could not write to file: %s" +"could not write to large object: %s" +"could not write to output file: %m" +"could not write to the communication channel: %m" +"creating %s \"%s\"" +"creating %s \"%s.%s\"" +"cross-database references are not implemented: %s" +"data block %d has wrong seek position" +"definition of view \"%s\" appears to be empty (length zero)" +"detail: " +"did not find magic string in file header" +"direct database connections are not supported in pre-1.3 archives" +"directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)" +"directory name too long: \"%s\"" +"disabling triggers for %s" +"don't know how to set owner for object type \"%s\"" +"dropping %s %s" +"dumping contents of table \"%s.%s\"" +"dumping database \"%s\"" +"enabling triggers for %s" +"entering main parallel loop" +"entry ID %d out of range -- perhaps a corrupt TOC" +"error during file seek: %m" +"error during writing: %m" +"error during writing: %s" +"error reading large object %u: %s" +"error reading large object TOC file \"%s\"" +"error returned by PQputCopyData: %s" +"error returned by PQputCopyEnd: %s" +"error: " +"errors ignored on restore: %d" +"excluding database \"%s\"" +"executing %s" +"executing %s %s" +"expected %d check constraint on table \"%s\" but found %d" +"expected format (%d) differs from format found in file (%d)" +"failed sanity check, parent OID %u of table \"%s\" (OID %u) not found" +"failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found" +"failed sanity check, parent table with OID %u of sequence with OID %u not found" +"failed sanity check, table OID %u appearing in pg_partitioned_table not found" +"file name too long: \"%s\"" +"file offset in dump file is too large" +"finding extension tables" +"finding inheritance relationships" +"finding table check constraints" +"finding table default expressions" +"finished item %d %s %s" +"finished main parallel loop" +"flagging indexes in partitioned tables" +"flagging inherited columns in subtables" +"found empty string where a compression option was expected" +"found unexpected block ID (%d) when reading data -- expected %d" +"from TOC entry %d; %u %u %s %s %s" +"function \"%s\" not found" +"grant of role \"%s\" to \"%s\" has invalid grantor OID %s" +"hint: " +"identifying extension members" +"ignoring role grant for missing role with OID %s" +"ignoring role grant to missing role with OID %s" +"implied data-only restore" +"improper qualified name (too many dotted names): %s" +"improper relation name (too many dotted names): %s" +"incomplete tar header found (%lu byte)" +"index \"%s\" not found" +"input file appears to be a text format dump. Please use psql." +"input file does not appear to be a valid archive" +"input file does not appear to be a valid archive (too short?)" +"input file is too short (read %lu, expected 5)" +"internal error -- WriteData cannot be called outside the context of a DataDumper routine" +"invalid ENCODING item: %s" +"invalid OID for large object" +"invalid OID for large object (%u)" +"invalid STDSTRINGS item: %s" +"invalid adnum value %d for table \"%s\"" +"invalid argument string (%s) for trigger \"%s\" on table \"%s\"" +"invalid binary \"%s\": %m" +"invalid client encoding \"%s\" specified" +"invalid collation \"%s\"" +"invalid column number %d for table \"%s\"" +"invalid column numbering in table \"%s\"" +"invalid compression specification: %s" +"invalid creation date in header" +"invalid dependency %d" +"invalid dumpId %d" +"invalid line in large object TOC file \"%s\": \"%s\"" +"invalid memory allocation request size %zu * %zu\n" +"invalid memory allocation request size %zu + %zu\n" +"invalid message received from worker: \"%s\"" +"invalid number of parents %d for table \"%s\"" +"invalid output format \"%s\" specified" +"invalid restrict key" +"invalid type \"%c\" of access method \"%s\"" +"invalid value \"%s\" for option %s" +"large-object output not supported in chosen format" +"last built-in OID is %u" +"launching item %d %s %s" +"line ignored: %s" +"mismatched number of columns and values for index statistics" +"mismatched number of configurations and conditions for extension" +"missing index for constraint \"%s\"" +"no matching extensions were found" +"no matching extensions were found for pattern \"%s\"" +"no matching foreign servers were found for pattern \"%s\"" +"no matching schemas were found" +"no matching schemas were found for pattern \"%s\"" +"no matching tables were found" +"no matching tables were found for pattern \"%s\"" +"no output directory specified" +"no referenced object %u %u" +"no referencing object %u %u" +"one of -d/--dbname and -f/--file must be specified" +"option --exclude-database cannot be used together with -g/--globals-only, -r/--roles-only, or -t/--tablespaces-only" +"option --if-exists requires option -c/--clean" +"option --include-foreign-data is not supported with parallel backup" +"option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts" +"option --restrict-key can only be used with --format=plain" +"options -C/--create and -1/--single-transaction cannot be used together" +"options -c/--clean and -a/--data-only cannot be used together" +"options -d/--dbname and --restrict-key cannot be used together" +"options -d/--dbname and -f/--file cannot be used together" +"options -g/--globals-only and -r/--roles-only cannot be used together" +"options -g/--globals-only and -t/--tablespaces-only cannot be used together" +"options -r/--roles-only and -t/--tablespaces-only cannot be used together" +"options -s/--schema-only and --include-foreign-data cannot be used together" +"options -s/--schema-only and -a/--data-only cannot be used together" +"out of memory" +"out of memory\n" +"out of on_exit_nicely slots" +"parallel backup only supported by the directory format" +"parallel dumps from standby servers are not supported by this server version" +"parallel restore from non-seekable file is not supported" +"parallel restore from standard input is not supported" +"parallel restore is not supported with archives made by pre-8.0 pg_dump" +"parallel restore is not supported with this archive file format" +"pg_dump failed on database \"%s\", exiting" +"pgpipe: %s() failed: error code %d" +"pgpipe: could not accept connection: error code %d" +"pgpipe: could not bind: error code %d" +"pgpipe: could not connect socket: error code %d" +"pgpipe: could not create second socket: error code %d" +"pgpipe: could not create socket: error code %d" +"pgpipe: could not listen: error code %d" +"postfix operators are not supported anymore (operator \"%s\")" +"processing %s" +"processing data for table \"%s.%s\"" +"processing item %d %s %s" +"processing missed item %d %s %s" +"program \"%s\" is needed by %s but was not found in the same directory as \"%s\"" +"program \"%s\" was found by \"%s\" but was not the same version as %s" +"query failed: %s" +"query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)" +"query returned %d row instead of one: %s" +"query to get data of sequence \"%s\" returned %d row (expected 1)" +"query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned" +"query to obtain definition of view \"%s\" returned more than one definition" +"query to obtain definition of view \"%s\" returned no data" +"reading column info for interesting tables" +"reading constraints" +"reading default privileges" +"reading dependency data" +"reading event triggers" +"reading extended statistics" +"reading extensions" +"reading indexes" +"reading large objects" +"reading partitioning data" +"reading policies" +"reading procedural languages" +"reading publication membership of schemas" +"reading publication membership of tables" +"reading publications" +"reading rewrite rules" +"reading row-level security policies" +"reading schemas" +"reading subscriptions" +"reading table inheritance information" +"reading transforms" +"reading triggers" +"reading type casts" +"reading user-defined access methods" +"reading user-defined aggregate functions" +"reading user-defined collations" +"reading user-defined conversions" +"reading user-defined foreign servers" +"reading user-defined foreign-data wrappers" +"reading user-defined functions" +"reading user-defined operator classes" +"reading user-defined operator families" +"reading user-defined operators" +"reading user-defined tables" +"reading user-defined text search configurations" +"reading user-defined text search dictionaries" +"reading user-defined text search parsers" +"reading user-defined text search templates" +"reading user-defined types" +"reconnection failed: %s" +"restored %d large object" +"restoring data out of order is not supported in this archive format: \"%s\" is required, but comes before \"%s\" in the archive file." +"restoring large object with OID %u" +"restoring tables WITH OIDS is not supported anymore" +"role name starting with \"pg_\" skipped (%s)" +"role with OID %u does not exist" +"running \"%s\"" +"sanity check on integer size (%lu) failed" +"saving database definition" +"saving encoding = %s" +"saving large objects" +"saving search_path = %s" +"saving standard_conforming_strings = %s" +"schema \"%s\" not found" +"schema with OID %u does not exist" +"server version: %s; %s version: %s" +"skipping item %d %s %s" +"subscriptions not dumped because current user is not a superuser" +"table \"%s\" could not be created, will not restore its data" +"table \"%s\" not found" +"there are circular foreign-key constraints on this table:" +"this build does not support compression with %s" +"this format cannot be read" +"too many command-line arguments (first is \"%s\")" +"trigger \"%s\" not found" +"typtype of data type \"%s\" appears to be invalid" +"unable to initialize LZ4 library: %s" +"unexpected COPY statement syntax: \"%s\"" +"unexpected column data for table \"%s\"" +"unexpected data offset flag %d" +"unexpected extra results during COPY of table \"%s\"" +"unexpected index data for table \"%s\"" +"unexpected policy command type: %c" +"unexpected section code %d" +"unexpected tgtype value: %d" +"unrecognized aggfinalmodify value for aggregate \"%s\"" +"unrecognized aggmfinalmodify value for aggregate \"%s\"" +"unrecognized archive format \"%s\"; please specify \"c\", \"d\", or \"t\"" +"unrecognized collation provider: %s" +"unrecognized command received from leader: \"%s\"" +"unrecognized compression algorithm: \"%s\"" +"unrecognized compression option: \"%s\"" +"unrecognized constraint type: %c" +"unrecognized data block type %d while restoring archive" +"unrecognized data block type (%d) while searching archive" +"unrecognized encoding \"%s\"" +"unrecognized file format \"%d\"" +"unrecognized locale provider: %s" +"unrecognized object type in default privileges: %d" +"unrecognized proparallel value for function \"%s\"" +"unrecognized provolatile value for function \"%s\"" +"unrecognized section name: \"%s\"" +"unrecognized sequence type: %s" +"unrecognized table OID %u" +"unsupported pg_init_privs entry: %u %u %d" +"unsupported version (%d.%d) in file header" +"value for compression option \"%s\" must be a Boolean value" +"value for compression option \"%s\" must be an integer" +"warning from original dump file: %s" +"warning: " +"while FINALIZING:" +"while INITIALIZING:" +"while PROCESSING TOC:" +"worker process failed: exit code %d" +"wrong number of fields retrieved from table \"%s\"" +"wrote %zu byte of large object data (result = %d)" diff --git a/tools/pgmsg/testdata/REL_17_STABLE.txt b/tools/pgmsg/testdata/REL_17_STABLE.txt new file mode 100644 index 0000000..2880f0d --- /dev/null +++ b/tools/pgmsg/testdata/REL_17_STABLE.txt @@ -0,0 +1,572 @@ +# msgid set of src/bin/pg_dump/po/{de,fr}.po at REL_17_STABLE +# generated by tools/pgmsg; one Go-quoted msgid per line +"\nConnection options:\n" +"\nGeneral options:\n" +"\nIf -f/--file is not used, then the SQL script will be written to the standard\noutput.\n\n" +"\nIf no database name is supplied, then the PGDATABASE environment\nvariable value is used.\n\n" +"\nIf no input file name is supplied, then standard input is used.\n\n" +"\nOptions controlling the output content:\n" +"\nOptions controlling the restore:\n" +"\nThe options -I, -n, -N, -P, -t, -T, and --section can be combined and specified\nmultiple times to select multiple objects.\n" +" %s [OPTION]...\n" +" %s [OPTION]... [DBNAME]\n" +" %s [OPTION]... [FILE]\n" +" --binary-upgrade for use by upgrade utilities only\n" +" --blobs (same as --large-objects, deprecated)\n" +" --column-inserts dump data as INSERT commands with column names\n" +" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n" +" --disable-triggers disable triggers during data-only restore\n" +" --enable-row-security enable row security\n" +" --enable-row-security enable row security (dump only content user has\n access to)\n" +" --exclude-database=PATTERN exclude databases whose name matches PATTERN\n" +" --exclude-extension=PATTERN do NOT dump the specified extension(s)\n" +" --exclude-table-and-children=PATTERN\n do NOT dump the specified table(s), including\n child and partition tables\n" +" --exclude-table-data-and-children=PATTERN\n do NOT dump data for the specified table(s),\n including child and partition tables\n" +" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n" +" --extra-float-digits=NUM override default setting for extra_float_digits\n" +" --filter=FILENAME exclude databases based on expressions in FILENAME\n" +" --filter=FILENAME include or exclude objects and data from dump\n based on expressions in FILENAME\n" +" --filter=FILENAME restore or skip objects based on expressions\n in FILENAME\n" +" --if-exists use IF EXISTS when dropping objects\n" +" --include-foreign-data=PATTERN\n include data of foreign tables on foreign\n servers matching PATTERN\n" +" --inserts dump data as INSERT commands, rather than COPY\n" +" --load-via-partition-root load partitions via the root table\n" +" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n" +" --no-blobs (same as --no-large-objects, deprecated)\n" +" --no-comments do not dump comments\n" +" --no-comments do not restore comments\n" +" --no-data-for-failed-tables do not restore data of tables that could not be\n created\n" +" --no-publications do not dump publications\n" +" --no-publications do not restore publications\n" +" --no-role-passwords do not dump passwords for roles\n" +" --no-security-labels do not dump security label assignments\n" +" --no-security-labels do not restore security labels\n" +" --no-subscriptions do not dump subscriptions\n" +" --no-subscriptions do not restore subscriptions\n" +" --no-sync do not wait for changes to be written safely to disk\n" +" --no-table-access-method do not dump table access methods\n" +" --no-table-access-method do not restore table access methods\n" +" --no-tablespaces do not dump tablespace assignments\n" +" --no-tablespaces do not restore tablespace assignments\n" +" --no-toast-compression do not dump TOAST compression methods\n" +" --no-unlogged-table-data do not dump unlogged table data\n" +" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n" +" --quote-all-identifiers quote all identifiers, even if not key words\n" +" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n" +" --role=ROLENAME do SET ROLE before dump\n" +" --role=ROLENAME do SET ROLE before restore\n" +" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n" +" --section=SECTION dump named section (pre-data, data, or post-data)\n" +" --section=SECTION restore named section (pre-data, data, or post-data)\n" +" --serializable-deferrable wait until the dump can run without anomalies\n" +" --snapshot=SNAPSHOT use given snapshot for the dump\n" +" --strict-names require table and/or schema include patterns to\n match at least one entity each\n" +" --sync-method=METHOD set method for syncing files to disk\n" +" --table-and-children=PATTERN dump only the specified table(s), including\n child and partition tables\n" +" --transaction-size=N commit after every N objects\n" +" --use-set-session-authorization\n use SET SESSION AUTHORIZATION commands instead of\n ALTER OWNER commands to set ownership\n" +" -1, --single-transaction restore as a single transaction\n" +" -?, --help show this help, then exit\n" +" -?, --help show this help, then exit\n" +" -B, --no-large-objects exclude large objects in dump\n" +" -C, --create create the target database\n" +" -C, --create include commands to create database in dump\n" +" -E, --encoding=ENCODING dump the data in encoding ENCODING\n" +" -F, --format=c|d|t backup file format (should be automatic)\n" +" -F, --format=c|d|t|p output file format (custom, directory, tar,\n plain text (default))\n" +" -I, --index=NAME restore named index\n" +" -L, --use-list=FILENAME use table of contents from this file for\n selecting/ordering output\n" +" -N, --exclude-schema=NAME do not restore objects in this schema\n" +" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n" +" -O, --no-owner skip restoration of object ownership\n" +" -O, --no-owner skip restoration of object ownership in\n plain-text format\n" +" -P, --function=NAME(args) restore named function\n" +" -S, --superuser=NAME superuser user name to use for disabling triggers\n" +" -S, --superuser=NAME superuser user name to use in plain-text format\n" +" -S, --superuser=NAME superuser user name to use in the dump\n" +" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n" +" -T, --trigger=NAME restore named trigger\n" +" -U, --username=NAME connect as specified database user\n" +" -V, --version output version information, then exit\n" +" -V, --version output version information, then exit\n" +" -W, --password force password prompt (should happen automatically)\n" +" -Z, --compress=METHOD[:DETAIL]\n compress as specified\n" +" -a, --data-only dump only the data, not the schema\n" +" -a, --data-only restore only the data, no schema\n" +" -b, --large-objects include large objects in dump\n" +" -c, --clean clean (drop) database objects before recreating\n" +" -c, --clean clean (drop) databases before recreating\n" +" -d, --dbname=CONNSTR connect using connection string\n" +" -d, --dbname=DBNAME database to dump\n" +" -d, --dbname=NAME connect to database name\n" +" -e, --exit-on-error exit on error, default is to continue\n" +" -e, --extension=PATTERN dump the specified extension(s) only\n" +" -f, --file=FILENAME output file name\n" +" -f, --file=FILENAME output file or directory name\n" +" -f, --file=FILENAME output file name (- for stdout)\n" +" -g, --globals-only dump only global objects, no databases\n" +" -h, --host=HOSTNAME database server host or socket directory\n" +" -j, --jobs=NUM use this many parallel jobs to dump\n" +" -j, --jobs=NUM use this many parallel jobs to restore\n" +" -l, --database=DBNAME alternative default database\n" +" -l, --list print summarized TOC of the archive\n" +" -n, --schema=NAME restore only objects in this schema\n" +" -n, --schema=PATTERN dump the specified schema(s) only\n" +" -p, --port=PORT database server port number\n" +" -r, --roles-only dump only roles, no databases or tablespaces\n" +" -s, --schema-only dump only the schema, no data\n" +" -s, --schema-only restore only the schema, no data\n" +" -t, --table=NAME restore named relation (table, view, etc.)\n" +" -t, --table=PATTERN dump only the specified table(s)\n" +" -t, --tablespaces-only dump only tablespaces, no databases or roles\n" +" -v, --verbose verbose mode\n" +" -v, --verbose verbose mode\n" +" -w, --no-password never prompt for password\n" +" -x, --no-privileges do not dump privileges (grant/revoke)\n" +" -x, --no-privileges skip restoration of access privileges (grant/revoke)\n" +"%s" +"%s dumps a database as a text file or to other formats.\n\n" +"%s extracts a PostgreSQL database cluster into an SQL script file.\n\n" +"%s filter for \"%s\" is not allowed" +"%s home page: <%s>\n" +"%s must be in range %d..%d" +"%s restores a PostgreSQL database from an archive created by pg_dump.\n\n" +"%s() failed: %m" +"%s() failed: error code %d" +"%s: %sCommand was: %s" +"COPY failed for table \"%s\": %s" +"Command was: %s" +"Consider using a full dump instead of a --data-only dump to avoid this problem." +"Dumping the contents of table \"%s\" failed: PQgetCopyData() failed." +"Dumping the contents of table \"%s\" failed: PQgetResult() failed." +"Error message from server: %s" +"Password: " +"Query was: %s" +"Report bugs to <%s>.\n" +"The system catalogs might be corrupted." +"This grant will be dumped without GRANTED BY." +"Try \"%s --help\" for more information." +"Usage:\n" +"WITH OIDS is not supported anymore (table \"%s\")" +"You are currently not connected to a database." +"You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints." +"a worker process died unexpectedly" +"aborting because of server version mismatch" +"actual file length (%lld) does not match expected (%lld)" +"already connected to a database" +"archive is compressed, but this installation does not support compression (%s) -- no data will be available" +"archive items not in correct section order" +"archive was made on a machine with larger integers, some operations might fail" +"bad dumpId" +"bad table dumpId for TABLE DATA item" +"bogus transform definition, at least one of trffromsql and trftosql should be nonzero" +"bogus value in pg_cast.castfunc or pg_cast.castmethod field" +"bogus value in pg_cast.castmethod field" +"bogus value in pg_transform.trffromsql field" +"bogus value in pg_transform.trftosql field" +"can only reopen input archives" +"cannot duplicate null pointer (internal error)\n" +"cannot restore from compressed archive (%s)" +"cannot specify both --single-transaction and multiple jobs" +"child process exited with exit code %d" +"child process exited with unrecognized status %d" +"child process was terminated by exception 0x%X" +"child process was terminated by signal %d: %s" +"command not executable" +"command not found" +"compression algorithm \"%s\" does not accept a compression level" +"compression algorithm \"%s\" does not accept a worker count" +"compression algorithm \"%s\" does not support long-distance mode" +"compression algorithm \"%s\" expects a compression level between %d and %d (default at %d)" +"compression is not supported by tar archive format" +"compression option \"%s\" is not currently supported by pg_dump" +"compression option \"%s\" requires a value" +"compressor active" +"connecting to database for restore" +"connecting to new database \"%s\"" +"corrupt tar header found in %s (expected %d, computed %d) file position %llu" +"could not alter table access method: %s" +"could not close LO data file: %m" +"could not close LOs TOC file: %m" +"could not close TOC file: %m" +"could not close archive file: %m" +"could not close compression library: %s" +"could not close compression stream: %s" +"could not close data file \"%s\": %m" +"could not close data file: %m" +"could not close directory \"%s\": %m" +"could not close file: %m" +"could not close filter file \"%s\": %m" +"could not close input file: %m" +"could not close large object TOC file \"%s\": %m" +"could not close output file: %m" +"could not close temporary file: %m" +"could not commit database transaction" +"could not compress data: %s" +"could not connect to database" +"could not connect to database \"%s\"" +"could not connect to databases \"postgres\" or \"template1\"\nPlease specify an alternative database." +"could not create LZ4 decompression context: %s" +"could not create communication channels: %m" +"could not create directory \"%s\": %m" +"could not create large object %u: %s" +"could not create worker process: %m" +"could not create worker thread: %m" +"could not decompress data: %s" +"could not decompress: %s" +"could not determine seek position in archive file: %m" +"could not end compression: %s" +"could not end decompression: %s" +"could not execute command \"%s\": %m" +"could not execute query" +"could not find a \"%s\" to execute" +"could not find a legal dump ordering for memberships in role \"%s\"" +"could not find block ID %d in archive -- possibly corrupt archive" +"could not find block ID %d in archive -- possibly due to out-of-order restore request, which cannot be handled due to non-seekable input file" +"could not find entry for ID %d" +"could not find file \"%s\" in archive" +"could not find function definition for function with OID %u" +"could not find header for file \"%s\" in tar archive" +"could not find operator with OID %s" +"could not find parent extension for %s %s" +"could not find referenced extension %u" +"could not find where to insert IF EXISTS in statement \"%s\"" +"could not free LZ4 decompression context: %s" +"could not fsync file \"%s\": %m" +"could not generate restrict key" +"could not generate temporary file name: %m" +"could not get server version" +"could not get server_version from libpq" +"could not identify dependency loop" +"could not initialize LZ4 compression: %s" +"could not initialize compression library" +"could not initialize compression library: %s" +"could not obtain lock on relation \"%s\"\nThis usually means that someone requested an ACCESS EXCLUSIVE lock on the table after the pg_dump parent process had gotten the initial ACCESS SHARE lock on the table." +"could not open TOC file \"%s\" for input: %m" +"could not open TOC file \"%s\" for output: %m" +"could not open TOC file \"%s\": %m" +"could not open TOC file for input: %m" +"could not open TOC file for output: %m" +"could not open directory \"%s\": %m" +"could not open file \"%s\": %m" +"could not open filter file \"%s\": %m" +"could not open input file \"%s\": %m" +"could not open input file: %m" +"could not open large object %u: %s" +"could not open large object TOC file \"%s\" for input: %m" +"could not open output file \"%s\": %m" +"could not open output file: %m" +"could not open stdout for appending: %m" +"could not parse %s array" +"could not parse ACL list (%s) for parameter \"%s\"" +"could not parse ACL list (%s) for tablespace \"%s\"" +"could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)" +"could not parse default ACL list (%s)" +"could not parse index statistic columns" +"could not parse index statistic values" +"could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)" +"could not parse numeric array \"%s\": invalid character in number" +"could not parse numeric array \"%s\": too many numbers" +"could not parse result of current_schemas()" +"could not parse server version \"%s\"" +"could not re-open the output file \"%s\": %m" +"could not read binary \"%s\": %m" +"could not read directory \"%s\": %m" +"could not read from command \"%s\": %m" +"could not read from filter file \"%s\": %m" +"could not read from input file: %m" +"could not read from input file: %s" +"could not read from input file: end of file" +"could not read input file: %m" +"could not rename file \"%s\" to \"%s\": %m" +"could not resolve dependency loop among these items:" +"could not resolve path \"%s\" to absolute form: %m" +"could not set \"default_table_access_method\": %s" +"could not set \"default_tablespace\" to %s: %s" +"could not set \"search_path\" to \"%s\": %s" +"could not set compression parameter \"%s\": %s" +"could not set seek position in archive file: %m" +"could not set session user to \"%s\": %s" +"could not start database transaction" +"could not stat file \"%s\": %m" +"could not synchronize file system for file \"%s\": %m" +"could not uncompress data: %s" +"could not write to file: %m" +"could not write to file: %s" +"could not write to large object: %s" +"could not write to output file: %m" +"could not write to the communication channel: %m" +"creating %s \"%s\"" +"creating %s \"%s.%s\"" +"cross-database references are not implemented: %s" +"data block %d has wrong seek position" +"database name contains a newline or carriage return: \"%s\"\n" +"definition of view \"%s\" appears to be empty (length zero)" +"detail: " +"did not find magic string in file header" +"direct database connections are not supported in pre-1.3 archives" +"directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)" +"directory name too long: \"%s\"" +"disabling triggers for %s" +"don't know how to set owner for object type \"%s\"" +"dropping %s %s" +"dumping contents of table \"%s.%s\"" +"dumping database \"%s\"" +"enabling triggers for %s" +"entering main parallel loop" +"entry ID %d out of range -- perhaps a corrupt TOC" +"error during file seek: %m" +"error during writing: %m" +"error during writing: %s" +"error reading large object %u: %s" +"error reading large object TOC file \"%s\"" +"error returned by PQputCopyData: %s" +"error returned by PQputCopyEnd: %s" +"error: " +"errors ignored on restore: %d" +"excluding database \"%s\"" +"executing %s" +"executing %s %s" +"expected %d check constraint on table \"%s\" but found %d" +"expected format (%d) differs from format found in file (%d)" +"failed sanity check, parent OID %u of table \"%s\" (OID %u) not found" +"failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found" +"failed sanity check, parent table with OID %u of sequence with OID %u not found" +"failed sanity check, table OID %u appearing in pg_partitioned_table not found" +"failed sanity check, table with OID %u not found" +"file name too long: \"%s\"" +"file offset in dump file is too large" +"finding extension tables" +"finding inheritance relationships" +"finding table check constraints" +"finding table default expressions" +"finished item %d %s %s" +"finished main parallel loop" +"flagging indexes in partitioned tables" +"flagging inherited columns in subtables" +"found empty string where a compression option was expected" +"found unexpected block ID (%d) when reading data -- expected %d" +"from TOC entry %d; %u %u %s %s %s" +"function \"%s\" not found" +"grant of role \"%s\" to \"%s\" has invalid grantor OID %s" +"hint: " +"identifying extension members" +"ignoring role grant for missing role with OID %s" +"ignoring role grant to missing role with OID %s" +"implied data-only restore" +"improper qualified name (too many dotted names): %s" +"improper relation name (too many dotted names): %s" +"incomplete tar header found (%lu byte)" +"index \"%s\" not found" +"input file appears to be a text format dump. Please use psql." +"input file does not appear to be a valid archive" +"input file does not appear to be a valid archive (too short?)" +"input file is too short (read %lu, expected 5)" +"internal error -- WriteData cannot be called outside the context of a DataDumper routine" +"invalid ENCODING item: %s" +"invalid OID for large object" +"invalid OID for large object (%u)" +"invalid STDSTRINGS item: %s" +"invalid adnum value %d for table \"%s\"" +"invalid binary \"%s\": %m" +"invalid client encoding \"%s\" specified" +"invalid collation \"%s\"" +"invalid column number %d for table \"%s\"" +"invalid column numbering in table \"%s\"" +"invalid compression specification: %s" +"invalid creation date in header" +"invalid dependency %d" +"invalid dumpId %d" +"invalid filter command (expected \"include\" or \"exclude\")" +"invalid format in filter read from file \"%s\" on line %d: %s" +"invalid format in filter read from standard input on line %d: %s" +"invalid line in large object TOC file \"%s\": \"%s\"" +"invalid memory allocation request size %zu * %zu\n" +"invalid memory allocation request size %zu + %zu\n" +"invalid message received from worker: \"%s\"" +"invalid number of parents %d for table \"%s\"" +"invalid output format \"%s\" specified" +"invalid restrict key" +"invalid type \"%c\" of access method \"%s\"" +"invalid value \"%s\" for option %s" +"large-object output not supported in chosen format" +"last built-in OID is %u" +"launching item %d %s %s" +"line ignored: %s" +"mismatched number of columns and values for index statistics" +"mismatched number of configurations and conditions for extension" +"missing filter object type" +"missing index for constraint \"%s\"" +"missing metadata for large objects \"%s\"" +"missing object name pattern" +"no data was returned by command \"%s\"" +"no filter command found (expected \"include\" or \"exclude\")" +"no matching extensions were found" +"no matching extensions were found for pattern \"%s\"" +"no matching foreign servers were found for pattern \"%s\"" +"no matching schemas were found" +"no matching schemas were found for pattern \"%s\"" +"no matching tables were found" +"no matching tables were found for pattern \"%s\"" +"no output directory specified" +"no referenced object %u %u" +"no referencing object %u %u" +"one of -d/--dbname and -f/--file must be specified" +"option --exclude-database cannot be used together with -g/--globals-only, -r/--roles-only, or -t/--tablespaces-only" +"option --if-exists requires option -c/--clean" +"option --include-foreign-data is not supported with parallel backup" +"option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts" +"option --restrict-key can only be used with --format=plain" +"options -1/--single-transaction and --transaction-size cannot be used together" +"options -C/--create and -1/--single-transaction cannot be used together" +"options -c/--clean and -a/--data-only cannot be used together" +"options -d/--dbname and --restrict-key cannot be used together" +"options -d/--dbname and -f/--file cannot be used together" +"options -g/--globals-only and -r/--roles-only cannot be used together" +"options -g/--globals-only and -t/--tablespaces-only cannot be used together" +"options -r/--roles-only and -t/--tablespaces-only cannot be used together" +"options -s/--schema-only and --include-foreign-data cannot be used together" +"options -s/--schema-only and -a/--data-only cannot be used together" +"out of memory" +"out of memory\n" +"out of on_exit_nicely slots" +"parallel backup only supported by the directory format" +"parallel dumps from standby servers are not supported by this server version" +"parallel restore from non-seekable file is not supported" +"parallel restore from standard input is not supported" +"parallel restore is not supported with archives made by pre-8.0 pg_dump" +"parallel restore is not supported with this archive file format" +"pg_dump failed on database \"%s\", exiting" +"pgpipe: %s() failed: error code %d" +"pgpipe: could not accept connection: error code %d" +"pgpipe: could not bind: error code %d" +"pgpipe: could not connect socket: error code %d" +"pgpipe: could not create second socket: error code %d" +"pgpipe: could not create socket: error code %d" +"pgpipe: could not listen: error code %d" +"postfix operators are not supported anymore (operator \"%s\")" +"processing %s" +"processing data for table \"%s.%s\"" +"processing item %d %s %s" +"processing missed item %d %s %s" +"program \"%s\" is needed by %s but was not found in the same directory as \"%s\"" +"program \"%s\" was found by \"%s\" but was not the same version as %s" +"query failed: %s" +"query returned %d row instead of one: %s" +"query to get data of sequence \"%s\" returned %d row (expected 1)" +"query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned" +"query to obtain definition of view \"%s\" returned more than one definition" +"query to obtain definition of view \"%s\" returned no data" +"reading column info for interesting tables" +"reading constraints" +"reading default privileges" +"reading dependency data" +"reading event triggers" +"reading extended statistics" +"reading extensions" +"reading indexes" +"reading large objects" +"reading partitioning data" +"reading policies" +"reading procedural languages" +"reading publication membership of schemas" +"reading publication membership of tables" +"reading publications" +"reading rewrite rules" +"reading row-level security policies" +"reading schemas" +"reading subscription membership of tables" +"reading subscriptions" +"reading table inheritance information" +"reading transforms" +"reading triggers" +"reading type casts" +"reading user-defined access methods" +"reading user-defined aggregate functions" +"reading user-defined collations" +"reading user-defined conversions" +"reading user-defined foreign servers" +"reading user-defined foreign-data wrappers" +"reading user-defined functions" +"reading user-defined operator classes" +"reading user-defined operator families" +"reading user-defined operators" +"reading user-defined tables" +"reading user-defined text search configurations" +"reading user-defined text search dictionaries" +"reading user-defined text search parsers" +"reading user-defined text search templates" +"reading user-defined types" +"reconnection failed: %s" +"restored %d large object" +"restoring data out of order is not supported in this archive format: \"%s\" is required, but comes before \"%s\" in the archive file." +"restoring large object with OID %u" +"restoring tables WITH OIDS is not supported anymore" +"role name starting with \"pg_\" skipped (%s)" +"role with OID %u does not exist" +"running \"%s\"" +"sanity check on integer size (%lu) failed" +"saving \"search_path = %s\"" +"saving \"standard_conforming_strings = %s\"" +"saving database definition" +"saving encoding = %s" +"saving large objects \"%s\"" +"schema \"%s\" not found" +"schema with OID %u does not exist" +"server version: %s; %s version: %s" +"shell command argument contains a newline or carriage return: \"%s\"\n" +"skipping item %d %s %s" +"subscription with OID %u does not exist" +"subscriptions not dumped because current user is not a superuser" +"table \"%s\" could not be created, will not restore its data" +"table \"%s\" not found" +"there are circular foreign-key constraints on this table:" +"this build does not support compression with %s" +"this build does not support sync method \"%s\"" +"this format cannot be read" +"too many command-line arguments (first is \"%s\")" +"trigger \"%s\" not found" +"typtype of data type \"%s\" appears to be invalid" +"unable to initialize LZ4 library: %s" +"unexpected COPY statement syntax: \"%s\"" +"unexpected column data for table \"%s\"" +"unexpected data offset flag %d" +"unexpected end of file" +"unexpected extra results during COPY of table \"%s\"" +"unexpected index data for table \"%s\"" +"unexpected policy command type: %c" +"unexpected section code %d" +"unrecognized aggfinalmodify value for aggregate \"%s\"" +"unrecognized aggmfinalmodify value for aggregate \"%s\"" +"unrecognized archive format \"%s\"; please specify \"c\", \"d\", or \"t\"" +"unrecognized collation provider: %s" +"unrecognized command received from leader: \"%s\"" +"unrecognized compression algorithm: \"%s\"" +"unrecognized compression option: \"%s\"" +"unrecognized constraint type: %c" +"unrecognized data block type %d while restoring archive" +"unrecognized data block type (%d) while searching archive" +"unrecognized encoding \"%s\"" +"unrecognized file format \"%d\"" +"unrecognized locale provider: %s" +"unrecognized object type in default privileges: %d" +"unrecognized proparallel value for function \"%s\"" +"unrecognized provolatile value for function \"%s\"" +"unrecognized section name: \"%s\"" +"unrecognized sequence type: %s" +"unrecognized sync method: %s" +"unrecognized table OID %u" +"unsupported filter object" +"unsupported filter object type: \"%.*s\"" +"unsupported pg_init_privs entry: %u %u %d" +"unsupported version (%d.%d) in file header" +"value for compression option \"%s\" must be a Boolean value" +"value for compression option \"%s\" must be an integer" +"warning from original dump file: %s" +"warning: " +"while FINALIZING:" +"while INITIALIZING:" +"while PROCESSING TOC:" +"worker process failed: exit code %d" +"wrong number of fields retrieved from table \"%s\"" +"wrote %zu byte of large object data (result = %d)" diff --git a/tools/pgmsg/testdata/REL_18_STABLE.txt b/tools/pgmsg/testdata/REL_18_STABLE.txt new file mode 100644 index 0000000..d0fe1ef --- /dev/null +++ b/tools/pgmsg/testdata/REL_18_STABLE.txt @@ -0,0 +1,585 @@ +# msgid set of src/bin/pg_dump/po/{de,fr}.po at REL_18_STABLE +# generated by tools/pgmsg; one Go-quoted msgid per line +"\nConnection options:\n" +"\nGeneral options:\n" +"\nIf -f/--file is not used, then the SQL script will be written to the standard\noutput.\n\n" +"\nIf no database name is supplied, then the PGDATABASE environment\nvariable value is used.\n\n" +"\nIf no input file name is supplied, then standard input is used.\n\n" +"\nOptions controlling the output content:\n" +"\nOptions controlling the restore:\n" +"\nThe options -I, -n, -N, -P, -t, -T, and --section can be combined and specified\nmultiple times to select multiple objects.\n" +" %s [OPTION]...\n" +" %s [OPTION]... [DBNAME]\n" +" %s [OPTION]... [FILE]\n" +" --binary-upgrade for use by upgrade utilities only\n" +" --blobs (same as --large-objects, deprecated)\n" +" --column-inserts dump data as INSERT commands with column names\n" +" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n" +" --disable-triggers disable triggers during data-only restore\n" +" --enable-row-security enable row security\n" +" --enable-row-security enable row security (dump only content user has\n access to)\n" +" --exclude-database=PATTERN exclude databases whose name matches PATTERN\n" +" --exclude-extension=PATTERN do NOT dump the specified extension(s)\n" +" --exclude-table-and-children=PATTERN\n do NOT dump the specified table(s), including\n child and partition tables\n" +" --exclude-table-data-and-children=PATTERN\n do NOT dump data for the specified table(s),\n including child and partition tables\n" +" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n" +" --extra-float-digits=NUM override default setting for extra_float_digits\n" +" --filter=FILENAME exclude databases based on expressions in FILENAME\n" +" --filter=FILENAME include or exclude objects and data from dump\n based on expressions in FILENAME\n" +" --filter=FILENAME restore or skip objects based on expressions\n in FILENAME\n" +" --if-exists use IF EXISTS when dropping objects\n" +" --include-foreign-data=PATTERN\n include data of foreign tables on foreign\n servers matching PATTERN\n" +" --inserts dump data as INSERT commands, rather than COPY\n" +" --load-via-partition-root load partitions via the root table\n" +" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n" +" --no-blobs (same as --no-large-objects, deprecated)\n" +" --no-comments do not dump comment commands\n" +" --no-comments do not restore comment commands\n" +" --no-data do not dump data\n" +" --no-data do not restore data\n" +" --no-data-for-failed-tables do not restore data of tables that could not be\n created\n" +" --no-policies do not dump row security policies\n" +" --no-policies do not restore row security policies\n" +" --no-publications do not dump publications\n" +" --no-publications do not restore publications\n" +" --no-role-passwords do not dump passwords for roles\n" +" --no-schema do not dump schema\n" +" --no-schema do not restore schema\n" +" --no-security-labels do not dump security label assignments\n" +" --no-security-labels do not restore security labels\n" +" --no-statistics do not dump statistics\n" +" --no-statistics do not restore statistics\n" +" --no-subscriptions do not dump subscriptions\n" +" --no-subscriptions do not restore subscriptions\n" +" --no-sync do not wait for changes to be written safely to disk\n" +" --no-table-access-method do not dump table access methods\n" +" --no-table-access-method do not restore table access methods\n" +" --no-tablespaces do not dump tablespace assignments\n" +" --no-tablespaces do not restore tablespace assignments\n" +" --no-toast-compression do not dump TOAST compression methods\n" +" --no-unlogged-table-data do not dump unlogged table data\n" +" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n" +" --quote-all-identifiers quote all identifiers, even if not key words\n" +" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n" +" --role=ROLENAME do SET ROLE before dump\n" +" --role=ROLENAME do SET ROLE before restore\n" +" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n" +" --section=SECTION dump named section (pre-data, data, or post-data)\n" +" --section=SECTION restore named section (pre-data, data, or post-data)\n" +" --sequence-data include sequence data in dump\n" +" --serializable-deferrable wait until the dump can run without anomalies\n" +" --snapshot=SNAPSHOT use given snapshot for the dump\n" +" --statistics dump the statistics\n" +" --statistics restore the statistics\n" +" --statistics-only dump only the statistics, not schema or data\n" +" --statistics-only restore only the statistics, not schema or data\n" +" --strict-names require table and/or schema include patterns to\n match at least one entity each\n" +" --sync-method=METHOD set method for syncing files to disk\n" +" --table-and-children=PATTERN dump only the specified table(s), including\n child and partition tables\n" +" --transaction-size=N commit after every N objects\n" +" --use-set-session-authorization\n use SET SESSION AUTHORIZATION commands instead of\n ALTER OWNER commands to set ownership\n" +" -1, --single-transaction restore as a single transaction\n" +" -?, --help show this help, then exit\n" +" -?, --help show this help, then exit\n" +" -B, --no-large-objects exclude large objects in dump\n" +" -C, --create create the target database\n" +" -C, --create include commands to create database in dump\n" +" -E, --encoding=ENCODING dump the data in encoding ENCODING\n" +" -F, --format=c|d|t backup file format (should be automatic)\n" +" -F, --format=c|d|t|p output file format (custom, directory, tar,\n plain text (default))\n" +" -I, --index=NAME restore named index\n" +" -L, --use-list=FILENAME use table of contents from this file for\n selecting/ordering output\n" +" -N, --exclude-schema=NAME do not restore objects in this schema\n" +" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n" +" -O, --no-owner skip restoration of object ownership\n" +" -O, --no-owner skip restoration of object ownership in\n plain-text format\n" +" -P, --function=NAME(args) restore named function\n" +" -S, --superuser=NAME superuser user name to use for disabling triggers\n" +" -S, --superuser=NAME superuser user name to use in plain-text format\n" +" -S, --superuser=NAME superuser user name to use in the dump\n" +" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n" +" -T, --trigger=NAME restore named trigger\n" +" -U, --username=NAME connect as specified database user\n" +" -V, --version output version information, then exit\n" +" -V, --version output version information, then exit\n" +" -W, --password force password prompt (should happen automatically)\n" +" -Z, --compress=METHOD[:DETAIL]\n compress as specified\n" +" -a, --data-only dump only the data, not the schema or statistics\n" +" -a, --data-only restore only the data, no schema\n" +" -b, --large-objects include large objects in dump\n" +" -c, --clean clean (drop) database objects before recreating\n" +" -c, --clean clean (drop) databases before recreating\n" +" -d, --dbname=CONNSTR connect using connection string\n" +" -d, --dbname=DBNAME database to dump\n" +" -d, --dbname=NAME connect to database name\n" +" -e, --exit-on-error exit on error, default is to continue\n" +" -e, --extension=PATTERN dump the specified extension(s) only\n" +" -f, --file=FILENAME output file name\n" +" -f, --file=FILENAME output file or directory name\n" +" -f, --file=FILENAME output file name (- for stdout)\n" +" -g, --globals-only dump only global objects, no databases\n" +" -h, --host=HOSTNAME database server host or socket directory\n" +" -j, --jobs=NUM use this many parallel jobs to dump\n" +" -j, --jobs=NUM use this many parallel jobs to restore\n" +" -l, --database=DBNAME alternative default database\n" +" -l, --list print summarized TOC of the archive\n" +" -n, --schema=NAME restore only objects in this schema\n" +" -n, --schema=PATTERN dump the specified schema(s) only\n" +" -p, --port=PORT database server port number\n" +" -r, --roles-only dump only roles, no databases or tablespaces\n" +" -s, --schema-only dump only the schema, no data or statistics\n" +" -s, --schema-only restore only the schema, no data\n" +" -t, --table=NAME restore named relation (table, view, etc.)\n" +" -t, --table=PATTERN dump only the specified table(s)\n" +" -t, --tablespaces-only dump only tablespaces, no databases or roles\n" +" -v, --verbose verbose mode\n" +" -v, --verbose verbose mode\n" +" -w, --no-password never prompt for password\n" +" -x, --no-privileges do not dump privileges (grant/revoke)\n" +" -x, --no-privileges skip restoration of access privileges (grant/revoke)\n" +"%s" +"%s exports a PostgreSQL database as an SQL script or to other formats.\n\n" +"%s exports a PostgreSQL database cluster as an SQL script.\n\n" +"%s filter for \"%s\" is not allowed" +"%s home page: <%s>\n" +"%s must be in range %d..%d" +"%s restores a PostgreSQL database from an archive created by pg_dump.\n\n" +"%s() failed: %m" +"%s() failed: error code %d" +"%s: %sCommand was: %s" +"COPY failed for table \"%s\": %s" +"Command was: %s" +"Consider using a full dump instead of a --data-only dump to avoid this problem." +"Dumping the contents of table \"%s\" failed: PQgetCopyData() failed." +"Dumping the contents of table \"%s\" failed: PQgetResult() failed." +"Error message from server: %s" +"Password: " +"Query was: %s" +"Report bugs to <%s>.\n" +"The system catalogs might be corrupted." +"This grant will be dumped without GRANTED BY." +"Try \"%s --help\" for more information." +"Usage:\n" +"WITH OIDS is not supported anymore (table \"%s\")" +"You are currently not connected to a database." +"You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints." +"a worker process died unexpectedly" +"aborting because of server version mismatch" +"actual file length (%lld) does not match expected (%lld)" +"already connected to a database" +"archive format \"%s\" is not supported; please use psql" +"archive is compressed, but this installation does not support compression (%s) -- no data will be available" +"archive items not in correct section order" +"archive was made on a machine with larger integers, some operations might fail" +"bad dumpId" +"bad table dumpId for TABLE DATA item" +"bogus transform definition, at least one of trffromsql and trftosql should be nonzero" +"bogus value in pg_cast.castfunc or pg_cast.castmethod field" +"bogus value in pg_cast.castmethod field" +"bogus value in pg_transform.trffromsql field" +"bogus value in pg_transform.trftosql field" +"can only reopen input archives" +"cannot dump statistics for relation kind \"%c\"" +"cannot duplicate null pointer (internal error)\n" +"cannot restore from compressed archive (%s)" +"cannot specify both --single-transaction and multiple jobs" +"child process exited with exit code %d" +"child process exited with unrecognized status %d" +"child process was terminated by exception 0x%X" +"child process was terminated by signal %d: %s" +"command not executable" +"command not found" +"compression algorithm \"%s\" does not accept a compression level" +"compression algorithm \"%s\" does not accept a worker count" +"compression algorithm \"%s\" does not support long-distance mode" +"compression algorithm \"%s\" expects a compression level between %d and %d (default at %d)" +"compression is not supported by tar archive format" +"compression option \"%s\" is not currently supported by pg_dump" +"compression option \"%s\" requires a value" +"compressor active" +"connecting to database for restore" +"connecting to new database \"%s\"" +"corrupt tar header found in %s (expected %d, computed %d) file position %llu" +"could not alter table access method: %s" +"could not change permissions of directory \"%s\": %m" +"could not close LO data file: %m" +"could not close LOs TOC file: %m" +"could not close TOC file: %m" +"could not close archive file: %m" +"could not close compression library: %s" +"could not close compression stream: %s" +"could not close data file \"%s\": %m" +"could not close data file: %m" +"could not close file: %m" +"could not close filter file \"%s\": %m" +"could not close input file: %m" +"could not close large object TOC file \"%s\": %m" +"could not close output file: %m" +"could not close temporary file: %m" +"could not commit database transaction" +"could not compress data: %s" +"could not connect to database \"%s\"" +"could not connect to databases \"postgres\" or \"template1\"\nPlease specify an alternative database." +"could not create LZ4 decompression context: %s" +"could not create communication channels: %m" +"could not create directory \"%s\": %m" +"could not create large object %u: %s" +"could not create worker process: %m" +"could not create worker thread: %m" +"could not decompress data: %s" +"could not decompress: %s" +"could not determine seek position in archive file: %m" +"could not end compression: %s" +"could not end decompression: %s" +"could not execute command \"%s\": %m" +"could not execute query" +"could not find a \"%s\" to execute" +"could not find a legal dump ordering for memberships in role \"%s\"" +"could not find block ID %d in archive -- possibly corrupt archive" +"could not find block ID %d in archive -- possibly due to out-of-order restore request, which cannot be handled due to non-seekable input file" +"could not find entry for ID %d" +"could not find file \"%s\" in archive" +"could not find function definition for function with OID %u" +"could not find header for file \"%s\" in tar archive" +"could not find index attname \"%s\"" +"could not find operator with OID %s" +"could not find parent extension for %s %s" +"could not find referenced extension %u" +"could not find where to insert IF EXISTS in statement \"%s\"" +"could not free LZ4 decompression context: %s" +"could not fsync file \"%s\": %m" +"could not generate restrict key" +"could not generate temporary file name: %m" +"could not get \"server_version\" from libpq" +"could not get server version" +"could not identify dependency loop" +"could not initialize LZ4 compression: %s" +"could not initialize compression library" +"could not initialize compression library: %s" +"could not obtain lock on relation \"%s\"\nThis usually means that someone requested an ACCESS EXCLUSIVE lock on the table after the pg_dump parent process had gotten the initial ACCESS SHARE lock on the table." +"could not open TOC file \"%s\" for input: %m" +"could not open TOC file \"%s\" for output: %m" +"could not open TOC file \"%s\": %m" +"could not open TOC file for input: %m" +"could not open TOC file for output: %m" +"could not open directory \"%s\": %m" +"could not open file \"%s\": %m" +"could not open filter file \"%s\": %m" +"could not open input file \"%s\": %m" +"could not open input file: %m" +"could not open large object %u: %s" +"could not open large object TOC file \"%s\" for input: %m" +"could not open output file \"%s\": %m" +"could not open output file: %m" +"could not open stdout for appending: %m" +"could not parse %s array" +"could not parse ACL list (%s) for parameter \"%s\"" +"could not parse ACL list (%s) for tablespace \"%s\"" +"could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)" +"could not parse default ACL list (%s)" +"could not parse index statistic columns" +"could not parse index statistic values" +"could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)" +"could not parse numeric array \"%s\": invalid character in number" +"could not parse numeric array \"%s\": too many numbers" +"could not parse result of current_schemas()" +"could not parse server version \"%s\"" +"could not re-open the output file \"%s\": %m" +"could not read binary \"%s\": %m" +"could not read directory \"%s\": %m" +"could not read from command \"%s\": %m" +"could not read from filter file \"%s\": %m" +"could not read from input file: %m" +"could not read from input file: %s" +"could not read from input file: end of file" +"could not read input file: %m" +"could not rename file \"%s\" to \"%s\": %m" +"could not resolve dependency loop among these items:" +"could not resolve path \"%s\" to absolute form: %m" +"could not set \"default_table_access_method\": %s" +"could not set \"default_tablespace\" to %s: %s" +"could not set \"search_path\" to \"%s\": %s" +"could not set compression parameter \"%s\": %s" +"could not set seek position in archive file: %m" +"could not set session user to \"%s\": %s" +"could not start database transaction" +"could not stat file \"%s\": %m" +"could not synchronize file system for file \"%s\": %m" +"could not uncompress data: %s" +"could not write to file: %m" +"could not write to file: %s" +"could not write to large object: %s" +"could not write to output file: %m" +"could not write to the communication channel: %m" +"creating %s \"%s\"" +"creating %s \"%s.%s\"" +"cross-database references are not implemented: %s" +"data block %d has wrong seek position" +"database name contains a newline or carriage return: \"%s\"\n" +"definition of view \"%s\" appears to be empty (length zero)" +"detail: " +"did not find magic string in file header" +"direct database connections are not supported in pre-1.3 archives" +"directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)" +"directory \"%s\" is not empty" +"directory name too long: \"%s\"" +"disabling triggers for %s" +"don't know how to set owner for object type \"%s\"" +"dropping %s %s" +"dumping contents of table \"%s.%s\"" +"dumping database \"%s\"" +"enabling triggers for %s" +"entering main parallel loop" +"entry ID %d out of range -- perhaps a corrupt TOC" +"error during file seek: %m" +"error during writing: %m" +"error during writing: %s" +"error reading large object %u: %s" +"error reading large object TOC file \"%s\"" +"error returned by PQputCopyData: %s" +"error returned by PQputCopyEnd: %s" +"error: " +"errors ignored on restore: %d" +"excluding database \"%s\"" +"executing %s" +"executing %s %s" +"expected %d check constraint on table \"%s\" but found %d" +"expected format (%d) differs from format found in file (%d)" +"failed sanity check, parent OID %u of table \"%s\" (OID %u) not found" +"failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found" +"failed sanity check, parent table with OID %u of sequence with OID %u not found" +"failed sanity check, table OID %u appearing in pg_partitioned_table not found" +"failed sanity check, table with OID %u not found" +"failed to get data for sequence \"%s\"; user may lack SELECT privilege on the sequence or the sequence may have been concurrently dropped" +"file name too long: \"%s\"" +"file offset in dump file is too large" +"finding extension tables" +"finding inheritance relationships" +"finding invalid not-null constraints" +"finding table check constraints" +"finding table default expressions" +"finished item %d %s %s" +"finished main parallel loop" +"flagging indexes in partitioned tables" +"flagging inherited columns in subtables" +"found empty string where a compression option was expected" +"found unexpected block ID (%d) when reading data -- expected %d" +"from TOC entry %d; %u %u %s %s %s" +"function \"%s\" not found" +"grant of role \"%s\" to \"%s\" has invalid grantor OID %s" +"hint: " +"identifying extension members" +"ignoring role grant for missing role with OID %s" +"ignoring role grant to missing role with OID %s" +"implied no-schema restore" +"improper qualified name (too many dotted names): %s" +"improper relation name (too many dotted names): %s" +"incomplete tar header found (%lu byte)" +"index \"%s\" not found" +"input file appears to be a text format dump. Please use psql." +"input file does not appear to be a valid archive (too short?)" +"input file does not appear to be a valid tar archive" +"input file is too short (read %lu, expected 5)" +"internal error -- WriteData cannot be called outside the context of a DataDumper routine" +"invalid ENCODING item: %s" +"invalid OID for large object" +"invalid OID for large object (%u)" +"invalid STDSTRINGS item: %s" +"invalid adnum value %d for table \"%s\"" +"invalid binary \"%s\": %m" +"invalid client encoding \"%s\" specified" +"invalid collation \"%s\"" +"invalid column number %d for table \"%s\"" +"invalid column numbering in table \"%s\"" +"invalid compression specification: %s" +"invalid creation date in header" +"invalid dependency %d" +"invalid dumpId %d" +"invalid filter command (expected \"include\" or \"exclude\")" +"invalid format in filter read from file \"%s\" on line %d: %s" +"invalid format in filter read from standard input on line %d: %s" +"invalid line in large object TOC file \"%s\": \"%s\"" +"invalid memory allocation request size %zu * %zu\n" +"invalid memory allocation request size %zu + %zu\n" +"invalid message received from worker: \"%s\"" +"invalid number of parents %d for table \"%s\"" +"invalid output format \"%s\" specified" +"invalid restrict key" +"invalid type \"%c\" of access method \"%s\"" +"invalid value \"%s\" for option %s" +"large-object output not supported in chosen format" +"last built-in OID is %u" +"launching item %d %s %s" +"line ignored: %s" +"mismatched number of columns and values for index statistics" +"mismatched number of configurations and conditions for extension" +"missing filter object type" +"missing index for constraint \"%s\"" +"missing metadata for large objects \"%s\"" +"missing object name pattern" +"no data was returned by command \"%s\"" +"no filter command found (expected \"include\" or \"exclude\")" +"no matching extensions were found" +"no matching extensions were found for pattern \"%s\"" +"no matching foreign servers were found for pattern \"%s\"" +"no matching schemas were found" +"no matching schemas were found for pattern \"%s\"" +"no matching tables were found" +"no matching tables were found for pattern \"%s\"" +"no output directory specified" +"no referenced object %u %u" +"no referencing object %u %u" +"one of -d/--dbname and -f/--file must be specified" +"option %s can only be used with %s" +"option %s cannot be used together with %s, %s, or %s" +"option %s is not supported with parallel backup" +"option %s requires option %s" +"option %s requires option %s, %s, or %s" +"options %s and %s cannot be used together" +"out of memory" +"out of memory\n" +"out of on_exit_nicely slots" +"parallel backup only supported by the directory format" +"parallel dumps from standby servers are not supported by this server version" +"parallel restore from non-seekable file is not supported" +"parallel restore from standard input is not supported" +"parallel restore is not supported with archives made by pre-8.0 pg_dump" +"parallel restore is not supported with this archive file format" +"pg_dump failed on database \"%s\", exiting" +"pgpipe: %s() failed: error code %d" +"pgpipe: could not accept connection: error code %d" +"pgpipe: could not bind: error code %d" +"pgpipe: could not connect socket: error code %d" +"pgpipe: could not create second socket: error code %d" +"pgpipe: could not create socket: error code %d" +"pgpipe: could not listen: error code %d" +"postfix operators are not supported anymore (operator \"%s\")" +"processing %s" +"processing data for table \"%s.%s\"" +"processing item %d %s %s" +"processing missed item %d %s %s" +"program \"%s\" is needed by %s but was not found in the same directory as \"%s\"" +"program \"%s\" was found by \"%s\" but was not the same version as %s" +"query failed: %s" +"query returned %d row instead of one: %s" +"query to get data of sequence \"%s\" returned %d row (expected 1)" +"query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned" +"query to obtain definition of view \"%s\" returned more than one definition" +"query to obtain definition of view \"%s\" returned no data" +"reading column info for interesting tables" +"reading constraints" +"reading default privileges" +"reading dependency data" +"reading event triggers" +"reading extended statistics" +"reading extensions" +"reading indexes" +"reading large objects" +"reading partitioning data" +"reading policies" +"reading procedural languages" +"reading publication membership of schemas" +"reading publication membership of tables" +"reading publications" +"reading rewrite rules" +"reading row-level security policies" +"reading schemas" +"reading subscription membership of tables" +"reading subscriptions" +"reading table inheritance information" +"reading transforms" +"reading triggers" +"reading type casts" +"reading user-defined access methods" +"reading user-defined aggregate functions" +"reading user-defined collations" +"reading user-defined conversions" +"reading user-defined foreign servers" +"reading user-defined foreign-data wrappers" +"reading user-defined functions" +"reading user-defined operator classes" +"reading user-defined operator families" +"reading user-defined operators" +"reading user-defined tables" +"reading user-defined text search configurations" +"reading user-defined text search dictionaries" +"reading user-defined text search parsers" +"reading user-defined text search templates" +"reading user-defined types" +"restored %d large object" +"restoring data out of order is not supported in this archive format: \"%s\" is required, but comes before \"%s\" in the archive file." +"restoring large object with OID %u" +"restoring tables WITH OIDS is not supported anymore" +"role name starting with \"pg_\" skipped (%s)" +"role with OID %u does not exist" +"running \"%s\"" +"sanity check on integer size (%lu) failed" +"saving \"search_path = %s\"" +"saving \"standard_conforming_strings = %s\"" +"saving database definition" +"saving encoding = %s" +"saving large objects \"%s\"" +"schema \"%s\" not found" +"schema with OID %u does not exist" +"server version: %s; %s version: %s" +"shell command argument contains a newline or carriage return: \"%s\"\n" +"skipping item %d %s %s" +"statistics dumped out of order (current: %d %s %s, expected: %d %s %s)" +"subscription with OID %u does not exist" +"subscriptions not dumped because current user is not a superuser" +"table \"%s\" could not be created, will not restore its data" +"table \"%s\" not found" +"there are circular foreign-key constraints on this table:" +"this build does not support compression with %s" +"this build does not support sync method \"%s\"" +"this format cannot be read" +"too many command-line arguments (first is \"%s\")" +"trigger \"%s\" not found" +"typtype of data type \"%s\" appears to be invalid" +"unable to initialize LZ4 library: %s" +"unexpected COPY statement syntax: \"%s\"" +"unexpected TOC entry in WriteToc(): %d %s %s" +"unexpected TOC entry in _printTocEntry(): %d %s %s" +"unexpected column data for table \"%s\"" +"unexpected data offset flag %d" +"unexpected end of file" +"unexpected extra results during COPY of table \"%s\"" +"unexpected index data for table \"%s\"" +"unexpected null attname" +"unexpected policy command type: %c" +"unexpected section code %d" +"unrecognized aggfinalmodify value for aggregate \"%s\"" +"unrecognized aggmfinalmodify value for aggregate \"%s\"" +"unrecognized archive format \"%s\"; please specify \"c\", \"d\", or \"t\"" +"unrecognized collation provider: %s" +"unrecognized command received from leader: \"%s\"" +"unrecognized compression algorithm: \"%s\"" +"unrecognized compression option: \"%s\"" +"unrecognized constraint type: %c" +"unrecognized data block type %d while restoring archive" +"unrecognized data block type (%d) while searching archive" +"unrecognized encoding \"%s\"" +"unrecognized file format \"%d\"" +"unrecognized locale provider: %s" +"unrecognized object type in default privileges: %d" +"unrecognized proparallel value for function \"%s\"" +"unrecognized provolatile value for function \"%s\"" +"unrecognized section name: \"%s\"" +"unrecognized sequence type: %d" +"unrecognized sequence type: %s" +"unrecognized sync method: %s" +"unrecognized table OID %u" +"unsupported filter object" +"unsupported filter object type: \"%.*s\"" +"unsupported pg_init_privs entry: %u %u %d" +"unsupported version (%d.%d) in file header" +"value for compression option \"%s\" must be a Boolean value" +"value for compression option \"%s\" must be an integer" +"warning from original dump file: %s" +"warning: " +"while FINALIZING:" +"while INITIALIZING:" +"while PROCESSING TOC:" +"worker process failed: exit code %d" +"wrong number of fields retrieved from table \"%s\"" +"wrote %zu byte of large object data (result = %d)" From 0de8baaa1b3632457ca21a1455f1d8981e4d5626 Mon Sep 17 00:00:00 2001 From: Eugene Date: Sun, 20 Sep 2026 15:33:50 +0300 Subject: [PATCH 3/4] README: countless mode, the new env vars, the generated table Documents restoring from stdin, ELE_LOG and ELE_PASSTHROUGH (and that plain output is still aggregated - passthrough is the only way to the firehose), the `--replay -` form, and where the parser's message wordings come from. --- README.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7523403..2bc89bf 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ happened, not just whether pg_restore was noisy. > [!NOTE] > Pre-1.0. The pipeline works end to end (live wrapper, error classification, -> exit-code normalization); an honest ETA is still to come. +> exit-code normalization, stdin restores); an honest ETA is still to come. ## Install @@ -82,6 +82,15 @@ ele --plan # print the parsed plan and exit; touches no databas ele --replay # replay a captured stderr log through the live view ``` +When the dump arrives on stdin there is nothing to preflight, so there are no +totals to count against. `ele` runs **countless** rather than falling back to the +firehose: the same spinner, current-object line, error panel and summary, with +per-phase object counts where the bars would be. + +```sh +cat latest.dump | ele -d myapp_dev --clean --no-owner +``` + `--plan` and `--replay` are offline: they never connect to a database. For both, `` is either a dump or a saved `pg_restore -l` listing (see below). @@ -96,6 +105,7 @@ Saving the listing once lets you dry-run (or re-`--plan`) without the dump on ha ```sh pg_restore -l latest.dump > latest.toc # capture the plan once (no database) ele --replay latest.toc ele-20260719.log # replay any captured log against it +ele --replay - ele-20260719.log # replay with no plan: the countless view ``` Tune the animation length with `ELE_REPLAY_SECONDS` (default 12; `0` feeds @@ -115,7 +125,10 @@ instantly and just prints the summary). through untouched. - **Parse & aggregate** turn that stream into progress and grouped errors, surviving the way parallel (`-j`) workers interleave their output. Errors are - fingerprinted (quoted identifiers blanked) and classified benign or real. + fingerprinted (quoted identifiers blanked) and classified benign or real. The + table of message wordings the parser matches on is generated from PostgreSQL's + own `pg_dump` message catalogs (`just gen-messages`), across release tags 13 + to 18, so a new major is a regeneration rather than a rewrite. - **Exit code** is normalized: if every error was benign, `ele` exits `0` with a note; any real error exits nonzero. Set `ELE_STRICT_EXIT=1` to keep pg_restore's raw code. @@ -127,12 +140,16 @@ collision with pg_restore's own flag surface. | Variable | Effect | |---|---| +| `ELE_LOG=path` | Write the raw log here instead of `./ele-.log`. `/dev/null` discards it. | | `ELE_STRICT_EXIT=1` | Don't normalize the exit code; return pg_restore's own. | | `NO_COLOR=1` | Disable color. | | `ELE_PLAIN=1` | Disable the repaint block; emit periodic one-line progress instead. | +| `ELE_PASSTHROUGH=1` | Don't wrap at all: raw `pg_restore` output and its own exit code. | `ele` also drops to plain output automatically when stderr isn't a terminal, or -under `CI` / `CLAUDECODE`. +under `CI` / `CLAUDECODE`. Plain output is still the aggregated view - a summary +and periodic progress, never the firehose. `ELE_PASSTHROUGH=1` is the only way +back to raw `pg_restore`. ## Feedback From 34ac25adbe58a9e399b66716d927c64e792f37ca Mon Sep 17 00:00:00 2001 From: Eugene Date: Sun, 20 Sep 2026 21:34:00 +0300 Subject: [PATCH 4/4] Fix the PlainProgress doc comment and the README stdin section The countless pacing constants had landed between PlainProgress's doc comment and the type, so the type had no doc comment at all. Constants moved above it. In the README, the stdin paragraph sat between the mode list and the sentence explaining those modes. It is now its own subsection at the end of Modes, and the sentence describing what `` accepts names `-` alongside a dump and a listing. --- README.md | 26 ++++++++++++++++---------- internal/render/plain.go | 12 ++++++------ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 2bc89bf..05dab20 100644 --- a/README.md +++ b/README.md @@ -82,17 +82,9 @@ ele --plan # print the parsed plan and exit; touches no databas ele --replay # replay a captured stderr log through the live view ``` -When the dump arrives on stdin there is nothing to preflight, so there are no -totals to count against. `ele` runs **countless** rather than falling back to the -firehose: the same spinner, current-object line, error panel and summary, with -per-phase object counts where the bars would be. - -```sh -cat latest.dump | ele -d myapp_dev --clean --no-owner -``` - `--plan` and `--replay` are offline: they never connect to a database. For both, -`` is either a dump or a saved `pg_restore -l` listing (see below). +`` is either a dump or a saved `pg_restore -l` listing (see below); +`--replay` also takes `-`, meaning no plan at all. `--replay` is the safe dry-run. Feed it a captured stderr log and a plan, and it reruns the whole pipeline: on a terminal it drives the real live block (progress, @@ -111,6 +103,20 @@ ele --replay - ele-20260719.log # replay with no plan: the countless Tune the animation length with `ELE_REPLAY_SECONDS` (default 12; `0` feeds instantly and just prints the summary). +### Restoring from stdin + +```sh +cat latest.dump | ele -d myapp_dev --clean --no-owner +``` + +Preflight needs a file it can open, so a dump arriving on a pipe has no table of +contents and no per-phase totals. `ele` still runs the whole view: spinner, +current-object line, grouped errors, summary and exit code, with a per-phase +object count in place of each bar. Percentages and the skipped-object count are +gone, because both need a total. + +`ele --replay - ` shows the same view offline, against a captured log. + ## How It Works - **Preflight** runs `pg_restore -l` (under `LC_ALL=C`) and parses the table of diff --git a/internal/render/plain.go b/internal/render/plain.go index 812b4f1..3191d8f 100644 --- a/internal/render/plain.go +++ b/internal/render/plain.go @@ -10,20 +10,20 @@ import ( "github.com/amberpixels/years" ) -// PlainProgress emits a one-line status to w at meaningful milestones - each -// phase completion and every 10% within a phase, or, with no denominators to -// measure against, every countlessStep objects. It is the degraded-mode -// substitute for the live repaint block (non-TTY, CI, NO_COLOR, ELE_PLAIN), -// never the raw firehose. Feed it snapshots on a ticker. // countlessStep and countlessInterval pace the line when there are no // denominators to hit deciles against: a milestone is every N objects, or every -// N seconds, whichever lands first. Without them a countless restore would +// N seconds, whichever comes first. Without them a countless restore would // print one line at the start and then nothing for the rest of the run. const ( countlessStep = 50 countlessInterval = 15 * time.Second ) +// PlainProgress emits a one-line status to w at meaningful milestones - each +// phase completion and every 10% within a phase, or, with no denominators to +// measure against, every countlessStep objects. It is the degraded-mode +// substitute for the live repaint block (non-TTY, CI, NO_COLOR, ELE_PLAIN), +// never the raw firehose. Feed it snapshots on a ticker. type PlainProgress struct { w io.Writer st *Styles