Skip to content

Commit 0011f39

Browse files
authored
Support array/slice expansion for named SQL parameters in parentheses (#7614)
* feat: support array/slice expansion for named parameters in parentheses * feat: support array/slice expansion for named parameters in parentheses, add testing * refactor: Extract slice/array processing logic into independent functions and replace duplicate code * test: Modify SQL expression test case Vars value type * refactor(expression): merge conditional branches, add parameter value processing functions and optimize the process * style: properly formatted
1 parent eabca1f commit 0011f39

File tree

2 files changed

+42
-39
lines changed

2 files changed

+42
-39
lines changed

clause/expression.go

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -34,25 +34,7 @@ func (expr Expr) Build(builder Builder) {
3434
for _, v := range []byte(expr.SQL) {
3535
if v == '?' && len(expr.Vars) > idx {
3636
if afterParenthesis || expr.WithoutParentheses {
37-
if _, ok := expr.Vars[idx].(driver.Valuer); ok {
38-
builder.AddVar(builder, expr.Vars[idx])
39-
} else {
40-
switch rv := reflect.ValueOf(expr.Vars[idx]); rv.Kind() {
41-
case reflect.Slice, reflect.Array:
42-
if rv.Len() == 0 {
43-
builder.AddVar(builder, nil)
44-
} else {
45-
for i := 0; i < rv.Len(); i++ {
46-
if i > 0 {
47-
builder.WriteByte(',')
48-
}
49-
builder.AddVar(builder, rv.Index(i).Interface())
50-
}
51-
}
52-
default:
53-
builder.AddVar(builder, expr.Vars[idx])
54-
}
55-
}
37+
processValue(builder, expr.Vars[idx])
5638
} else {
5739
builder.AddVar(builder, expr.Vars[idx])
5840
}
@@ -130,7 +112,11 @@ func (expr NamedExpr) Build(builder Builder) {
130112
} else if v == ' ' || v == ',' || v == ')' || v == '"' || v == '\'' || v == '`' || v == '\r' || v == '\n' || v == ';' {
131113
if inName {
132114
if nv, ok := namedMap[string(name)]; ok {
133-
builder.AddVar(builder, nv)
115+
if afterParenthesis {
116+
processValue(builder, nv)
117+
} else {
118+
builder.AddVar(builder, nv)
119+
}
134120
} else {
135121
builder.WriteByte('@')
136122
builder.WriteString(string(name))
@@ -142,25 +128,7 @@ func (expr NamedExpr) Build(builder Builder) {
142128
builder.WriteByte(v)
143129
} else if v == '?' && len(expr.Vars) > idx {
144130
if afterParenthesis {
145-
if _, ok := expr.Vars[idx].(driver.Valuer); ok {
146-
builder.AddVar(builder, expr.Vars[idx])
147-
} else {
148-
switch rv := reflect.ValueOf(expr.Vars[idx]); rv.Kind() {
149-
case reflect.Slice, reflect.Array:
150-
if rv.Len() == 0 {
151-
builder.AddVar(builder, nil)
152-
} else {
153-
for i := 0; i < rv.Len(); i++ {
154-
if i > 0 {
155-
builder.WriteByte(',')
156-
}
157-
builder.AddVar(builder, rv.Index(i).Interface())
158-
}
159-
}
160-
default:
161-
builder.AddVar(builder, expr.Vars[idx])
162-
}
163-
}
131+
processValue(builder, expr.Vars[idx])
164132
} else {
165133
builder.AddVar(builder, expr.Vars[idx])
166134
}
@@ -188,6 +156,31 @@ func (expr NamedExpr) Build(builder Builder) {
188156
}
189157
}
190158

159+
// processValue handles different value types appropriately for SQL parameter binding
160+
// It checks for driver.Valuer first, then handles slices/arrays, and finally adds single values
161+
func processValue(builder Builder, value interface{}) {
162+
if _, ok := value.(driver.Valuer); ok {
163+
builder.AddVar(builder, value)
164+
return
165+
}
166+
167+
switch rv := reflect.ValueOf(value); rv.Kind() {
168+
case reflect.Slice, reflect.Array:
169+
if rv.Len() == 0 {
170+
builder.AddVar(builder, nil)
171+
} else {
172+
for i := 0; i < rv.Len(); i++ {
173+
if i > 0 {
174+
builder.WriteByte(',')
175+
}
176+
builder.AddVar(builder, rv.Index(i).Interface())
177+
}
178+
}
179+
default:
180+
builder.AddVar(builder, value)
181+
}
182+
}
183+
191184
// IN Whether a value is within a set of values
192185
type IN struct {
193186
Column interface{}

clause/expression_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ func TestNamedExpr(t *testing.T) {
8585
Vars: []interface{}{NamedArgument{Name1: "jinzhu", Base: Base{Name2: "jinzhu2"}}},
8686
Result: "@@test AND name1 = ? AND name2 = ? AND name3 = ? @notexist",
8787
ExpectedVars: []interface{}{"jinzhu", "jinzhu2", "jinzhu"},
88+
}, {
89+
SQL: "name in (@names)",
90+
Vars: []interface{}{map[string]interface{}{"names": []interface{}{"jinzhu", "jinzhu2"}}},
91+
Result: "name in (?,?)",
92+
ExpectedVars: []interface{}{"jinzhu", "jinzhu2"},
93+
}, {
94+
SQL: "name in (@names)",
95+
Vars: []interface{}{map[string]interface{}{"names": "jinzhu"}},
96+
Result: "name in (?)",
97+
ExpectedVars: []interface{}{"jinzhu"},
8898
}, {
8999
SQL: "create table ? (? ?, ? ?)",
90100
Vars: []interface{}{},

0 commit comments

Comments
 (0)