Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

meta: introduce metabuild.Context to build meta #56176

Merged
merged 12 commits into from
Sep 26, 2024
5 changes: 5 additions & 0 deletions pkg/ddl/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ go_library(
"job_scheduler.go",
"job_submitter.go",
"job_worker.go",
"metabuild.go",
"mock.go",
"modify_column.go",
"multi_schema_change.go",
Expand Down Expand Up @@ -99,6 +100,7 @@ go_library(
"//pkg/expression/exprctx",
"//pkg/expression/exprstatic",
"//pkg/infoschema",
"//pkg/infoschema/context",
"//pkg/kv",
"//pkg/lightning/backend",
"//pkg/lightning/backend/external",
Expand All @@ -107,6 +109,7 @@ go_library(
"//pkg/lightning/config",
"//pkg/meta",
"//pkg/meta/autoid",
"//pkg/meta/metabuild",
"//pkg/meta/model",
"//pkg/metrics",
"//pkg/owner",
Expand Down Expand Up @@ -242,6 +245,7 @@ go_test(
"job_submitter_test.go",
"job_worker_test.go",
"main_test.go",
"metabuild_test.go",
"modify_column_test.go",
"multi_schema_change_test.go",
"mv_index_test.go",
Expand Down Expand Up @@ -298,6 +302,7 @@ go_test(
"//pkg/lightning/backend/external",
"//pkg/meta",
"//pkg/meta/autoid",
"//pkg/meta/metabuild",
"//pkg/meta/model",
"//pkg/parser",
"//pkg/parser/ast",
Expand Down
85 changes: 43 additions & 42 deletions pkg/ddl/add_column.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/pingcap/tidb/pkg/infoschema"
"github.com/pingcap/tidb/pkg/meta"
"github.com/pingcap/tidb/pkg/meta/autoid"
"github.com/pingcap/tidb/pkg/meta/metabuild"
"github.com/pingcap/tidb/pkg/meta/model"
"github.com/pingcap/tidb/pkg/parser/ast"
"github.com/pingcap/tidb/pkg/parser/charset"
Expand Down Expand Up @@ -243,17 +244,17 @@ func CreateNewColumn(ctx sessionctx.Context, schema *model.DBInfo, spec *ast.Alt
}
}

tableCharset, tableCollate, err := ResolveCharsetCollation(ctx.GetSessionVars(),
ast.CharsetOpt{Chs: t.Meta().Charset, Col: t.Meta().Collate},
ast.CharsetOpt{Chs: schema.Charset, Col: schema.Collate},
)
tableCharset, tableCollate, err := ResolveCharsetCollation([]ast.CharsetOpt{
{Chs: t.Meta().Charset, Col: t.Meta().Collate},
{Chs: schema.Charset, Col: schema.Collate},
}, ctx.GetSessionVars().DefaultCollationForUTF8MB4)
if err != nil {
return nil, errors.Trace(err)
}
// Ignore table constraints now, they will be checked later.
// We use length(t.Cols()) as the default offset firstly, we will change the column's offset later.
col, _, err := buildColumnAndConstraint(
ctx,
NewMetaBuildContextWithSctx(ctx),
len(t.Cols()),
specNewColumn,
nil,
Expand All @@ -277,7 +278,7 @@ func CreateNewColumn(ctx sessionctx.Context, schema *model.DBInfo, spec *ast.Alt
// outPriKeyConstraint is the primary key constraint out of column definition. For example:
// `create table t1 (id int , age int, primary key(id));`
func buildColumnAndConstraint(
ctx sessionctx.Context,
ctx *metabuild.Context,
offset int,
colDef *ast.ColumnDef,
outPriKeyConstraint *ast.Constraint,
Expand All @@ -289,20 +290,20 @@ func buildColumnAndConstraint(
}

// specifiedCollate refers to the last collate specified in colDef.Options.
chs, coll, err := getCharsetAndCollateInColumnDef(ctx.GetSessionVars(), colDef)
chs, coll, err := getCharsetAndCollateInColumnDef(colDef, ctx.GetDefaultCollationForUTF8MB4())
if err != nil {
return nil, nil, errors.Trace(err)
}
chs, coll, err = ResolveCharsetCollation(ctx.GetSessionVars(),
ast.CharsetOpt{Chs: chs, Col: coll},
ast.CharsetOpt{Chs: tblCharset, Col: tblCollate},
)
chs, coll = OverwriteCollationWithBinaryFlag(ctx.GetSessionVars(), colDef, chs, coll)
chs, coll, err = ResolveCharsetCollation([]ast.CharsetOpt{
{Chs: chs, Col: coll},
{Chs: tblCharset, Col: tblCollate},
}, ctx.GetDefaultCollationForUTF8MB4())
chs, coll = OverwriteCollationWithBinaryFlag(colDef, chs, coll, ctx.GetDefaultCollationForUTF8MB4())
if err != nil {
return nil, nil, errors.Trace(err)
}

if err := setCharsetCollationFlenDecimal(colDef.Tp, colDef.Name.Name.O, chs, coll, ctx.GetSessionVars()); err != nil {
if err := setCharsetCollationFlenDecimal(ctx, colDef.Tp, colDef.Name.Name.O, chs, coll); err != nil {
return nil, nil, errors.Trace(err)
}
decodeEnumSetBinaryLiteralToUTF8(colDef.Tp, chs)
Expand All @@ -315,11 +316,11 @@ func buildColumnAndConstraint(

// getCharsetAndCollateInColumnDef will iterate collate in the options, validate it by checking the charset
// of column definition. If there's no collate in the option, the default collate of column's charset will be used.
func getCharsetAndCollateInColumnDef(sessVars *variable.SessionVars, def *ast.ColumnDef) (chs, coll string, err error) {
func getCharsetAndCollateInColumnDef(def *ast.ColumnDef, defaultUTF8MB4Coll string) (chs, coll string, err error) {
chs = def.Tp.GetCharset()
coll = def.Tp.GetCollate()
if chs != "" && coll == "" {
if coll, err = GetDefaultCollation(sessVars, chs); err != nil {
if coll, err = GetDefaultCollation(chs, defaultUTF8MB4Coll); err != nil {
return "", "", errors.Trace(err)
}
}
Expand All @@ -345,14 +346,14 @@ func getCharsetAndCollateInColumnDef(sessVars *variable.SessionVars, def *ast.Co
// CREATE TABLE t (a VARCHAR(255) BINARY) CHARSET utf8 COLLATE utf8_general_ci;
//
// The 'BINARY' sets the column collation to *_bin according to the table charset.
func OverwriteCollationWithBinaryFlag(sessVars *variable.SessionVars, colDef *ast.ColumnDef, chs, coll string) (newChs string, newColl string) {
func OverwriteCollationWithBinaryFlag(colDef *ast.ColumnDef, chs, coll string, defaultUTF8MB4Coll string) (newChs string, newColl string) {
ignoreBinFlag := colDef.Tp.GetCharset() != "" && (colDef.Tp.GetCollate() != "" || containsColumnOption(colDef, ast.ColumnOptionCollate))
if ignoreBinFlag {
return chs, coll
}
needOverwriteBinColl := types.IsString(colDef.Tp.GetType()) && mysql.HasBinaryFlag(colDef.Tp.GetFlag())
if needOverwriteBinColl {
newColl, err := GetDefaultCollation(sessVars, chs)
newColl, err := GetDefaultCollation(chs, defaultUTF8MB4Coll)
if err != nil {
return chs, coll
}
Expand All @@ -361,7 +362,7 @@ func OverwriteCollationWithBinaryFlag(sessVars *variable.SessionVars, colDef *as
return chs, coll
}

func setCharsetCollationFlenDecimal(tp *types.FieldType, colName, colCharset, colCollate string, sessVars *variable.SessionVars) error {
func setCharsetCollationFlenDecimal(ctx *metabuild.Context, tp *types.FieldType, colName, colCharset, colCollate string) error {
var err error
if typesNeedCharset(tp.GetType()) {
tp.SetCharset(colCharset)
Expand Down Expand Up @@ -389,7 +390,7 @@ func setCharsetCollationFlenDecimal(tp *types.FieldType, colName, colCharset, co
return err
}
}
return checkTooBigFieldLengthAndTryAutoConvert(tp, colName, sessVars)
return checkTooBigFieldLengthAndTryAutoConvert(ctx, tp, colName)
}

func decodeEnumSetBinaryLiteralToUTF8(tp *types.FieldType, chs string) {
Expand Down Expand Up @@ -422,18 +423,18 @@ func typesNeedCharset(tp byte) bool {

// checkTooBigFieldLengthAndTryAutoConvert will check whether the field length is too big
// in non-strict mode and varchar column. If it is, will try to adjust to blob or text, see issue #30328
func checkTooBigFieldLengthAndTryAutoConvert(tp *types.FieldType, colName string, sessVars *variable.SessionVars) error {
if sessVars != nil && !sessVars.SQLMode.HasStrictMode() && tp.GetType() == mysql.TypeVarchar {
func checkTooBigFieldLengthAndTryAutoConvert(ctx *metabuild.Context, tp *types.FieldType, colName string) error {
if !ctx.GetSQLMode().HasStrictMode() && tp.GetType() == mysql.TypeVarchar {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems ctx here is always not nil. So I removed sessVars != nil

err := types.IsVarcharTooBigFieldLength(tp.GetFlen(), colName, tp.GetCharset())
if err != nil && terror.ErrorEqual(types.ErrTooBigFieldLength, err) {
tp.SetType(mysql.TypeBlob)
if err = adjustBlobTypesFlen(tp, tp.GetCharset()); err != nil {
return err
}
if tp.GetCharset() == charset.CharsetBin {
sessVars.StmtCtx.AppendWarning(dbterror.ErrAutoConvert.FastGenByArgs(colName, "VARBINARY", "BLOB"))
ctx.AppendWarning(dbterror.ErrAutoConvert.FastGenByArgs(colName, "VARBINARY", "BLOB"))
} else {
sessVars.StmtCtx.AppendWarning(dbterror.ErrAutoConvert.FastGenByArgs(colName, "VARCHAR", "TEXT"))
ctx.AppendWarning(dbterror.ErrAutoConvert.FastGenByArgs(colName, "VARCHAR", "TEXT"))
}
}
}
Expand All @@ -442,7 +443,7 @@ func checkTooBigFieldLengthAndTryAutoConvert(tp *types.FieldType, colName string

// columnDefToCol converts ColumnDef to Col and TableConstraints.
// outPriKeyConstraint is the primary key constraint out of column definition. such as: create table t1 (id int , age int, primary key(id));
func columnDefToCol(ctx sessionctx.Context, offset int, colDef *ast.ColumnDef, outPriKeyConstraint *ast.Constraint) (*table.Column, []*ast.Constraint, error) {
func columnDefToCol(ctx *metabuild.Context, offset int, colDef *ast.ColumnDef, outPriKeyConstraint *ast.Constraint) (*table.Column, []*ast.Constraint, error) {
var constraints = make([]*ast.Constraint, 0)
col := table.ToColumn(&model.ColumnInfo{
Offset: offset,
Expand Down Expand Up @@ -511,7 +512,7 @@ func columnDefToCol(ctx sessionctx.Context, offset int, colDef *ast.ColumnDef, o
col.AddFlag(mysql.UniqueKeyFlag)
}
case ast.ColumnOptionDefaultValue:
hasDefaultValue, err = SetDefaultValue(ctx, col, v)
hasDefaultValue, err = SetDefaultValue(ctx.GetExprCtx(), col, v)
if err != nil {
return nil, nil, errors.Trace(err)
}
Expand All @@ -527,7 +528,7 @@ func columnDefToCol(ctx sessionctx.Context, offset int, colDef *ast.ColumnDef, o
col.AddFlag(mysql.OnUpdateNowFlag)
setOnUpdateNow = true
case ast.ColumnOptionComment:
err := setColumnComment(ctx, col, v)
err := setColumnComment(ctx.GetExprCtx(), col, v)
if err != nil {
return nil, nil, errors.Trace(err)
}
Expand All @@ -549,10 +550,10 @@ func columnDefToCol(ctx sessionctx.Context, offset int, colDef *ast.ColumnDef, o
col.FieldType.SetCollate(v.StrValue)
}
case ast.ColumnOptionFulltext:
ctx.GetSessionVars().StmtCtx.AppendWarning(dbterror.ErrTableCantHandleFt.FastGenByArgs())
ctx.AppendWarning(dbterror.ErrTableCantHandleFt.FastGenByArgs())
case ast.ColumnOptionCheck:
if !variable.EnableCheckConstraint.Load() {
ctx.GetSessionVars().StmtCtx.AppendWarning(errCheckConstraintIsOff)
ctx.AppendWarning(errCheckConstraintIsOff)
} else {
// Check the column CHECK constraint dependency lazily, after fill all the name.
// Extract column constraint from column option.
Expand All @@ -570,7 +571,7 @@ func columnDefToCol(ctx sessionctx.Context, offset int, colDef *ast.ColumnDef, o
}
}

if err = processAndCheckDefaultValueAndColumn(ctx, col, outPriKeyConstraint, hasDefaultValue, setOnUpdateNow, hasNullFlag); err != nil {
if err = processAndCheckDefaultValueAndColumn(ctx.GetExprCtx(), col, outPriKeyConstraint, hasDefaultValue, setOnUpdateNow, hasNullFlag); err != nil {
return nil, nil, errors.Trace(err)
}
return col, constraints, nil
Expand All @@ -585,11 +586,11 @@ func isExplicitTimeStamp() bool {
}

// SetDefaultValue sets the default value of the column.
func SetDefaultValue(ctx sessionctx.Context, col *table.Column, option *ast.ColumnOption) (hasDefaultValue bool, err error) {
func SetDefaultValue(ctx expression.BuildContext, col *table.Column, option *ast.ColumnOption) (hasDefaultValue bool, err error) {
var value any
var isSeqExpr bool
value, isSeqExpr, err = getDefaultValue(
exprctx.CtxWithHandleTruncateErrLevel(ctx.GetExprCtx(), errctx.LevelError),
exprctx.CtxWithHandleTruncateErrLevel(ctx, errctx.LevelError),
col, option,
)
if err != nil {
Expand All @@ -604,10 +605,10 @@ func SetDefaultValue(ctx sessionctx.Context, col *table.Column, option *ast.Colu

// When the default value is expression, we skip check and convert.
if !col.DefaultIsExpr {
if hasDefaultValue, value, err = checkColumnDefaultValue(ctx.GetExprCtx(), col, value); err != nil {
if hasDefaultValue, value, err = checkColumnDefaultValue(ctx, col, value); err != nil {
return hasDefaultValue, errors.Trace(err)
}
value, err = convertTimestampDefaultValToUTC(ctx, value, col)
value, err = convertTimestampDefaultValToUTC(ctx.GetEvalCtx().TypeCtx(), value, col)
if err != nil {
return hasDefaultValue, errors.Trace(err)
}
Expand Down Expand Up @@ -895,21 +896,21 @@ func setDefaultValueWithBinaryPadding(col *table.Column, value any) error {
return nil
}

func setColumnComment(ctx sessionctx.Context, col *table.Column, option *ast.ColumnOption) error {
value, err := expression.EvalSimpleAst(ctx.GetExprCtx(), option.Expr)
func setColumnComment(ctx expression.BuildContext, col *table.Column, option *ast.ColumnOption) error {
value, err := expression.EvalSimpleAst(ctx, option.Expr)
if err != nil {
return errors.Trace(err)
}
if col.Comment, err = value.ToString(); err != nil {
return errors.Trace(err)
}

sessionVars := ctx.GetSessionVars()
col.Comment, err = validateCommentLength(sessionVars.StmtCtx.ErrCtx(), sessionVars.SQLMode, col.Name.L, &col.Comment, dbterror.ErrTooLongFieldComment)
evalCtx := ctx.GetEvalCtx()
col.Comment, err = validateCommentLength(evalCtx.ErrCtx(), evalCtx.SQLMode(), col.Name.L, &col.Comment, dbterror.ErrTooLongFieldComment)
return errors.Trace(err)
}

func processAndCheckDefaultValueAndColumn(ctx sessionctx.Context, col *table.Column,
func processAndCheckDefaultValueAndColumn(ctx expression.BuildContext, col *table.Column,
outPriKeyConstraint *ast.Constraint, hasDefaultValue, setOnUpdateNow, hasNullFlag bool) error {
processDefaultValue(col, hasDefaultValue, setOnUpdateNow)
processColumnFlags(col)
Expand All @@ -921,7 +922,7 @@ func processAndCheckDefaultValueAndColumn(ctx sessionctx.Context, col *table.Col
if err = checkColumnValueConstraint(col, col.GetCollate()); err != nil {
return errors.Trace(err)
}
if err = checkDefaultValue(ctx.GetExprCtx(), col, hasDefaultValue); err != nil {
if err = checkDefaultValue(ctx, col, hasDefaultValue); err != nil {
return errors.Trace(err)
}
if err = checkColumnFieldLength(col); err != nil {
Expand Down Expand Up @@ -1215,17 +1216,17 @@ func checkSequenceDefaultValue(col *table.Column) error {
return dbterror.ErrColumnTypeUnsupportedNextValue.GenWithStackByArgs(col.ColumnInfo.Name.O)
}

func convertTimestampDefaultValToUTC(ctx sessionctx.Context, defaultVal any, col *table.Column) (any, error) {
func convertTimestampDefaultValToUTC(tc types.Context, defaultVal any, col *table.Column) (any, error) {
if defaultVal == nil || col.GetType() != mysql.TypeTimestamp {
return defaultVal, nil
}
if vv, ok := defaultVal.(string); ok {
if vv != types.ZeroDatetimeStr && !strings.EqualFold(vv, ast.CurrentTimestamp) {
t, err := types.ParseTime(ctx.GetSessionVars().StmtCtx.TypeCtx(), vv, col.GetType(), col.GetDecimal())
t, err := types.ParseTime(tc, vv, col.GetType(), col.GetDecimal())
if err != nil {
return defaultVal, errors.Trace(err)
}
err = t.ConvertTimeZone(ctx.GetSessionVars().Location(), time.UTC)
err = t.ConvertTimeZone(tc.Location(), time.UTC)
if err != nil {
return defaultVal, errors.Trace(err)
}
Expand Down
Loading