Skip to content

fix: serialize retvarno field in PLpgSQL RETURN/RETURN NEXT JSON output - #333

Open
pyramation wants to merge 2 commits into
pganalyze:17-latestfrom
constructive-io:fix/retvarno
Open

fix: serialize retvarno field in PLpgSQL RETURN/RETURN NEXT JSON output#333
pyramation wants to merge 2 commits into
pganalyze:17-latestfrom
constructive-io:fix/retvarno

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

Problem

The PLpgSQL_stmt_return and PLpgSQL_stmt_return_next C structs have a retvarno field — an index into the datums array identifying which variable is being returned. The parser populates this field, but the JSON serializer in pg_query_json_plpgsql.c had it commented out:

//WRITE_INT_FIELD(retvarno);

This made it impossible for downstream deparsers (e.g. pgsql-parser) to recover the variable name in RETURN NEXT variable statements. Without retvarno, a deparser sees:

{ "PLpgSQL_stmt_return_next": { "lineno": 9 } }

…and has no way to know that the original SQL was RETURN NEXT r; vs RETURN NEXT v_count;. The datums array lists all declared variables, but without retvarno there's no pointer from the RETURN NEXT statement to the specific datum.

Fix

Uncomment WRITE_INT_FIELD for retvarno in both dump_return() and dump_return_next(), using the correct 3-argument macro syntax:

WRITE_INT_FIELD(retvarno, retvarno, retvarno);

The original commented-out line only had 1 argument (//WRITE_INT_FIELD(retvarno)) which would have been a compile error — the macro requires (outname, outname_json, fldname).

Output values

retvarno value Meaning Example
≥ 0 Index into datums[] for the returned variable RETURN NEXT r;retvarno: 1datums[1].refname = "r"
-1 No variable reference; uses expr field instead RETURN v_name || '/' || v_version;

Note: WRITE_INT_FIELD has a != 0 guard, so retvarno: 0 would not be serialized. In practice this is fine — datum 0 is always the auto-created found boolean, which is never the target of RETURN/RETURN NEXT.

Backward compatibility

  • Non-breaking: adding a new JSON field is additive. JSON parsers ignore unknown keys by default.
  • No existing consumers use this field since it was never serialized before.
  • Downstream consumers should check retvarno >= 0 before using it as a datum index.

Commits

  1. test: expected JSON should include retvarno for RETURN/RETURN NEXT — updates plpgsql_samples.expected.json to include retvarno values. This test FAILS on 17-latest (proving the bug).
  2. fix: serialize retvarno field in PLpgSQL RETURN/RETURN NEXT JSON output — uncomments the serializer. All tests pass.

The PLpgSQL_stmt_return and PLpgSQL_stmt_return_next nodes have a
retvarno field that references the datum index of the variable being
returned. This field is populated by the parser but not serialized
to JSON because WRITE_INT_FIELD(retvarno) is commented out in
pg_query_json_plpgsql.c.

This test will FAIL until the serializer is fixed, proving the bug.
Uncomment WRITE_INT_FIELD(retvarno) in dump_return() and
dump_return_next() with the correct 3-argument macro syntax.

The retvarno field is an index into the datums array that identifies
which variable is being returned. It was populated by the parser but
never serialized to JSON, making it impossible for downstream
deparsers to recover the variable name in RETURN NEXT statements.
@lfittl

lfittl commented May 21, 2026

Copy link
Copy Markdown
Member

@pyramation Thanks for the PR! I think this makes sense, but the way I'd like to fix this is to auto-generate the output functions (#323), which is on my short-list for a follow-up release after the Postgres 18 release (which I just tagged, finally).

@pyramation

Copy link
Copy Markdown
Contributor Author

cool sounds good! whatever is best :)

@pyramation

Copy link
Copy Markdown
Contributor Author

and btw, thanks for the Postgres 18 release! Just released the the first downstream package https://github.com/constructive-io/libpg-query-node and now going to continue to https://github.com/constructive-io/pgsql-parser for the full toolset :)

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.

2 participants