cutoff 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -1
- data/lib/cutoff/patch/mysql2.rb +18 -1
- data/lib/cutoff/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8e267a7090c7eee2e054ccc060c18a38a4f6d27277477d7fcfc3263b7f16091a
|
|
4
|
+
data.tar.gz: f7a34c730fe930080da8a539b5c864b4b4af467a042c7ddf075ba7df7242da79
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1853882757fc2da5bae7c836423893dcd2b673f09ff4ebb191dcababd8b44fbf114617664a7974bf67b2a615dbb2fb2f8c2da31876bf5a580d47f9b908d9af79
|
|
7
|
+
data.tar.gz: 75eec1648d14ac62203989bb51ab2b4e3e6710006c0c072d4e98933c367ebd96fde88b7a33705983f1ba09cc44b5e486dacde80e06b9e47291a804883c16872b
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.0] - 2026-08-07
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- The Mysql2 patch now finds the first `SELECT` when a statement begins with a
|
|
15
|
+
parenthesized query block, as in `(SELECT ...) UNION (SELECT ...)`.
|
|
16
|
+
Previously the leading `(` was treated as an unrecognized token and the
|
|
17
|
+
parser bailed out, so `MAX_EXECUTION_TIME` was silently never inserted and
|
|
18
|
+
the query ran with no server-side ceiling. MySQL applies a hint in the first
|
|
19
|
+
query block to the whole statement, so these queries are now capped
|
|
20
|
+
correctly.
|
|
21
|
+
- Fixed a check in the Mysql2 patch that used `String#casecmp` where a boolean
|
|
22
|
+
was expected. Because `casecmp` returns `0` for a match (which is truthy in
|
|
23
|
+
Ruby), the guard never fired and any leading token merely *starting with*
|
|
24
|
+
`select` (such as `selections`) had a hint comment spliced into it,
|
|
25
|
+
producing invalid SQL. It now uses `casecmp?`.
|
|
26
|
+
|
|
27
|
+
### Upgrading
|
|
28
|
+
|
|
29
|
+
Queries beginning with a parenthesized query block were previously never given
|
|
30
|
+
a `MAX_EXECUTION_TIME` hint, so they ran unbounded on the server even with an
|
|
31
|
+
active cutoff. They are now capped, which means a query that used to slowly
|
|
32
|
+
succeed may instead raise `Mysql2::Error`. That is the intended behavior of the
|
|
33
|
+
patch, but it can surface as new errors on upgrade. If you have queries in this
|
|
34
|
+
shape, check that their callers handle the error, or give them a longer cutoff.
|
|
35
|
+
|
|
36
|
+
Statements beginning with `WITH` (common table expressions) are still not
|
|
37
|
+
given a hint.
|
|
38
|
+
|
|
10
39
|
## [1.1.0] - 2026-05-12
|
|
11
40
|
|
|
12
41
|
### Fixed
|
|
@@ -107,7 +136,8 @@ to `Timeout::Error`. `CutoffError` changes from a class to a module.
|
|
|
107
136
|
- Cutoff class
|
|
108
137
|
- Mysql2 patch
|
|
109
138
|
|
|
110
|
-
[Unreleased]: https://github.com/justinhoward/cutoff/compare/v1.
|
|
139
|
+
[Unreleased]: https://github.com/justinhoward/cutoff/compare/v1.2.0...HEAD
|
|
140
|
+
[1.2.0]: https://github.com/justinhoward/cutoff/compare/v1.1.0...v1.2.0
|
|
111
141
|
[1.1.0]: https://github.com/justinhoward/cutoff/compare/v1.0.0...v1.1.0
|
|
112
142
|
[1.0.0]: https://github.com/justinhoward/cutoff/compare/v0.5.2...v1.0.0
|
|
113
143
|
[0.5.2]: https://github.com/justinhoward/cutoff/compare/v0.5.1...v0.5.2
|
data/lib/cutoff/patch/mysql2.rb
CHANGED
|
@@ -69,6 +69,8 @@ class Cutoff
|
|
|
69
69
|
hint_comment
|
|
70
70
|
elsif token.start_with?('/*')
|
|
71
71
|
block_comment
|
|
72
|
+
elsif !@found_select && token.start_with?('(')
|
|
73
|
+
open_paren
|
|
72
74
|
elsif token.match?(/^select/i)
|
|
73
75
|
select
|
|
74
76
|
else
|
|
@@ -133,6 +135,21 @@ class Cutoff
|
|
|
133
135
|
@scanner.terminate
|
|
134
136
|
end
|
|
135
137
|
|
|
138
|
+
def open_paren
|
|
139
|
+
# A statement can begin with a parenthesized query block, as in
|
|
140
|
+
# `(SELECT ...) UNION (SELECT ...)`. MySQL accepts an optimizer hint
|
|
141
|
+
# at the start of the first block and applies MAX_EXECUTION_TIME to
|
|
142
|
+
# the whole statement, so consume the parentheses and keep looking
|
|
143
|
+
# for the select.
|
|
144
|
+
#
|
|
145
|
+
# Go back to the beginning of the token and skip only the parens
|
|
146
|
+
# (and any whitespace after them) so the rest of the token is
|
|
147
|
+
# re-examined as its own token. This always advances the scanner by
|
|
148
|
+
# at least one character, so the token loop can't spin.
|
|
149
|
+
@scanner.unscan
|
|
150
|
+
@scanner.skip(/\(+\s*/)
|
|
151
|
+
end
|
|
152
|
+
|
|
136
153
|
def select
|
|
137
154
|
# If we encounter a select, we're ready to place our hint comment
|
|
138
155
|
@scanner.unscan
|
|
@@ -140,7 +157,7 @@ class Cutoff
|
|
|
140
157
|
|
|
141
158
|
# Make sure our word is actually select
|
|
142
159
|
# We only checked that it starts with select before
|
|
143
|
-
return other unless word.casecmp('select')
|
|
160
|
+
return other unless word.casecmp?('select')
|
|
144
161
|
|
|
145
162
|
@found_select = true
|
|
146
163
|
@hint_pos = @scanner.pos
|
data/lib/cutoff/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cutoff
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Howard
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-08-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|
|
@@ -84,7 +84,7 @@ licenses:
|
|
|
84
84
|
- MIT
|
|
85
85
|
metadata:
|
|
86
86
|
changelog_uri: https://github.com/justinhoward/cutoff/blob/master/CHANGELOG.md
|
|
87
|
-
documentation_uri: https://www.rubydoc.info/gems/cutoff/1.
|
|
87
|
+
documentation_uri: https://www.rubydoc.info/gems/cutoff/1.2.0
|
|
88
88
|
rubygems_mfa_required: 'true'
|
|
89
89
|
post_install_message:
|
|
90
90
|
rdoc_options: []
|