func (c *Context) ApplyOpts(opts ...ContextOption) {
	for _, opt := range opts {
		opt(c)
	}
}
Applys the options given to the context. Mostly for tests, not safe for use after construction of the context.
package sql
import (
	"context"
	"fmt"
	"io"
	"os"
	"strings"
	"sync"
	"sync/atomic"
	"time"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/log"
	"github.com/sirupsen/logrus"
	"golang.org/x/sync/errgroup"
)
type key uint
const (
	QueryKey key = iota
)
const (
	CurrentDBSessionVar  = "current_database"
	AutoCommitSessionVar = "autocommit"
)
type Client struct {
	User string
	Address string
	Capabilities uint32
}
type Session interface {
	Address() string
	Client() Client
	SetSessionVariable(ctx *Context, sysVarName string, value interface{}) error
	SetUserVariable(ctx *Context, varName string, value interface{}) error
	GetSessionVariable(ctx *Context, sysVarName string) (interface{}, error)
	GetUserVariable(ctx *Context, varName string) (Type, interface{}, error)
	GetAllSessionVariables() map[string]interface{}
	GetCurrentDatabase() string
	SetCurrentDatabase(dbName string)
	CommitTransaction(ctx *Context, dbName string, transaction Transaction) error
	ID() uint32
	Warn(warn *Warning)
	Warnings() []*Warning
	ClearWarnings()
	WarningCount() uint16
	AddLock(lockName string) error
	DelLock(lockName string) error
	IterLocks(cb func(name string) error) error
	SetLastQueryInfo(key string, value int64)
	GetLastQueryInfo(key string) int64
	GetTransaction() Transaction
	SetTransaction(tx Transaction)
	SetIgnoreAutoCommit(ignore bool)
	GetIgnoreAutoCommit() bool
	GetLogger() *logrus.Entry
	SetLogger(*logrus.Entry)
	GetIndexRegistry() *IndexRegistry
	GetViewRegistry() *ViewRegistry
	SetIndexRegistry(*IndexRegistry)
	SetViewRegistry(*ViewRegistry)
}
type PersistableSession interface {
	Session
	PersistGlobal(sysVarName string, value interface{}) error
	RemovePersistedGlobal(sysVarName string) error
	RemoveAllPersistedGlobals() error
	GetPersistedValue(k string) (interface{}, error)
}
type BaseSession struct {
	id     uint32
	addr   string
	client Client
	mu sync.RWMutex
	logger           *logrus.Entry
	currentDB        string
	systemVars       map[string]interface{}
	userVars         map[string]interface{}
	idxReg           *IndexRegistry
	viewReg          *ViewRegistry
	warnings         []*Warning
	warncnt          uint16
	locks            map[string]bool
	queriedDb        string
	lastQueryInfo    map[string]int64
	tx               Transaction
	ignoreAutocommit bool
}
func (s *BaseSession) GetLogger() *logrus.Entry {
	s.mu.Lock()
	defer s.mu.Unlock()
	if s.logger == nil {
		log := logrus.StandardLogger()
		s.logger = logrus.NewEntry(log)
	}
	return s.logger
}
func (s *BaseSession) SetLogger(logger *logrus.Entry) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.logger = logger
}
func (s *BaseSession) SetIgnoreAutoCommit(ignore bool) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.ignoreAutocommit = ignore
}
func (s *BaseSession) GetIgnoreAutoCommit() bool {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.ignoreAutocommit
}
var _ Session = (*BaseSession)(nil)
func (s *BaseSession) CommitTransaction(*Context, string, Transaction) error {
	return nil
}
func (s *BaseSession) Address() string { return s.addr }
func (s *BaseSession) Client() Client { return s.client }
func (s *BaseSession) GetAllSessionVariables() map[string]interface{} {
	m := make(map[string]interface{})
	s.mu.RLock()
	defer s.mu.RUnlock()
	for k, v := range s.systemVars {
		m[k] = v
	}
	return m
}
func (s *BaseSession) SetSessionVariable(ctx *Context, sysVarName string, value interface{}) error {
	sysVar, _, ok := SystemVariables.GetGlobal(sysVarName)
	if !ok {
		return ErrUnknownSystemVariable.New(sysVarName)
	}
	if sysVar.Scope == SystemVariableScope_Global {
		return ErrSystemVariableGlobalOnly.New(sysVarName)
	}
	if !sysVar.Dynamic {
		return ErrSystemVariableReadOnly.New(sysVarName)
	}
	convertedVal, err := sysVar.Type.Convert(value)
	if err != nil {
		return err
	}
	s.mu.Lock()
	defer s.mu.Unlock()
	s.systemVars[sysVar.Name] = convertedVal
	return nil
}
func (s *BaseSession) SetUserVariable(ctx *Context, varName string, value interface{}) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.userVars[strings.ToLower(varName)] = value
	return nil
}
func (s *BaseSession) GetSessionVariable(ctx *Context, sysVarName string) (interface{}, error) {
	sysVar, _, ok := SystemVariables.GetGlobal(sysVarName)
	if !ok {
		return nil, ErrUnknownSystemVariable.New(sysVarName)
	}
	s.mu.Lock()
	defer s.mu.Unlock()
	val, ok := s.systemVars[strings.ToLower(sysVarName)]
	if !ok {
		s.systemVars[strings.ToLower(sysVarName)] = sysVar.Default
		val = sysVar.Default
	}
	return val, nil
}
func (s *BaseSession) GetUserVariable(ctx *Context, varName string) (Type, interface{}, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	val, ok := s.userVars[strings.ToLower(varName)]
	if !ok {
		return Null, nil, nil
	}
	return ApproximateTypeFromValue(val), val, nil
}
func (s *BaseSession) GetCurrentDatabase() string {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.currentDB
}
func (s *BaseSession) SetCurrentDatabase(dbName string) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.currentDB = dbName
}
func (s *BaseSession) ID() uint32 { return s.id }
func (s *BaseSession) Warn(warn *Warning) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.warnings = append(s.warnings, warn)
}
func (s *BaseSession) Warnings() []*Warning {
	s.mu.RLock()
	defer s.mu.RUnlock()
	n := len(s.warnings)
	warns := make([]*Warning, n)
	for i := 0; i < n; i++ {
		warns[i] = s.warnings[n-i-1]
	}
	return warns
}
func (s *BaseSession) ClearWarnings() {
	s.mu.Lock()
	defer s.mu.Unlock()
	cnt := uint16(len(s.warnings))
	if s.warncnt == cnt {
		if s.warnings != nil {
			s.warnings = s.warnings[:0]
		}
		s.warncnt = 0
	} else {
		s.warncnt = cnt
	}
}
func (s *BaseSession) WarningCount() uint16 {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return uint16(len(s.warnings))
}
func (s *BaseSession) AddLock(lockName string) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.locks[lockName] = true
	return nil
}
func (s *BaseSession) DelLock(lockName string) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	delete(s.locks, lockName)
	return nil
}
func (s *BaseSession) IterLocks(cb func(name string) error) error {
	s.mu.RLock()
	defer s.mu.RUnlock()
	for name := range s.locks {
		err := cb(name)
		if err != nil {
			return err
		}
	}
	return nil
}
func (s *BaseSession) GetQueriedDatabase() string {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.queriedDb
}
func (s *BaseSession) SetQueriedDatabase(dbName string) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.queriedDb = dbName
}
func (s *BaseSession) GetIndexRegistry() *IndexRegistry {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.idxReg
}
func (s *BaseSession) GetViewRegistry() *ViewRegistry {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.viewReg
}
func (s *BaseSession) SetIndexRegistry(reg *IndexRegistry) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.idxReg = reg
}
func (s *BaseSession) SetViewRegistry(reg *ViewRegistry) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.viewReg = reg
}
type (
	TypedValue struct {
		Typ   Type
		Value interface{}
	}
	Warning struct {
		Level   string
		Message string
		Code    int
	}
)
const (
	RowCount     = "row_count"
	FoundRows    = "found_rows"
	LastInsertId = "last_insert_id"
)
func defaultLastQueryInfo() map[string]int64 {
	return map[string]int64{
		RowCount:     0,
		FoundRows:    1,  
		LastInsertId: 0,
	}
}
func (s *BaseSession) SetLastQueryInfo(key string, value int64) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.lastQueryInfo[key] = value
}
func (s *BaseSession) GetLastQueryInfo(key string) int64 {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.lastQueryInfo[key]
}
func GetTmpdirSessionVar() string {
	ret := os.Getenv("TMPDIR")
	if ret != "" {
		return ret
	}
	ret = os.Getenv("TEMP")
	if ret != "" {
		return ret
	}
	ret = os.Getenv("TMP")
	if ret != "" {
		return ret
	}
	return ""
}
func HasDefaultValue(ctx *Context, s Session, key string) (bool, interface{}) {
	val, err := s.GetSessionVariable(ctx, key)
	if err == nil {
		sysVar, _, ok := SystemVariables.GetGlobal(key)
		if ok {
			return sysVar.Default == val, val
		}
	}
	return true, nil
}
func (s *BaseSession) GetTransaction() Transaction {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.tx
}
func (s *BaseSession) SetTransaction(tx Transaction) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.tx = tx
}
func NewBaseSessionWithClientServer(server string, client Client, id uint32) *BaseSession {
	return &BaseSession{
		addr:          server,
		client:        client,
		id:            id,
		systemVars:    SystemVariables.NewSessionMap(),
		userVars:      make(map[string]interface{}),
		idxReg:        NewIndexRegistry(),
		viewReg:       NewViewRegistry(),
		mu:            sync.RWMutex{},
		locks:         make(map[string]bool),
		lastQueryInfo: defaultLastQueryInfo(),
	}
}
var autoSessionIDs uint32 = 1
func NewBaseSession() *BaseSession {
	return &BaseSession{
		id:            atomic.AddUint32(&autoSessionIDs, 1),
		systemVars:    SystemVariables.NewSessionMap(),
		userVars:      make(map[string]interface{}),
		idxReg:        NewIndexRegistry(),
		viewReg:       NewViewRegistry(),
		mu:            sync.RWMutex{},
		locks:         make(map[string]bool),
		lastQueryInfo: defaultLastQueryInfo(),
	}
}
type Context struct {
	context.Context
	Session
	Memory      *MemoryManager
	ProcessList ProcessList
	pid         uint64
	query       string
	queryTime   time.Time
	tracer      opentracing.Tracer
	rootSpan    opentracing.Span
}
type ContextOption func(*Context)
func WithSession(s Session) ContextOption {
	return func(ctx *Context) {
		ctx.Session = s
	}
}
func WithTracer(t opentracing.Tracer) ContextOption {
	return func(ctx *Context) {
		ctx.tracer = t
	}
}
func WithPid(pid uint64) ContextOption {
	return func(ctx *Context) {
		ctx.pid = pid
	}
}
func WithQuery(q string) ContextOption {
	return func(ctx *Context) {
		ctx.query = q
	}
}
func WithMemoryManager(m *MemoryManager) ContextOption {
	return func(ctx *Context) {
		ctx.Memory = m
	}
}
func WithRootSpan(s opentracing.Span) ContextOption {
	return func(ctx *Context) {
		ctx.rootSpan = s
	}
}
func WithProcessList(p ProcessList) ContextOption {
	return func(ctx *Context) {
		ctx.ProcessList = p
	}
}
var ctxNowFunc = time.Now
var ctxNowFuncMutex = &sync.Mutex{}
func RunWithNowFunc(nowFunc func() time.Time, fn func() error) error {
	ctxNowFuncMutex.Lock()
	defer ctxNowFuncMutex.Unlock()
	initialNow := ctxNowFunc
	ctxNowFunc = nowFunc
	defer func() {
		ctxNowFunc = initialNow
	}()
	return fn()
}
func NewContext(
	ctx context.Context,
	opts ...ContextOption,
) *Context {
	c := &Context{
		Context:   ctx,
		Session:   NewBaseSession(),
		queryTime: ctxNowFunc(),
		tracer:    opentracing.NoopTracer{},
	}
	for _, opt := range opts {
		opt(c)
	}
	if c.Memory == nil {
		c.Memory = NewMemoryManager(ProcessMemory)
	}
	if c.ProcessList == nil {
		c.ProcessList = EmptyProcessList{}
	}
	return c
}