Skip to content

perf(transpiler): skip operator retargeting when source has no retargetable construct [W7-01] - #946

Open
ajitpratap0 wants to merge 4 commits into
mainfrom
perf/w7-01-skip-retarget-ops
Open

ajitpratap0 wants to merge 4 commits into
mainfrom
perf/w7-01-skip-retarget-ops

Conversation

@ajitpratap0

@ajitpratap0 ajitpratap0 commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

Summary

Transpile ran the reflective ast.RetargetOperators walk on every statement. A new ops flag in the existing single-pass, table-driven scanSource records whether the source contains any spelling the pass rewrites or refuses (^ | & # ~ @ ? ! { $, <<, >>, ->, U&, plus conservative <-, =>, :=). When it is false the walk is skipped. No API, output or error-text change. Differential/equivalence tests (TestPrefilterEquivalence, TestTranspileDifferential, new TestOpsSkipIsSafe, TestOpsPrefilterRequiredConstructs, TestScanSourceOps) enforce it. [W7-01]

Test Plan

  • task check, task test:cbinding, go test ./pkg/compatibility/..., task goldens, staticcheck on changed packages, go vet, gofmt: all pass. (One task test:race run flaked once under heavy machine load; re-run passed.)
  • Mutation proof: removing any of ^ & # ~ @ ? ! {, the |/$ ops bits, the < pair, or the - half of -> fails at least one test. There is no separate U& scan class: U& is caught by & (the redundant U/u class was removed in 768015e).
  • Local M4 task bench:ab (layout-randomized gate, 20 layouts, loaded machine, indicative): RW pg_mysql -19.4%, mysql_pg -18.2%, mssql_pg -15.5%, pg_pg +1.2% (p=0.84, ok); allocs/op down 0.2-0.3%, B/op down. Shape small cross pairs -40..-48%, large -27..-29%, medium flat (contains ^/||). An earlier byte-switch variant of scanSource showed pg_pg +3.9..+6.6% (significant) so it was replaced by the table-driven loop.
  • CI layout-randomized gate (20 layouts, sticky comment, head 018e396): PASS, no gated metric moved, A/A' 0/52, geomean -0.03%. The gated suite has no Transpile benchmark, so this shows no regression only, not the gain.
  • amd64 matrix A/B (workflow_dispatch run 41692809755, head 3a3a4ee, 5 randlayout layouts per arm, Xeon 8370C): PASS. TranspileRW cross pairs -13.8% to -18.4% (p=0.008, the minimum attainable with 5 layouts), allocs/op down 0.2-0.9%, B/op not up; identity pairs about -1% to -2%. TranspileShape small about -28% to -35%, large about -24% to -25%, medium -3.5% to -8.4%; suite geomean -1.56%. Caveat: 5 layouts is low power, as the matrix report warns.
  • Post-merge (head a924650, merged origin/main incl. W6-03): task check, test:cbinding, compatibility and staticcheck all pass; gate re-running.

Breaking Changes

None.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DnbRnTFErhoMJdAjVEeCg2

…ntain a retargetable construct [W7-01]

scanSource gains an ops flag computed in the existing single byte pass
(table-driven); Transpile runs ast.RetargetOperators only when it is set.
Output and error text are unchanged.

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

vercel Bot commented Nov 3, 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 Nov 3, 2026 8:35pm UTC

@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

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


Review of PR #946: skip operator retargeting when source has no retargetable construct

I read the transpiler.go and retarget_operators.go changes. I did not run the test suite, and I did not read ops_prefilter_test.go in full.

Verdict: the change looks correct and the prefilter looks safe. I have a few small suggestions below.

Correctness

  • Coverage of rewritten spellings. I checked the prefilter against the spellings in retarget_operators.go and retarget_bitwise.go. The bytes ^ | & # ~ @ ? ! { $ set ops on their own. <<, >>, ->, ->>, #>, @>, <@ and U& are covered by a single-byte entry or a pair, and $ covers SQL Server money literals. Nothing I found is missed.
  • Error cases. All the refusals are triggered by the same bytes: factorial !/!!, ~, {, U& and money $. Skipping the walk can't hide an error that the walk would have raised.
  • Pair logic. In scanSource, >, - and = followed by >, < followed by < or -, : followed by =, and U/u followed by & are all handled correctly. A pair that ends at the last byte is bounds-checked.
  • Conservative direction. Every error in the prefilter makes it set ops when it didn't need to (for example !=, ? placeholders, and # comments). These cost a skipped optimisation, not correctness. != and ? are common, so they will reduce the speedup on real workloads. It would be worth reporting how often ops fires on a representative corpus.
  • Nesting guard. The comment says the 512 nesting guard can't trigger because parser.MaxRecursionDepth is 100. That relies on a constant in another package. A test that fails if MaxRecursionDepth ever exceeds the guard would stop the two from drifting apart. If one already exists in ops_prefilter_test.go, ignore this.
  • Prefilter off. !prefilter || src.ops correctly keeps the old always-run behaviour for the equivalence tests.

Performance

  • The table-driven loop does one table load per byte, and only the pair-opening bytes branch. That fits the measured result (the earlier byte-switch version regressed pg_pg).
  • U/u, -, =, <, > and : all take the pair branch. They are common letters and operators, so the branch is not free. It is cheap, though, and the benchmark numbers in the PR body cover it.

Maintainability

  • The coupling between the ast and transpiler packages is documented on both sides, and TestOpsPrefilterRequiredConstructs and the differential vocabulary enforce it. That is the right approach.
  • The U& entry is dead weight today, because & already sets ops. The PR says W7-05 will prune it, so no action is needed.
  • sourceFeatures still uses plain bools while the scan uses bit flags. The final conversion is fine.

Tests

  • Coverage looks strong: the equivalence and differential tests, a mutation-style required-constructs test, and a unit test for scanSource.
  • The PR body says the amd64 perf-gate verdict is still pending. Please confirm it passes before merging.

No blocking issues.

@github-actions github-actions Bot added documentation Improvements or additions to documentation ast AST node changes labels Nov 3, 2026
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Perf gate: PASS (shadow mode: report only, this check never fails)

Base 6d29d6802dc6, head 8a10ac01b3cd. 20 interleaved rounds, 20 randomized code layouts per arm (-randlayout seeds 417137881142..417137881161; A/A' 417137881162..417137881181), benchtime 100ms, -cpu 1, GOMEMLIMIT 64MiB, pinned to CPU 3 (SMT siblings 2-3) with taskset.

Runner CPU: AMD EPYC 7763 64-Core Processor (x86_64). Base and head ran interleaved in this job, so the tables show their ratios only; absolute timings (raw files in the artifact) hold for this CPU and this job alone and are never compared across jobs.

  • no gated metric moved past its threshold

Rules: each arm runs 20 randomized code layouts (-ldflags=-randlayout); time regresses at >= +3% when significant at a false discovery rate of 0.01 over the suite (Benjamini-Hochberg on exact Mann-Whitney U p-values of the per-layout medians, so a regression must hold across layouts, not within one binary), or a suite geomean >= +1.5% (per-layout suite geomeans, same test); allocs/op must not increase; B/op must not rise more than 2%; instructions/op must not rise more than 1.5%. The A/A' control runs the base revision under a disjoint set of layout seeds; when more than 10% of benchmarks move over 3% in it, the run is noisy: re-run once, then inconclusive (neutral).

Gated suite (GOGC=off, GOMAXPROCS=1)

benchmark time p A/A' spread B/op allocs/op status
ParseE2E/simple_select -0.36% 0.409 -0.24% 0.99% +0.00% 5 → 5 ok
ParseE2E/select_where -0.71% 0.058 +0.04% 1.78% +0.00% 18 → 18 ok
ParseE2E/join -0.16% 0.543 +0.13% 1.01% +0.00% 17 → 17 ok
ParseE2E/aggregate +0.10% 0.935 +0.09% 1.89% +0.00% 18 → 18 ok
ParseE2E/subquery -0.99% 0.035 -0.49% 1.63% +0.00% 14 → 14 ok
ParseE2E/cte -0.63% 0.262 -0.26% 1.48% +0.00% 21 → 21 ok
ParseE2E/window -0.34% 0.409 -0.31% 1.12% +0.00% 11 → 11 ok
ParseE2E/complex -1.17% 0.086 -0.99% 2.30% +0.00% 49 → 49 ok
ParseE2E/insert -0.87% 0.058 -0.78% 1.08% +0.00% 17 → 17 ok
ParseE2E/update -0.61% 0.126 -0.46% 1.25% +0.00% 13 → 13 ok
ParseE2E/delete -0.72% 0.093 -0.32% 1.31% +0.00% 5 → 5 ok
ParseRW/postgresql/medium -0.64% 0.369 -0.28% 1.21% +0.00% 646 → 646 ok
ParseRW/mysql/medium +0.01% 0.989 -0.17% 0.98% +0.00% 368 → 368 ok
ParseRW/mariadb/medium -0.06% 0.799 -0.13% 1.18% -0.00% 528 → 528 ok
ParseRW/sqlserver/medium -0.29% 0.355 -0.71% 1.19% +0.00% 927 → 927 ok
ParseRW/oracle/medium -0.53% 0.006 -0.95% 0.52% +0.00% 1090 → 1090 ok
ParseRW/sqlite/medium +0.70% 0.289 +0.05% 2.65% +0.00% 347 → 347 ok
ParseRW/snowflake/medium -0.10% 0.799 +0.22% 0.68% +0.00% 776 → 776 ok
ParseRW/clickhouse/medium -0.58% 0.640 -0.43% 3.50% +0.00% 383 → 383 ok
ParseFresh/simple_select -0.32% 0.409 +0.07% 0.96% +0.00% 6 → 6 ok
ParseFresh/join -0.92% 0.072 -0.46% 1.61% +0.00% 18 → 18 ok
ParseFresh/complex -0.30% 0.417 +0.25% 1.58% +0.00% 50 → 50 ok
PoolGetPut/serial -0.20% 0.598 -0.44% 0.80% +0.00% 0 → 0 ok
Tokenize/scratch/join +0.27% 0.675 +0.89% 2.17% +0.00% 0 → 0 ok
Tokenize/scratch/complex -0.28% 0.636 +1.11% 2.36% +0.00% 0 → 0 ok
Tokenize/scratch/insert +0.19% 0.818 -0.58% 2.25% +0.00% 0 → 0 ok
Normalize/simple_select +0.23% 0.499 -0.38% 0.91% +0.00% 7 → 7 ok
Normalize/join -0.10% 0.776 -0.39% 0.91% +0.00% 23 → 23 ok
Normalize/complex +0.32% 0.369 -0.43% 1.03% +0.00% 68 → 68 ok
TransformParse/simple_select -0.20% 0.645 -0.42% 1.39% +0.00% 5 → 5 ok
TransformParse/join -0.60% 0.056 -0.36% 0.92% +0.00% 17 → 17 ok
TransformParse/complex -1.02% 0.108 -0.62% 2.28% +0.00% 49 → 49 ok
LintParallel/rules -0.23% 0.758 -0.44% 1.38% -0.00% 158312.5 → 158312 ok
LintParallel/lint +0.06% 0.925 +0.09% 0.94% +0.00% 236892 → 236893 ok
LintRW/postgresql -0.61% 0.134 -0.14% 1.14% +0.00% 26500 → 26500 ok
LintRW/mysql -0.38% 0.414 -0.04% 0.98% -0.00% 32413 → 32413 ok
LintRW/mariadb -0.62% 0.201 +0.01% 1.44% +0.00% 29610 → 29610 ok
LintRW/sqlserver -0.52% 0.201 -0.65% 1.12% +0.00% 25622 → 25622 ok
LintRW/oracle -0.32% 0.314 -0.01% 0.67% -0.00% 31614 → 31614 ok
LintRW/sqlite -0.39% 0.583 +0.82% 2.50% +0.00% 29427 → 29427 ok
LintRW/snowflake -0.31% 0.529 -0.67% 0.78% -0.00% 28806 → 28806 ok
LintRW/clickhouse -0.90% 0.383 +1.23% 2.51% +0.00% 32891 → 32891 ok
LintRule/L007 -0.62% 0.355 -0.81% 2.37% +0.00% 1194 → 1194 ok
LintRule/L010 -0.08% 0.547 -0.02% 0.70% +0.00% 0 → 0 ok
ParseError/syntax_mid/parse -0.43% 0.194 -0.59% 1.12% +0.00% 12 → 12 ok
ParseError/syntax_mid/validate -0.50% 0.151 -0.88% 1.56% +0.00% 12 → 12 ok
ParseError/syntax_end/parse -1.29% 0.022 -1.24% 1.12% +0.00% 16 → 16 ok
ParseError/syntax_end/validate -0.96% 0.037 -0.94% 1.11% +0.00% 16 → 16 ok
ParseError/tokenize/parse -0.16% 0.839 -0.43% 2.10% +0.00% 4 → 4 ok
ParseError/tokenize/validate -0.45% 0.261 -0.44% 1.37% +0.00% 21 → 21 ok
ParseError/long_prefix/parse -0.56% 0.213 -0.01% 1.84% -0.00% 219 → 219 ok
ParseError/long_prefix/validate -1.49% 0.074 -0.55% 2.69% +0.00% 219 → 219 ok
geomean -0.42% 0.030 -0.26%

time and A/A' are Hodges-Lehmann shifts over the per-layout medians. spread: the base arm's robust standard deviation across its layouts (1.4826 x MAD, relative), i.e. how much this benchmark moves between builds that differ only in function placement, plus run-to-run noise; a change much smaller than it cannot be resolved in one run.

A/A' control (base revision, disjoint layout seeds): 0 of 52 benchmarks moved more than 3%; 0 would have been flagged by the time rule; suite geomean -0.26%, p 0.398.

Low power

1 benchmark(s) have under 80% estimated power to be flagged on their own for a +5% slowdown (their spread across layouts is too wide for 20 layouts at the Benjamini-Hochberg level alpha/m = 0.000192). A slowdown below the last column usually goes unflagged there; instructions/op, allocs/op and the suite geomean still guard them.

benchmark spread power at +5% slowdown caught 80% of the time
ParseRW/clickhouse/medium 3.50% 72% +5.3%

Power is estimated with the normal approximation for the U test (Noether): power = Phi(ln(1+shift)/s * sqrt(K/2) * sqrt(3/pi) - z(1 - alpha/(2m))), with s the spread and K the layouts per arm.

Instructions per operation (cmd/perfdriver)

case instructions/op status
e2e/aggregate +0.06% ok
e2e/complex +0.04% ok
e2e/cte +0.03% ok
e2e/delete +0.08% ok
e2e/insert +0.00% ok
e2e/join +0.03% ok
e2e/select_where -0.05% ok
e2e/simple_select +0.05% ok
e2e/subquery -0.14% ok
e2e/update +0.01% ok
e2e/window +0.10% ok
rw/postgresql/medium +0.08% ok
Secondary metric: default GC, GOMAXPROCS=1 (informational)
benchmark time p
ParseE2E/simple_select +0.43% 0.472
ParseE2E/select_where +0.91% 0.364
ParseE2E/join +0.04% 0.880
ParseE2E/aggregate -0.54% 0.199
ParseE2E/subquery -1.15% 0.247
ParseE2E/cte -1.11% 0.280
ParseE2E/window +0.43% 0.650
ParseE2E/complex -0.01% 0.971
ParseE2E/insert -0.27% 0.650
ParseE2E/update -0.16% 0.820
ParseE2E/delete -0.40% 0.739
ParseRW/postgresql/medium -0.78% 0.315
ParseRW/mysql/medium -0.30% 0.684
ParseRW/mariadb/medium +0.20% 0.796
ParseRW/sqlserver/medium +0.38% 0.631
ParseRW/oracle/medium +0.75% 0.143
ParseRW/sqlite/medium +0.45% 0.631
ParseRW/snowflake/medium +0.38% 0.631
ParseRW/clickhouse/medium +0.54% 0.631
ParseFresh/simple_select +0.10% 0.912
ParseFresh/join -0.22% 0.912
ParseFresh/complex -0.32% 0.529
PoolGetPut/serial +0.12% 0.853
Tokenize/scratch/join +0.38% 0.820
Tokenize/scratch/complex -0.00% 1.000
Tokenize/scratch/insert -0.29% 0.912
Normalize/simple_select -0.08% 0.791
Normalize/join +0.32% 0.631
Normalize/complex +0.75% 0.315
TransformParse/simple_select -0.26% 0.496
TransformParse/join +0.18% 0.796
TransformParse/complex +0.39% 0.684
LintParallel/rules +0.11% 0.853
LintParallel/lint +0.40% 0.631
LintRW/postgresql +0.13% 0.796
LintRW/mysql -0.26% 0.529
LintRW/mariadb +0.45% 0.393
LintRW/sqlserver -0.09% 0.912
LintRW/oracle +0.03% 0.971
LintRW/sqlite -0.36% 0.481
LintRW/snowflake +0.23% 0.684
LintRW/clickhouse -0.05% 1.000
LintRule/L007 +0.73% 0.393
LintRule/L010 +0.01% 1.000
ParseError/syntax_mid/parse -0.35% 0.571
ParseError/syntax_mid/validate -0.31% 0.596
ParseError/syntax_end/parse -0.67% 0.520
ParseError/syntax_end/validate +0.39% 0.597
ParseError/tokenize/parse +1.27% 0.198
ParseError/tokenize/validate +0.87% 0.241
ParseError/long_prefix/parse -0.14% 0.796
ParseError/long_prefix/validate -0.37% 0.393
geomean +0.05%
Environment
date:        2026-11-03T20:40:41Z
base:        6d29d6802dc6c910264e0d0ee4ff820a323fd2a9
head:        working tree of 8a10ac01b3cd724cd7f223c095787c5835d57284
cpu model:   AMD EPYC 7763 64-Core Processor (x86_64)
go:          go version go1.26.9 linux/amd64
kernel:      Linux 7.0.0-1017-azure x86_64
layouts:     20 per arm, -ldflags=-randlayout seeds 417137881142..417137881161 (base, head), 417137881162..417137881181 (A/A')
pinning:     pinned to CPU 3 (SMT siblings 2-3) with taskset
gcoff env:   GOGC=off GOMEMLIMIT=64MiB
clocksource: tsc
load:        9.34, 3.31, 1.20
instr count: cachegrind
perf probe:  Error: No supported events found. The instructions:u event is not supported. 

Architecture:                            x86_64
CPU(s):                                  4
Model name:                              AMD EPYC 7763 64-Core Processor
Thread(s) per core:                      2
Core(s) per socket:                      2
Socket(s):                               1
Hypervisor vendor:                       Microsoft
L1d cache:                               64 KiB (2 instances)
L1i cache:                               64 KiB (2 instances)
L2 cache:                                1 MiB (2 instances)
L3 cache:                                32 MiB (1 instance)
benchstat (primary metric, samples pooled across layouts: informational, the verdict uses the per-layout test)
goos: linux
goarch: amd64
pkg: github.com/ajitpratap0/GoSQLX/pkg/fingerprint
cpu: AMD EPYC 7763 64-Core Processor                
                        │    base     │                head                │
                        │   sec/op    │   sec/op     vs base               │
Normalize/simple_select   2.355µ ± 1%   2.358µ ± 1%       ~ (p=0.499 n=20)
Normalize/join            7.197µ ± 1%   7.192µ ± 1%       ~ (p=0.774 n=20)
Normalize/complex         19.72µ ± 1%   19.74µ ± 2%       ~ (p=0.369 n=20)
geomean                   6.939µ        6.944µ       +0.07%

                        │     base     │                 head                  │
                        │     B/op     │     B/op      vs base                 │
Normalize/simple_select     896.0 ± 0%     896.0 ± 0%       ~ (p=1.000 n=20) ¹
Normalize/join            2.211Ki ± 0%   2.211Ki ± 0%       ~ (p=1.000 n=20) ¹
Normalize/complex         6.117Ki ± 0%   6.117Ki ± 0%       ~ (p=1.000 n=20) ¹
geomean                   2.279Ki        2.279Ki       +0.00%
¹ all samples are equal

                        │    base    │                head                 │
                        │ allocs/op  │ allocs/op   vs base                 │
Normalize/simple_select   7.000 ± 0%   7.000 ± 0%       ~ (p=1.000 n=20) ¹
Normalize/join            23.00 ± 0%   23.00 ± 0%       ~ (p=1.000 n=20) ¹
Normalize/complex         68.00 ± 0%   68.00 ± 0%       ~ (p=1.000 n=20) ¹
geomean                   22.20        22.20       +0.00%
¹ all samples are equal

pkg: github.com/ajitpratap0/GoSQLX/pkg/gosqlx
                                │    base     │                head                │
                                │   sec/op    │   sec/op     vs base               │
ParseE2E/simple_select            1.646µ ± 1%   1.645µ ± 1%       ~ (p=0.409 n=20)
ParseE2E/select_where             3.458µ ± 4%   3.432µ ± 0%       ~ (p=0.057 n=20)
ParseE2E/join                     4.608µ ± 1%   4.612µ ± 1%       ~ (p=0.542 n=20)
ParseE2E/aggregate                3.454µ ± 1%   3.446µ ± 1%       ~ (p=0.931 n=20)
ParseE2E/subquery                 3.137µ ± 1%   3.125µ ± 1%       ~ (p=0.033 n=20)
ParseE2E/cte                      4.459µ ± 1%   4.455µ ± 1%       ~ (p=0.262 n=20)
ParseE2E/window                   2.920µ ± 1%   2.921µ ± 1%       ~ (p=0.410 n=20)
ParseE2E/complex                  12.30µ ± 2%   12.08µ ± 2%       ~ (p=0.086 n=20)
ParseE2E/insert                   2.189µ ± 1%   2.173µ ± 1%       ~ (p=0.057 n=20)
ParseE2E/update                   1.958µ ± 1%   1.942µ ± 1%       ~ (p=0.126 n=20)
ParseE2E/delete                   1.247µ ± 1%   1.236µ ± 1%       ~ (p=0.092 n=20)
ParseRW/postgresql/medium         170.8µ ± 1%   169.9µ ± 1%       ~ (p=0.369 n=20)
ParseRW/mysql/medium              96.55µ ± 1%   96.72µ ± 1%       ~ (p=0.989 n=20)
ParseRW/mariadb/medium            137.6µ ± 1%   137.5µ ± 1%       ~ (p=0.799 n=20)
ParseRW/sqlserver/medium          275.4µ ± 1%   275.0µ ± 1%       ~ (p=0.355 n=20)
ParseRW/oracle/medium             328.2µ ± 0%   326.7µ ± 1%  -0.48% (p=0.006 n=20)
ParseRW/sqlite/medium             73.45µ ± 2%   74.29µ ± 1%       ~ (p=0.289 n=20)
ParseRW/snowflake/medium          190.2µ ± 0%   190.3µ ± 1%       ~ (p=0.799 n=20)
ParseRW/clickhouse/medium         89.51µ ± 3%   88.88µ ± 2%       ~ (p=0.640 n=20)
ParseFresh/simple_select          7.085µ ± 2%   7.101µ ± 1%       ~ (p=0.410 n=20)
ParseFresh/join                   11.55µ ± 1%   11.41µ ± 1%       ~ (p=0.071 n=20)
ParseFresh/complex                20.65µ ± 1%   20.58µ ± 1%       ~ (p=0.417 n=20)
PoolGetPut/serial                 67.10n ± 2%   67.11n ± 1%       ~ (p=0.597 n=20)
ParseError/syntax_mid/parse       2.444µ ± 1%   2.431µ ± 1%       ~ (p=0.194 n=20)
ParseError/syntax_mid/validate    2.192µ ± 1%   2.182µ ± 1%       ~ (p=0.151 n=20)
ParseError/syntax_end/parse       2.838µ ± 1%   2.792µ ± 1%       ~ (p=0.021 n=20)
ParseError/syntax_end/validate    2.679µ ± 1%   2.655µ ± 1%       ~ (p=0.036 n=20)
ParseError/tokenize/parse         912.7n ± 2%   913.7n ± 1%       ~ (p=0.836 n=20)
ParseError/tokenize/validate      2.861µ ± 1%   2.856µ ± 1%       ~ (p=0.262 n=20)
ParseError/long_prefix/parse      60.21µ ± 1%   59.90µ ± 1%       ~ (p=0.214 n=20)
ParseError/long_prefix/validate   57.54µ ± 2%   56.52µ ± 1%       ~ (p=0.073 n=20)
geomean                           9.575µ        9.534µ       -0.43%

                                │     base     │                head                 │
                                │     B/s      │     B/s       vs base               │
ParseE2E/simple_select            15.07Mi ± 1%   15.08Mi ± 1%       ~ (p=0.394 n=20)
ParseE2E/select_where             28.41Mi ± 4%   28.62Mi ± 0%       ~ (p=0.055 n=20)
ParseE2E/join                     26.08Mi ± 1%   26.05Mi ± 1%       ~ (p=0.551 n=20)
ParseE2E/aggregate                23.19Mi ± 1%   23.25Mi ± 1%       ~ (p=0.941 n=20)
ParseE2E/subquery                 24.93Mi ± 1%   25.02Mi ± 1%       ~ (p=0.037 n=20)
ParseE2E/cte                      26.53Mi ± 1%   26.55Mi ± 1%       ~ (p=0.268 n=20)
ParseE2E/window                   30.70Mi ± 1%   30.69Mi ± 1%       ~ (p=0.402 n=20)
ParseE2E/complex                  29.31Mi ± 2%   29.83Mi ± 2%       ~ (p=0.087 n=20)
ParseE2E/insert                   33.11Mi ± 1%   33.35Mi ± 1%       ~ (p=0.055 n=20)
ParseE2E/update                   26.79Mi ± 1%   27.02Mi ± 1%       ~ (p=0.119 n=20)
ParseE2E/delete                   39.77Mi ± 1%   40.12Mi ± 1%       ~ (p=0.092 n=20)
ParseRW/postgresql/medium         21.01Mi ± 1%   21.12Mi ± 1%       ~ (p=0.358 n=20)
ParseRW/mysql/medium              28.03Mi ± 1%   27.99Mi ± 1%       ~ (p=0.941 n=20)
ParseRW/mariadb/medium            25.77Mi ± 1%   25.79Mi ± 1%       ~ (p=0.774 n=20)
ParseRW/sqlserver/medium          24.16Mi ± 1%   24.20Mi ± 1%       ~ (p=0.358 n=20)
ParseRW/oracle/medium             25.54Mi ± 0%   25.66Mi ± 1%  +0.49% (p=0.005 n=20)
ParseRW/sqlite/medium             28.12Mi ± 2%   27.80Mi ± 1%       ~ (p=0.274 n=20)
ParseRW/snowflake/medium          26.73Mi ± 0%   26.72Mi ± 1%       ~ (p=0.794 n=20)
ParseRW/clickhouse/medium         25.18Mi ± 2%   25.35Mi ± 2%       ~ (p=0.635 n=20)
ParseError/syntax_mid/parse       18.73Mi ± 1%   18.83Mi ± 1%       ~ (p=0.185 n=20)
ParseError/syntax_mid/validate    20.89Mi ± 1%   20.99Mi ± 1%       ~ (p=0.163 n=20)
ParseError/syntax_end/parse       13.10Mi ± 1%   13.33Mi ± 1%       ~ (p=0.021 n=20)
ParseError/syntax_end/validate    13.89Mi ± 1%   14.01Mi ± 1%       ~ (p=0.039 n=20)
ParseError/tokenize/parse         48.07Mi ± 2%   48.01Mi ± 1%       ~ (p=0.836 n=20)
ParseError/tokenize/validate      15.34Mi ± 1%   15.36Mi ± 1%       ~ (p=0.267 n=20)
ParseError/long_prefix/parse      38.36Mi ± 1%   38.56Mi ± 1%       ~ (p=0.213 n=20)
ParseError/long_prefix/validate   40.14Mi ± 2%   40.86Mi ± 1%       ~ (p=0.073 n=20)
geomean                           25.32Mi        25.43Mi       +0.45%

                                │      base      │                 head                  │
                                │      B/op      │     B/op      vs base                 │
ParseE2E/simple_select              816.0 ± 0%       816.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/select_where             1.523Ki ± 0%     1.523Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/join                     1.836Ki ± 0%     1.836Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/aggregate                1.812Ki ± 0%     1.812Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/subquery                 1.828Ki ± 0%     1.828Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/cte                      2.336Ki ± 0%     2.336Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/window                   1.281Ki ± 0%     1.281Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/complex                  5.025Ki ± 0%     5.025Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/insert                     824.0 ± 0%       824.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/update                     736.0 ± 0%       736.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/delete                     400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/postgresql/medium         65.91Ki ± 0%     65.91Ki ± 0%       ~ (p=0.875 n=20)
ParseRW/mysql/medium              42.37Ki ± 0%     42.37Ki ± 0%       ~ (p=0.095 n=20)
ParseRW/mariadb/medium            60.61Ki ± 0%     60.61Ki ± 0%       ~ (p=0.211 n=20)
ParseRW/sqlserver/medium          83.68Ki ± 0%     83.68Ki ± 0%       ~ (p=1.000 n=20)
ParseRW/oracle/medium             104.8Ki ± 0%     104.8Ki ± 0%       ~ (p=0.262 n=20)
ParseRW/sqlite/medium             38.12Ki ± 0%     38.12Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/snowflake/medium          77.63Ki ± 0%     77.63Ki ± 0%       ~ (p=0.407 n=20)
ParseRW/clickhouse/medium         34.82Ki ± 0%     34.82Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseFresh/simple_select            896.0 ± 0%       896.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseFresh/join                   1.914Ki ± 0%     1.914Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseFresh/complex                5.102Ki ± 0%     5.102Ki ± 0%       ~ (p=1.000 n=20) ¹
PoolGetPut/serial                   0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_mid/parse         680.0 ± 0%       680.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_mid/validate      680.0 ± 0%       680.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_end/parse       1.430Ki ± 0%     1.430Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_end/validate    1.430Ki ± 0%     1.430Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseError/tokenize/parse           272.0 ± 0%       272.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/tokenize/validate      1.758Ki ± 0%     1.758Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseError/long_prefix/parse      22.75Ki ± 0%     22.75Ki ± 0%       ~ (p=0.207 n=20)
ParseError/long_prefix/validate   22.68Ki ± 0%     22.68Ki ± 0%       ~ (p=1.000 n=20) ¹
geomean                                        ²                 -0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                │     base      │                 head                 │
                                │   allocs/op   │  allocs/op   vs base                 │
ParseE2E/simple_select             5.000 ± 0%      5.000 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/select_where              18.00 ± 0%      18.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/join                      17.00 ± 0%      17.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/aggregate                 18.00 ± 0%      18.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/subquery                  14.00 ± 0%      14.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/cte                       21.00 ± 0%      21.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/window                    11.00 ± 0%      11.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/complex                   49.00 ± 0%      49.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/insert                    17.00 ± 0%      17.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/update                    13.00 ± 0%      13.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/delete                    5.000 ± 0%      5.000 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/postgresql/medium          646.0 ± 0%      646.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/mysql/medium               368.0 ± 0%      368.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/mariadb/medium             528.0 ± 0%      528.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/sqlserver/medium           927.0 ± 0%      927.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/oracle/medium             1.090k ± 0%     1.090k ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/sqlite/medium              347.0 ± 0%      347.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/snowflake/medium           776.0 ± 0%      776.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/clickhouse/medium          383.0 ± 0%      383.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseFresh/simple_select           6.000 ± 0%      6.000 ± 0%       ~ (p=1.000 n=20) ¹
ParseFresh/join                    18.00 ± 0%      18.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseFresh/complex                 50.00 ± 0%      50.00 ± 0%       ~ (p=1.000 n=20) ¹
PoolGetPut/serial                  0.000 ± 0%      0.000 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_mid/parse        12.00 ± 0%      12.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_mid/validate     12.00 ± 0%      12.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_end/parse        16.00 ± 0%      16.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_end/validate     16.00 ± 0%      16.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/tokenize/parse          4.000 ± 0%      4.000 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/tokenize/validate       21.00 ± 0%      21.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/long_prefix/parse       219.0 ± 0%      219.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/long_prefix/validate    219.0 ± 0%      219.0 ± 0%       ~ (p=1.000 n=20) ¹
geomean                                       ²                +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                          │    base     │                head                │
                          │  sec/stmt   │  sec/stmt    vs base               │
ParseRW/postgresql/medium   14.23µ ± 1%   14.15µ ± 1%       ~ (p=0.358 n=20)
ParseRW/mysql/medium        12.07µ ± 1%   12.09µ ± 1%       ~ (p=0.974 n=20)
ParseRW/mariadb/medium      15.29µ ± 1%   15.28µ ± 1%       ~ (p=0.794 n=20)
ParseRW/sqlserver/medium    13.12µ ± 1%   13.09µ ± 1%       ~ (p=0.344 n=20)
ParseRW/oracle/medium       13.68µ ± 0%   13.61µ ± 1%  -0.48% (p=0.006 n=20)
ParseRW/sqlite/medium       12.24µ ± 2%   12.38µ ± 1%       ~ (p=0.289 n=20)
ParseRW/snowflake/medium    14.63µ ± 0%   14.64µ ± 1%       ~ (p=0.805 n=20)
ParseRW/clickhouse/medium   12.79µ ± 3%   12.70µ ± 2%       ~ (p=0.640 n=20)
geomean                     13.46µ        13.45µ       -0.08%

pkg: github.com/ajitpratap0/GoSQLX/pkg/linter
                   │     base     │                head                 │
                   │    sec/op    │    sec/op     vs base               │
LintParallel/rules   29.48m ±  1%   29.47m ±  1%       ~ (p=0.758 n=20)
LintParallel/lint    52.13m ±  1%   52.23m ±  0%       ~ (p=0.925 n=20)
LintRW/postgresql    6.615m ±  1%   6.592m ±  1%       ~ (p=0.134 n=20)
LintRW/mysql         6.877m ±  1%   6.845m ±  1%       ~ (p=0.414 n=20)
LintRW/mariadb       6.309m ±  1%   6.271m ±  1%       ~ (p=0.201 n=20)
LintRW/sqlserver     5.887m ±  1%   5.847m ±  1%       ~ (p=0.201 n=20)
LintRW/oracle        7.014m ±  0%   6.993m ±  1%       ~ (p=0.314 n=20)
LintRW/sqlite        5.985m ±  5%   5.942m ±  3%       ~ (p=0.583 n=20)
LintRW/snowflake     6.131m ±  1%   6.122m ±  4%       ~ (p=0.529 n=20)
LintRW/clickhouse    6.841m ±  3%   6.770m ±  3%       ~ (p=0.383 n=20)
LintRule/L007        2.763m ±  2%   2.744m ±  1%       ~ (p=0.355 n=20)
LintRule/L010        699.2µ ± 27%   699.1µ ± 27%       ~ (p=0.547 n=20)
geomean              6.743m         6.715m        -0.41%

                  │     base     │                head                 │
                  │     B/s      │     B/s       vs base               │
LintRW/postgresql   4.282Mi ± 1%   4.296Mi ± 1%       ~ (p=0.098 n=20)
LintRW/mysql        4.759Mi ± 1%   4.778Mi ± 1%       ~ (p=0.371 n=20)
LintRW/mariadb      4.835Mi ± 1%   4.864Mi ± 1%       ~ (p=0.217 n=20)
LintRW/sqlserver    5.260Mi ± 1%   5.298Mi ± 1%       ~ (p=0.213 n=20)
LintRW/oracle       5.665Mi ± 0%   5.679Mi ± 1%       ~ (p=0.323 n=20)
LintRW/sqlite       4.797Mi ± 5%   4.830Mi ± 3%       ~ (p=0.542 n=20)
LintRW/snowflake    5.083Mi ± 1%   5.093Mi ± 4%       ~ (p=0.456 n=20)
LintRW/clickhouse   4.749Mi ± 3%   4.792Mi ± 3%       ~ (p=0.337 n=20)
geomean             4.914Mi        4.939Mi       +0.51%

                   │      base      │                 head                  │
                   │      B/op      │     B/op      vs base                 │
LintParallel/rules   8.111Mi ± 0%     8.111Mi ± 0%       ~ (p=0.085 n=20)
LintParallel/lint    28.08Mi ± 0%     28.08Mi ± 0%       ~ (p=0.304 n=20)
LintRW/postgresql    3.089Mi ± 0%     3.089Mi ± 0%       ~ (p=0.542 n=20)
LintRW/mysql         3.880Mi ± 0%     3.880Mi ± 0%       ~ (p=0.250 n=20)
LintRW/mariadb       3.570Mi ± 0%     3.570Mi ± 0%       ~ (p=0.095 n=20)
LintRW/sqlserver     3.124Mi ± 0%     3.124Mi ± 0%       ~ (p=0.794 n=20)
LintRW/oracle        3.818Mi ± 0%     3.818Mi ± 0%       ~ (p=0.664 n=20)
LintRW/sqlite        3.385Mi ± 0%     3.385Mi ± 0%       ~ (p=0.189 n=20)
LintRW/snowflake     3.384Mi ± 0%     3.384Mi ± 0%       ~ (p=0.372 n=20)
LintRW/clickhouse    3.832Mi ± 0%     3.832Mi ± 0%       ~ (p=0.673 n=20)
LintRule/L007        92.98Ki ± 0%     92.98Ki ± 0%       ~ (p=1.000 n=20) ¹
LintRule/L010          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=20) ¹
geomean                           ²                 -0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                   │     base      │                 head                 │
                   │   allocs/op   │  allocs/op   vs base                 │
LintParallel/rules   158.3k ± 0%     158.3k ± 0%       ~ (p=0.338 n=20)
LintParallel/lint    236.9k ± 0%     236.9k ± 0%       ~ (p=0.032 n=20)
LintRW/postgresql    26.50k ± 0%     26.50k ± 0%       ~ (p=0.754 n=20)
LintRW/mysql         32.41k ± 0%     32.41k ± 0%       ~ (p=0.501 n=20)
LintRW/mariadb       29.61k ± 0%     29.61k ± 0%       ~ (p=0.513 n=20)
LintRW/sqlserver     25.62k ± 0%     25.62k ± 0%       ~ (p=1.000 n=20) ¹
LintRW/oracle        31.61k ± 0%     31.61k ± 0%       ~ (p=1.000 n=20)
LintRW/sqlite        29.43k ± 0%     29.43k ± 0%       ~ (p=1.000 n=20) ¹
LintRW/snowflake     28.81k ± 0%     28.81k ± 0%       ~ (p=1.000 n=20)
LintRW/clickhouse    32.89k ± 0%     32.89k ± 0%       ~ (p=1.000 n=20)
LintRule/L007        1.194k ± 0%     1.194k ± 0%       ~ (p=1.000 n=20) ¹
LintRule/L010         0.000 ± 0%      0.000 ± 0%       ~ (p=1.000 n=20) ¹
geomean                          ²                +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                  │     base     │                head                 │
                  │   sec/stmt   │   sec/stmt    vs base               │
LintRW/postgresql   21.69µ ±  1%   21.61µ ±  1%       ~ (p=0.136 n=20)
LintRW/mysql        16.61µ ±  1%   16.53µ ±  1%       ~ (p=0.410 n=20)
LintRW/mariadb      16.60µ ±  1%   16.50µ ±  1%       ~ (p=0.194 n=20)
LintRW/sqlserver    21.25µ ±  1%   21.11µ ±  1%       ~ (p=0.199 n=20)
LintRW/oracle       19.06µ ±  0%   19.00µ ±  1%       ~ (p=0.317 n=20)
LintRW/sqlite       17.20µ ±  5%   17.07µ ±  3%       ~ (p=0.569 n=20)
LintRW/snowflake    18.75µ ±  1%   18.72µ ±  4%       ~ (p=0.529 n=20)
LintRW/clickhouse   17.36µ ±  3%   17.18µ ±  3%       ~ (p=0.383 n=20)
LintRule/L007       982.2n ±  2%   975.4n ±  1%       ~ (p=0.358 n=20)
LintRule/L010       248.6n ± 27%   248.5n ± 27%       ~ (p=0.569 n=20)
geomean             8.954µ         8.909µ        -0.51%

pkg: github.com/ajitpratap0/GoSQLX/pkg/sql/tokenizer
                         │    base     │                head                │
                         │   sec/op    │   sec/op     vs base               │
Tokenize/scratch/join      1.469µ ± 2%   1.478µ ± 2%       ~ (p=0.673 n=20)
Tokenize/scratch/complex   3.865µ ± 3%   3.875µ ± 2%       ~ (p=0.635 n=20)
Tokenize/scratch/insert    739.4n ± 2%   741.8n ± 2%       ~ (p=0.815 n=20)
geomean                    1.613µ        1.620µ       +0.41%

                         │     base     │                head                 │
                         │     B/s      │     B/s       vs base               │
Tokenize/scratch/join      81.81Mi ± 2%   81.28Mi ± 2%       ~ (p=0.678 n=20)
Tokenize/scratch/complex   93.28Mi ± 3%   93.04Mi ± 2%       ~ (p=0.635 n=20)
Tokenize/scratch/insert    98.02Mi ± 2%   97.72Mi ± 2%       ~ (p=0.815 n=20)
geomean                    90.77Mi        90.41Mi       -0.40%

                         │     base     │                head                 │
                         │     B/op     │    B/op     vs base                 │
Tokenize/scratch/join      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=20) ¹
Tokenize/scratch/complex   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=20) ¹
Tokenize/scratch/insert    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=20) ¹
geomean                               ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                         │     base     │                head                 │
                         │  allocs/op   │ allocs/op   vs base                 │
