SQLTemplate: Make Ident only work for identifiers (not any string) (#92387)

This commit is contained in:
Ryan McKinley
2024-08-27 13:22:40 +03:00
committed by GitHub
parent 437747f250
commit 5a30e12a10
79 changed files with 284 additions and 261 deletions
+29 -3
View File
@@ -1,6 +1,7 @@
package sqltemplate
import (
"bytes"
"errors"
"strconv"
"strings"
@@ -9,6 +10,7 @@ import (
// Dialect-agnostic errors.
var (
ErrEmptyIdent = errors.New("empty identifier")
ErrInvalidIdentInput = errors.New("identifier contains invalid characters")
ErrInvalidRowLockingClause = errors.New("invalid row-locking clause")
)
@@ -40,7 +42,8 @@ type Dialect interface {
// Ident returns the given string quoted in a way that is suitable to be
// used as an identifier. Database names, schema names, table names, column
// names are all examples of identifiers.
// names are all examples of identifiers. When the value includes a "."
// each part side of the separator will be escaped: (eg: `db`.`table`)
Ident(string) (string, error)
// ArgPlaceholder returns a safe argument suitable to be used in a SQL
@@ -126,11 +129,34 @@ var rowLockingClauseAll = rowLockingClauseMap{
// standardIdent provides standard SQL escaping of identifiers.
type standardIdent struct{}
func (standardIdent) Ident(s string) (string, error) {
func escapeIdentity(s string, quote rune, clean func(string) string) (string, error) {
if s == "" {
return "", ErrEmptyIdent
}
return `"` + strings.ReplaceAll(s, `"`, `""`) + `"`, nil
var buffer bytes.Buffer
for i, part := range strings.Split(s, ".") {
// We may want to check that the identifier is simple alphanumeric
// var alphanumeric = regexp.MustCompile("^[a-zA-Z0-9_]*$")
if i > 1 {
return "", ErrInvalidIdentInput
}
if i > 0 {
_, _ = buffer.WriteRune('.')
}
_, _ = buffer.WriteRune(quote)
_, _ = buffer.WriteString(clean(part))
_, _ = buffer.WriteRune(quote)
}
return buffer.String(), nil
}
func (standardIdent) Ident(s string) (string, error) {
return escapeIdentity(s, '"', func(s string) string {
// not sure we should support escaping quotes in table/column names,
// but it is valid so we will support it for now
return strings.ReplaceAll(s, `"`, `""`)
})
}
type argPlaceholderFunc func(int) string