fix(rt): allow duplicate query arguments (#10809)

This commit is contained in:
Tim Möhlmann
2025-09-27 16:16:15 +03:00
committed by GitHub
parent 096eb4fd91
commit c7b333fb95
2 changed files with 9 additions and 31 deletions

View File

@@ -1,7 +1,6 @@
package database
import (
"encoding/hex"
"strconv"
"strings"
)
@@ -17,8 +16,7 @@ const (
// StatementBuilder is a helper to build SQL statement.
type StatementBuilder struct {
strings.Builder
args []any
existingArgs map[any]string
args []any
}
type argWriter interface {
@@ -47,30 +45,16 @@ func (b *StatementBuilder) WriteArgs(args ...any) {
// AppendArg adds the argument to the statement and returns the placeholder.
func (b *StatementBuilder) AppendArg(arg any) (placeholder string) {
if b.existingArgs == nil {
b.existingArgs = make(map[any]string)
}
// the key is used to work around the following panic:
// runtime error: hash of unhashable type []uint8
key := arg
if argBytes, ok := arg.([]uint8); ok {
key = `\\bytes-` + hex.EncodeToString(argBytes)
}
if placeholder, ok := b.existingArgs[key]; ok {
return placeholder
}
if instruction, ok := arg.(Instruction); ok {
return string(instruction)
}
b.args = append(b.args, arg)
placeholder = "$" + strconv.Itoa(len(b.args))
b.existingArgs[key] = placeholder
return placeholder
}
// AppendArgs adds the arguments to the statement and doesn't return the placeholders.
// If an argument is already added, it will not be added again.
func (b *StatementBuilder) AppendArgs(args ...any) {
for _, arg := range args {
b.AppendArg(arg)

View File

@@ -8,13 +8,12 @@ import (
)
func TestStatementBuilder_AppendArg(t *testing.T) {
t.Run("same arg returns same placeholder", func(t *testing.T) {
t.Run("same arg returns different placeholder", func(t *testing.T) {
var b StatementBuilder
placeholder1 := b.AppendArg("same")
placeholder2 := b.AppendArg("same")
assert.Equal(t, placeholder1, placeholder2)
assert.Len(t, b.Args(), 1)
assert.Len(t, b.existingArgs, 1)
assert.NotEqual(t, placeholder1, placeholder2)
assert.Len(t, b.Args(), 2)
})
t.Run("same arg different types", func(t *testing.T) {
@@ -23,9 +22,8 @@ func TestStatementBuilder_AppendArg(t *testing.T) {
placeholder2 := b.AppendArg([]byte("same"))
placeholder3 := b.AppendArg("same")
assert.NotEqual(t, placeholder1, placeholder2)
assert.Equal(t, placeholder1, placeholder3)
assert.Len(t, b.Args(), 2)
assert.Len(t, b.existingArgs, 2)
assert.NotEqual(t, placeholder1, placeholder3)
assert.Len(t, b.Args(), 3)
})
t.Run("Instruction args are always different", func(t *testing.T) {
@@ -34,30 +32,26 @@ func TestStatementBuilder_AppendArg(t *testing.T) {
placeholder2 := b.AppendArg(DefaultInstruction)
assert.Equal(t, placeholder1, placeholder2)
assert.Len(t, b.Args(), 0)
assert.Len(t, b.existingArgs, 0)
})
}
func TestStatementBuilder_AppendArgs(t *testing.T) {
t.Run("same arg returns same placeholder", func(t *testing.T) {
t.Run("same arg returns different placeholder", func(t *testing.T) {
var b StatementBuilder
b.AppendArgs("same", "same")
assert.Len(t, b.Args(), 1)
assert.Len(t, b.existingArgs, 1)
assert.Len(t, b.Args(), 2)
})
t.Run("same arg different types", func(t *testing.T) {
var b StatementBuilder
b.AppendArgs("same", []byte("same"), "same")
assert.Len(t, b.Args(), 2)
assert.Len(t, b.existingArgs, 2)
assert.Len(t, b.Args(), 3)
})
t.Run("Instruction args are always different", func(t *testing.T) {
var b StatementBuilder
b.AppendArgs(DefaultInstruction, DefaultInstruction)
assert.Len(t, b.Args(), 0)
assert.Len(t, b.existingArgs, 0)
})
}