func (conn *Conn) PrepareContext(ctx context.Context, command string) (*Statement, error) {
	return conn.prepareContext(ctx, command)
}
PrepareContext prepares a statement with context and returns a *Statement
package clickhouse
import (
	"context"
	"fmt"
	"strings"
	"github.com/ClickHouse/clickhouse-go"
	"github.com/romberli/go-util/common"
	"github.com/romberli/go-util/constant"
)
const (
	DefaultDatabase     = "default"
	DefaultReadTimeout  = 10
	DefaultWriteTimeout = 10
)
type Config struct {
	Addr         string
	DBName       string
	DBUser       string
	DBPass       string
	Debug        bool
	ReadTimeout  int
	WriteTimeout int
	AltHosts     []string
}
func NewConfig(addr, dbName, dbUser, dbPass string, debug bool, readTimeout, writeTimeout int, altHosts ...string) Config {
	return Config{
		Addr:         addr,
		DBName:       dbName,
		DBUser:       dbUser,
		DBPass:       dbPass,
		Debug:        debug,
		ReadTimeout:  readTimeout,
		WriteTimeout: writeTimeout,
		AltHosts:     altHosts,
	}
}
func NewConfigWithDefault(addr, dbName, dbUser, dbPass string, altHosts ...string) Config {
	return Config{
		Addr:         addr,
		DBName:       dbName,
		DBUser:       dbUser,
		DBPass:       dbPass,
		Debug:        false,
		ReadTimeout:  DefaultReadTimeout,
		WriteTimeout: DefaultWriteTimeout,
		AltHosts:     altHosts,
	}
}
func (c *Config) AltHostsExist() bool {
	if c.AltHosts != nil && len(c.AltHosts) > constant.ZeroInt {
		return true
	}
	return false
}
func (c *Config) AltHostsString() string {
	if c.AltHosts == nil {
		return constant.EmptyString
	}
	switch len(c.AltHosts) {
	case 0:
		return constant.EmptyString
	case 1:
		return c.AltHosts[constant.ZeroInt]
	default:
		s := c.AltHosts[constant.ZeroInt]
		for _, host := range c.AltHosts[1:] {
			s = ", " + host
		}
		return s
	}
}
func (c *Config) GetConnectionString() string {
	connStr := fmt.Sprintf("tcp://%s?", c.Addr)
	if c.DBName == constant.EmptyString {
		connStr += fmt.Sprintf("database=%s&", DefaultDatabase)
	} else {
		connStr += fmt.Sprintf("database=%s&", c.DBName)
	}
	if c.DBUser != constant.EmptyString {
		connStr += fmt.Sprintf("username=%s&", c.DBUser)
	}
	if c.DBPass != constant.EmptyString {
		connStr += fmt.Sprintf("password=%s&", c.DBPass)
	}
	if c.Debug {
		connStr += "debug=true&"
	}
	if c.ReadTimeout != constant.ZeroInt {
		connStr += fmt.Sprintf("read_timeout=%d&", c.ReadTimeout)
	}
	if c.WriteTimeout != constant.ZeroInt {
		connStr += fmt.Sprintf("write_time=%d&", c.WriteTimeout)
	}
	if c.AltHostsExist() {
		connStr += fmt.Sprintf("alter_hosts=%s&", c.AltHostsString())
	}
	return strings.Trim(connStr, "&")
}
type Conn struct {
	Config
	clickhouse.Clickhouse
}
func NewConnWithConfig(config Config) (*Conn, error) {
	client, err := clickhouse.OpenDirect(config.GetConnectionString())
	if err != nil {
		return nil, err
	}
	return &Conn{
		config,
		client,
	}, nil
}
func NewConn(addr, dbName, dbUser, dbPass string, debug bool, readTimeout, writeTimeout int, altHosts ...string) (*Conn, error) {
	config := NewConfig(addr, dbName, dbUser, dbPass, debug, readTimeout, writeTimeout, altHosts...)
	return NewConnWithConfig(config)
}
func NewConnWithDefault(addr, dbName, dbUser, dbPass string, altHosts ...string) (*Conn, error) {
	config := NewConfigWithDefault(addr, dbName, dbUser, dbPass, altHosts...)
	return NewConnWithConfig(config)
}
func (conn *Conn) Prepare(command string) (*Statement, error) {
	return conn.prepareContext(context.Background(), command)
}