Beispiel #1
0
// 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
}
Beispiel #2
0
// 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
}
Beispiel #3
0
// GetCurrentSchema gets current schema name from context.
func GetCurrentSchema(ctx context.Context) string {
	v, ok := ctx.Value(currentDBKey).(string)
	if !ok {
		return ""
	}
	return v
}
Beispiel #4
0
// 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
}
Beispiel #5
0
// GetExecArgs gets executive args from context.
func GetExecArgs(ctx context.Context) []interface{} {
	v, ok := ctx.Value(execArgsKey).([]interface{})
	if !ok {
		return nil
	}
	return v
}
Beispiel #6
0
// 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
}
Beispiel #7
0
// 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)
}
Beispiel #8
0
// 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
}
Beispiel #9
0
// 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
}
Beispiel #10
0
// 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)
}
Beispiel #11
0
// 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
}
Beispiel #12
0
func getRowStack(ctx context.Context) *RowStack {
	v := ctx.Value(rowStackKey)
	if v == nil {
		return nil
	}
	// must be RowStack
	t := v.(*RowStack)
	return t
}
Beispiel #13
0
// 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
}
Beispiel #14
0
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
}
Beispiel #15
0
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
}
Beispiel #16
0
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)
}
Beispiel #17
0
// 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
	}
}
Beispiel #18
0
// 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)
	})
}
Beispiel #19
0
// 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
}
Beispiel #20
0
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
}
Beispiel #21
0
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)
	}
}
Beispiel #22
0
// GetPrivilegeChecker gets Checker from context.
func GetPrivilegeChecker(ctx context.Context) Checker {
	if v, ok := ctx.Value(key).(Checker); ok {
		return v
	}
	return nil
}