Skip to content

Milestones 10 and 11: Summary and PL/pgSQL — every entry point implemented, corpus at 100% - #8

Merged
kyleconroy merged 5 commits into
mainfrom
claude/milestones-10-11-070yw3
Aug 17, 2026
Merged

Milestones 10 and 11: Summary and PL/pgSQL — every entry point implemented, corpus at 100%#8
kyleconroy merged 5 commits into
mainfrom
claude/milestones-10-11-070yw3

Conversation

@kyleconroy

Copy link
Copy Markdown
Contributor

Lands the last two entry points of the pg_query_go API surface. Every public function is now implemented, and the corpus todo list is empty across all eleven suites: 2,067 golden files / 308,561 cases, all passing (including under -race).

Corpus first (7b53c48)

The milestone-2 deferrals land as their own commit, so the acceptance gates exist before the ports:

  • summary — postgres_regress + plpgsql_regress untruncated, plus libpg_query's summary test-call inputs. Upstream's summary tests are call sites rather than tests[] tables, so cmd/regenerate grew a mechanical call extractor (summary("...", 0, limit), C line splices removed); inputs are transcribed mechanically, expectations always from the oracle.
  • summary_truncate — the same regress statements at limit 100, the upstream truncate tests at their exact limits, and every summary input at limit 50. The limit rides along as a -- truncate_limit: N directive line in the case input, stripped identically by regenerate and the harness.
  • plpgsqlplpgsql_regress/ + plpgsql_samples.sql, one ParsePlPgSqlToJSON golden per statement. The plpgsql_regress files also feed the five standard SQL suites; all of those passed the existing implementation on arrival.

Goldens verified byte-identical across regeneration runs, before and after the ports.

Milestone 10: Summary (1d0bb54)

internal/summary ports pg_query_summary.c, ..._statement_type.c, and ..._truncate.c over a faithful raw_expression_tree_walker (PostgreSQL 17 nodeFuncs.c, gated by pg_query_raw_tree_walker_supports). The quirks the goldens encode are preserved deliberately: WHERE clauses are walked twice (functions there recorded once per pass), the filter-column pass aborts at sub-SELECTs, MERGE ... USING sources are never tables, and list nodes count as depth levels in the truncation walk. Truncation tie-ordering needed the exact pg_qsort algorithm again — list_sort maps to it at the pin, so equal (depth, length) pairs are ordered by the partition scheme, not the comparator. pg_query_go's summary_test.go is ported verbatim (import swap only).

Milestone 11: PL/pgSQL (eca5f82)

internal/plpgsql ports what libpg_query builds, not vanilla PostgreSQL — extract_source.rb's mocks are the authority: parse_datatype keeps the type text verbatim (no catalog round trip), %TYPE/%ROWTYPE lookups return NULL, make_return_stmt drops the return-type checks, and function_parse_error_transpose always fails, so compile errors carry the compilation of PL/pgSQL function "f" near line N context and no cursor.

  • The pl scanner layers on the milestone-3 lexer: the core scanner's PL-reserved keyword list is modeled by re-classifying the SQL lexer's output, plus the pushback stack, A.B.C datum composition, and the statement-start/unreserved-keyword logic.
  • pl_gram.y became recursive descent with statement linenos computed at bison's exact reduce points — plpgsql_latest_lineno is stateful and feeds the error context, so call order is part of conformance.
  • internal/parse gains ParseWithMode with the RAW_PARSE_PLPGSQL_EXPR and ASSIGN1..3 grammar modes (PLpgSQL_Expr / PLAssignStmt productions) for check_sql_expr's embedded-SQL validation.
  • The raw walker moves to shared internal/rawwalk; cmd/generate -plpgsql emits the keyword/errcode tables from newly vendored pl_reserved_kwlist.h / pl_unreserved_kwlist.h / plerrcodes.h.

All 690 plpgsql cases passed on the port's first corpus run, as does the ported TestParsePlPgSQL.

Docs and tooling (3d30257, 4014bd8)

PLAN.md as-built notes for milestones 10–11, README status table caught up with milestones 3–11, CLAUDE.md's generated-file list, provenance for the vendored PL reference sources, CI's generate-clean job verifying -plpgsql output, and cmd/next-test covering the three new suites.

Verification

  • go test ./... and go test -race ./... fully green; corpus at 0 todos.
  • A final full regeneration against the pinned oracle after all commits shows zero drift, so the weekly reproducibility CI job stays green.
  • Remaining roadmap (out of scope here): milestone 12 (difftest mutation fuzzing, benchmarks) and milestone 13 (sqlc integration).

