Skip to content

Commit bc274dd

Browse files
authored
PMM-13807 fingerprint keywords (#64)
* migrate from dep to go modules * move fingerprint tests to table drive test * handle keywords as literals when in parenthesis * cover where-in edge case * downgrade go version
1 parent 68cfc99 commit bc274dd

File tree

4 files changed

+52
-9
lines changed

4 files changed

+52
-9
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/percona/go-mysql
22

3-
go 1.24.2
3+
go 1.23.4
44

55
require (
66
github.com/pkg/errors v0.9.1

go.sum

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
22
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3-
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
43
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
54
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
65
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=

query/query.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -728,13 +728,13 @@ func Fingerprint(q string) string {
728728
default:
729729
if s != inWord && s != inOp {
730730
// If in a word or operator then keep copying the query, else
731-
// previous chars were being ignored for some reasons but now
731+
// previous chars were being ignored for some reason, but now
732732
// we should start copying again, so set cpFromOffset. Example:
733733
// col=NOW(). 'col' will be set to copy, but then '=' will put
734734
// us in inOp state which, if a value follows, will trigger a
735735
// copy of "col=", but "NOW()" is not a value so "N" is caught
736736
// here and since s=inOp still we do not copy yet (this block is
737-
// is not entered).
737+
// not entered).
738738
if Debug {
739739
fmt.Println("Random character")
740740
}
@@ -766,12 +766,21 @@ func Fingerprint(q string) string {
766766
copy(f[fi:fi+l], prevWord)
767767
fi += l
768768
cpFromOffset = cpToOffset
769-
if wordIn(prevWord, "in", "value", "values") && sqlState != onDupeKeyUpdate {
770-
// IN () -> in(?+)
771-
// VALUES () -> values(?+)
769+
valueKeywords := []string{"in", "value", "values"}
770+
if wordIn(prevWord, valueKeywords...) && sqlState != onDupeKeyUpdate {
772771
addSpace = false
773-
s = inValues
774-
sqlState = inValues
772+
// since we only consider the keywords if it exists at a top-level (except onDupeKeyUpdate),
773+
// we only do the conversion below if the "keywords" actually open a value list (i.e., before opening a parenthesis).
774+
if r == '(' || (isSpace(r) && (q[qi+1] == '(') || (q[qi+1] == ' ')) {
775+
// IN () -> in(?+)
776+
// VALUES () -> values(?+)
777+
s = inValues
778+
sqlState = inValues
779+
} else {
780+
f[fi] = ' '
781+
fi++
782+
cpFromOffset++
783+
}
775784
} else if addSpace {
776785
if Debug {
777786
fmt.Println("Add space")

query/query_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,41 @@ func TestFingerprintBasic(t *testing.T) {
165165
query: "select * from foo limit 5 offset 10",
166166
expected: "select * from foo limit ? offset ?",
167167
},
168+
{
169+
name: "insert with quoted keyword as column",
170+
query: "INSERT INTO test (ID, `Value`) VALUES (1 ,1)",
171+
expected: "insert into test (id, `value`) values(?+)",
172+
},
173+
{
174+
name: "insert with non-quoted keyword as column",
175+
query: "INSERT INTO test (ID, Value) VALUES (1 ,1)",
176+
expected: "insert into test (id, value) values(?+)",
177+
},
178+
{
179+
name: "insert with non-quoted keyword and space as column",
180+
query: "INSERT INTO test (ID, Value ) VALUES (1 ,1)",
181+
expected: "insert into test (id, value ) values(?+)",
182+
},
183+
{
184+
name: "insert with keyword as first column name",
185+
query: "INSERT INTO test ( In , ID) VALUES (1,1)",
186+
expected: "insert into test ( in , id) values(?+)",
187+
},
188+
{
189+
name: "insert with value keyword as first column name",
190+
query: "INSERT INTO test ( In , ID) VALUES (1,1)",
191+
expected: "insert into test ( in , id) values(?+)",
192+
},
193+
{
194+
name: "insert duplicate with keyword as column name",
195+
query: "INSERT INTO test (id, value) VALUES (1, 10) ON DUPLICATE KEY UPDATE value = VALUES(value) + 5",
196+
expected: "insert into test (id, value) values(?+) on duplicate key update value = values(value) + ?",
197+
},
198+
{
199+
name: "insert duplicate with keyword and space as column name",
200+
query: "INSERT INTO test (id, value ) VALUES (1, 10) ON DUPLICATE KEY UPDATE value = VALUES(value ) + 5",
201+
expected: "insert into test (id, value ) values(?+) on duplicate key update value = values(value ) + ?",
202+
},
168203
{
169204
name: "fingerprint load data infile",
170205
query: "LOAD DATA INFILE '/tmp/foo.txt' INTO db.tbl",

0 commit comments

Comments
 (0)