mirror of
https://github.com/golang/go
synced 2024-11-23 20:00:04 -07:00
database/sql: document expectations for named parameters
Require parameter names to not begin with a symbol. Change-Id: I5dfe9d4e181f0daf71dad2f395aca41c68678cbe Reviewed-on: https://go-review.googlesource.com/33493 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
ea1b90f855
commit
e5e0562774
@ -13,6 +13,8 @@ import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
|
||||
@ -24,6 +26,17 @@ func describeNamedValue(nv *driver.NamedValue) string {
|
||||
return fmt.Sprintf("with name %q", nv.Name)
|
||||
}
|
||||
|
||||
func validateNamedValueName(name string) error {
|
||||
if len(name) == 0 {
|
||||
return nil
|
||||
}
|
||||
r, _ := utf8.DecodeRuneInString(name)
|
||||
if unicode.IsLetter(r) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("name %q does not begin with a letter", name)
|
||||
}
|
||||
|
||||
// driverArgs converts arguments from callers of Stmt.Exec and
|
||||
// Stmt.Query into driver Values.
|
||||
//
|
||||
@ -43,6 +56,9 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.NamedValue, error)
|
||||
nv := &nvargs[n]
|
||||
nv.Ordinal = n + 1
|
||||
if np, ok := arg.(NamedArg); ok {
|
||||
if err := validateNamedValueName(np.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
arg = np.Value
|
||||
nvargs[n].Name = np.Name
|
||||
}
|
||||
@ -60,6 +76,9 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.NamedValue, error)
|
||||
nv := &nvargs[n]
|
||||
nv.Ordinal = n + 1
|
||||
if np, ok := arg.(NamedArg); ok {
|
||||
if err := validateNamedValueName(np.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
arg = np.Value
|
||||
nv.Name = np.Name
|
||||
}
|
||||
|
@ -27,13 +27,18 @@ import (
|
||||
type Value interface{}
|
||||
|
||||
// NamedValue holds both the value name and value.
|
||||
// The Ordinal is the position of the parameter starting from one and is always set.
|
||||
// If the Name is not empty it should be used for the parameter identifier and
|
||||
// not the ordinal position.
|
||||
type NamedValue struct {
|
||||
Name string
|
||||
// If the Name is not empty it should be used for the parameter identifier and
|
||||
// not the ordinal position.
|
||||
//
|
||||
// Name will not have a symbol prefix.
|
||||
Name string
|
||||
|
||||
// Ordinal position of the parameter starting from one and is always set.
|
||||
Ordinal int
|
||||
Value Value
|
||||
|
||||
// Value is the parameter value.
|
||||
Value Value
|
||||
}
|
||||
|
||||
// Driver is the interface that must be implemented by a database
|
||||
|
@ -713,7 +713,7 @@ func (s *fakeStmt) execInsert(args []driver.NamedValue, doInsert bool) (driver.R
|
||||
} else {
|
||||
// Assign value from argument placeholder name.
|
||||
for _, a := range args {
|
||||
if a.Name == strvalue {
|
||||
if a.Name == strvalue[1:] {
|
||||
val = a.Value
|
||||
break
|
||||
}
|
||||
@ -818,7 +818,7 @@ func (s *fakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (
|
||||
} else {
|
||||
// Assign arg value from placeholder name.
|
||||
for _, a := range args {
|
||||
if a.Name == wcol.Placeholder {
|
||||
if a.Name == wcol.Placeholder[1:] {
|
||||
argValue = a.Value
|
||||
break
|
||||
}
|
||||
|
@ -76,6 +76,8 @@ type NamedArg struct {
|
||||
|
||||
// Name of the parameter placeholder. If empty the ordinal position in the
|
||||
// argument list will be used.
|
||||
//
|
||||
// Name must omit any symbol prefix.
|
||||
Name string
|
||||
|
||||
// Value of the parameter. It may be assigned the same value types as
|
||||
|
@ -486,8 +486,8 @@ func TestQueryNamedArg(t *testing.T) {
|
||||
rows, err := db.Query(
|
||||
// Ensure the name and age parameters only match on placeholder name, not position.
|
||||
"SELECT|people|age,name|name=?name,age=?age",
|
||||
Named("?age", 2),
|
||||
Named("?name", "Bob"),
|
||||
Named("age", 2),
|
||||
Named("name", "Bob"),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Query: %v", err)
|
||||
|
Loading…
Reference in New Issue
Block a user