Skip to content

Commit fc56bc8

Browse files
committed
ignore empty values and expressions to prevent syntax error
1 parent b0b0b02 commit fc56bc8

8 files changed

+57
-17
lines changed

cond.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func (c *Cond) LTE(field string, value interface{}) string {
186186

187187
// In is used to construct the expression "field IN (value...)".
188188
func (c *Cond) In(field string, values ...interface{}) string {
189-
if len(field) == 0 {
189+
if len(field) == 0 || len(values) == 0 {
190190
return ""
191191
}
192192

@@ -202,7 +202,7 @@ func (c *Cond) In(field string, values ...interface{}) string {
202202

203203
// NotIn is used to construct the expression "field NOT IN (value...)".
204204
func (c *Cond) NotIn(field string, values ...interface{}) string {
205-
if len(field) == 0 {
205+
if len(field) == 0 || len(values) == 0 {
206206
return ""
207207
}
208208

@@ -369,6 +369,8 @@ func (c *Cond) NotBetween(field string, lower, upper interface{}) string {
369369

370370
// Or is used to construct the expression OR logic like "expr1 OR expr2 OR expr3".
371371
func (c *Cond) Or(orExpr ...string) string {
372+
orExpr = filterEmptyStrings(orExpr)
373+
372374
if len(orExpr) == 0 {
373375
return ""
374376
}
@@ -392,6 +394,8 @@ func (c *Cond) Or(orExpr ...string) string {
392394

393395
// And is used to construct the expression AND logic like "expr1 AND expr2 AND expr3".
394396
func (c *Cond) And(andExpr ...string) string {
397+
andExpr = filterEmptyStrings(andExpr)
398+
395399
if len(andExpr) == 0 {
396400
return ""
397401
}
@@ -453,7 +457,7 @@ func (c *Cond) NotExists(subquery interface{}) string {
453457

454458
// Any is used to construct the expression "field op ANY (value...)".
455459
func (c *Cond) Any(field, op string, values ...interface{}) string {
456-
if len(field) == 0 || len(op) == 0 {
460+
if len(field) == 0 || len(op) == 0 || len(values) == 0 {
457461
return ""
458462
}
459463

@@ -471,7 +475,7 @@ func (c *Cond) Any(field, op string, values ...interface{}) string {
471475

472476
// All is used to construct the expression "field op ALL (value...)".
473477
func (c *Cond) All(field, op string, values ...interface{}) string {
474-
if len(field) == 0 || len(op) == 0 {
478+
if len(field) == 0 || len(op) == 0 || len(values) == 0 {
475479
return ""
476480
}
477481

@@ -489,7 +493,7 @@ func (c *Cond) All(field, op string, values ...interface{}) string {
489493

490494
// Some is used to construct the expression "field op SOME (value...)".
491495
func (c *Cond) Some(field, op string, values ...interface{}) string {
492-
if len(field) == 0 || len(op) == 0 {
496+
if len(field) == 0 || len(op) == 0 || len(values) == 0 {
493497
return ""
494498
}
495499

cond_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@ func TestEmptyCond(t *testing.T) {
123123
func(cond *Cond) string { return cond.LessThan("", 123) },
124124
func(cond *Cond) string { return cond.LessEqualThan("", 123) },
125125
func(cond *Cond) string { return cond.In("", 1, 2, 3) },
126+
func(cond *Cond) string { return cond.In("a") },
126127
func(cond *Cond) string { return cond.NotIn("", 1, 2, 3) },
128+
func(cond *Cond) string { return cond.NotIn("a") },
127129
func(cond *Cond) string { return cond.Like("", "%Huan%") },
128130
func(cond *Cond) string { return cond.ILike("", "%Huan%") },
129131
func(cond *Cond) string { return cond.NotLike("", "%Huan%") },
@@ -137,14 +139,17 @@ func TestEmptyCond(t *testing.T) {
137139
func(cond *Cond) string { return cond.Any("", "", 1, 2) },
138140
func(cond *Cond) string { return cond.Any("", ">", 1, 2) },
139141
func(cond *Cond) string { return cond.Any("$a", "", 1, 2) },
142+
func(cond *Cond) string { return cond.Any("$a", ">") },
140143

141144
func(cond *Cond) string { return cond.All("", "", 1) },
142145
func(cond *Cond) string { return cond.All("", ">", 1) },
143146
func(cond *Cond) string { return cond.All("$a", "", 1) },
147+
func(cond *Cond) string { return cond.All("$a", ">") },
144148

145149
func(cond *Cond) string { return cond.Some("", "", 1, 2, 3) },
146150
func(cond *Cond) string { return cond.Some("", ">", 1, 2, 3) },
147151
func(cond *Cond) string { return cond.Some("$a", "", 1, 2, 3) },
152+
func(cond *Cond) string { return cond.Some("$a", ">") },
148153

149154
func(cond *Cond) string { return cond.IsDistinctFrom("", 1) },
150155
func(cond *Cond) string { return cond.IsNotDistinctFrom("", 1) },

delete.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ func (db *DeleteBuilder) Build() (sql string, args []interface{}) {
172172
// BuildWithFlavor returns compiled DELETE string and args with flavor and initial args.
173173
// They can be used in `DB#Query` of package `database/sql` directly.
174174
func (db *DeleteBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
175-
176175
buf := newStringBuilder()
177176
db.injection.WriteTo(buf, deleteMarkerInit)
178177

select.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,9 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
390390
buf.WriteLeadingString("JOIN ")
391391
buf.WriteString(sb.joinTables[i])
392392

393-
if exprs := sb.joinExprs[i]; len(exprs) > 0 {
393+
if exprs := filterEmptyStrings(sb.joinExprs[i]); len(exprs) > 0 {
394394
buf.WriteString(" ON ")
395-
buf.WriteStrings(sb.joinExprs[i], " AND ")
395+
buf.WriteStrings(exprs, " AND ")
396396
}
397397
}
398398

@@ -414,9 +414,9 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
414414
buf.WriteLeadingString("GROUP BY ")
415415
buf.WriteStrings(sb.groupByCols, ", ")
416416

417-
if len(sb.havingExprs) > 0 {
417+
if havingExprs := filterEmptyStrings(sb.havingExprs); len(havingExprs) > 0 {
418418
buf.WriteString(" HAVING ")
419-
buf.WriteStrings(sb.havingExprs, " AND ")
419+
buf.WriteStrings(havingExprs, " AND ")
420420
}
421421

422422
sb.injection.WriteTo(buf, selectMarkerAfterGroupBy)

stringbuilder.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,29 @@ func (sb *stringBuilder) Reset() {
7575
func (sb *stringBuilder) Grow(n int) {
7676
sb.builder.Grow(n)
7777
}
78+
79+
// filterEmptyStrings removes empty strings from ss.
80+
// As ss rarely contains empty strings, filterEmptyStrings tries to avoid allocation if possible.
81+
func filterEmptyStrings(ss []string) []string {
82+
emptyStrings := 0
83+
84+
for _, s := range ss {
85+
if len(s) == 0 {
86+
emptyStrings++
87+
}
88+
}
89+
90+
if emptyStrings == 0 {
91+
return ss
92+
}
93+
94+
filtered := make([]string, 0, len(ss)-emptyStrings)
95+
96+
for _, s := range ss {
97+
if len(s) != 0 {
98+
filtered = append(filtered, s)
99+
}
100+
}
101+
102+
return filtered
103+
}

update.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,9 @@ func (ub *UpdateBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
260260

261261
ub.injection.WriteTo(buf, updateMarkerAfterUpdate)
262262

263-
if len(ub.assignments) > 0 {
263+
if assignments := filterEmptyStrings(ub.assignments); len(assignments) > 0 {
264264
buf.WriteLeadingString("SET ")
265-
buf.WriteStrings(ub.assignments, ", ")
265+
buf.WriteStrings(assignments, ", ")
266266
}
267267

268268
ub.injection.WriteTo(buf, updateMarkerAfterSet)

whereclause.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,14 @@ type clause struct {
3838
}
3939

4040
func (c *clause) Build(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
41+
exprs := filterEmptyStrings(c.andExprs)
42+
43+
if len(exprs) == 0 {
44+
return
45+
}
46+
4147
buf := newStringBuilder()
42-
buf.WriteStrings(c.andExprs, " AND ")
48+
buf.WriteStrings(exprs, " AND ")
4349
sql, args = c.args.CompileWithFlavor(buf.String(), flavor, initialArg...)
4450
return
4551
}

whereclause_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,10 +245,10 @@ func TestWhereClauseSharedInstances(t *testing.T) {
245245

246246
func TestEmptyWhereExpr(t *testing.T) {
247247
a := assert.New(t)
248-
var emptyExpr []string
249-
sb := Select("*").From("t").Where(emptyExpr...)
250-
ub := Update("t").Set("foo = 1").Where(emptyExpr...)
251-
db := DeleteFrom("t").Where(emptyExpr...)
248+
blankExprs := []string{"", ""}
249+
sb := Select("*").From("t").Where(blankExprs...)
250+
ub := Update("t").Set("foo = 1").Where(blankExprs...)
251+
db := DeleteFrom("t").Where(blankExprs...)
252252

253253
a.Equal(sb.String(), "SELECT * FROM t")
254254
a.Equal(ub.String(), "UPDATE t SET foo = 1")

0 commit comments

Comments
 (0)