🤖 Generated with Claude Code

https://claude.ai/code/session_01C5Ummi5YEg7pxk5fvRUd3U


Generated by Claude Code

claude added 5 commits August 17, 2026 04:01
Extend the oracle protocol with summary (truncation limit riding along as
a directive line in summary_truncate case inputs) and parse_plpgsql ops,
extract libpg_query's summary test calls and the plpgsql_regress +
plpgsql_samples tiers, and wire the three new suites through
cmd/regenerate, the corpus harness, and difftodo.

- postgres_regress runs summary untruncated plus summary_truncate at
  limit 100; inline summary calls keep their upstream limits and also
  run at limit 50.
- plpgsql_regress feeds the standard SQL suites too; all of those cases
  pass the existing implementation and are harvested immediately.
- Goldens verified byte-identical across two regeneration runs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5Ummi5YEg7pxk5fvRUd3U
Port pg_query_summary.c, pg_query_summary_statement_type.c, and
pg_query_summary_truncate.c into internal/summary:

- A faithful raw_expression_tree_walker (nodeFuncs.c, PostgreSQL 17)
  over the protobuf tree, gated exactly as
  pg_query_raw_tree_walker_supports allows; list nodes are walked as
  nodes so the truncation pass's depth accounting matches.
- The summary walk (tables with contexts, aliases, CTE names, functions,
  filter columns) including its quirks: WHERE clauses walked twice, the
  filter-column pass aborting at sub-SELECTs, and functions in WHERE
  clauses recorded once per pass.
- The statement-type walk (insertion-ordered set of node type names).
- Truncation: possible truncations collected with depth/length priority,
  sorted with the pg_qsort port (list_sort maps to pg_qsort at the pin,
  so tie order needs the exact algorithm), applied cumulatively against
  the milestone-9 deparser, with the multibyte-aware fallback chop.

pg_query_go's summary_test.go is ported verbatim (import swap only).
Gate: all 43,992 summary and 43,345 summary_truncate corpus cases pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5Ummi5YEg7pxk5fvRUd3U
…ToJSON

Port the PL/pgSQL support libpg_query builds at the pin:

- internal/plpgsql: pl_gram.y as recursive descent (statement linenos
  computed at bison's reduce points, since plpgsql_latest_lineno is
  stateful and feeds the compile error context), the pl_scanner.c token
  layer over the core lexer (PL reserved keywords re-classified from the
  SQL scanner's output, pushback stack, A.B.C composition), the
  pl_comp.c/pl_funcs.c subset (namespace chain, datums, recfields,
  exception conditions), pg_query_json_plpgsql.c's dump, and the
  pg_query_parse_plpgsql.c driver — including libpg_query's mocks:
  parse_datatype keeps the type text verbatim, %TYPE/%ROWTYPE lookups
  return NULL, make_return_stmt drops return-type checks, and
  function_parse_error_transpose always fails (errors carry the
  "near line N" context, no cursor).
- internal/parse: ParseWithMode with the RAW_PARSE_PLPGSQL_EXPR and
  ASSIGN1..3 grammar modes (PLpgSQL_Expr / PLAssignStmt productions),
  which check_sql_expr uses to validate embedded SQL.
- internal/rawwalk: the raw_expression_tree_walker port moves out of
  internal/summary so the driver's statement collection can share it.
- cmd/generate -plpgsql emits internal/plpgsql/tables.go from the newly
  vendored pl_reserved_kwlist.h / pl_unreserved_kwlist.h / plerrcodes.h
  (internal/reference gains those plus patched pl_gram.y, pl_scanner.c).

Gate: all 690 plpgsql corpus cases (plpgsql_regress + plpgsql_samples +
per-statement tiers) pass, as does pg_query_go's TestParsePlPgSQL; the
corpus todo list is now empty across all eleven suites — 308,561 cases.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5Ummi5YEg7pxk5fvRUd3U
PLAN.md gains the milestones 10–11 as-built notes (corpus tiers, the
libpg_query mocks the PL/pgSQL port follows, the pg_qsort tie-order
dependency in truncation, the raw-parse modes); README's status table
catches up with milestones 3–11; CLAUDE.md and internal/reference/README
cover the new generated file and vendored PL reference sources.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5Ummi5YEg7pxk5fvRUd3U
The suite order predates milestones 10-11; with it stale, a future pin
advance would put todos back on those suites that next-test silently
skips.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5Ummi5YEg7pxk5fvRUd3U
@kyleconroy
kyleconroy merged commit 6c85244 into main Aug 17, 2026
2 checks passed
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