Tokenize/scratch/join      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=20) ¹
Tokenize/scratch/complex   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=20) ¹
Tokenize/scratch/insert    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=20) ¹
geomean                               ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

pkg: github.com/ajitpratap0/GoSQLX/pkg/transform
                             │    base     │                head                │
                             │   sec/op    │   sec/op     vs base               │
TransformParse/simple_select   1.543µ ± 3%   1.540µ ± 4%       ~ (p=0.644 n=20)
TransformParse/join            5.018µ ± 1%   4.993µ ± 1%       ~ (p=0.055 n=20)
TransformParse/complex         13.14µ ± 2%   13.02µ ± 1%       ~ (p=0.108 n=20)
geomean                        4.668µ        4.643µ       -0.54%

                             │     base     │                 head                  │
                             │     B/op     │     B/op      vs base                 │
TransformParse/simple_select     816.0 ± 0%     816.0 ± 0%       ~ (p=1.000 n=20) ¹
TransformParse/join            1.836Ki ± 0%   1.836Ki ± 0%       ~ (p=1.000 n=20) ¹
TransformParse/complex         5.023Ki ± 0%   5.023Ki ± 0%       ~ (p=1.000 n=20) ¹
geomean                        1.944Ki        1.944Ki       +0.00%
¹ all samples are equal

                             │    base    │                head                 │
                             │ allocs/op  │ allocs/op   vs base                 │
