func (dbs *DBs) NamedExec(query string, arg interface{}) (sql.Result, error) {
	return _namedExec(context.Background(), dbs.masters, query, arg)
}
NamedExec do named exec.
Any named placeholder parameters are replaced with fields from arg.
package mssqlx
import (
	"context"
	"database/sql"
	"errors"
	"os"
	"sync"
	"time"
	"github.com/hashicorp/go-multierror"
	"github.com/jmoiron/sqlx"
)
var (
	ErrNoConnection = errors.New("no connection available")
	ErrNoConnectionOrWsrep = errors.New("no connection available or Wsrep is not ready")
)
const (
	DefaultHealthCheckPeriodInMilli = 40
)
var hostName string
func init() {
	hostName, _ = os.Hostname()
}
func ping(w *wrapper) (err error) {
	_, err = w.db.Exec("SELECT 1")
	return
}
type DBs struct {
	driverName      string
	readQuerySource ReadQuerySource
	masters *balancer
	slaves  *balancer
	all     *balancer
	_masters []*wrapper
	_slaves  []*wrapper
	_all     []*wrapper
}
func (dbs *DBs) DriverName() string {
	return dbs.driverName
}
func (dbs *DBs) getDBs(s []*wrapper) ([]*sqlx.DB, int) {
	n := len(s)
	r := make([]*sqlx.DB, n)
	for i, v := range s {
		r[i] = v.db
	}
	return r, n
}
func (dbs *DBs) readBalancer() *balancer {
	if dbs.readQuerySource == ReadQuerySourceAll {
		return dbs.all
	}
	return dbs.slaves
}
func (dbs *DBs) GetAllMasters() ([]*sqlx.DB, int) {
	return dbs.getDBs(dbs._masters)
}
func (dbs *DBs) GetAllSlaves() ([]*sqlx.DB, int) {
	return dbs.getDBs(dbs._slaves)
}
func _ping(target []*wrapper) []error {
	if target == nil {
		return nil
	}
	nn := len(target)
	if nn == 0 {
		return nil
	}
	errResult := make([]error, nn)
	var wg sync.WaitGroup
	for i := range target {
		if target[i] != nil && target[i].db != nil {
			wg.Add(1)
			go func(ind int, wg *sync.WaitGroup) {
				errResult[ind] = target[ind].db.Ping()
				wg.Done()
			}(i, &wg)
		}
	}
	wg.Wait()
	return errResult
}
func (dbs *DBs) Ping() []error {
	return _ping(dbs._all)
}
func (dbs *DBs) PingMaster() []error {
	return _ping(dbs._masters)
}
func (dbs *DBs) PingSlave() []error {
	return _ping(dbs._slaves)
}
func _close(target []*wrapper) []error {
	if target == nil {
		return nil
	}
	nn := len(target)
	if nn == 0 {
		return nil
	}
	errResult := make([]error, nn)
	var wg sync.WaitGroup
	for i, db := range target {
		if db != nil && db.db != nil {
			wg.Add(1)
			go func(db *wrapper, ind int, wg *sync.WaitGroup) {
				errResult[ind] = db.db.Close()
				wg.Done()
			}(db, i, &wg)
		}
	}
	wg.Wait()
	return errResult
}
func (dbs *DBs) Destroy() []error {
	res := _close(dbs._all)
	if dbs.masters != nil {
		dbs.masters.destroy()
	}
	if dbs.slaves != nil {
		dbs.slaves.destroy()
	}
	dbs.all.destroy()
	return res
}
func (dbs *DBs) DestroyMaster() []error {
	if dbs.masters != nil {
		dbs.masters.destroy()
	}
	return _close(dbs._masters)
}
func (dbs *DBs) DestroySlave() []error {
	if dbs.slaves != nil {
		dbs.slaves.destroy()
	}
	return _close(dbs._slaves)
}
func _setMaxIdleConns(target []*wrapper, n int) {
	if target == nil {
		return
	}
	nn := len(target)
	if nn == 0 {
		return
	}
	var wg sync.WaitGroup
	for _, db := range target {
		if db != nil && db.db != nil {
			wg.Add(1)
			go func(db *wrapper, wg *sync.WaitGroup) {
				db.db.SetMaxIdleConns(n)
				wg.Done()
			}(db, &wg)
		}
	}
	wg.Wait()
}
func (dbs *DBs) SetHealthCheckPeriod(period uint64) {
	dbs.masters.setHealthCheckPeriod(period)
	dbs.slaves.setHealthCheckPeriod(period)
}
func (dbs *DBs) SetMasterHealthCheckPeriod(period uint64) {
	dbs.masters.setHealthCheckPeriod(period)
}
func (dbs *DBs) SetSlaveHealthCheckPeriod(period uint64) {
	dbs.slaves.setHealthCheckPeriod(period)
}
func (dbs *DBs) SetMaxIdleConns(n int) {
	_setMaxIdleConns(dbs._all, n)
}
func (dbs *DBs) SetMasterMaxIdleConns(n int) {
	_setMaxIdleConns(dbs._masters, n)
}
func (dbs *DBs) SetSlaveMaxIdleConns(n int) {
	_setMaxIdleConns(dbs._slaves, n)
}
func _setMaxOpenConns(target []*wrapper, n int) {
	if target == nil {
		return
	}
	nn := len(target)
	if nn == 0 {
		return
	}
	var wg sync.WaitGroup
	for _, db := range target {
		if db != nil && db.db != nil {
			wg.Add(1)
			go func(db *wrapper, wg *sync.WaitGroup) {
				db.db.SetMaxOpenConns(n)
				wg.Done()
			}(db, &wg)
		}
	}
	wg.Wait()
}
func (dbs *DBs) SetMaxOpenConns(n int) {
	_setMaxOpenConns(dbs._all, n)
}
func (dbs *DBs) SetMasterMaxOpenConns(n int) {
	_setMaxOpenConns(dbs._masters, n)
}
func (dbs *DBs) SetSlaveMaxOpenConns(n int) {
	_setMaxOpenConns(dbs._slaves, n)
}
func _setConnMaxLifetime(target []*wrapper, d time.Duration) {
	if target == nil {
		return
	}
	nn := len(target)
	if nn == 0 {
		return
	}
	var wg sync.WaitGroup
	for _, db := range target {
		if db != nil && db.db != nil {
			wg.Add(1)
			go func(db *wrapper, wg *sync.WaitGroup) {
				db.db.SetConnMaxLifetime(d)
				wg.Done()
			}(db, &wg)
		}
	}
	wg.Wait()
}
func (dbs *DBs) SetConnMaxLifetime(d time.Duration) {
	_setConnMaxLifetime(dbs._all, d)
}
func (dbs *DBs) SetMasterConnMaxLifetime(d time.Duration) {
	_setConnMaxLifetime(dbs._masters, d)
}
func (dbs *DBs) SetSlaveConnMaxLifetime(d time.Duration) {
	_setConnMaxLifetime(dbs._slaves, d)
}
func _stats(target []*wrapper) []sql.DBStats {
	if target == nil {
		return nil
	}
	nn := len(target)
	if nn == 0 {
		return nil
	}
	result := make([]sql.DBStats, nn)
	var wg sync.WaitGroup
	for ind, db := range target {
		if db != nil && db.db != nil {
			wg.Add(1)
			go func(db *wrapper, ind int, wg *sync.WaitGroup) {
				result[ind] = db.db.Stats()
				wg.Done()
			}(db, ind, &wg)
		}
	}
	wg.Wait()
	return result
}
func (dbs *DBs) Stats() (stats []sql.DBStats) {
	stats = _stats(dbs._all)
	return
}
func (dbs *DBs) StatsMaster() (stats []sql.DBStats) {
	stats = _stats(dbs._masters)
	return
}
func (dbs *DBs) StatsSlave() (stats []sql.DBStats) {
	stats = _stats(dbs._slaves)
	return
}
func _mapperFunc(target []*wrapper, mf func(string) string) {
	if target == nil {
		return
	}
	nn := len(target)
	if nn == 0 {
		return
	}
	var wg sync.WaitGroup
	for ind, db := range target {
		if db != nil {
			wg.Add(1)
			go func(db *wrapper, ind int) {
				db.db.MapperFunc(mf)
				wg.Done()
			}(db, ind)
		}
	}
	wg.Wait()
}
func (dbs *DBs) MapperFunc(mf func(string) string) {
	_mapperFunc(dbs._all, mf)
}
func (dbs *DBs) MapperFuncMaster(mf func(string) string) {
	_mapperFunc(dbs._masters, mf)
}
func (dbs *DBs) MapperFuncSlave(mf func(string) string) {
	_mapperFunc(dbs._slaves, mf)
}
func (dbs *DBs) Rebind(query string) string {
	if dbs._all == nil || len(dbs._all) == 0 {
		return ""
	}
	for _, db := range dbs._all {
		if db != nil && db.db != nil {
			return db.db.Rebind(query)
		}
	}
	return ""
}
func (dbs *DBs) BindNamed(query string, arg interface{}) (string, []interface{}, error) {
	if dbs._all == nil || len(dbs._all) == 0 {
		return "", nil, ErrNoConnection
	}
	for _, db := range dbs._all {
		if db != nil {
			return db.db.BindNamed(query, arg)
		}
	}
	return "", nil, ErrNoConnection
}
func getDBFromBalancer(target *balancer) (db *wrapper, err error) {
	if db = target.get(target.isMulti); db != nil {
		return
	}
	for i := 0; i < 3; i++ {
		time.Sleep(time.Duration(target.getHealthCheckPeriod()) * time.Millisecond)
		if db = target.get(target.isMulti); db != nil {
			return
		}
	}
	if target.isWsrep {
		err = ErrNoConnectionOrWsrep
	} else {
		err = ErrNoConnection
	}
	return
}
func shouldFailure(w *wrapper, isWsrep bool, err error) (bool, error) {
	if err == nil || isStdErr(err) {
		return false, err
	}
	if isWsrep && IsWsrepNotReady(err) {
		return true, err
	}
	if e := ping(w); e != nil {
		err = multierror.Append(err, e).ErrorOrNil()
		return true, err
	}
	return false, err
}
func _namedQuery(ctx context.Context, target *balancer, query string, arg interface{}) (res *sqlx.Rows, err error) {
	var (
		w *wrapper
		r interface{}
	)
	for {
		if w, err = getDBFromBalancer(target); err != nil {
			reportError(query, err)
			return
		}
		r, err = retryFunc(query, func() (interface{}, error) {
			return w.db.NamedQueryContext(ctx, query, arg)
		})
		if r != nil {
			res = r.(*sqlx.Rows)
		}
		var should bool
		if should, err = shouldFailure(w, target.isWsrep, err); should {
			target.failure(w, err)
			continue
		}
		return
	}
}
func (dbs *DBs) NamedQuery(query string, arg interface{}) (*sqlx.Rows, error) {
	return _namedQuery(context.Background(), dbs.readBalancer(), query, arg)
}
func (dbs *DBs) NamedQueryOnMaster(query string, arg interface{}) (*sqlx.Rows, error) {
	return _namedQuery(context.Background(), dbs.masters, query, arg)
}
func (dbs *DBs) NamedQueryContext(ctx context.Context, query string, arg interface{}) (*sqlx.Rows, error) {
	return _namedQuery(ctx, dbs.readBalancer(), query, arg)
}
func (dbs *DBs) NamedQueryContextOnMaster(ctx context.Context, query string, arg interface{}) (*sqlx.Rows, error) {
	return _namedQuery(ctx, dbs.masters, query, arg)
}
func _namedExec(ctx context.Context, target *balancer, query string, arg interface{}) (res sql.Result, err error) {
	var (
		w *wrapper
		r interface{}
	)
	for {
		if w, err = getDBFromBalancer(target); err != nil {
			reportError(query, err)
			return
		}
		r, err = retryFunc(query, func() (interface{}, error) {
			return w.db.NamedExecContext(ctx, query, arg)
		})
		if r != nil {
			res = r.(sql.Result)
		}
		var should bool
		if should, err = shouldFailure(w, target.isWsrep, err); should {
			target.failure(w, err)
			continue
		}
		return
	}
}