GROOVY-12342: report, and document, values composed into batch SQL as… - #2866
Merged
Conversation
… 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 Report❌ Patch coverage is
Additional details and impacted files@@ 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
🚀 New features to boost your workflow:
|
✅ All tests passed ✅🏷️ Commit: b4ecf77 Learn more about TestLens at testlens.app/docs. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
… 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.