// IsAutocommit checks if it is in the auto-commit mode. func (s *session) isAutocommit(ctx context.Context) bool { if ctx.Value(&sqlexec.RestrictedSQLExecutorKeyType{}) != nil { return false } autocommit, ok := variable.GetSessionVars(ctx).Systems["autocommit"] if !ok { if s.initing { return false } var err error autocommit, err = s.GetGlobalSysVar(ctx, "autocommit") if err != nil { log.Errorf("Get global sys var error: %v", err) return false } variable.GetSessionVars(ctx).Systems["autocommit"] = autocommit ok = true } if ok && (autocommit == "ON" || autocommit == "on" || autocommit == "1") { variable.GetSessionVars(ctx).SetStatusFlag(mysql.ServerStatusAutocommit, true) return true } variable.GetSessionVars(ctx).SetStatusFlag(mysql.ServerStatusAutocommit, false) return false }
// GetSessionVars gets the session vars from context. func GetSessionVars(ctx context.Context) *SessionVars { v, ok := ctx.Value(sessionVarsKey).(*SessionVars) if !ok { return nil } return v }
// GetCurrentSchema gets current schema name from context. func GetCurrentSchema(ctx context.Context) string { v, ok := ctx.Value(currentDBKey).(string) if !ok { return "" } return v }
// GetGlobalVarAccessor gets accessor from ctx. func GetGlobalVarAccessor(ctx context.Context) GlobalVarAccessor { v, ok := ctx.Value(accessorKey).(GlobalVarAccessor) if !ok { panic("Miss global sysvar accessor") } return v }
// GetExecArgs gets executive args from context. func GetExecArgs(ctx context.Context) []interface{} { v, ok := ctx.Value(execArgsKey).([]interface{}) if !ok { return nil } return v }
// IsAutocommit checks if it is in the auto-commit mode. func (s *session) isAutocommit(ctx context.Context) (bool, error) { sessionVar := variable.GetSessionVars(ctx) autocommit := sessionVar.GetSystemVar("autocommit") if autocommit.IsNull() { if ctx.Value(context.Initing) != nil { return false, nil } autocommitStr, err := s.GetGlobalSysVar(ctx, "autocommit") if err != nil { return false, errors.Trace(err) } autocommit.SetString(autocommitStr) err = sessionVar.SetSystemVar("autocommit", autocommit) if err != nil { return false, errors.Trace(err) } } autocommitStr := autocommit.GetString() if autocommitStr == "ON" || autocommitStr == "on" || autocommitStr == "1" { variable.GetSessionVars(ctx).SetStatusFlag(mysql.ServerStatusAutocommit, true) return true, nil } variable.GetSessionVars(ctx).SetStatusFlag(mysql.ServerStatusAutocommit, false) return false, nil }
// ExecRestrictedSQL implements SQLHelper interface. // This is used for executing some restricted sql statements. func (s *session) ExecRestrictedSQL(ctx context.Context, sql string) (rset.Recordset, error) { if ctx.Value(&sqlexec.RestrictedSQLExecutorKeyType{}) != nil { // We do not support run this function concurrently. // TODO: Maybe we should remove this restriction latter. return nil, errors.New("Should not call ExecRestrictedSQL concurrently.") } statements, err := Compile(ctx, sql) if err != nil { log.Errorf("Compile %s with error: %v", sql, err) return nil, errors.Trace(err) } if len(statements) != 1 { log.Errorf("ExecRestrictedSQL only executes one statement. Too many/few statement in %s", sql) return nil, errors.New("Wrong number of statement.") } st := statements[0] // Check statement for some restriction // For example only support DML on system meta table. // TODO: Add more restrictions. log.Debugf("Executing %s [%s]", st.OriginText(), sql) ctx.SetValue(&sqlexec.RestrictedSQLExecutorKeyType{}, true) defer ctx.ClearValue(&sqlexec.RestrictedSQLExecutorKeyType{}) rs, err := st.Exec(ctx) return rs, errors.Trace(err) }
// GetSchemaVersion gets schema version in the context. func GetSchemaVersion(ctx context.Context) int64 { v, ok := ctx.Value(schemaVersionKey).(int64) if !ok { log.Error("get schema version failed") } return v }
// GetTiDBSystemVar get variable value for name. // The variable should be a TiDB specific system variable (The vars in tidbSysVars map). // If the session scope variable is not set, it will get global scope value and fill session scope value. func (s *SessionVars) GetTiDBSystemVar(ctx context.Context, name string) (string, error) { key := strings.ToLower(name) _, ok := tidbSysVars[key] if !ok { return "", errors.Errorf("%s is not a TiDB specific system variable.", name) } sVal, ok := s.systems[key] if ok { return sVal, nil } if ctx.Value(context.Initing) != nil { // When running bootstrap or upgrade job, we should not access global storage. return SysVars[key].Value, nil } if key == DistSQLScanConcurrencyVar { // Get global variable need to scan table which depends on DistSQLScanConcurrencyVar. // So we should add it here to break the dependency loop. s.systems[DistSQLScanConcurrencyVar] = SysVars[key].Value } globalVars := GetGlobalVarAccessor(ctx) globalVal, err := globalVars.GetGlobalSysVar(ctx, key) if err != nil { if key == DistSQLScanConcurrencyVar { // Clean up. delete(s.systems, DistSQLScanConcurrencyVar) } return "", errors.Trace(err) } s.systems[key] = globalVal return globalVal, nil }
// ShouldAutocommit gets checker from ctx and checks if it should autocommit. func ShouldAutocommit(ctx context.Context) (bool, error) { v, ok := ctx.Value(key).(Checker) if !ok { panic("Miss autocommit checker") } return v.ShouldAutocommit(ctx) }
// GetDomain gets domain from context. func GetDomain(ctx context.Context) *domain.Domain { v, ok := ctx.Value(domainKey).(*domain.Domain) if !ok { return nil } return v }
func getRowStack(ctx context.Context) *RowStack { v := ctx.Value(rowStackKey) if v == nil { return nil } // must be RowStack t := v.(*RowStack) return t }
// GetPrewriteValue gets binlog prewrite value in the context. func GetPrewriteValue(ctx context.Context, createIfNotExists bool) *binlog.PrewriteValue { v, ok := ctx.Value(binlogKey).(*binlog.PrewriteValue) if !ok && createIfNotExists { schemaVer := GetSchemaVersion(ctx) v = &binlog.PrewriteValue{SchemaVersion: schemaVer} ctx.SetValue(binlogKey, v) } return v }
func (s *session) ShouldAutocommit(ctx context.Context) bool { if ctx.Value(&sqlexec.RestrictedSQLExecutorKeyType{}) != nil { return false } // With START TRANSACTION, autocommit remains disabled until you end // the transaction with COMMIT or ROLLBACK. if variable.GetSessionVars(ctx).Status&mysql.ServerStatusInTrans == 0 && s.isAutocommit(ctx) { return true } return false }
func getDirtyDB(ctx context.Context) *dirtyDB { var udb *dirtyDB x := ctx.Value(DirtyDBKey) if x == nil { udb = &dirtyDB{tables: make(map[int64]*dirtyTable)} ctx.SetValue(DirtyDBKey, udb) } else { udb = x.(*dirtyDB) } return udb }
func (sq *SubQuery) push(ctx context.Context) { var st []*SubQuery v := ctx.Value(subQueryStackKey) if v == nil { st = []*SubQuery{} } else { // must ok st = v.([]*SubQuery) } st = append(st, sq) ctx.SetValue(subQueryStackKey, st) }
// SetOuterQueryUsed is called when current running subquery uses outer query. func SetOuterQueryUsed(ctx context.Context) { v := ctx.Value(subQueryStackKey) if v == nil { return } st := v.([]*SubQuery) // if current sub query uses outer query, the select result can not be cached, // at the same time, all the upper sub query must not cache the result too. for i := len(st) - 1; i >= 0; i-- { st[i].UseOuterQuery = true } }
// addDDLJob gets a global job ID and puts the DDL job in the DDL queue. func (d *ddl) addDDLJob(ctx context.Context, job *model.Job) error { job.Query, _ = ctx.Value(context.QueryString).(string) return kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error { t := meta.NewMeta(txn) var err error job.ID, err = t.GenGlobalID() if err != nil { return errors.Trace(err) } err = t.EnQueueDDLJob(job) return errors.Trace(err) }) }
// GetGlobalSysVar implements GlobalVarAccessor.GetGlobalSysVar interface. func (s *session) GetGlobalSysVar(ctx context.Context, name string) (string, error) { if ctx.Value(context.Initing) != nil { // When running bootstrap or upgrade, we should not access global storage. return "", nil } sql := fmt.Sprintf(`SELECT VARIABLE_VALUE FROM %s.%s WHERE VARIABLE_NAME="%s";`, mysql.SystemDB, mysql.GlobalVariablesTable, name) sysVar, err := s.getExecRet(ctx, sql) if err != nil { if terror.ExecResultIsEmpty.Equal(err) { return "", variable.UnknownSystemVar.Gen("unknown sys variable:%s", name) } return "", errors.Trace(err) } return sysVar, nil }
func (sq *SubQuery) pop(ctx context.Context) error { v := ctx.Value(subQueryStackKey) if v == nil { return errors.Errorf("pop empty sub query stack") } st := v.([]*SubQuery) // can not empty n := len(st) - 1 if st[n] != sq { return errors.Errorf("pop invalid top sub query in stack, want %v, but top is %v", sq, st[n]) } st[n] = nil st = st[0:n] if len(st) == 0 { ctx.ClearValue(subQueryStackKey) return nil } ctx.SetValue(subQueryStackKey, st) return nil }
func (d *ddl) doDDLJob(ctx context.Context, job *model.Job) error { // for every DDL, we must commit current transaction. if err := ctx.CommitTxn(); err != nil { return errors.Trace(err) } var startTS uint64 err := kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error { t := meta.NewMeta(txn) var err error job.ID, err = t.GenGlobalID() startTS = txn.StartTS() return errors.Trace(err) }) if err != nil { return errors.Trace(err) } ddlQuery, _ := ctx.Value(context.QueryString).(string) job.Query = ddlQuery // Create a new job and queue it. err = kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error { t := meta.NewMeta(txn) err1 := t.EnQueueDDLJob(job) return errors.Trace(err1) }) if err != nil { return errors.Trace(err) } // notice worker that we push a new job and wait the job done. asyncNotify(d.ddlJobCh) log.Warnf("[ddl] start DDL job %v", job) var historyJob *model.Job jobID := job.ID // for a job from start to end, the state of it will be none -> delete only -> write only -> reorganization -> public // for every state changes, we will wait as lease 2 * lease time, so here the ticker check is 10 * lease. ticker := time.NewTicker(chooseLeaseTime(10*d.lease, 10*time.Second)) startTime := time.Now() jobsGauge.WithLabelValues(JobType(ddlJobFlag).String(), job.Type.String()).Inc() defer func() { ticker.Stop() jobsGauge.WithLabelValues(JobType(ddlJobFlag).String(), job.Type.String()).Dec() retLabel := handleJobSucc if err != nil { retLabel = handleJobFailed } handleJobHistogram.WithLabelValues(JobType(ddlJobFlag).String(), job.Type.String(), retLabel).Observe(time.Since(startTime).Seconds()) }() for { select { case <-d.ddlJobDoneCh: case <-ticker.C: } historyJob, err = d.getHistoryDDLJob(jobID) if err != nil { log.Errorf("[ddl] get history DDL job err %v, check again", err) continue } else if historyJob == nil { log.Warnf("[ddl] DDL job %d is not in history, maybe not run", jobID) continue } // if a job is a history table, the state must be JobDone or JobCancel. if historyJob.State == model.JobDone { return nil } return errors.Trace(historyJob.Error) } }
// GetPrivilegeChecker gets Checker from context. func GetPrivilegeChecker(ctx context.Context) Checker { if v, ok := ctx.Value(key).(Checker); ok { return v } return nil }