diff --git a/README.md b/README.md index 5bfd231a1..b5c1a0ace 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,19 @@ will get major version number bumps. go get github.com/jmoiron/sqlx +### Note: `sqlx.In` placeholders + +`sqlx.In` always expects `?` bindvars in the input query, **even for PostgreSQL**. +Do not write `$1` in the string passed to `In` — expand first, then rebind: + +```go +query, args, err := sqlx.In("SELECT * FROM users WHERE level IN (?)", levels) +query = db.Rebind(query) +err = db.Select(&users, query, args...) +``` + +Using `$1` with `In` commonly fails with `number of bindVars less than number arguments`. + ## issues Row headers can be ambiguous (`SELECT 1 AS a, 2 AS a`), and the result of diff --git a/bind.go b/bind.go index e6980392b..bc8a4db42 100644 --- a/bind.go +++ b/bind.go @@ -139,6 +139,16 @@ func asSliceForIn(i interface{}) (v reflect.Value, ok bool) { // In expands slice values in args, returning the modified query string // and a new arg list that can be executed by a database. The `query` should // use the `?` bindVar. The return value uses the `?` bindVar. +// +// Callers must write `?` placeholders even when the target database uses +// `$1` (PostgreSQL), `@p1` (SQL Server), or named binds. Using `$1` in the +// query passed to In will not expand correctly and commonly surfaces as +// "number of bindVars less than number arguments". After In returns, rebind +// for the driver, for example: +// +// query, args, err := sqlx.In("SELECT * FROM users WHERE level IN (?)", levels) +// query = db.Rebind(query) +// err = db.Select(&users, query, args...) func In(query string, args ...interface{}) (string, []interface{}, error) { // argMeta stores reflect.Value and length for slices and // the value itself for non-slice arguments