diff --git a/interpolate.go b/interpolate.go index cc8b6c07..7761f59f 100644 --- a/interpolate.go +++ b/interpolate.go @@ -43,11 +43,9 @@ func InterpolateForDialect(query string, value []interface{}, d Dialect) (string return i.String(), nil } -func (i *interpolator) interpolate(query string, value []interface{}, topLevel bool) error { - if strings.Count(query, placeholder) != len(value) { - return ErrPlaceholderCount - } +var escapedPlaceholder = strings.Repeat(placeholder, 2) +func (i *interpolator) interpolate(query string, value []interface{}, topLevel bool) error { valueIndex := 0 for { @@ -56,6 +54,17 @@ func (i *interpolator) interpolate(query string, value []interface{}, topLevel b break } + // escape placeholder by repeating it twice + if strings.HasPrefix(query[index:], escapedPlaceholder) { + i.WriteString(query[:index+len(escapedPlaceholder)]) + query = query[index+len(escapedPlaceholder):] + continue + } + + if valueIndex >= len(value) { + break + } + i.WriteString(query[:index]) if _, ok := value[valueIndex].([]byte); ok && i.IgnoreBinary { i.WriteString(i.Placeholder(i.N)) @@ -71,6 +80,10 @@ func (i *interpolator) interpolate(query string, value []interface{}, topLevel b valueIndex++ } + if valueIndex != len(value) { + return ErrPlaceholderCount + } + // placeholder not found; write remaining query i.WriteString(query) diff --git a/interpolate_test.go b/interpolate_test.go index 1f6b962b..8eb48edf 100644 --- a/interpolate_test.go +++ b/interpolate_test.go @@ -136,6 +136,16 @@ func TestInterpolateForDialect(t *testing.T) { value: []interface{}{(*int64)(nil)}, want: "NULL", }, + { + query: "???? ? ?? ? ??", + value: []interface{}{1, 2}, + want: "???? 1 ?? 2 ??", + }, + { + query: "???", + value: []interface{}{1}, + want: "??1", + }, } { s, err := InterpolateForDialect(test.query, test.value, dialect.MySQL) require.NoError(t, err)