Skip to content

Commit 1136e4b

Browse files
authored
Merge fix: escape identifier delimiters in Flavor.Quote
Merges the identifier quoting SQL injection fix after passing CI.
2 parents 8952635 + ef74ab1 commit 1136e4b

2 files changed

Lines changed: 31 additions & 3 deletions

File tree

flavor.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package sqlbuilder
66
import (
77
"errors"
88
"fmt"
9+
"strings"
910
)
1011

1112
// Supported flavors.
@@ -168,11 +169,11 @@ func (f Flavor) NewCTEQueryBuilder() *CTEQueryBuilder {
168169
func (f Flavor) Quote(name string) string {
169170
switch f {
170171
case MySQL, ClickHouse, Doris:
171-
return fmt.Sprintf("`%s`", name)
172+
return fmt.Sprintf("`%s`", strings.ReplaceAll(name, "`", "``"))
172173
case PostgreSQL, SQLServer, SQLite, Presto, Oracle, Informix:
173-
return fmt.Sprintf(`"%s"`, name)
174+
return fmt.Sprintf(`"%s"`, strings.ReplaceAll(name, `"`, `""`))
174175
case CQL:
175-
return fmt.Sprintf("'%s'", name)
176+
return fmt.Sprintf("'%s'", strings.ReplaceAll(name, "'", "''"))
176177
}
177178

178179
return name

flavor_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,33 @@ func TestFlavor(t *testing.T) {
3131
}
3232
}
3333

34+
func TestFlavorQuoteEscapesDelimiters(t *testing.T) {
35+
cases := []struct {
36+
flavor Flavor
37+
input string
38+
want string
39+
}{
40+
{MySQL, "name` DESC", "`name`` DESC`"},
41+
{ClickHouse, "name` DESC", "`name`` DESC`"},
42+
{Doris, "name` DESC", "`name`` DESC`"},
43+
{PostgreSQL, `name" DESC`, `"name"" DESC"`},
44+
{SQLServer, `name" DESC`, `"name"" DESC"`},
45+
{SQLite, `name" DESC`, `"name"" DESC"`},
46+
{Presto, `name" DESC`, `"name"" DESC"`},
47+
{Oracle, `name" DESC`, `"name"" DESC"`},
48+
{Informix, `name" DESC`, `"name"" DESC"`},
49+
{CQL, "name' DESC", "'name'' DESC'"},
50+
}
51+
52+
for _, tc := range cases {
53+
t.Run(tc.flavor.String(), func(t *testing.T) {
54+
if got := tc.flavor.Quote(tc.input); got != tc.want {
55+
t.Fatalf("Quote(%q) = %q, want %q", tc.input, got, tc.want)
56+
}
57+
})
58+
}
59+
}
60+
3461
func ExampleFlavor() {
3562
// Create a flavored builder.
3663
sb := PostgreSQL.NewSelectBuilder()

0 commit comments

Comments
 (0)