Re: [PATCH] Add PROMPT_COMMAND and dynamic prompt support to psql

From: Kirk Roybal <kirk(dot)roybal(at)gmail(dot)com>
To: pgsql-hackers(at)postgresql(dot)org
Subject: Re: [PATCH] Add PROMPT_COMMAND and dynamic prompt support to psql
Date: 2026-08-04 15:49:43
Message-ID: CAE==DwevFQkHCBzXRrwtGj4eLc-QCG_gUctqONqPvv7abC2ZMg@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

v2 follow-up: one-page merge rationale, explicit review ask, and a TAP test
(as offered in the original post). Patch attached.

========================================================================
Why merge this (one page)
========================================================================

Problem
-------
Interactive psql prompts are static between PROMPT1/PROMPT2 redefinitions.
Users who want connection context, transaction state, or last-command status
in the prompt today either fork psql or abuse %`shell` on every redraw.
There
is no bash-shaped hook to regenerate the prompt once per readline.

Bash-shaped solution
--------------------
Mirror bash, not invent a plugin API:

* PROMPT_COMMAND — if set, run a shell command before each interactive
prompt; capture the first line of stdout (existing prompt buffer limit).
* %D — PROMPT1/PROMPT2 escape for that captured line (renderer output).
* SHELL_EXIT — last *user* command status (SQL or \!); PROMPT_COMMAND does
not overwrite it, so themes can show the prior command’s outcome.
* Prompt refresh — run_prompt_command() immediately before readline() in
input.c (not rl_pre_input_hook, which left the prompt blank until a
key).
* \connect housekeeping — reset ROW_COUNT / SHELL_EXIT after successful
\connect; optional :txid refresh when that variable already exists.

Zero behavior change unless configured
--------------------------------------
Defaults are inert:

| Knob | Default | Effect when unset/off |
|-------------------------|---------|------------------------------------|
| PROMPT_COMMAND | unset | no shell, no popen |
| %D | unused | empty substitution if referenced |
| PROMPT_SESSION_EXPORT | off | no PG*/PSQL_* export into subprocess |
| SHELL_EXIT | "0" | new variable only; scripts ignore it |

Non-interactive use, existing scripts, and default interactive sessions are
unchanged. No .psqlrc change ⇒ no new behavior.

Security / gating story (PROMPT_SESSION_EXPORT + shell)
-------------------------------------------------------
PROMPT_COMMAND uses popen() — the same trust model as existing %`command`
prompt escapes and \!. It only runs when the user (or their .psqlrc)
explicitly sets PROMPT_COMMAND.

PROMPT_SESSION_EXPORT is a separate, default-off gate:

* Off (default): PROMPT_COMMAND subprocess inherits the normal process
environment only; no extra session dump.
* On: export current-session PG* / PSQL_* (database, user, host, port,
PSQL_TXN, PSQL_ROW_COUNT, PSQL_SHELL_EXIT, PSQL_SUPERUSER, optional
PSQL_TXID) so external renderers need not re-query.

Keeping export opt-in means “I only want %D from a fixed command” never
leaks connection metadata into the child env. Reviewers who want a
narrower first commit can take PROMPT_COMMAND + %D + SHELL_EXIT alone and
leave PROMPT_SESSION_EXPORT for a follow-up.

========================================================================
Looking for a reviewer to walk this path
========================================================================

Please walk the psql + readline path (not a general “please review”):

1. src/bin/psql/input.c
— run_prompt_command() immediately before readline() / gets_fromFile
2. src/bin/psql/prompt.c + prompt.h
— run_prompt_command(), export_prompt_environment(),
prompt_session_export_enabled(), %D in get_prompt(),
reset_prompt_status_after_connect()
3. src/bin/psql/mainloop.c
— gets_interactive() call sites (when prompts are drawn)
4. src/bin/psql/common.c
— SetLastExitVariable() / SHELL_EXIT; confirm PROMPT_COMMAND does not
call it
5. src/bin/psql/command.c
— reset_prompt_status_after_connect() after successful \connect
6. src/bin/psql/help.c + startup.c
— --help=variables / initial SHELL_EXIT
7. src/bin/psql/t/040_prompt_command.pl
— TAP coverage (below)

Optional companion doc (not installed):
src/bin/psql/powerline-integration.md

========================================================================
Testing (v2: TAP added)
========================================================================

src/bin/psql/t/040_prompt_command.pl (registered in meson.build):

Non-interactive:
* SHELL_EXIT after successful SQL, failed SQL, \! true, \! false
* \connect clears ROW_COUNT and SHELL_EXIT
* --help=variables lists PROMPT_COMMAND, PROMPT_SESSION_EXPORT,
SHELL_EXIT

Interactive (IO::Pty + readline, same pattern as t/010 / t/030):
* PROMPT_COMMAND + %D in PROMPT1
* first line only of multi-line PROMPT_COMMAND stdout
* %D empty when PROMPT_COMMAND unset
* PROMPT_SESSION_EXPORT off → PSQL_TXN / PSQL_SUPERUSER not exported
* PROMPT_SESSION_EXPORT on → PSQL_TXN / PSQL_SUPERUSER exported
* PROMPT_COMMAND does not overwrite SHELL_EXIT after a failed SQL

Manual still useful for visual / powerline end-to-end; automation no longer
depends on it for the core knobs.

========================================================================
v2 patch notes
========================================================================

Relative to the original submission:

* Added src/bin/psql/t/040_prompt_command.pl
* Listed that test in src/bin/psql/meson.build
* No intentional functional change to the feature code

Happy to rename variables, drop PROMPT_SESSION_EXPORT from v1, or further
split if that helps commit.

Companion (not part of this patch):
https://github.com/powerline/powerline/pull/2287

Fork branch:
https://github.com/bithead2k/postgres/tree/psql-prompt-command

Comments welcome.

Regards,
Kirk Roybal

Attachment Content-Type Size
0001-Add-PROMPT_COMMAND-and-dynamic-prompt-support-to-psq.patch text/x-patch 23.5 KB
0003-Add-TAP-coverage-for-PROMPT_COMMAND-and-session-expo.patch text/x-patch 9.1 KB
0002-Add-powerline-prompt-example-screenshot-to-integrati.patch text/x-patch 134.8 KB

Browse pgsql-hackers by date

  From Date Subject
Next Message Bharath Rupireddy 2026-08-04 15:55:11 Re: enhance wraparound warnings
Previous Message Álvaro Herrera 2026-08-04 15:14:43 Re: Fix a host of strto*() bugs