diff --git a/pkg/ddl/partition.go b/pkg/ddl/partition.go index 87a1f7b0b4f64..55ef0d59b624c 100644 --- a/pkg/ddl/partition.go +++ b/pkg/ddl/partition.go @@ -59,7 +59,6 @@ import ( "github.com/pingcap/tidb/pkg/util/dbterror" "github.com/pingcap/tidb/pkg/util/hack" "github.com/pingcap/tidb/pkg/util/mathutil" - "github.com/pingcap/tidb/pkg/util/mock" decoder "github.com/pingcap/tidb/pkg/util/rowDecoder" "github.com/pingcap/tidb/pkg/util/slice" "github.com/pingcap/tidb/pkg/util/stringutil" @@ -4259,9 +4258,7 @@ func (cns columnNameSlice) At(i int) string { } func isPartExprUnsigned(ectx expression.EvalContext, tbInfo *model.TableInfo) bool { - // We should not rely on any configuration, system or session variables, so use a mock ctx! - // Same as in tables.newPartitionExpr - ctx := mock.NewContext() + ctx := tables.NewPartitionExprBuildCtx() expr, err := expression.ParseSimpleExpr(ctx, tbInfo.Partition.Expr, expression.WithTableInfo("", tbInfo)) if err != nil { logutil.DDLLogger().Error("isPartExpr failed parsing expression!", zap.Error(err)) diff --git a/pkg/table/tables/BUILD.bazel b/pkg/table/tables/BUILD.bazel index 45ecf0d557ded..c0c5c70ebc5fd 100644 --- a/pkg/table/tables/BUILD.bazel +++ b/pkg/table/tables/BUILD.bazel @@ -18,6 +18,7 @@ go_library( "//pkg/errno", "//pkg/expression", "//pkg/expression/context", + "//pkg/expression/contextstatic", "//pkg/kv", "//pkg/meta", "//pkg/meta/autoid", @@ -43,7 +44,6 @@ go_library( "//pkg/util/generatedexpr", "//pkg/util/hack", "//pkg/util/logutil", - "//pkg/util/mock", "//pkg/util/ranger", "//pkg/util/rowcodec", "//pkg/util/sqlexec", diff --git a/pkg/table/tables/partition.go b/pkg/table/tables/partition.go index 0525258813866..918407c0061d9 100644 --- a/pkg/table/tables/partition.go +++ b/pkg/table/tables/partition.go @@ -29,6 +29,7 @@ import ( "github.com/pingcap/errors" "github.com/pingcap/tidb/pkg/errctx" "github.com/pingcap/tidb/pkg/expression" + "github.com/pingcap/tidb/pkg/expression/contextstatic" "github.com/pingcap/tidb/pkg/kv" "github.com/pingcap/tidb/pkg/parser" "github.com/pingcap/tidb/pkg/parser/ast" @@ -44,7 +45,6 @@ import ( "github.com/pingcap/tidb/pkg/util/dbterror" "github.com/pingcap/tidb/pkg/util/hack" "github.com/pingcap/tidb/pkg/util/logutil" - "github.com/pingcap/tidb/pkg/util/mock" "github.com/pingcap/tidb/pkg/util/ranger" "github.com/pingcap/tidb/pkg/util/stringutil" "go.uber.org/zap" @@ -238,10 +238,30 @@ func initPartition(t *partitionedTable, def model.PartitionDefinition) (*partiti return &newPart, nil } +// NewPartitionExprBuildCtx returns a context to build partition expression. +func NewPartitionExprBuildCtx() expression.BuildContext { + return contextstatic.NewStaticExprContext( + contextstatic.WithEvalCtx(contextstatic.NewStaticEvalContext( + // Set a non-strict SQL mode and allow all date values if possible to make sure constant fold can work to + // estimate some undetermined result when locating a row to a partition. + // See issue: https://github.com/pingcap/tidb/issues/54271 for details. + contextstatic.WithSQLMode(mysql.ModeAllowInvalidDates), + contextstatic.WithTypeFlags(types.StrictFlags. + WithIgnoreTruncateErr(true). + WithIgnoreZeroDateErr(true). + WithIgnoreZeroInDate(true). + WithIgnoreInvalidDateErr(true), + ), + contextstatic.WithErrLevelMap(errctx.LevelMap{ + errctx.ErrGroupTruncate: errctx.LevelIgnore, + }), + )), + ) +} + func newPartitionExpr(tblInfo *model.TableInfo, tp model.PartitionType, expr string, partCols []model.CIStr, defs []model.PartitionDefinition) (*PartitionExpr, error) { - // a partitioned table cannot rely on session context/sql modes, so use a default one! - ctx := mock.NewContext() - dbName := model.NewCIStr(ctx.GetSessionVars().CurrentDB) + ctx := NewPartitionExprBuildCtx() + dbName := model.NewCIStr(ctx.GetEvalCtx().CurrentDB()) columns, names, err := expression.ColumnInfos2ColumnsAndNames(ctx, dbName, tblInfo.Name, tblInfo.Cols(), tblInfo) if err != nil { return nil, err diff --git a/tests/integrationtest/r/table/partition.result b/tests/integrationtest/r/table/partition.result index dd0e89f64c8cc..35e13c1a5a2fe 100644 --- a/tests/integrationtest/r/table/partition.result +++ b/tests/integrationtest/r/table/partition.result @@ -569,3 +569,20 @@ a -1 0 1 +set @@sql_mode='allow_invalid_dates'; +create table t_54271(a datetime primary key) partition by range columns(a) ( +partition p0 values less than ('2020-02-31 00:00:00'), +partition p1 values less than (MAXVALUE) +); +insert into t_54271 values('2020-03-01 00:00:00'); +set @@sql_mode=''; +insert into t_54271 values('2020-03-01 00:00:00'); +Error 1062 (23000): Duplicate entry '2020-03-01 00:00:00' for key 't_54271.PRIMARY' +select * from t_54271; +a +2020-03-01 00:00:00 +select * from t_54271 partition (p0); +a +select * from t_54271 partition (p1); +a +2020-03-01 00:00:00 diff --git a/tests/integrationtest/t/table/partition.test b/tests/integrationtest/t/table/partition.test index a0117b376c973..2856d0d303318 100644 --- a/tests/integrationtest/t/table/partition.test +++ b/tests/integrationtest/t/table/partition.test @@ -430,3 +430,17 @@ alter table t partition by range(a) (partition p0 values less than (0), partitio alter table t remove partitioning; select * from t; +# Issue #54271 +set @@sql_mode='allow_invalid_dates'; +create table t_54271(a datetime primary key) partition by range columns(a) ( + partition p0 values less than ('2020-02-31 00:00:00'), + partition p1 values less than (MAXVALUE) +); +insert into t_54271 values('2020-03-01 00:00:00'); +set @@sql_mode=''; +--error 1062 +insert into t_54271 values('2020-03-01 00:00:00'); +select * from t_54271; +select * from t_54271 partition (p0); +select * from t_54271 partition (p1); +