Skip to content

perf(ast): fix release-path defects and stop ReleaseAST pooling node types the parser never draws (#555, #556) - #581

Merged
ajitpratap0 merged 7 commits into
mainfrom
perf/ast-pool-release-fixes
Oct 11, 2026
Merged

ajitpratap0 merged 7 commits into
mainfrom
perf/ast-pool-release-fixes

Conversation

@ajitpratap0

Copy link
Copy Markdown
Owner

Summary

#555 perf(ast): fix release-path defects: double Put via JoinClause.Left, incomplete node reset, unbounded work-queue clearing

Fixes three defects in the AST release path (#555): PutSelectStatement no longer releases through Joins[i].Left (a non-owning value copy of From[0]), which previously Put the derived-table subquery twice and made two later GetSelectStatement calls return the same object; every pooled expression node is now reset by whole-struct assignment (keeping only hot slice capacity) and FunctionCall's Over/Filter/OrderBy/WithinGroup plus the children of Rollup/Cube/GroupingSets/NamedArgument/VariantPath are released instead of dropped; the PutExpression work queue is cleared only to its high-water mark, queues with cap > 1024 are not returned to the pool, and Identifier/LiteralValue take a queue-free fast path. Measured effect (benchstat, count=6): PutLeafAfterBigList 2995ns -> 19ns and PutBinaryAfterBigList 3183ns -> 47ns, both now within 1.1x of the no-big-list case; allocs/op and B/op are unchanged on every benchmark. Validated independently: race gate green across 44 packages, golangci-lint 0 issues, no exported API change, and the new regression tests fail on the pre-fix code and pass on this branch. CHANGELOG.md and performance_baselines.json are intentionally left for the consolidated follow-up PR.

#556 perf(ast): stop ReleaseAST Putting node types the parser never draws from (or make the parser draw them)

ReleaseAST/ReleaseStatements now thread an unexported releaseMode through the unchanged release walk and Put only the node types the parser actually draws (Tuple/ArrayConstructor/ArraySubscript/ArraySlice; Unsupported/Alter/Show/Describe/Replace/sequence statements), leaving Identifier/LiteralValue/BinaryExpression/FunctionCall and Select/Insert/Update/Delete to the GC; the exported Put* functions keep full releaseAll semantics and the exported API is byte-identical (542 go doc func lines). This is the issue's recommended option (b); option (a), having the parser draw hot node types from pools, remains a possible follow-up now that #555 made the pools safe. Independent validation ran the repository race gate (44 packages, 0 failures), vet/lint clean, and a 221-input corpus contamination test (176 parsed, 4,408 sequential + 3,200 concurrent parse -> ReleaseAST -> parse pairs compared against untouched-pool reference dumps, plus 10k+ drawn-pool Gets with no double Put), all passing with and without -race. A drawn-only policy test and the new repo policy tests pass on HEAD and fail on the parent commit 3facfca. DDL statements and the query inside CREATE VIEW / CREATE MATERIALIZED VIEW (and MERGE) are still fully recycled by their Put* functions, as the docs state.

Commits (3), one per issue:

9 files changed, 1638 insertions(+), 343 deletions(-)

Test Plan

  • Independent validator ran the repository race gate (CGO_ENABLED=1 go test -race -timeout 120s $(go list ./... | grep -v /cbinding)), go vet, and golangci-lint on this branch.
  • Each change was reviewed by an independent reviewer with access to the code and benchmarks before validation.
  • Benchmarks compared with benchstat -count=6 before/after on the same machine; allocs/op and B/op are the deterministic signal, ns/op is directional on a loaded machine.

#555 benchstat

benchstat before.txt after.txt (count=6, Apple M4, load avg 13-20 during runs):
sec/op: PutLeafAfterBigList 2995.00n -> 19.10n (-99.36%, p=0.002); PutBinaryAfterBigList 3183.00n -> 47.33n (-98.51%, p=0.002); PutBinary 183.88n -> 44.46n (-75.82%); PutExpression/PutIdentifier 39.90n -> 23.46n (-41.21%); PutLeaf 46.34n -> 25.65n (~, p=0.065). PutLeafAfterBigList/PutLeaf = 0.74x and PutBinaryAfterBigList/PutBinary = 1.06x (criterion: within 2x). Apparent slowdowns in the noisy run (ASTPool +171%, IdentifierPool +93%, BinaryExpressionPool +76%, Parallel +80%) do not reproduce in the interleaved A/B run (ab_old.txt vs ab_new.txt, n=8): all ~ with p>0.19 and new medians lower; PutExpression/PutIdentifier -82.5% and PutLeaf -72% there.
B/op: unchanged on every benchmark (PutLeaf, PutLeafAfterBigList, PutBinary, PutBinaryAfterBigList, ASTPool, IdentifierPool, PutExpression/* all 0 B; SelectStatementPool 317->327.5 B ~ p=0.331; BinaryExpressionPool 148.5->146.5 ~; Parallel 316.5->317.5 ~).
allocs/op: identical on every benchmark (0 for all Put*/ASTPool/IdentifierPool/PutExpression; 4 for SelectStatementPool and Parallel; 2 for BinaryExpressionPool).
Out-of-tree repro (scratchpad/fix/555/repro, replace -> worktree): TestDoublePut PASS (Get#0/#1/#2 distinct), TestStaleState PASS, TestBigListSlowdown ratio=1.0x (15ns vs 15ns).
Parser TestPerformanceRegression (plan sanity item, not an acceptance criterion): FAILs under load 13-15 but readings swing 2x between consecutive runs (SimpleSelect 1279/692/1180 ns; INSERT -22.8%/+42%/+38.7%); the test calls no Put*/Release*/pool function and the diff changes only release paths, so this is machine noise, not a regression from this branch.

#555 race gate: cd /Users/ajitpratapsingh/dev/GoSQLX-worktrees/perf-ast-pool-release-fixes && CGO_ENABLED=1 go test -count=1 -race -timeout 120s $(go list ./... | grep -v /cbinding) -> exit 0; 44 packages ok, 0 FAIL, no DATA RACE/panic lines (output saved to scratchpad/fix/555/validator_race2.txt). Targeted -race -v run of the new tests also green: TestReleaseAST_DerivedTableJoin_NoDoublePut, TestPutSelectStatement_HandBuilt_LeftAliasFrom, TestPutExpression_ResetsEveryField_Reflective, TestPutExpression_FunctionCall_ReleasesOverFilterOrderBy, TestPutExpression_UnpooledParents_ReleaseChildren, TestPutExpressi
#556 benchstat

benchstat (implementer n=6 and validator 3facfca-vs-HEAD n=4 agree):
allocs/op: identical in every row (ParseRelease SampleJoin 25/23, MediumCTE 123/121, DrawnTypes 38/27; ReleaseASTOnly 0; ParserComplexity 34/217/2020/25/15; exported Put* benchmarks unchanged).
B/op: ReleaseASTOnly SampleJoin 243 -> 24 (-90.1%), MediumCTE 1399 -> 39 (-97.2%), DrawnTypes 547 -> 207 (-62.2%); ParseRelease/Release SampleJoin 3.633Ki -> 3.457Ki (-4.8%), MediumCTE 17.04Ki -> 15.60Ki (-8.5%), DrawnTypes 4.607Ki -> 4.270Ki (-7.3%); NoRelease rows and ParserComplexity identical.
ns/op: ReleaseASTOnly -47.9% / -45.7% / -33.5%; ParseRelease/Release -14.3% / -17.6% / -15.0%; untouched paths within noise.
Race gate: CGO_ENABLED=1 go test -race -timeout 120s $(go list ./... | grep -v /cbinding) -> 44 packages ok, 0 FAIL, 0 DATA RACE. go vet clean, golangci-lint 0 issues.

#556 race gate: full race gate passed (see notes)

Breaking Changes

  • perf(ast): fix release-path defects: double Put via JoinClause.Left, incomplete node reset, unbounded work-queue clearing #555: none — no exported signature, type, or constant changes. Observable behaviour changes are all tightenings toward the documented contract: (a) pooled nodes returned by Get* are now fully zero (previously Not/CustomOp/Pos/Table/Try/NullTreatment/OrderBy/WithinGroup/Parameters could be stale); (b) typed PutX wrappers now release nested subtrees (FunctionCall.Over/Filter/OrderBy/WithinGroup) instead of dropping them; (c) PutExpression now releases pooled children reachable through RollupExpression, CubeExpression, GroupingSetsExpression, NamedArgument and VariantPath (parents remain GC-owned, no new pools); (d) PutSelectStatement no longer releases through Joins[i].Left (documented as a non-owning copy) and zeroes the whole JoinClause including Pos; (e) Select/Insert/Update/Delete Pos is reset on Put; (f) AST.Comments elements are cleared on ReleaseAST; (g) work queues with cap > 1024 are no longer returned to the pool (unexported constant maxPooledWorkQueueCap). No breaking changes; no CHANGELOG edit per ground rules (note the above in the PR description for the consolidated changelog PR).
  • perf(ast): stop ReleaseAST Putting node types the parser never draws from (or make the parser draw them) #556: No exported signature changes and no removals. ReleaseAST and ReleaseStatements change observable pool behaviour only: they continue to return the AST container and every node type the parser draws from pools (TupleExpression, ArrayConstructorExpression, ArraySubscriptExpression, ArraySliceExpression, UnsupportedStatement, AlterStatement, ShowStatement, DescribeStatement, ReplaceStatement, sequence statements, plus DDL statements via their unchanged Put* functions), but no longer Put Identifier, LiteralValue, BinaryExpression, FunctionCall, AliasedExpression, Case/In/Between/Cast/Subquery/Unary/Exists/Any/All/List/Extract/Position/Substring/Interval expressions or Select/Insert/Update/Delete statements; those become garbage. All exported Get*/Put* functions (PutExpression, PutIdentifier, PutSelectStatement, ...) keep full semantics and remain the documented way to recycle hand-built trees. Handled by godoc updates on ReleaseAST, ReleaseStatements, PutExpression and doc.go, and by tests that pin both contracts. Not a breaking change: nothing stops compiling, no leaks, no double Put; only pool hit rates for hand-built undrawn nodes released through ReleaseAST drop, which the issue explicitly accepts. Internal additions: unexported releaseMode type, releaseExpression, releaseSelect/Insert/Update/DeleteStatement, and a mode parameter on putExpressionImpl, releaseStatement, releaseTableReference, releaseTimeTravelClause.

Notes

Fixes #555
Fixes #556
Part of #566

🤖 Generated with Claude Code

https://claude.ai/code/session_01UZSk1292jPc8ipDboNxeve

Ajit Pratap Singh and others added 3 commits October 11, 2026 11:40
…#555)

Three defects in the AST release path:

1. Double Put on derived-table JOINs. The parser builds Joins[0].Left as a
   value copy of From[0], so PutSelectStatement released the derived-table
   subquery twice and two later GetSelectStatement calls returned the same
   object. Joins[i].Left is now documented as non-owning and is never
   released; the whole JoinClause is zeroed (also clearing Pos).

2. Incomplete resets. Pooled nodes came back with stale Not/CustomOp/Pos
   (BinaryExpression), Table/Pos (Identifier), NullTreatment/OrderBy/
   WithinGroup/Pos (FunctionCall), Try (CastExpression), etc., and
   FunctionCall.Over/Filter/OrderBy/WithinGroup children were dropped
   unreleased. Every loop case now pushes all children and resets the node
   with a whole-struct assignment that keeps only hot slice capacity. The
   standalone PutX wrappers delegate to PutExpression so there is a single
   reset path. Pooled children of Rollup/Cube/GroupingSets/NamedArgument/
   VariantPath (no pool of their own) are released and detached.
   Select/Insert/Update/Delete reset Pos; ReleaseAST clears Comments.

3. Work-queue pinning. putExpressionImpl cleared workQueue[:cap] on every
   call and returned queues of any size to the pool, so after one
   20,000-element IN list every later Put paid for clearing it. It now
   clears only up to the high-water mark, drops queues with cap > 1024
   (maxPooledWorkQueueCap), and Identifier/LiteralValue take a leaf fast
   path that skips the queue.

benchstat (count=6, Apple M4, shared noisy machine; allocs/op and B/op
unchanged for every benchmark, all new benchmarks 0 allocs/op, 0 B/op):
  PutLeafAfterBigList     2995ns -> 19.1ns  (-99.4%)
  PutBinaryAfterBigList   3183ns -> 47.3ns  (-98.5%)
  PutExpression/PutIdentifier 39.9ns -> 23.5ns (-41%)
An interleaved old/new A/B run shows no significant ns/op change on
ASTPool, SelectStatementPool, IdentifierPool, BinaryExpressionPool or
Parallel.

Fixes #555

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UZSk1292jPc8ipDboNxeve
…from (#556)

ReleaseAST walked every tree and Put each Identifier, LiteralValue,
BinaryExpression, FunctionCall, AliasedExpression, Case/In/Between/...
expression and Select/Insert/Update/Delete statement into its sync.Pool,
although the parser builds all of them as heap literals and never Gets
them. Those pools only ever received objects, so release was pure cost
(tree walk, resets, Puts and poolChain growth).

An unexported releaseMode is now threaded through the existing walk:

- releaseAll: used by the exported Put* functions (PutExpression,
  PutSelectStatement, PutInsert/Update/DeleteStatement, ...). Unchanged
  semantics: every reachable pooled node is reset and Put.
- releaseDrawn: used by ReleaseAST and ReleaseStatements. The walk and
  child pushes are byte-identical (pooled Tuple/ArrayConstructor/
  ArraySubscript/ArraySlice nodes can be nested under any parent, and the
  work-queue/overflow-drain invariants from #555 are kept), but only the
  types the parser draws are reset and Put: those four expressions plus
  Unsupported/Alter/Show/Describe/Replace/sequence and the other DDL
  statements (releaseStatement cases untouched). Identifier/LiteralValue
  leaves return immediately; Select/Insert/Update/Delete fields are still
  cleared but the statement itself is left to the GC.

No exported signature changes (go doc func list identical). Godoc on
ReleaseAST, ReleaseStatements, PutExpression and doc.go documents the
policy and that hand-built trees should be released with Put*.
TestReleaseAST_DerivedTableJoin_NoDoublePut now passes trivially on the
ReleaseAST path because SelectStatements are no longer Put there; the
hand-built PutSelectStatement path still guards #555.

Tests: pool_release_policy_test.go pins both contracts (drawn nodes reset
and undrawn left alone after ReleaseAST; undrawn pointers never come back
from Get*; hand-built trees under ReleaseAST vs PutSelectStatement /
PutExpression; drawn-pool contamination across different tuple/array
arities compared with a fresh parse). Benchmarks BenchmarkParseRelease
and BenchmarkReleaseASTOnly added.

benchstat (count=6, Apple M4; allocs/op and B/op are the hard signal):
  ReleaseASTOnly/SampleJoin   242 -> 24 B/op (-90%), 155ns -> 81ns (-48%)
  ReleaseASTOnly/MediumCTE   1399 -> 39 B/op (-97%), 768ns -> 391ns (-49%)
  ReleaseASTOnly/DrawnTypes   551 -> 209 B/op (-62%)
  ParseRelease/SampleJoin/Release  3.632Ki -> 3.458Ki (-4.8%)
  ParseRelease/MediumCTE/Release   17.02Ki -> 15.60Ki (-8.3%), -22% ns/op
  ParseRelease/DrawnTypes/Release  4.604Ki -> 4.270Ki (-7.3%), -19% ns/op
  allocs/op unchanged everywhere (MediumCTE/Release 122 -> 121);
  NoRelease rows, exported Put* benchmarks and BenchmarkParserComplexity
  unchanged in B/op and allocs/op. DrawnTypes still benefits from pooling
  (27 allocs with release vs 38 without).

Fixes #556

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UZSk1292jPc8ipDboNxeve
…nger double-Put test

Reword the ReleaseAST and package docs to list exactly which types
ReleaseAST Puts, and to state that DDL statements and the query inside
CREATE VIEW / CREATE MATERIALIZED VIEW are still fully recycled by their
Put* functions. Document the shared-parent hazard in putExpressionImpl.
Extend TestReleaseAST_DerivedTableJoin_NoDoublePut with ARRAY and tuple
expressions and assert the ArrayConstructor and Tuple pools never hand
out the same pointer twice.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UZSk1292jPc8ipDboNxeve
@vercel

vercel Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
gosqlx-website Ready Ready Preview Oct 11, 2026 6:41pm UTC

@github-actions

github-actions Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 30s —— View job


Review of PR #581 (AST pool release fixes, #555 and #556)

I read the pool.go, pool_expression_release.go and pool_statement_release.go diffs. I did not run the tests, benchmarks or race gate. The sandbox has no merge base for origin/main, so I diffed against HEAD~3. I also did not read the test files closely.

Overall: The design is sound and the invariants are well documented. I found no blocking issues.

What looks good

  • Double Put fix: Not releasing through JoinClause.Left is correct, because Left is a non-owning copy of From[0]. The doc comment added in ast_clauses.go records that contract.
  • Whole-struct reset: *e = T{...}, keeping only hot slice capacity, removes the stale-field class of bugs. Clearing the kept slices first with clear(args) also avoids pinning pointers.
  • High-water-mark clearing:
    • hw is updated at the end of each loop iteration, after all appends. Pops only happen at the start of an iteration, so hw is the true maximum length.
    • The deferred clear(workQueue[:hw]) runs after the overflow drain, so it covers everything.
    • Dropping queues with cap > 1024 fixes the pinning problem.
  • releaseMode: Sharing a single walk between releaseAll and releaseDrawn keeps nested drawn nodes reachable under un-drawn parents. This is better than maintaining two walkers.

Suggestions and risks (non-blocking)

  1. Drawn-type list can drift from the parser.
    • The releaseDrawn list (Tuple, ArrayConstructor, ArraySubscript, ArraySlice, and the Unsupported/Alter/Show/Describe/Replace/sequence statements) is hand-maintained. The comment says it must stay in sync with the parser's Get* calls.
    • If someone makes the parser draw a new type and forgets this switch, the result is silent pool growth or loss, not a failure.
    • I'd add a test that scans pkg/sql/parser for ast.Get* and ast.New*Statement calls and compares them against the policy list. If pool_release_policy_test.go already does this, ignore this point.
  2. Latent double Put in releaseDrawn.
    • The hazard is documented in the putExpressionImpl comment. If a shared parent such as a named window or a reused expression is reachable twice, its drawn children are Put twice. Un-drawn parents are not reset, so nothing marks them as visited.
    • It is safe today. A cheap guard would be to have the policy test parse a corpus and assert that no drawn node is reachable twice. The PR mentions a 221-input corpus test, so this may already be covered.
  3. Overflow drain with MaxCleanupDepth. At depth ≥ 100 the code accepts the leak and only bumps poolLeakCount. That is fine, but the overflow path now clears and returns queues differently, so confirm a test exercises it with more than MaxWorkQueueSize nodes in both modes.
  4. Observable behaviour change for hand-built trees. After ReleaseAST, Identifier, BinaryExpression and Select nodes are no longer recycled. This is documented, but anyone who built trees with GetBinaryExpression() and relied on ReleaseAST to recycle them will lose pool hits. The doc.go note helps. A one-line mention in the consolidated CHANGELOG PR would help more.
  5. Benchmark claims. The ns/op numbers come from a loaded machine. B/op and allocs/op are the reliable signal, and they match the claim of no allocation regressions. Given the noise, I would not update performance_baselines.json from the ns/op figures.

Process notes

Verdict: Approve-worthy once CI is green, including task test:race. Items 1 and 3 are the two I'd double-check.
· branch perf/ast-pool-release-fixes

Ajit Pratap Singh and others added 2 commits October 11, 2026 23:52
…ow paths

Add TestReleaseDrawnPolicy_MatchesParser, which parses pkg/sql/parser with
go/parser and compares the pool constructors it references with the new
releaseDrawnConstructors list, plus a behavioural check that every listed
type is reset in releaseDrawn mode.

Add overflow tests for both release modes: trees above MaxWorkQueueSize,
the MaxCleanupDepth truncation (via putExpressionBounded, which takes the
budget and depth as parameters; production callers pass the constants),
and subquery nesting far deeper than MaxCleanupDepth. They assert no
panic, reset pooled nodes, no oversized pooled work queue, and the exact
leak-counter delta.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 14s —— View job


Review of PR #581 (AST pool release fixes, #555 and #556)

I read the test file list and the earlier diff review. I did not run the tests, benchmarks or race gate in this pass.

Update since the previous review: the latest commit (ec610ed) adds the two tests I asked for.

  • Parser drift (previous item 1): TestReleaseDrawnPolicy_MatchesParser and TestReleaseDrawnPolicy_EveryListedTypeIsReleased in pool_drawn_policy_test.go now guard the drawn-type list against the parser.
  • Overflow paths (previous item 3): pool_release_overflow_test.go adds WorkQueueBudget, DrawnNodesResetAcrossOverflow, DepthLimit and NestedSubqueries.

Overall: The design is sound, the invariants are documented, and I found no blocking issues. Both of my earlier concerns are covered by tests.

Remaining non-blocking notes

  1. Double Put under releaseDrawn: TestReleaseAST_DrawnPoolNoContamination covers this for the corpus. A hand-built tree that shares a drawn child under two un-drawn parents would still double Put it. The code comment documents this. Consider one explicit test that pins the behavior.
  2. Behavior change for hand-built trees: ReleaseAST no longer recycles Identifier, BinaryExpression or Select nodes. Please put this in the consolidated CHANGELOG PR under the breaking-changes or behavior-change heading, and land that PR before the next release.
  3. Benchmarks: ns/op was measured on a loaded machine. B/op and allocs/op are the reliable signal. I would not update performance_baselines.json from the ns/op figures.
  4. PR description: the perf(ast): fix release-path defects: double Put via JoinClause.Left, incomplete node reset, unbounded work-queue clearing #555 race-gate line is truncated, and the perf(ast): stop ReleaseAST Putting node types the parser never draws from (or make the parser draw them) #556 gate says "see notes". Both are cosmetic.

Verdict: Approve-worthy once CI is green, including task test:race.
· branch perf/ast-pool-release-fixes

@github-actions

github-actions Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 14s —— View job


Review of PR #581 (AST pool release fixes, #555 and #556)

I did not run the tests, benchmarks or race gate in this pass. The sandbox denied go test. This is based on the earlier diff reviews and the changed-file list.

Overall: The design is sound and the invariants are documented. I found no blocking issues. The parser-drift and overflow tests from ec610ed cover the two main concerns from the earlier reviews.

What looks good

  • PutSelectStatement no longer releases through Joins[i].Left, which is a non-owning copy of From[0]. This fixes the double Put.
  • Whole-struct reset (*e = T{...}, keeping only hot slice capacity) removes the stale-field class of bugs.
  • The work queue is cleared only to its high-water mark, and queues with cap > 1024 are not returned to the pool. This fixes the pinning problem.
  • releaseMode shares a single walk between releaseAll and releaseDrawn, so nested drawn nodes stay reachable under un-drawn parents.
  • The exported API is unchanged.

Non-blocking suggestions

  1. Shared drawn child in a hand-built tree. releaseDrawn does not reset un-drawn parents, so a drawn child shared under two such parents would be Put twice. The code comment documents this. One explicit test would pin the behaviour.
  2. Behaviour change for hand-built trees. ReleaseAST no longer recycles Identifier, BinaryExpression, Select and similar nodes. Please list this under behaviour changes in the consolidated CHANGELOG PR, and land that PR before the next release.
  3. Benchmarks. The ns/op figures come from a loaded machine. B/op and allocs/op are the reliable signal. I would not update performance_baselines.json from the ns/op numbers.
  4. PR description. The perf(ast): fix release-path defects: double Put via JoinClause.Left, incomplete node reset, unbounded work-queue clearing #555 race-gate line is truncated, and the perf(ast): stop ReleaseAST Putting node types the parser never draws from (or make the parser draw them) #556 gate says "see notes". Both are cosmetic.

Verdict: Approve-worthy once CI is green, including task test:race.
· branch perf/ast-pool-release-fixes

The list has no production use, so golangci-lint's unused check failed
on it. Keep it next to the test that compares it with the parser.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 16s —— View job


Re-review of PR #581 after 74a9567

I reviewed the latest commit's diff only. I did not run tests, benchmarks or the race gate.

Latest commit (74a9567)

  • It moves releaseDrawnConstructors from pool_expression_release.go into pool_drawn_policy_test.go. The variable's only consumer is the test, so keeping it out of production code is a good change.
  • The releaseDrawn doc comment and the test failure message now point at the new location.
  • The list contents are unchanged: 9 Get* constructors and 3 New*SequenceStatement constructors.
  • Trade-off: the drift guard is now less visible to someone editing putExpressionImpl or releaseStatement. The releaseDrawn constant's doc comment mentions the test file, which mostly covers this.

Nits

  1. In pool_drawn_policy_test.go, the new comment's line "...use: TestReleaseDrawnPolicy_MatchesParser compares ..." is much longer than the other lines. Please re-wrap it.
  2. The commit also changes .claude/settings.json by swapping the qodo-skills plugin for qodo and reordering. It has nothing to do with this PR. Drop it, or confirm it is intended.
  3. The "Notes" in the PR description say CHANGELOG.md and performance_baselines.json are untouched. That is fine. Please list the behaviour change for hand-built trees in the consolidated PR: ReleaseAST no longer recycles Identifier, BinaryExpression, Select and similar nodes.

Carried over from earlier reviews (non-blocking)

  • A hand-built tree that shares a drawn child under two un-drawn parents would be Put twice in releaseDrawn mode. The code documents this. One explicit test would pin the behaviour.
  • Use B/op and allocs/op for the benchmark claims. Do not update performance_baselines.json from the loaded-machine ns/op numbers.

Verdict: No blocking issues. Approve-worthy once CI is green, including task test:race.
· branch perf/ast-pool-release-fixes

@ajitpratap0
ajitpratap0 merged commit 0465ae7 into main Oct 11, 2026
28 checks passed
ajitpratap0 added a commit that referenced this pull request Oct 13, 2026
)

The second merge commit in PR #526 (b8a1924, "Merge remote-tracking
branch 'origin/main' into HEAD") resolved a conflict by truncating
CHANGELOG.md to zero bytes, dropping all 1,825 lines of release history.
Nothing since has touched the file, so main has shipped with an empty
changelog since 2026-10-10.

Restore the file to its last good state (acc3d23, which already carries
the #525 "Fixed" entry) and re-add the "Added" entry for the --dialect
CLI flag that PR #526's own feature commit (4d75b95) contributed but the
merge lost.

Entries for the perf PRs merged since (#568-#578, #581) are deliberately
left for the consolidated changelog/baselines follow-up tracked in #566.


Claude-Session: https://claude.ai/code/session_01UZSk1292jPc8ipDboNxeve

Co-authored-by: Ajit Pratap Singh <ajitpratapsingh@Ajits-Mac-mini-2655.local>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
ajitpratap0 added a commit that referenced this pull request Oct 14, 2026
…resh performance baselines (#566)

CHANGELOG [Unreleased] now covers every PR merged since v1.14.0, with a
Behavior changes section for the observable changes in #597, #595, #584,
#585, #588, #581, #582/#570, #517/#518 and #511, plus Added, Changed,
Fixed, Performance, Security and Internal entries. The two existing
entries (#526 and the tokenizer-pool dialect fix) are kept verbatim.

performance_baselines.json is re-measured on an Apple M4 with
BenchmarkPerformanceBaseline -count=10 -benchmem (median). Baselines are
set at about 2.5x the M4 median rather than 1.5x: the CI Benchmark job on
ubuntu-latest measures these queries about 1.5-3.2x slower than M4 (last
9 Tests runs on main, 0715bb9..61ca6c8), so 1.5x with the unchanged
tolerances would fail CI's slowest runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UZSk1292jPc8ipDboNxeve
ajitpratap0 added a commit that referenced this pull request Oct 14, 2026
…xes; refresh performance baselines (#566) (#598)

* docs: consolidate CHANGELOG for the perf audit and batch-2 fixes; refresh performance baselines (#566)

CHANGELOG [Unreleased] now covers every PR merged since v1.14.0, with a
Behavior changes section for the observable changes in #597, #595, #584,
#585, #588, #581, #582/#570, #517/#518 and #511, plus Added, Changed,
Fixed, Performance, Security and Internal entries. The two existing
entries (#526 and the tokenizer-pool dialect fix) are kept verbatim.

performance_baselines.json is re-measured on an Apple M4 with
BenchmarkPerformanceBaseline -count=10 -benchmem (median). Baselines are
set at about 2.5x the M4 median rather than 1.5x: the CI Benchmark job on
ubuntu-latest measures these queries about 1.5-3.2x slower than M4 (last
9 Tests runs on main, 0715bb9..61ca6c8), so 1.5x with the unchanged
tolerances would fail CI's slowest runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UZSk1292jPc8ipDboNxeve

* docs(changelog): add batch-3 follow-up fixes (#599-#620)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UZSk1292jPc8ipDboNxeve

* docs(changelog): record #632 render-injection hardening and #624 quote guards

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UZSk1292jPc8ipDboNxeve

* docs(changelog): correct batch-3 entries after review; record measured costs

- #628: SQLite still rejects count(*) [cnt]; only SQL Server keeps it.
- #631: bare FORMAT / FORMAT <name> rules apply after SETTINGS.
- Performance: record the measured costs of the batch-3 correctness fixes
  (Identifier and TableReference growth, quoting in SQL(), lineStarts
  reallocation, sorted Extract results).
- #632: note the lıke, WITH CHECK OPTION and MINUS rendering changes.
- Fix the [Unreleased] compare link (v1.14.0...HEAD) and add [1.14.0].
- Keep each section a single tight list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UZSk1292jPc8ipDboNxeve

* docs(changelog): describe the release as source-compatible with runtime behaviour changes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UZSk1292jPc8ipDboNxeve

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — 74a95677 Deployed Oct 11, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

1 participant