Skip to content

WIP: command_tag_format — protocol-level command tag negotiation via _pq_#16

Open
NikolayS wants to merge 2720 commits into
masterfrom
command-tag-omit-oid
Open

WIP: command_tag_format — protocol-level command tag negotiation via _pq_#16
NikolayS wants to merge 2720 commits into
masterfrom
command-tag-omit-oid

Conversation

@NikolayS

@NikolayS NikolayS commented Mar 11, 2026

Copy link
Copy Markdown
Owner

(live hacking session: https://www.youtube.com/watch?v=VKuxQZlvd8E)

Adds a new protocol-level feature _pq_.command_tag_format that allows clients to negotiate richer command completion tags at connection time.

The problem

Every INSERT returns INSERT 0 N — the 0 is a vestigial OID field, hardcoded to zero since PG12 dropped table OIDs. It wastes bytes and confuses users, but changing the wire format breaks old clients.

Solution: protocol negotiation

New clients send _pq_.command_tag_format in the startup packet. Old clients never send it, so they always get legacy format. Zero breakage.

Formats

Format Output Example
legacy INSERT 0 N (default) INSERT 0 1
verbose INSERT tablename N INSERT users 1
fqn INSERT schema.tablename N INSERT public.users 1

verbose and fqn also work for UPDATE, DELETE, and MERGE.

Safety guarantees

Scenario Result
Old client + new server (no _pq_) INSERT 0 1 — always safe
New client + old server (_pq_ sent) silently ignored
SET command_tag_format = 'verbose' ERROR: cannot be changed
options=-ccommand_tag_format=verbose FATAL: cannot be changed

The GUC is PGC_INTERNAL — only the _pq_ startup packet path can set it. SET, options=-c, ALTER SYSTEM, and postgresql.conf are all blocked.

Implementation (8 files, ~115 insertions)

  • cmdtag.h / cmdtag.c — format constants, format-aware BuildQueryCompletionString
  • pquery.c — populates relation name from executor for verbose/fqn
  • backend_startup.c_pq_ handler, stores in Port->pq_command_tag_format
  • libpq-be.h — new Port field for deferred protocol option
  • postinit.c — deferred application via SetConfigOption(PGC_INTERNAL, PGC_S_OVERRIDE)
  • guc_parameters.dat / guc_tables.c — GUC registration with GUC_REPORT

NOT changed: fe-exec.c (libpq)

Old protocol is completely untouched. New-protocol-aware clients handle the new format themselves.

Evolution

  1. v1: command_tag_omit_oid — simple bool GUC (PGC_USERSET) + libpq patch
  2. v2: command_tag_format — enum with 4 modes, _pq_ negotiation, GUC_REPORT
  3. v3 (current): protocol-only — PGC_INTERNAL, removed modern mode, reverted libpq, separate Port field + PGC_S_OVERRIDE deferred application

Test results

See comment with full test evidence — 8/8 scenarios pass with both stock PG17 psql and raw _pq_ startup packet test.

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.