From 81cc7bc6cf6fc5661b4cd18decdcca12610c3db2 Mon Sep 17 00:00:00 2001 From: tiancaiamao Date: Thu, 12 Sep 2019 13:37:49 +0800 Subject: [PATCH] expression,planner/core: support unix_timestamp() function in partition pruning (#12035) --- expression/constant_test.go | 24 ++++++++++++++--- expression/constraint_propagation.go | 3 ++- expression/simple_rewriter_test.go | 5 ++++ planner/core/partition_pruning_test.go | 37 ++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/expression/constant_test.go b/expression/constant_test.go index d495f963d5643..84860356d5fd7 100644 --- a/expression/constant_test.go +++ b/expression/constant_test.go @@ -56,14 +56,22 @@ func newLonglong(value int64) *Constant { } func newDate(year, month, day int) *Constant { + return newTimeConst(year, month, day, 0, 0, 0, mysql.TypeDate) +} + +func newTimestamp(yy, mm, dd, hh, min, ss int) *Constant { + return newTimeConst(yy, mm, dd, hh, min, ss, mysql.TypeTimestamp) +} + +func newTimeConst(yy, mm, dd, hh, min, ss int, tp uint8) *Constant { var tmp types.Datum tmp.SetMysqlTime(types.Time{ - Time: types.FromDate(year, month, day, 0, 0, 0, 0), - Type: mysql.TypeDate, + Time: types.FromDate(yy, mm, dd, 0, 0, 0, 0), + Type: tp, }) return &Constant{ Value: tmp, - RetType: types.NewFieldType(mysql.TypeDate), + RetType: types.NewFieldType(tp), } } @@ -202,6 +210,7 @@ func (*testExpressionSuite) TestConstantPropagation(c *C) { func (*testExpressionSuite) TestConstraintPropagation(c *C) { defer testleak.AfterTest(c)() col1 := newColumnWithType(1, types.NewFieldType(mysql.TypeDate)) + col2 := newColumnWithType(2, types.NewFieldType(mysql.TypeTimestamp)) tests := []struct { solver constraintSolver conditions []Expression @@ -267,6 +276,15 @@ func (*testExpressionSuite) TestConstraintPropagation(c *C) { }, result: "0", }, + { + solver: newConstraintSolver(ruleColumnOPConst), + // col2 > unixtimestamp('2008-05-01 00:00:00') and unixtimestamp(col2) < unixtimestamp('2008-04-01 00:00:00') => false + conditions: []Expression{ + newFunction(ast.GT, col2, newTimestamp(2008, 5, 1, 0, 0, 0)), + newFunction(ast.LT, newFunction(ast.UnixTimestamp, col2), newLonglong(1206979200)), + }, + result: "0", + }, } for _, tt := range tests { ctx := mock.NewContext() diff --git a/expression/constraint_propagation.go b/expression/constraint_propagation.go index 1140f6c2e6fd4..4ff6b7b7c7279 100644 --- a/expression/constraint_propagation.go +++ b/expression/constraint_propagation.go @@ -299,7 +299,8 @@ func negOP(cmp string) string { // monotoneIncFuncs are those functions that for any x y, if x > y => f(x) > f(y) var monotoneIncFuncs = map[string]struct{}{ - ast.ToDays: {}, + ast.ToDays: {}, + ast.UnixTimestamp: {}, } // compareConstant compares two expressions. c1 and c2 should be constant with the same type. diff --git a/expression/simple_rewriter_test.go b/expression/simple_rewriter_test.go index 37486b1de1aec..b08b139005831 100644 --- a/expression/simple_rewriter_test.go +++ b/expression/simple_rewriter_test.go @@ -165,4 +165,9 @@ func (s *testEvaluatorSuite) TestSimpleRewriter(c *C) { c.Assert(err, IsNil) num, _, _ = exprs[0].EvalInt(ctx, chunk.Row{}) c.Assert(num, Equals, int64(31842)) + + exprs, err = ParseSimpleExprsWithSchema(ctx, "unix_timestamp('2008-05-01 00:00:00')", sch) + c.Assert(err, IsNil) + num, _, _ = exprs[0].EvalInt(ctx, chunk.Row{}) + c.Assert(num, Equals, int64(1209571200)) } diff --git a/planner/core/partition_pruning_test.go b/planner/core/partition_pruning_test.go index 3a50fa6610f8d..6623a4b75ae35 100644 --- a/planner/core/partition_pruning_test.go +++ b/planner/core/partition_pruning_test.go @@ -60,4 +60,41 @@ func (s *testPartitionPruningSuite) TestCanBePrune(c *C) { succ, err = s.canBePruned(ctx, nil, partitionExpr[0], queryExpr) c.Assert(err, IsNil) c.Assert(succ, IsTrue) + + // For the following case: + // CREATE TABLE quarterly_report_status ( + // report_id INT NOT NULL, + // report_status VARCHAR(20) NOT NULL, + // report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP) + // PARTITION BY RANGE (UNIX_TIMESTAMP(report_updated)) ( + // PARTITION p0 VALUES LESS THAN (UNIX_TIMESTAMP('2008-01-01 00:00:00')), + // PARTITION p1 VALUES LESS THAN (UNIX_TIMESTAMP('2008-04-01 00:00:00')), + // PARTITION p2 VALUES LESS THAN (UNIX_TIMESTAMP('2010-01-01 00:00:00')), + // PARTITION p3 VALUES LESS THAN (MAXVALUE) + // ); + stmt, err = p.ParseOneStmt("create table t (report_updated timestamp)", "", "") + c.Assert(err, IsNil) + tblInfo, err = ddl.BuildTableInfoFromAST(stmt.(*ast.CreateTableStmt)) + c.Assert(err, IsNil) + columns = expression.ColumnInfos2ColumnsWithDBName(ctx, model.NewCIStr("t"), tblInfo.Name, tblInfo.Columns) + schema = expression.NewSchema(columns...) + + partitionExpr, err = expression.ParseSimpleExprsWithSchema(ctx, "unix_timestamp(report_updated) < unix_timestamp('2008-04-01') and unix_timestamp(report_updated) >= unix_timestamp('2008-01-01')", schema) + c.Assert(err, IsNil) + queryExpr, err = expression.ParseSimpleExprsWithSchema(ctx, "report_updated > '2008-05-01 00:00:00'", schema) + c.Assert(err, IsNil) + succ, err = s.canBePruned(ctx, nil, partitionExpr[0], queryExpr) + c.Assert(err, IsNil) + c.Assert(succ, IsTrue) + + queryExpr, err = expression.ParseSimpleExprsWithSchema(ctx, "report_updated > unix_timestamp('2008-05-01 00:00:00')", schema) + c.Assert(err, IsNil) + succ, err = s.canBePruned(ctx, nil, partitionExpr[0], queryExpr) + c.Assert(err, IsNil) + _ = succ + // c.Assert(succ, IsTrue) + // TODO: Uncomment the check after fixing issue https://github.com/pingcap/tidb/issues/12028 + // report_updated > unix_timestamp('2008-05-01 00:00:00') is converted to gt(t.t.report_updated, ) + // Because unix_timestamp('2008-05-01 00:00:00') is fold to constant int 1564761600, and compare it with timestamp (report_updated) + // need to convert 1564761600 to a timestamp, during that step, an error happen and the result is set to }