TransformParse/simple_select   5.000 ± 0%   5.000 ± 0%       ~ (p=1.000 n=20) ¹
TransformParse/join            17.00 ± 0%   17.00 ± 0%       ~ (p=1.000 n=20) ¹
TransformParse/complex         49.00 ± 0%   49.00 ± 0%       ~ (p=1.000 n=20) ¹
geomean                        16.09        16.09       +0.00%
¹ all samples are equal

Run, raw data and benchstat

Test and others added 2 commits November 3, 2026 23:49
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

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


Review of PR #946: skip operator retargeting when source has no retargetable construct

I read the transpiler.go and retarget_operators.go diffs against origin/main. I did not run the tests. The perf-gate result is already in the PR comments.

Verdict: no blocking issues. The prefilter is conservative in the safe direction.

Correctness

  • Single-byte triggers. ^ | & # ~ @ ? ! { $ each set ops on their own. That covers the bitwise and JSON operators (#>, @>, <@, ->>), factorial, ~, { objects, money $, and U& (via &).
  • Pairs. <<, <-, >>, ->, => and := are detected in scanSource. The i+1 < len(sql) check covers a pair ending at the last byte. An earlier review mentioned a U/u pair; that entry is gone from this diff, so it needs no action.
  • Error parity. Every spelling the walk refuses is in the trigger set, so skipping the walk cannot hide a refusal.
  • Prefilter off. !prefilter || src.ops keeps the original always-run path for the equivalence tests.

