Repository navigation
pgwire extended protocol collapses duplicate output column names to one cell #337
Description
Activity
- addedtype:bugA defect — broken, incorrect, or lost dataA defect — broken, incorrect, or lost datastatus:needs-triageAwaiting maintainer triage (severity + priority)Awaiting maintainer triage (severity + priority)area:pgwirePostgreSQL wire protocol / client compatPostgreSQL wire protocol / client compat
on Sep 17, 2026 Triage (static review at
a89b56ddb) — root cause confirmed line-for-line; no running-server repro attempted.Chain
pgwire/handler/prepared/execute.rs:136-149builds the Describe-phaseOutputSchemawithlookup_key = display_name = f.name(); duplicate names collide there.pgwire/handler/routing/execute.rs:153-160replaces the planner's columns with those, keeping onlycp_computed— the planner'scell_keyskeys are lost.response_shape/compose/kernel.rs:60-75writes cells undercell_keys(display_names)(id,id_1) and reads them underlookup_key; after the override both reads targetid, so the second column renders the first cell (kernel.rs:149-181,project_row).
Simple-query stays correct because
planner/sql_plan_convert/output_schema/build.rs:191already deriveslookup_keys = cell_keys(columns).Fix plan
Merge at
routing/execute.rsinstead of replacing:lookup_keyfrom the planner (the single derivation),display_name/ty/is_starfrom the Describe phase,cp_computedunchanged; on arity mismatch, keep the Describe columns but derive their keys withcell_keysso writer and reader stay consistent.Tests: extended-protocol wire cases (
SELECT nextval('s'), nextval('s')→(1, 2);SELECT w.id, b.idjoin →(w1, b1)) plus a unit test pinning the merged keys (id,id_1).Severity stays as proposed (
sev:2-high) — silently wrong cells on one protocol path, stored data intact.- addedsev:2-highMajor functionality broken; no acceptable workaroundMajor functionality broken; no acceptable workaroundstatus:in-progressActively being worked onActively being worked onand removedstatus:needs-triageAwaiting maintainer triage (severity + priority)Awaiting maintainer triage (severity + priority)
on Sep 19, 2026
Version / build tested against
origin/main @ d3d73be
Deployment mode
Origin — single node (local)
Engine(s) involved
Not engine-specific / unsure
Summary
Over the extended-query protocol (Parse/Bind/Execute), a SELECT with two output columns of the same name renders one cell in both columns. The Describe phase rebuilds the result projection from the announced PG fields with
lookup_key = display_name = field name(nodedb/src/control/server/pgwire/handler/prepared/execute.rs, theOutputSchemabuilt fromstmt.result_fields). That projection overrides the planner'sOutputSchemaatnodedb/src/control/server/pgwire/handler/routing/execute.rs(shaping.projection.or(Some(&output_schema))). The shaper then reads both cells through the same key. Every producer stores cells under the unique keys fromcell_keys(response_shape/project.rs), so the second column's cell (<name>_1) is never read. The simple-query protocol uses the planner schema and is correct after #327.Found by static review of #327. Derived from the code, not reproduced on a running server.
Steps to reproduce
Expected behavior
Each output column renders its own cell on every protocol. The lookup keys come from one place: the planner's
build_output_schema, which already derives per-column unique keys viacell_keys. The Describe-built projection must not replace those keys. It can supply display names, types, and result formats only.Actual behavior
On Bind/Execute the duplicate columns both read the first stored cell (
nextval→1,1). Stored data is intact. Simple-query protocol returns the correct row.What actually happened? (check all that are true)
Workarounds: alias each column to a distinct name, or use the simple-query protocol.
Proposed severity
SEV-2 — High: major functionality broken or silently-wrong results; stored data intact
Reproducibility
Always — every attempt
Last known-good version / commit (if a regression)
Never worked. The override predates
cell_keys.Environment & logs
Linux x86_64. No server log output: the wrong row is returned without error.
Before submitting
mainbuild (not a stale local branch). — Derived from code reading atd3d73bed, not run.