Repository navigation
Releases
pgman v0.5.0
Added
- Encrypted dumps.
encrypt = "kms:<key>"on an environment wraps a
fresh key per dump with AWS KMS, bound to the dump's header;encrypt = "age:<public key>"encrypts to your own key, made bypgman key new.
Masked and raw dumps are both encrypted, pg_dump's output piped straight
into the encryptor;pgman restoreopens them. The journal records
what each copy is encrypted to, andpgman copies showsays it.
pgman key new|listmakes and lists your age keys.
Changed
- A protected environment's raw and masked dumps need
encrypt.
Until the environment sayskms:,age:ornone(masked copies
only), they are refused, with the lines that settle it. Schema-only
dumps, and protected targets that aren't environments, are unchanged
(the latter dumped masked and unencrypted, which is said). - An encrypted raw dump is pgman's archive, a
.pgman-dumpdirectory,
and its link<label>-latest.pgman-dump, not<label>-latest.dump:
a script restoring the old link name finds the last unencrypted dump.
Masked and raw copies of one label now share that link.
Fixed
- Over MCP, the confirmation for
dump,restoreandapply_patches
starts ticked. Claude Code kept showing the form again while its box
was unticked, and the call failed after 300s with "no answer from the
operator". Accept or Decline is the answer; a protected environment
still takes its typed name. - Over MCP,
dumpandrestoregiven a connection name only
discovery knows (oneconnectionslists from the project) say so,
and to pass its URL or add it to connections.toml. They used to say
there was no such name. - A restore's result says that owners and grants were left out, who
owns what it restored, and how to grant another role (the
application's) access: until then that role can read none of it. - A dump refused because its user can't read everything names the
first 20 tables and sequences, then counts partitions under their
parent (app.events: 106 partitions). It used to name the first 8
and say "and 106 more", which could hide the few tables that decide
whether--skip-unreadableis safe. - Masking rehashes a hash whose word isn't last
(long_value_hash_lower_case), a barehashon a cards or users
table, and a card number's (ccnum_hash). - A key into a lookup that refines another (
sub_religionsinto
religions) is NULLed as one into the lookup is; a text-keyed lookup
of categories keeps its key; a lookup's translations keyed by a
language_idaren't refused. - The tap monitor's status says a sender's drop count is events
"dropped in the app, never sent", not "JAR backpressure": OTLP
senders never report one, and pgman's own drops are the footer's. - The tap's transactions and pools views drop numeric columns on a
narrow screen instead of their text column: at 60 columns a row
ended on a bare…, and at 80 the transactions view readcon…and
the pools view showed the pool under aPOOL · APPheader with no
app. The pools header names the app only when a row has room for one. - A connection the server ends while a page of rows loads, a transaction
commits or rolls back, or pgman is first connecting shows the
connection-lost card with the server's reason, as a failed query's
did. A failed:readonly onleaves the header as the session is.
pgman v0.4.4
Added
- Masked dumps keep Odoo's models, views and menus whole (their names
are JSON, which the defaults NULL, and the restored app wouldn't
start). Its attachments, settings and mail servers are masked as before.
Fixed
- A key into a lookup of personal answers (
gender_idintogenders,
marital_status,country_of_birth) took the lookup's kept id, or
was hashed alongside it, so the copy still joined to the answer. It is
NULLed now, a rules-filenullon it too, and where it can't be NULL
the plan asks the rules file to decide. The lookup's own key is kept.
Masked copies taken with an earlier version of a schema with such keys,
key-value or settings tables, data columns, or the hashes below should
be deleted (pgman copies rm, then by hand whatever it says it kept,
and any dump file copied elsewhere). - Keycloak's session tables are dumped empty: their notes hold a
device's address and details. - A key-value table's value is NULLed whatever its length: Keycloak's
user_attribute.value(a user's phone or address) and
realm_smtp_config.value(the SMTP password) were kept as bounded
varchar. So is a column named for a bag of data (metadata,
extra,raw_data). - A hash of a card, an account or a user (
card_hash,account_hash,
user_hash) is rehashed, not kept: there are few enough of each to
try every one.
pgman v0.4.3
Added
- Masked dumps keep Rails', Django's, Alembic's and Knex's migration
tables whole, as Flyway's and Liquibase's are, and dump Django's
sessions empty.
Fixed
- A CHECK constraint that only bounds a column's length, an array's
cardinality, or asks for a JSON object no longer stops a masked dump:
the empty value and a hash pass it for certain. A bound on a text
column's length is taken as its length, so a hash or a fake fits it.
On GitLab's schema this takespgman masking checkfrom 850 problems
to 87 real ones. - A domain's CHECK constraint (
CREATE DOMAIN … CHECK (VALUE <> '')) is
read too: a masked value it refuses stopped the restore part-way. - A unique column too short for the hash that keeps it unique is a
problem however the hash came about. A NOT NULL unique column NULLed by
default is hashed, and a short one passed the plan and lost its unique
index on restore. - Masking keeps a date, time or boolean column named for a password or
secret (password_changed_at,token_expires), which can't hold one. - Masking finds comment, description and similar words inside a folded
camelCase name whose other words it doesn't know. A free-text word no
longer masks a
number, date or boolean (note_events, afailure_reasoncode), which
can't hold free text. - Masking keeps settings named for a personal thing: a feature switched
off (emails_disabled; a baredisabledis still special-category
data), a theme, colour or mode (login_theme,mobile_view_mode; not
an eye, skin or hair colour), a bounded template, layout or style, and
a boolean about a signature. An email's subject or body is NULLed
as free text, not given a fake address. - Masking knows more personal words, found by running it over GitLab's,
Keycloak's, Odoo's, Synapse's and AdventureWorks' schemas: an
identification_id(a national ID number), a visa or work permit, an
abbreviatedacc_number, a bonus or commission, social handles
(linkedin,twitter, …), OAuth device and user codes, an access key,
sick leave, pronouns, a login or external id (extern_uid), a
reviewer's or attendee's name, a partner's or guest's name,reply_to,
ansms_number, a browser, a TLS fingerprint (ja3). A word with
digits in it (ipv4,last4) now matches. A hash of something
personal and easy to guess (holder_name_hash,last_digits_hash,
email_digest) is hashed again, so it still joins; any other*_hash
is kept, and the rules file's[classify]words reach both. pgman copies rmsays what to do when it can't drop a copy restored
through a URL with the password in it: drop it by hand, or restore
through aconnections.tomlentry withpassword_env.
pgman v0.4.2
Fixed
- Masked dumps judge a camelCase column name that Postgres folded to
lower case by its words: an unquoteddateOfBirthis stored
dateofbirth, which pgman read as one unknown word and kept. On such
a schema a masked dump kept dates of birth, phone and mobile numbers,
email addresses, password hashes, bank sort codes and account numbers,
passport and social security numbers, and special-category columns
such as sexual orientation. Runpgman masking showagain on a schema
named this way; copies taken with 0.4.0 or 0.4.1 should be deleted
(pgman copies rm). A phrase such as "account number" now matches
accountnumbertoo, and "social security", "building society" and
"account name" are known. pgman masking check, and a masked dump, stop at a masked column a
validated CHECK constraint names when its masked value may fail it
(wage > 0on a nulledNOT NULLwage became 0): the restore stopped
part-way at the first such row, after the whole dump.pgman copies rmnames the database it keeps and why; one restored
through a URL with a password in it said only "invalid configuration:
password missing".
pgman v0.4.1
Fixed
- Slow queries work on PostgreSQL 12, which names
pg_stat_statements'
timestotal_timeandmean_time. - Masked dumps work on PostgreSQL 10 and 11.
- A restore into a database it created counts "already exists" from
the new database's template as harmless and names it, instead of
saying the database wasn't empty: every restore into YugabyteDB
exited 1 for its own foreign server. - The schema wizard and
schema_lintleave alone what is in a schema
an extension made, such as TimescaleDB's chunks. - A masked dump of a database with TimescaleDB hypertables stops and
names them, instead of restoring them as plain tables without the rows
of their compressed chunks. - The schema wizard's "foreign key without an index" (LINT101) no
longer flags a key whose column leads an index: it read the index's
second column.
pgman v0.4.0
Added
-
Masked dumps:
pgman dump --masked, the default for a protected
environment, takes a copy with what looks personal replaced as it is
read — emails, names, phones, postcodes, dates of birth, IPs and
passwords by realistic fakes, secrets, special-category data,
identifiers, addresses and free text removed — judged from each
column's name and type, with framework presets (Flyway, Liquibase,
Envers, Spring Session). Foreign keys keep joining; a fresh key per
copy, never sent to the server. One snapshot, a.pgman-dump
directory with checksums, whichpgman restoreloads rows-then-keys. -
.pgman/masking/<database>.toml: the team's own rules (keep with a
reason, fixed, hash, email, name, phone, ip, postcode, year,
date.shift, rows dropped), andpgman masking show/checkto see
and test them from the catalog alone, in CI too. -
docs/privacy.md: what pgman does with personal data, for a client's
DPO. -
pgman copies: every dump taken on this machine, from a journal
pgman now keeps (~/.local/share/pgman/journal.jsonl): when, of what,
raw or schema, why, the file, when it expires, where it was restored.
copies showgives one in full,copies rmdeletes one (and repoints
its-latestlink),copies reportprints the whole account as text,
markdown or JSON. No data, connection details or secrets are recorded. -
A dump policy per environment in
environments.toml:dump
(unmasked,masked,schema,never),dump_ttl,dump_reason
andunattended. A project's.pgman/pgman.tomlcan lower an
environment's ([dumps.environments.<name>] dump = "schema"), never
raise it. -
journal = { group = "/pgman/dumps" }on an environment sends the
journal's events for its copies to that CloudWatch Logs group with the
awsCLI, as the IAM identity that sent them: file names without
paths, no server addresses. A send that fails never fails the dump and
is retried by the nextpgman dumporpgman copies; each event is
sent once. -
pgman dump --schema-only,--reasonand--ticket. The reason
prompt offers the ticket in the branch's name (feature/APP-101-…),
else the last reason given;[dumps] ticket_urllinks tickets in
pgman copies.
Changed
- A dump of a protected environment asks why it is taken, and a raw
dump of one (every row) also takes the environment's name typed,
after a warning that it copies personal data to this machine. Without
a terminal, a raw dump of a protected environment is refused unless
the environment saysunattended = truein your own
environments.toml; scripts that need only the structure use
--schema-only --reason …. Other environments are dumped as before. - A protected environment is dumped masked by default; a raw copy of
one needsdump = "unmasked"on it in your ownenvironments.toml,
--unmasked, and its name typed at a terminal. - A dump with no FILE goes to
~/.local/share/pgman/dumpsrather than
the current directory. A raw dump of a protected environment is
refused in iCloud Drive, Dropbox, OneDrive or Google Drive; every dump
is excluded from Time Machine. pgman copies rmalso drops the databases restored from a copy (only
local, unprotected ones whose comment names it).- MCP's
dumptakes a protected environment masked (or schema only),
using a rules file only when it is committed and you have confirmed it
at a terminal; a raw dump of one over MCP, which v0.3 allowed after its
name was typed, is refused, and every MCP tool refuses a database
restored from one. The reason is given by you in the confirmation.
Each MCP dump and restore is journaled. environments.tomlhas new keys (dump,dump_ttl,dump_reason,
unattended): an older pgman reading a file that uses them refuses
it as unknown keys.- MCP's
restoretakes a masked dump, or a dump this machine's pgman
took; a dump the journal doesn't know, or a raw copy of a protected
environment (copied or moved too: each dump's fingerprint is
recorded), is refused, yours to restore at a terminal. - A restore that fails part-way is journaled, and the database it made
is marked as the copy's from the moment it exists. - A dump of a database restored from a raw copy of a protected
environment is treated as a dump of that environment.
Fixed
pgman … | head(any command whose reader goes away early) ends
quietly instead of aborting.pgman restoreinto a protected environment of replicas only says it
is protected, not to name or add its primary.
pgman v0.3.1
Changed
- The Homebrew formula depends on
libpq, sopgman dumpandpgman restorework from a brew install with nothing else installed or
linked: its wrapper tells pgman where libpq'spg_dumpand
pg_restoreare (PGMAN_PG_BIN). dumpandrestorelook for the tools in--pg-bin, then
$PGMAN_PG_BIN, then Homebrew's libpq, thenPATH, and say which
they ran. Homebrew's libpq now comes beforePATH, so an older
PostgreSQL onPATHdoesn't win over it.- A pg_dump older than the server says
brew upgrade libpqtoo, since
the libpq found may be the stale one.
pgman v0.3.0
Highlights
- A local copy of an environment in two commands.
pgman dump staging/ledgertakes it from the replica through the bastion, the
password read at that moment and never on a command line or on disk;
pgman restore … local --as ledger_copy --cleanputs it into a local
database, never a protected one. - Scripts and patches from the command line.
pgman runruns a
script that manages its own transactions,\cbetween databases;
pgman applyis the environments view'sP,--outsideincluded. - For a coding agent: MCP
dumpandrestore, each confirmed by
you, so an agent can refresh its copy without ever holding the
environment's credentials.
Added
pgman dump <target> [FILE]: a dump by your ownpg_dump, through
pgman's connection — the environment's replica unless--primary, the
password read from its secret at that moment and given to pg_dump only
in its environment, the ssh tunnel opened for it. The local pg_dump's
version is checked against the server first; the dump is written to a
hidden name and renamed into place on success, private to you, with a
-latestlink for a default name. A replica cancelling the dump (a
recovery conflict) and a permission failure are explained. What the
dump's user can't read (no SELECT, no USAGE on its schema, row-level
security, large objects) is found before pg_dump starts and refused
by name;--skip-unreadableleaves exactly that out and says so. A
sequence that a readable table owns can't be left out, and is named
with the GRANT that fixes it. See
docs/dump-restore.md.pgman restore <FILE> <target>: a dump restored by your own
pg_restore, never into a protected environment and only on this
machine unless--allow-remote.--as NAMErestores into another
database,--createmakes it,--cleanreplaces it; other sessions
refuse it unless--terminate; it is confirmed, or--yes. It exits
1 when pg_restore went past real errors, counting a newer pg_dump's
SETof a setting the server doesn't have as harmless.--jobs,
--keep-ownersand options after--go to pg_restore; a plain SQL
dump is psql's.pgman run <target> <FILE>: a script that runs its own transactions
(BEGIN … COMMIT), aspsql -fdoes, with\c DATABASEmoving it
to another database of the environment. Checked against safety.toml
first; confirmed (a protected target by typing its name); a failure
or Ctrl-C reports what stayed committed, what rolled back and what
never ran.VACUUMandCONCURRENTLYrun without the statement
timeout; a standby is refused. Seedocs/run.md.pgman apply <target> [--outside] [--dry-run | --copy]: the
environments view'sPfrom the command line. An--outsideplan or
a protected environment takes the typed name, which--yesdoesn't
answer.- MCP:
dumpandrestoretools, each confirmed by the operator
through elicitation (a protected environment, or a database to be
replaced, by typing its name); files stay inside the server's
working directory, and a restore is local and unprotected only. - A
<target>on the command line isENV,ENV/DATABASE,
ENV/SERVER/DATABASE, aconnections.tomlname, or a URL. It is
protected by its environment, by "prod" in its name, or by being on a
server a protected environment reaches, however that is written. pgman dumppsaysunknown command "dumpp" (did you mean dump?).- Ctrl-C, SIGTERM and SIGHUP stop
dump,restore,runandapply
cleanly: the tool stopped, a partial file removed, a transaction
rolled back.
Fixed
- Ctrl-C in the editor (and Esc twice while patches run) now cancels
the running statement on a server reached withsslmode=requireor
verify-*, such as RDS: the cancel request went out without TLS,
which the client library refuses for such a session, so it never
reached the server.
pgman v0.2.1
Fixed
- The help overlay names the JDBC tap and the NOTIFY panel by
:tap/
:notifyfirst, withF4/F3beside them, and the start card
does the same for the tap: on a Mac terminal the F-keys often never
reach pgman. The section list's teasers lead with their key
(:tap / F4 · your app's statements, live,S · schemas, …), so it
survives at 60 columns, and each fits whole at 80; the tap's ended
(:…at 80x24. - The result diff's title names its key (
key: id (primary key)) before
the A and B query text, so an 80-column terminal no longer cuts it
off; a title too long for its border ends on…. A diff of results
with different columns sayscolumns differin its title and under
the counts, which read as a fault (key: full row, every row added
and removed) without it. :fixtureandYon a partial result end their status on "fetched
rows only, more not fetched", which the footer keeps whole; at 160
columns it was cut mid-note, along with the file name.- The schema wizard's detail pane wraps between words (it broke
referen/cesat 80x24), and its list sizes the object column to
leave the title room: at 80 columns the title column was three
letters wide and its header readtit. - A result column's header squeezed with its column ends on
…, as
its cells do, and keeps its sort marker: at 80x24billing_email
readbilling_over cells readingbilling…. - The result title is fitted to its border: with a filter on and
five-digit counts, an 80-column title ran into the corner mid-word;
it now drops whole segments from the end and ends on…. - The JDBC tap's views cut a long cell with
…rather than at the
border: N+1 and callers keep the caller whole and add the fingerprint
only when there is room to read one, hotspots'fingerprint · caller
and transactions'txn · last sqlfit their column (at 80x24 the
hotspots header readFINGERPRINT · LAST CAover· InvoiceS), and
any row or header too wide for the panel ends on…. - The NOTIFY panel cuts a long payload, and its title's key hints, with
…at the border rather than mid-token, and shows a payload's
newline as⏎on its row. - The start card's two key columns line up:
:tap JDBC tap (F4)
started four columns right of theS/T/L/ctrl-tabove
and below it, asctrl-l's key is wider than the others. At 100
columns the card takes the shortctrl-lwording so
S schema browser (26 tables)fits, and a right-hand hint too long
for a narrower card ends on…rather than at the border. - A start card too short for every key hint keeps its
? all keys
line and says how many it left off (+3 more); at 60x16 the hints
went with nothing to say so. - The README lists cell editing (
u) and paging (M), and its links
todocs/and the licence files are absolute, so they resolve on
crates.io too; it says to runbrew trust tombaldwin/tapfirst on
Homebrew 6 or newer. --demono longer writespgman.logor creates pgman's cache,
config and data directories, as its "no disk writes" promised, and
\fixture/\reportwith no path write nothing to the cache
dir: they say--demo writes no filesand ask for a path.- docs/tap.md says the monitor's "JAR backpressure" drop count comes
from TCP and UDP senders only, and never appears with--tap-otlp. - A connect no longer hangs at "connecting…" behind another session's
ACCESS EXCLUSIVElock: the schema fetch skips the sizes and indexes
the lock covers, the connect's own catalog reads give up after a 2 s
lock_timeout(the session's own setting is restored), and the status
line says the schema is incomplete, names the holder's pid first (a
narrow footer cut it off) then the lock — for a read that gave up
behind a lock on a catalog too — and how to reload. The schema
browser sayssize: not fetched (locked)andindexes: not fetched
for such a table, which read as a table with no indexes. A reload (S
thenr, or the refresh after DDL) is bounded the same way, puts back
your ownlock_timeoutwith nothing of yours running in between, and
no longer says "schema reloaded" over a read the server cancelled: any
failed catalog read is named. Inside an open transaction it reads
nothing and says so, since a read the server cancelled there would
abort your transaction. - A session the server ends under a running statement
(pg_terminate_backend, a crash shutdown) shows the server's reason
on the connection-lost card, not "the connection to the server closed"
with the reason in the footer; a session lost while still connecting
keeps its reason too. The server's hint comes with it: a hot-standby
conflict's says to reconnect and repeat the command. - The header no longer says
Session: writableon a standby whose
connect-time probe went unanswered: when a paged run's probe finds the
server in recovery, the session is pinned read-only there, in the
header and on the server, as the connect would have pinned it; nor
after a:readonly onon a standby that failed to apply, or a
:readonly offthe server took just as the standby was pinned. - A primary is no longer pinned read-only as "a read replica" when a
schema ahead ofpg_catalogon the search path has a
pg_is_in_recovery()of its own: the connect's probe, and MCP's,
the dashboard's and the advisor's, callpg_catalog's. So do
apply_patches'statement_timeoutrestore and the sessions panel's
terminate, which a shadow could make report a session ended that
wasn't. - Under a read-only session the confirm card no longer says Postgres
will refuse a statement pgman can't classify, such asSET, which it
runs: it says Postgres refuses it if it writes.
Changed
- The header and About box say the date beside the version is the
release date:pgman 0.2.0 · released 2026-10-23. At 60
columns the header now shows the version alone.
pgman v0.2.0
Highlights
- Edit a cell in place.
uon a result cell writes a one-row
UPDATEby primary key, shown in the same safety confirm as any
statement you run. - Page past 1000 rows.
Mfetches the next 1000 rows of a
SELECT, through a server-side cursor that pgman closes after 60 s
idle, 10 min open, or before any other work; a standby holds none. - A config advisor in the schema wizard (
W). Read-only findings
on cache hit ratio, temp-file spills, dead tuples, lock waits and
checkpoints, each with its evidence, a conservative setting and the
RDS / Aurora parameter to change. - The whole JDBC tap event.
Enteron a tap row shows the full
SQL, every bound parameter, the error's cause chain and the caller
stack; the list shows the focused statement's parameters beneath it. - Help in sections. One section at a time instead of one long page,
with a summary for each and a filter across them all. - More logs read. Logs → SQL now reads Postgres's
csvlogand
jsonlog, p6spy and datasource-proxy logs, and statements that
failed with anERROR:. sslrootcertin a connection string pins the trusted CAs, as in
libpq.
Added
- Cell editing:
uon a cell in the grid (or a field in row detail)
edits it in place. Enter writes a one-rowUPDATE … WHERE <primary key>and sends it through the safety guard like any editor statement,
the statement shown in the confirm;Ctrl-Nsets NULL (and NULL ↔ the
empty string). It works on a SELECT from one table with its primary
key in the result, and otherwise says why not (a join, a view, no
primary key, the key not selected, a computed column, read-only). The
UPDATE changes exactly one row or is rolled back, and the cell then
shows the value as the server stored it. Before it commits, pgman
checks the server still calls the table, the column and the key what
pgman's schema cache does; a column renamed since pgman read the
schema (and another added under its old name) is rolled back with
the table changed since pgman read it, never written to the wrong
column. Min the results fetches past the first 1000 rows. A plainSELECT
from the editor now reads through a server-side cursor; while it has
more, the title sayspartial · M fetches more, and eachMappends
1000 rows (up to 100 000 held), keeping the sort and filter. While
the cursor is open the session is idle in transaction, holding an
ACCESS SHARElock on the tables the query reads: DDL on them (a
migration,ALTER,TRUNCATE,VACUUM FULL,REINDEX) waits behind
it, and later statements on those tables queue behind that DDL. pgman
closes the cursor after 60 s without a fetch or 10 min open (sooner if
the server's own timeouts are), before any other database work, and
at the end of the result;Mthen re-runs the query. On a standby
no cursor is held at all (a recovery conflict would end the session):
the first page commits at once andMre-runs the query for more.
EXPLAIN, scripts,\watch, lockingSELECTs, aSELECTthat calls
a function other than a short list of read-only built-ins (count,
coalesce,lower,now, …) — or one of those names that a schema
has its own function for — and aSELECTinside an open
transaction stay capped at 1000 as before.- Config advisor in the schema wizard (
W): read-only findings from the
server's statistics — buffer cache hit ratio, temp-file spills (with the
spilling statements frompg_stat_statements), dead tuples and the
autovacuum setting behind them, lock-wait chains, and requested
checkpoints (pg_stat_checkpointerfrom PG17), blamed on
max_wal_sizeonly whenpg_stat_walshows the WAL to have forced
them. Each shows its
evidence, how long the counters have accumulated, a conservative
setting, and its RDS / Aurora parameter-group name, static or dynamic.
eyanks a finding's evidence query. Enteron a JDBC tap List row opens the whole event: the full SQL,
pool/conn/txn, every bound parameter, the error's cause chain
down to the root cause, and the caller stack. A failed row used to be
only coloured red, and only the innermost caller frame reached the
Callers view.- The JDBC tap's List view shows the focused statement's bound
parameters beneath the list, labelledparams (some redacted)when
the producer masked a value andparams (withheld by source)for
OpenTelemetry spans, which carry none. sslrootcert=<file>in a connection string pins the trusted CAs, as
in libpq (andrequirewith a CA file checks the chain). It used to
be ignored, with the default trust store used instead.sslcrland
sslcrldirare refused rather than ignored.- A Postgres log's
ERROR:+STATEMENT:pair is reconstructed as a
query marked failed with the error message — what the default
log_min_error_statementlogs with nothing else on. A statement
log_statementalready logged is marked failed rather than listed
twice. The log picker marks a failed pick✗and shows its error. - Logs → SQL reads Postgres's
csvlogandjsonlog(PG 15+) formats as
well as stderr: same pairing of parameters and errors, by pid. - Logs → SQL reads p6spy (default single-line format) and
datasource-proxy query logs, tagged[p6spy]/[ds-proxy]in the
picker. Tabafter:helpcompletes the help section names, as it completes
command names.docs/tap.md: the JDBC tap for pgman users — the OpenTelemetry, TCP
and UDP ways in, the v1 event fields, the limits and drop counts,
--tap-record/--tap-replay, redaction and security.
Changed
Ctrl-Cin the results cancels a running query, as it does in the
editor, instead of arming quit; with nothing running it still asks
for a second press.Yand:fixturesayfetched rows onlywhen the result has more
rows than pgman holds.- The result diff (
D) matches rows on the table's real primary key
when A and B are the same columns from one table and the key is in
both (key: id (primary key)in the title), instead of the leftmost
column that happens to be unique; otherwise it infers as before. - Help is a list of sections and one section at a time instead of one
~275-row page: from 110 columns the list sits beside the section, and
on a narrower terminal the list comes first, each section with a
one-line summary, andEnteropens one.Tab/]/[move between
sections,/filters every section live (matching rows under their
headings), and:help allkeeps the single page.:help <topic>
takes any section name or the start of one, and an unknown topic lists
every section. - One size format everywhere: database sizes on the start card and in
the environments overview, and table sizes in the schema browser, read
9.0 MB/212 MB/1.2 GB. The start card usedpg_size_pretty,
which stays in kB up to 10 MB (10199 kBbeside10 MB), and the
schema browser usedMiBwith two decimals. - In the editor and the prompts the error footer points at
F2 / :error detail, not F2 alone: F2 takes fn on a Mac. - The start card's
recentlist says how to bring an entry back:in the editor, ctrl-p recalls · ctrl-r searches. - Loading a saved query (after its
:paramvalues, if any) ends the
status with the key that runs it:⏎ runs it, oralt-⏎ runs itwhen
the statement has no;and Enter would be a newline. - The tab bar's hint reads
[ ] prev/next tabinstead of] [ switch,
which looked like a stray pair of brackets. - One TLS crypto provider (ring) instead of two: no cmake / C build of
aws-lc, and a smaller binary (x86_64 macOS 11.9 MB to 9.1 MB). The
Postgres connection no longer offers the post-quantum X25519MLKEM768
key exchange, which only the aws-lc provider had. - Logs → SQL: a Postgres
FATAL:orPANIC:followed by its
STATEMENT:(a read replica'sterminating connection due to conflict with recovery) is reconstructed as a failed query, like an
ERROR:'s.
Fixed
:readonly onunder a writable profile could be undone from the
editor:SET default_transaction_read_only = offgot theother
guard's confirm, and afterythe session wrote while the header still
saidread-only. A session read-only by:readonly onor a standby's
pin now blocks thatSET(andBEGIN READ WRITE,set_config(…)) as
a read-only profile does, and says:readonly offis the way out.- A connection that dropped under a running pgman — a session the server
ended (pg_terminate_backend, a restart, an idle timeout) or a network
that went — left the header sayingconnected, and every later command
failed withconnection closed; the log said onlypostgres connection error: db error. pgman now shows the connection-failed screen, with
connection lostand the server's own message (terminating connection due to administrator command), andrreconnects; the log keeps the
message and its SQLSTATE. - A long pattern typed into a footer prompt (the schema browser's and
help's/filter, the grid's/filter andffind,ctrl-r
history search) no longer loses itsfilter: //find:head or the
cursor: the head stays, the pattern shows its end after a…, and
the cursor sits after it. The key hints go first. - The JDBC tap monitor read "no events yet", and the footer showed no
TAPbadge, while only commits / rollbacks had arrived; the status
now counts them (2 commits/rollbacks). - The schema wizard, slow queries, sessions and notifications lists,
and the JDBC tap's List, Hotspots, Callers, Transactions, N+1 and
Baseline views, scrolled as if their header row were a list row, so
moving the cursor past the bottom left the focused row hidden one
line below the edge. - After
SELECT … FROM ONLY t,Iyanked anINSERT INTO public.only:
ONLYwas read as the table's name. It...