Skip to content

Commit

Permalink
executor: fix DATA RACE for reading information_schema.columns where …
Browse files Browse the repository at this point in the history
…there are views (#34538)

close #34509
  • Loading branch information
tiancaiamao authored May 16, 2022
1 parent 4b00ee2 commit e1ccd33
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 28 deletions.
73 changes: 52 additions & 21 deletions executor/infoschema_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import (
"github.com/pingcap/tidb/util/codec"
"github.com/pingcap/tidb/util/collate"
"github.com/pingcap/tidb/util/deadlockhistory"
"github.com/pingcap/tidb/util/hint"
"github.com/pingcap/tidb/util/keydecoder"
"github.com/pingcap/tidb/util/logutil"
"github.com/pingcap/tidb/util/mathutil"
Expand Down Expand Up @@ -677,10 +678,29 @@ func (e *hugeMemTableRetriever) setDataForColumns(ctx context.Context, sctx sess
}

func (e *hugeMemTableRetriever) dataForColumnsInTable(ctx context.Context, sctx sessionctx.Context, schema *model.DBInfo, tbl *model.TableInfo, priv mysql.PrivilegeType, extractor *plannercore.ColumnsTableExtractor) {
if err := tryFillViewColumnType(ctx, sctx, sctx.GetInfoSchema().(infoschema.InfoSchema), schema.Name, tbl); err != nil {
sctx.GetSessionVars().StmtCtx.AppendWarning(err)
return
is := sessiontxn.GetTxnManager(sctx).GetTxnInfoSchema()
var viewSchema *expression.Schema
var viewOutputNames types.NameSlice
if tbl.IsView() {
var viewLogicalPlan plannercore.Plan
// Build plan is not thread safe, there will be concurrency on sessionctx.
if err := runWithSystemSession(sctx, func(s sessionctx.Context) error {
planBuilder, _ := plannercore.NewPlanBuilder().Init(s, is, &hint.BlockHintProcessor{})
var err error
viewLogicalPlan, err = planBuilder.BuildDataSourceFromView(ctx, schema.Name, tbl)
if err != nil {
return errors.Trace(err)
}
return nil
}); err != nil {
sctx.GetSessionVars().StmtCtx.AppendWarning(err)
return
}

viewSchema = viewLogicalPlan.Schema()
viewOutputNames = viewLogicalPlan.OutputNames()
}

var tableSchemaRegexp, tableNameRegexp, columnsRegexp []collate.WildcardPattern
var tableSchemaFilterEnable,
tableNameFilterEnable, columnsFilterEnable bool
Expand Down Expand Up @@ -715,6 +735,17 @@ ForColumnsTag:
if col.Hidden {
continue
}

ft := &col.FieldType
if viewSchema != nil {
// If this is a view, replace the column with the view column.
idx := expression.FindFieldNameIdxByColName(viewOutputNames, col.Name.L)
if idx >= 0 {
col1 := viewSchema.Columns[idx]
ft = col1.GetType()
}
}

if !extractor.SkipRequest {
if tableSchemaFilterEnable && !extractor.TableSchema.Exist(schema.Name.L) {
continue
Expand Down Expand Up @@ -743,58 +774,58 @@ ForColumnsTag:
}

var charMaxLen, charOctLen, numericPrecision, numericScale, datetimePrecision interface{}
colLen, decimal := col.GetFlen(), col.GetDecimal()
defaultFlen, defaultDecimal := mysql.GetDefaultFieldLengthAndDecimal(col.GetType())
colLen, decimal := ft.GetFlen(), ft.GetDecimal()
defaultFlen, defaultDecimal := mysql.GetDefaultFieldLengthAndDecimal(ft.GetType())
if decimal == types.UnspecifiedLength {
decimal = defaultDecimal
}
if colLen == types.UnspecifiedLength {
colLen = defaultFlen
}
if col.GetType() == mysql.TypeSet {
if ft.GetType() == mysql.TypeSet {
// Example: In MySQL set('a','bc','def','ghij') has length 13, because
// len('a')+len('bc')+len('def')+len('ghij')+len(ThreeComma)=13
// Reference link: https://bugs.mysql.com/bug.php?id=22613
colLen = 0
for _, ele := range col.GetElems() {
for _, ele := range ft.GetElems() {
colLen += len(ele)
}
if len(col.GetElems()) != 0 {
colLen += (len(col.GetElems()) - 1)
if len(ft.GetElems()) != 0 {
colLen += (len(ft.GetElems()) - 1)
}
charMaxLen = colLen
charOctLen = calcCharOctLength(colLen, col.GetCharset())
} else if col.GetType() == mysql.TypeEnum {
charOctLen = calcCharOctLength(colLen, ft.GetCharset())
} else if ft.GetType() == mysql.TypeEnum {
// Example: In MySQL enum('a', 'ab', 'cdef') has length 4, because
// the longest string in the enum is 'cdef'
// Reference link: https://bugs.mysql.com/bug.php?id=22613
colLen = 0
for _, ele := range col.GetElems() {
for _, ele := range ft.GetElems() {
if len(ele) > colLen {
colLen = len(ele)
}
}
charMaxLen = colLen
charOctLen = calcCharOctLength(colLen, col.GetCharset())
} else if types.IsString(col.GetType()) {
charOctLen = calcCharOctLength(colLen, ft.GetCharset())
} else if types.IsString(ft.GetType()) {
charMaxLen = colLen
charOctLen = calcCharOctLength(colLen, col.GetCharset())
} else if types.IsTypeFractionable(col.GetType()) {
charOctLen = calcCharOctLength(colLen, ft.GetCharset())
} else if types.IsTypeFractionable(ft.GetType()) {
datetimePrecision = decimal
} else if types.IsTypeNumeric(col.GetType()) {
} else if types.IsTypeNumeric(ft.GetType()) {
numericPrecision = colLen
if col.GetType() != mysql.TypeFloat && col.GetType() != mysql.TypeDouble {
if ft.GetType() != mysql.TypeFloat && ft.GetType() != mysql.TypeDouble {
numericScale = decimal
} else if decimal != -1 {
numericScale = decimal
}
}
columnType := col.FieldType.InfoSchemaStr()
columnType := ft.InfoSchemaStr()
columnDesc := table.NewColDesc(table.ToColumn(col))
var columnDefault interface{}
if columnDesc.DefaultValue != nil {
columnDefault = fmt.Sprintf("%v", columnDesc.DefaultValue)
if col.GetType() == mysql.TypeBit {
if ft.GetType() == mysql.TypeBit {
defaultStr := fmt.Sprintf("%v", columnDesc.DefaultValue)
defaultValBinaryLiteral := types.BinaryLiteral(defaultStr)
columnDefault = defaultValBinaryLiteral.ToBitLiteralString(true)
Expand All @@ -808,7 +839,7 @@ ForColumnsTag:
i+1, // ORIGINAL_POSITION
columnDefault, // COLUMN_DEFAULT
columnDesc.Null, // IS_NULLABLE
types.TypeToStr(col.GetType(), col.GetCharset()), // DATA_TYPE
types.TypeToStr(ft.GetType(), ft.GetCharset()), // DATA_TYPE
charMaxLen, // CHARACTER_MAXIMUM_LENGTH
charOctLen, // CHARACTER_OCTET_LENGTH
numericPrecision, // NUMERIC_PRECISION
Expand Down
7 changes: 0 additions & 7 deletions executor/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -1929,13 +1929,6 @@ func runWithSystemSession(sctx sessionctx.Context, fn func(sessionctx.Context) e
if err != nil {
return err
}
// TODO(tangenta): remove the CurrentDB assignment after
// https://github.com/pingcap/tidb/issues/34090 is fixed.
originDB := sysCtx.GetSessionVars().CurrentDB
sysCtx.GetSessionVars().CurrentDB = sctx.GetSessionVars().CurrentDB
defer func() {
sysCtx.GetSessionVars().CurrentDB = originDB
}()
defer b.releaseSysSession(sysCtx)
return fn(sysCtx)
}

0 comments on commit e1ccd33

Please sign in to comment.