Suggestions (non-blocking)

  1. Nesting guard. The comment says the 512 nesting guard can't fire because parser.MaxRecursionDepth is 100. Please check that a test fails if that constant ever exceeds the guard. Otherwise the two can drift apart silently, and deeply nested input without trigger bytes would skip the guard.
  2. Hit rate. !=, ? placeholders and # comments set ops without needing the walk. Please report how often ops fires on a realistic corpus. The reported gains come from synthetic shapes, and the medium shape already contains ^ and ||, which disables the skip.
  3. Comment formatting. In retarget_operators.go, the new doc comment has one long line ("conservative pairs). U& is caught by '&'. A construct whose…") that breaks the wrapping of the lines around it. Please rewrap it.
  4. Stale scan data. srcPair is set for <>-=:, and > alone is only a trigger via >>/->. This is correct. The table-driven design is also well justified by the earlier byte-switch regression.

Performance

  • Allocations and B/op are unchanged.
  • The amd64 perf gate passes: geomean -0.14%, no gated metric moved, and A/A' noise was 0 of 52. This was shadow mode.
  • The gate suite barely exercises Transpile. Its benefit rests on the local M4 numbers in the PR body (about 15-19% on RW cross-dialect pairs). The gate does confirm there is no regression on the non-transpile paths.
  • The TestOpsSkipIsSafe and TestPrefilterEquivalence runs matter more than the benchmark here.

