Skip to content

Commit

Permalink
meta: introduce metabuild.Context to build meta
Browse files Browse the repository at this point in the history
  • Loading branch information
lcwangchao committed Sep 20, 2024
1 parent 68fdf55 commit c734008
Show file tree
Hide file tree
Showing 28 changed files with 997 additions and 271 deletions.
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 @@ -244,6 +247,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 @@ -300,6 +304,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 {
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

0 comments on commit c734008

Please sign in to comment.