Skip to content

GROOVY-12342: report, and document, values composed into batch SQL as… - #2866

Merged
paulk-asert merged 1 commit into
apache:masterfrom
paulk-asert:groovy12342
Sep 3, 2026
Merged

GROOVY-12342: report, and document, values composed into batch SQL as…#2866
paulk-asert merged 1 commit into
apache:masterfrom
paulk-asert:groovy12342

Conversation

@paulk-asert

Copy link
Copy Markdown
Contributor

… text

Inside withBatch { ... } the wrapper's only SQL-accepting method takes a String, so a GString handed to it is coerced and its values become part of the statement. Every query method on Sql binds the same idiom, and the class documentation said so without qualification, so the one surface where it does not hold read exactly like the ones where it does.

It is documented rather than rejected. A JDBC Statement batch may hold different statements, which is why it takes text and has nothing to bind against, and there is no parameterized equivalent to send callers to: batching heterogeneous statements, generated DDL, and identifiers that cannot be bound are all legitimate here. The module's own SqlBatchTest uses this idiom. Rejecting would remove a capability with no replacement, which is the same test applied to the quoted-expression case that is rejected precisely because removing the quotes costs nothing.

So: an addBatch(GString) overload that renders and adds the command as before, and logs once per batch when a value was composed in that was not marked with Sql.expand. That mirrors asSql, which warns whenever it inlines rather than binds; the difference is that inlining is the only option here, so there is no strict mode to fall back from. Deliberate interpolation marked with Sql.expand passes quietly and now substitutes the expanded value, which plain GString rendering did not do.

The documentation is the substance of the fix: the class-level guidance now carries the exception, both withBatch forms that hand out this wrapper say the commands are text, and addBatch says it on the method itself.

P1 gains the rule that settles the finding's disposition: an API qualifies when it has a GString form that binds, so this surface is outside P1 rather than violating it, and the obligation is to say so and report the coercion.

… text

Inside withBatch { ... } the wrapper's only SQL-accepting method takes a
String, so a GString handed to it is coerced and its values become part of
the statement. Every query method on Sql binds the same idiom, and the
class documentation said so without qualification, so the one surface
where it does not hold read exactly like the ones where it does.

It is documented rather than rejected. A JDBC Statement batch may hold
different statements, which is why it takes text and has nothing to bind
against, and there is no parameterized equivalent to send callers to:
batching heterogeneous statements, generated DDL, and identifiers that
cannot be bound are all legitimate here. The module's own SqlBatchTest
uses this idiom. Rejecting would remove a capability with no replacement,
which is the same test applied to the quoted-expression case that is
rejected precisely because removing the quotes costs nothing.

So: an addBatch(GString) overload that renders and adds the command as
before, and logs once per batch when a value was composed in that was not
marked with Sql.expand. That mirrors asSql, which warns whenever it inlines
rather than binds; the difference is that inlining is the only option here,
so there is no strict mode to fall back from. Deliberate interpolation
marked with Sql.expand passes quietly and now substitutes the expanded
value, which plain GString rendering did not do.

The documentation is the substance of the fix: the class-level guidance now
carries the exception, both withBatch forms that hand out this wrapper say
the commands are text, and addBatch says it on the method itself.

P1 gains the rule that settles the finding's disposition: an API qualifies
when it has a GString form that binds, so this surface is outside P1 rather
than violating it, and the obligation is to say so and report the coercion.
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.29630% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 70.8197%. Comparing base (dd1fa5a) to head (b4ecf77).
⚠️ Report is 5 commits behind head on master.

Files with missing lines Patch % Lines
...main/java/groovy/sql/BatchingStatementWrapper.java 96.2963% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##               master      #2866        +/-   ##
==================================================
- Coverage     70.8227%   70.8197%   -0.0031%     
- Complexity      37011      37017         +6     
==================================================
  Files            1576       1576                
  Lines          134831     134858        +27     
  Branches        24970      24978         +8     
==================================================
+ Hits            95491      95506        +15     
- Misses          30735      30744         +9     
- Partials         8605       8608         +3     
Files with missing lines Coverage Δ
...jects/groovy-sql/src/main/java/groovy/sql/Sql.java 67.1818% <ø> (+0.0909%) ⬆️
...main/java/groovy/sql/BatchingStatementWrapper.java 85.5263% <96.2963%> (+5.9345%) ⬆️

... and 9 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@testlens-app

testlens-app Bot commented Sep 2, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: b4ecf77
▶️ Tests: 115607 executed
⚪️ Checks: 31/31 completed


Learn more about TestLens at testlens.app/docs.

@paulk-asert
paulk-asert merged commit e48e173 into apache:master Sep 3, 2026
32 checks passed
@paulk-asert
paulk-asert deleted the groovy12342 branch September 3, 2026 23:16
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