Repository: pingcap/tidb
File: pkg/sessionctx/stmtctx/stmtctx.go (Go)

Code before:
	sc.PlanCacheTracker = contextutil.NewPlanCacheTracker(sc)
	sc.RangeFallbackHandler = contextutil.NewRangeFallbackHandler(&sc.PlanCacheTracker, sc)
	if h, ok := sc.WarnHandler.(interface{ Reset() }); ok && sc.WarnHandler != nil {
		h.Reset()
	} else {
		sc.WarnHandler = contextutil.NewStaticWarnHandler(0)
	}
	if h, ok := sc.ExtraWarnHandler.(interface{ Reset() }); ok && sc.ExtraWarnHandler != nil {
		h.Reset()
	} else {
		sc.ExtraWarnHandler = contextutil.NewStaticWarnHandler(0)
	}
	return true
}

// CheckMViewUpdatable checks whether a DML operation on a materialized view or materialized view
// log table should be rejected. It returns an error if the table is an MV or MV log and the
// current statement is not an internal maintenance operation.
//
// This guard is called at two layers for defense-in-depth:
//   - Planner layer: provides early rejection during plan building, including at PREPARE time, and
//     keeps consistency with how View and Sequence non-updatability is checked in the same paths.
//   - Executor build layer: the essential correctness check. When a prepared statement is created
//     in a maintenance context but executed after leaving that context, the planner does not
//     re-run — only the executor build phase catches this.
func (sc *StatementContext) CheckMViewUpdatable(tableInfo *model.TableInfo, tableName, op string) error {
	if tableInfo == nil {
		return nil
	}

	if tableName == "" {
		tableName = tableInfo.Name.O
	}

	if sc.InMaterializedViewMaintenance {
		return nil
	}

	if tableInfo.MaterializedView == nil && tableInfo.MaterializedViewLog == nil {
		return nil
	}

	return plannererrors.ErrNonUpdatableTable.GenWithStackByArgs(tableName, op)
}

// CtxID returns the context id of the statement
func (sc *StatementContext) CtxID() uint64 {
	return sc.ctxID
}

// TimeZone returns the timezone of the type context

Review comment (suggestion):
is tableName necessary? because we can get it from `tableInfo.Name`

Code after:
		h.Reset()
	} else {
		sc.WarnHandler = contextutil.NewStaticWarnHandler(0)
	}
	if h, ok := sc.ExtraWarnHandler.(interface{ Reset() }); ok && sc.ExtraWarnHandler != nil {
		h.Reset()
	} else {
		sc.ExtraWarnHandler = contextutil.NewStaticWarnHandler(0)
	}
	return true
}

// CtxID returns the context id of the statement
func (sc *StatementContext) CtxID() uint64 {
	return sc.ctxID
}

// TimeZone returns the timezone of the type context
func (sc *StatementContext) TimeZone() *time.Location {
	intest.AssertNotNil(sc)
	if sc == nil {
		return time.UTC
	}

	return sc.typeCtx.Location()
}

// SetTimeZone sets the timezone
func (sc *StatementContext) SetTimeZone(tz *time.Location) {
	intest.AssertNotNil(tz)
	sc.typeCtx = sc.typeCtx.WithLocation(tz)
}

// TypeCtx returns the type context
func (sc *StatementContext) TypeCtx() types.Context {
	return sc.typeCtx
}

// ErrCtx returns the error context
func (sc *StatementContext) ErrCtx() errctx.Context {
	return sc.errCtx
}

// SetErrLevels sets the error levels for statement
// The argument otherLevels is used to set the error levels except truncate
func (sc *StatementContext) SetErrLevels(otherLevels errctx.LevelMap) {
	sc.errCtx = newErrCtx(sc.typeCtx, otherLevels, sc)
}

// ErrLevels returns the current `errctx.LevelMap`
func (sc *StatementContext) ErrLevels() errctx.LevelMap {