func In(query string, args ...interface{}) (string, []interface{}, error) {
	type argMeta struct {
		v      reflect.Value
		i      interface{}
		length int
	}
	var flatArgsCount int
	var anySlices bool
	meta := make([]argMeta, len(args))
	for i, arg := range args {
		if a, ok := arg.(driver.Valuer); ok {
			arg, _ = a.Value()
		}
		v := reflect.ValueOf(arg)
		t := reflectx.Deref(v.Type())
		if t.Kind() == reflect.Slice && t != reflect.TypeOf([]byte{}) {
			meta[i].length = v.Len()
			meta[i].v = v
			anySlices = true
			flatArgsCount += meta[i].length
			if meta[i].length == 0 {
				return "", nil, errors.New("empty slice passed to 'in' query")
			}
		} else {
			meta[i].i = arg
			flatArgsCount++
		}
	}
	if !anySlices {
		return query, args, nil
	}
	newArgs := make([]interface{}, 0, flatArgsCount)
	buf := make([]byte, 0, len(query)+len(", ?")*flatArgsCount)
	var arg, offset int
	for i := strings.IndexByte(query[offset:], '?'); i != -1; i = strings.IndexByte(query[offset:], '?') {
		if arg >= len(meta) {
			return "", nil, errors.New("number of bindVars exceeds arguments")
		}
		argMeta := meta[arg]
		arg++
		if argMeta.length == 0 {
			offset = offset + i + 1
			newArgs = append(newArgs, argMeta.i)
			continue
		}
		buf = append(buf, query[:offset+i+1]...)
		for si := 1; si < argMeta.length; si++ {
			buf = append(buf, ", ?"...)
		}
		newArgs = appendReflectSlice(newArgs, argMeta.v, argMeta.length)
		query = query[offset+i+1:]
		offset = 0
	}
	buf = append(buf, query...)
	if arg < len(meta) {
		return "", nil, errors.New("number of bindVars less than number arguments")
	}
	return string(buf), newArgs, nil
}
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.
package sqlx
import (
	"bytes"
	"database/sql/driver"
	"errors"
	"reflect"
	"strconv"
	"strings"
	"github.com/jmoiron/sqlx/reflectx"
)
const (
	UNKNOWN = iota
	QUESTION
	DOLLAR
	NAMED
	AT
)
func BindType(driverName string) int {
	switch driverName {
	case "postgres", "pgx", "pq-timeouts", "cloudsqlpostgres":
		return DOLLAR
	case "mysql":
		return QUESTION
	case "sqlite3":
		return QUESTION
	case "oci8", "ora", "goracle":
		return NAMED
	case "sqlserver":
		return AT
	}
	return UNKNOWN
}
func Rebind(bindType int, query string) string {
	switch bindType {
	case QUESTION, UNKNOWN:
		return query
	}
	rqb := make([]byte, 0, len(query)+10)
	var i, j int
	for i = strings.Index(query, "?"); i != -1; i = strings.Index(query, "?") {
		rqb = append(rqb, query[:i]...)
		switch bindType {
		case DOLLAR:
			rqb = append(rqb, '$')
		case NAMED:
			rqb = append(rqb, ':', 'a', 'r', 'g')
		case AT:
			rqb = append(rqb, '@', 'p')
		}
		j++
		rqb = strconv.AppendInt(rqb, int64(j), 10)
		query = query[i+1:]
	}
	return string(append(rqb, query...))
}
func rebindBuff(bindType int, query string) string {
	if bindType != DOLLAR {
		return query
	}
	b := make([]byte, 0, len(query))
	rqb := bytes.NewBuffer(b)
	j := 1
	for _, r := range query {
		if r == '?' {
			rqb.WriteRune('$')
			rqb.WriteString(strconv.Itoa(j))
			j++
		} else {
			rqb.WriteRune(r)
		}
	}
	return rqb.String()
}