Security

No new input handling. The change only skips a pass whose refusals are keyed on the same bytes.

Tests

Coverage is strong: the differential test, the required-constructs mutation test, and a scanSource unit test. The PR body notes that removing only the U& pair is undetectable because & sets ops independently. That is acceptable since W7-05 will prune it.
· branch perf/w7-01-skip-retarget-ops

…perators godoc [W7-01]

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

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

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


Review of PR #946: skip operator retargeting when source has no retargetable construct

I read the diff of transpiler.go and retarget_operators.go against origin/main. I did not run the tests. The amd64 perf gate already passed (shadow mode), and its report is in the PR comments.

Verdict: no blocking issues.

Correctness

  • Single-byte triggers. ^ | & # ~ @ ? ! { $ each set srcOps through the srcClass table. That covers the bitwise and JSON operators, factorial, ~, {, money $ and U& (via &).
  • Pairs. scanSource handles <<, <-, >>, ->, => and :=. The i+1 < len(sql) check covers a pair ending at the last byte. A pair-opening byte that doesn't complete a pair correctly contributes nothing.
  • Error parity. Every spelling the walk refuses has a trigger byte, so skipping the walk can't hide a refusal.
  • Prefilter off. !prefilter || src.ops keeps the original always-run path for the equivalence tests.
  • Nesting guard. The comment relies on parser.MaxRecursionDepth (100) staying below the 512 guard. differential_test.go:110 has iterative-chain fixtures without ops bytes, and it covers depths straddling 512. That pins the behaviour today. A direct assertion that MaxRecursionDepth < 512 would catch drift earlier and with a clearer failure message. I couldn't confirm one exists, and adding it is optional.

