Skip to content

Commit

Permalink
ddl: avoid panic when creating partition table with unsupported expre…
Browse files Browse the repository at this point in the history
…ssion(#14295) (#14769)
  • Loading branch information
Lingyu Song authored Feb 25, 2020
1 parent f68baab commit 037b369
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 17 deletions.
33 changes: 19 additions & 14 deletions ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1323,25 +1323,30 @@ func buildTableInfoWithCheck(ctx sessionctx.Context, d *ddl, s *ast.CreateTableS
tbInfo.Collate = tableCollate
tbInfo.Charset = tableCharset

pi, err := buildTablePartitionInfo(ctx, d, s)
if err != nil {
return nil, errors.Trace(err)
}

if pi != nil {
switch pi.Type {
case model.PartitionTypeRange:
err = checkPartitionByRange(ctx, tbInfo, pi, cols, s)
case model.PartitionTypeHash:
err = checkPartitionByHash(ctx, pi, s, cols, tbInfo)
}
if s.Partition != nil {
err := checkPartitionExprValid(ctx, tbInfo, s.Partition.Expr)
if err != nil {
return nil, errors.Trace(err)
}
if err = checkRangePartitioningKeysConstraints(ctx, s, tbInfo, newConstraints); err != nil {
pi, err := buildTablePartitionInfo(ctx, d, s)
if err != nil {
return nil, errors.Trace(err)
}
tbInfo.Partition = pi
if pi != nil {
switch pi.Type {
case model.PartitionTypeRange:
err = checkPartitionByRange(ctx, tbInfo, pi, cols, s)
case model.PartitionTypeHash:
err = checkPartitionByHash(ctx, pi, s, cols, tbInfo)
}
if err != nil {
return nil, errors.Trace(err)
}
if err = checkRangePartitioningKeysConstraints(ctx, s, tbInfo, newConstraints); err != nil {
return nil, errors.Trace(err)
}
tbInfo.Partition = pi
}
}

if err = handleTableOptions(s.Options, tbInfo); err != nil {
Expand Down
57 changes: 54 additions & 3 deletions ddl/partition.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,10 @@ func checkAddPartitionNameUnique(tbInfo *model.TableInfo, pi *model.PartitionInf
return nil
}

// checkPartitionFuncValid checks partition function validly.
func checkPartitionFuncValid(ctx sessionctx.Context, tblInfo *model.TableInfo, expr ast.ExprNode) error {
// checkPartitionExprValid checks partition expression validly.
func checkPartitionExprValid(ctx sessionctx.Context, tblInfo *model.TableInfo, expr ast.ExprNode) error {
switch v := expr.(type) {
case *ast.FuncCastExpr, *ast.CaseExpr:
case *ast.FuncCastExpr, *ast.CaseExpr, *ast.SubqueryExpr, *ast.WindowFuncExpr, *ast.RowExpr, *ast.DefaultExpr, *ast.ValuesExpr:
return errors.Trace(ErrPartitionFunctionIsNotAllowed)
case *ast.FuncCallExpr:
// check function which allowed in partitioning expressions
Expand Down Expand Up @@ -224,12 +224,63 @@ func checkPartitionFuncValid(ctx sessionctx.Context, tblInfo *model.TableInfo, e
switch v.Op {
case opcode.Or, opcode.And, opcode.Xor, opcode.LeftShift, opcode.RightShift, opcode.BitNeg, opcode.Div:
return errors.Trace(ErrPartitionFunctionIsNotAllowed)
default:
if err := checkPartitionExprValid(ctx, tblInfo, v.L); err != nil {
return errors.Trace(err)
}
if err := checkPartitionExprValid(ctx, tblInfo, v.R); err != nil {
return errors.Trace(err)
}
}
return nil
case *ast.UnaryOperationExpr:
if v.Op == opcode.BitNeg {
return errors.Trace(ErrPartitionFunctionIsNotAllowed)
}
if err := checkPartitionExprValid(ctx, tblInfo, v.V); err != nil {
return errors.Trace(err)
}
return nil
}
return nil
}

// checkPartitionFuncValid checks partition function validly.
func checkPartitionFuncValid(ctx sessionctx.Context, tblInfo *model.TableInfo, expr ast.ExprNode) error {
err := checkPartitionExprValid(ctx, tblInfo, expr)
if err != nil {
return err
}
// check constant.
_, err = checkPartitionColumns(tblInfo, expr)
return err
}

func checkPartitionColumns(tblInfo *model.TableInfo, expr ast.ExprNode) ([]*model.ColumnInfo, error) {
buf := new(bytes.Buffer)
expr.Format(buf)
partCols, err := extractPartitionColumns(buf.String(), tblInfo)
if err != nil {
return nil, err
}

if len(partCols) == 0 {
return nil, errors.Trace(errWrongExprInPartitionFunc)
}

return partCols, nil
}

// For partition tables, mysql do not support Constant, random or timezone-dependent expressions
// Based on mysql code to check whether field is valid, every time related type has check_valid_arguments_processor function.
// See https://github.com/mysql/mysql-server/blob/5.7/sql/item_timefunc.
func checkPartitionFunc(isTimezoneDependent bool, err error) error {
if err != nil {
return err
}

if !isTimezoneDependent {
return errors.Trace(errWrongExprInPartitionFunc)
}
return nil
}
Expand Down
14 changes: 14 additions & 0 deletions table/tables/partition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (

. "github.com/pingcap/check"
"github.com/pingcap/parser/model"
"github.com/pingcap/tidb/ddl"
"github.com/pingcap/tidb/expression"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/sessionctx"
Expand Down Expand Up @@ -365,3 +366,16 @@ func (ts *testSuite) TestTimeZoneChange(c *C) {
tk.MustQuery("SELECT * FROM timezone_test PARTITION (p8)").Check(testkit.Rows())
tk.MustQuery("SELECT * FROM timezone_test PARTITION (p9)").Check(testkit.Rows())
}

func (ts *testSuite) TestCreatePartitionTableNotSupport(c *C) {
tk := testkit.NewTestKitWithInit(c, ts.store)
tk.MustExec("use test")
_, err := tk.Exec(`create table t7 (a int) partition by range (mod((select * from t), 5)) (partition p1 values less than (1));`)
c.Assert(ddl.ErrPartitionFunctionIsNotAllowed.Equal(err), IsTrue)
_, err = tk.Exec(`create table t7 (a int) partition by range (1 + (select * from t)) (partition p1 values less than (1));`)
c.Assert(ddl.ErrPartitionFunctionIsNotAllowed.Equal(err), IsTrue)
_, err = tk.Exec(`create table t7 (a int) partition by range (a + row(1, 2, 3)) (partition p1 values less than (1));`)
c.Assert(ddl.ErrPartitionFunctionIsNotAllowed.Equal(err), IsTrue)
_, err = tk.Exec(`create table t7 (a int) partition by range (-(select * from t)) (partition p1 values less than (1));`)
c.Assert(ddl.ErrPartitionFunctionIsNotAllowed.Equal(err), IsTrue)
}

0 comments on commit 037b369

Please sign in to comment.