Suggestions (non-blocking)

  1. Hit rate on real SQL. !=, ? placeholders, # comments and || set ops without needing the walk. The medium benchmark shape already contains ^ and ||, so it never takes the skip. The gains are therefore measured on small synthetic shapes. A one-line figure for how often ops fires on a realistic corpus would show the real benefit.
  2. Dead U& entry. U& is covered by &, so it adds nothing today. The PR says W7-05 will prune it, so no action is needed.
  3. Doc comment. The new comment in retarget_operators.go is wrapped consistently now. The earlier rewrap request is resolved.

Performance

  • The loop does one table load per byte, and only pair-opening bytes branch. That fits the measurements: the earlier byte-switch variant regressed pg_pg.
  • Allocations and B/op are unchanged.
  • The amd64 gate shows geomean -0.03%, no gated metric moved, and the A/A' control was clean. The gate barely exercises Transpile, so the 15-19% gain on cross-dialect pairs rests on the local M4 numbers. The gate confirms no regression elsewhere.

Security

No new input handling. The change only skips a pass whose refusals are keyed on the same bytes.

Tests

Coverage is strong: the differential test, the required-constructs mutation test (TestOpsPrefilterRequiredConstructs), TestOpsSkipIsSafe and the scanSource unit test. Mutation checks are documented in the PR body.
· branch perf/w7-01-skip-retarget-ops

This branch was successfully deployed

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

Labels

ast AST node changes documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant