Skip to content

Commit

Permalink
expression: not push invalid cast to tiflash (#28458) (#28651)
Browse files Browse the repository at this point in the history
close #23907
  • Loading branch information
ti-srebot authored Dec 20, 2021
1 parent 9895605 commit 7fae4e7
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 20 deletions.
6 changes: 3 additions & 3 deletions executor/show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,13 @@ func (s *testSuite5) TestShowWarningsForExprPushdown(c *C) {
tk.MustExec(testSQL)
tk.MustExec("explain select * from show_warnings_expr_pushdown where date_add(value, interval 1 day) = '2020-01-01'")
c.Assert(tk.Se.GetSessionVars().StmtCtx.WarningCount(), Equals, uint16(1))
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1105|Scalar function 'date_add'(signature: AddDateDatetimeInt) can not be pushed to tikv"))
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1105|Scalar function 'date_add'(signature: AddDateDatetimeInt, return type: datetime) can not be pushed to tikv"))
tk.MustExec("explain select max(date_add(value, interval 1 day)) from show_warnings_expr_pushdown group by a")
c.Assert(tk.Se.GetSessionVars().StmtCtx.WarningCount(), Equals, uint16(2))
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1105|Scalar function 'date_add'(signature: AddDateDatetimeInt) can not be pushed to tikv", "Warning|1105|Aggregation can not be pushed to tikv because arguments of AggFunc `max` contains unsupported exprs"))
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1105|Scalar function 'date_add'(signature: AddDateDatetimeInt, return type: datetime) can not be pushed to tikv", "Warning|1105|Aggregation can not be pushed to tikv because arguments of AggFunc `max` contains unsupported exprs"))
tk.MustExec("explain select max(a) from show_warnings_expr_pushdown group by date_add(value, interval 1 day)")
c.Assert(tk.Se.GetSessionVars().StmtCtx.WarningCount(), Equals, uint16(2))
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1105|Scalar function 'date_add'(signature: AddDateDatetimeInt) can not be pushed to tikv", "Warning|1105|Aggregation can not be pushed to tikv because groupByItems contain unsupported exprs"))
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1105|Scalar function 'date_add'(signature: AddDateDatetimeInt, return type: datetime) can not be pushed to tikv", "Warning|1105|Aggregation can not be pushed to tikv because groupByItems contain unsupported exprs"))
tk.MustExec("set tidb_opt_distinct_agg_push_down=0")
tk.MustExec("explain select max(distinct a) from show_warnings_expr_pushdown group by value")
c.Assert(tk.Se.GetSessionVars().StmtCtx.WarningCount(), Equals, uint16(1))
Expand Down
47 changes: 42 additions & 5 deletions expression/expr_to_pb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,8 @@ func (s *testEvaluatorSuite) TestExprPushDownToFlash(c *C) {
datetimeColumn := dg.genColumn(mysql.TypeDatetime, 6)
binaryStringColumn := dg.genColumn(mysql.TypeString, 7)
binaryStringColumn.RetType.Collate = charset.CollationBin
int32Column := dg.genColumn(mysql.TypeLong, 8)
float32Column := dg.genColumn(mysql.TypeFloat, 9)

function, err := NewFunction(mock.NewContext(), ast.JSONLength, types.NewFieldType(mysql.TypeLonglong), jsonColumn)
c.Assert(err, IsNil)
Expand Down Expand Up @@ -662,28 +664,31 @@ func (s *testEvaluatorSuite) TestExprPushDownToFlash(c *C) {
c.Assert(err, IsNil)
exprs = append(exprs, function)

validDecimalType := types.NewFieldType(mysql.TypeNewDecimal)
validDecimalType.Flen = 20
validDecimalType.Decimal = 2
// CastIntAsDecimal
function, err = NewFunction(mock.NewContext(), ast.Cast, types.NewFieldType(mysql.TypeNewDecimal), intColumn)
function, err = NewFunction(mock.NewContext(), ast.Cast, validDecimalType, intColumn)
c.Assert(err, IsNil)
exprs = append(exprs, function)

// CastRealAsDecimal
function, err = NewFunction(mock.NewContext(), ast.Cast, types.NewFieldType(mysql.TypeNewDecimal), realColumn)
function, err = NewFunction(mock.NewContext(), ast.Cast, validDecimalType, realColumn)
c.Assert(err, IsNil)
exprs = append(exprs, function)

// CastDecimalAsDecimal
function, err = NewFunction(mock.NewContext(), ast.Cast, types.NewFieldType(mysql.TypeNewDecimal), decimalColumn)
function, err = NewFunction(mock.NewContext(), ast.Cast, validDecimalType, decimalColumn)
c.Assert(err, IsNil)
exprs = append(exprs, function)

// CastStringAsDecimal
function, err = NewFunction(mock.NewContext(), ast.Cast, types.NewFieldType(mysql.TypeNewDecimal), stringColumn)
function, err = NewFunction(mock.NewContext(), ast.Cast, validDecimalType, stringColumn)
c.Assert(err, IsNil)
exprs = append(exprs, function)

// CastTimeAsDecimal
function, err = NewFunction(mock.NewContext(), ast.Cast, types.NewFieldType(mysql.TypeNewDecimal), datetimeColumn)
function, err = NewFunction(mock.NewContext(), ast.Cast, validDecimalType, datetimeColumn)
c.Assert(err, IsNil)
exprs = append(exprs, function)

Expand Down Expand Up @@ -832,6 +837,16 @@ func (s *testEvaluatorSuite) TestExprPushDownToFlash(c *C) {
c.Assert(function.(*ScalarFunction).Function.PbCode(), Equals, tipb.ScalarFuncSig_UnixTimestampDec)
exprs = append(exprs, function)

// cast Int32 to Int32
function, err = NewFunction(mock.NewContext(), ast.Cast, types.NewFieldType(mysql.TypeLong), int32Column)
c.Assert(err, IsNil)
exprs = append(exprs, function)

// cast float32 to float32
function, err = NewFunction(mock.NewContext(), ast.Cast, types.NewFieldType(mysql.TypeFloat), float32Column)
c.Assert(err, IsNil)
exprs = append(exprs, function)

canPush := CanExprsPushDown(sc, exprs, client, kv.TiFlash)
c.Assert(canPush, Equals, true)

Expand Down Expand Up @@ -861,6 +876,28 @@ func (s *testEvaluatorSuite) TestExprPushDownToFlash(c *C) {
c.Assert(err, IsNil)
exprs = append(exprs, function)

// Cast to Int32: not supported
function, err = NewFunction(mock.NewContext(), ast.Cast, types.NewFieldType(mysql.TypeLong), stringColumn)
c.Assert(err, IsNil)
exprs = append(exprs, function)

// Cast to Float: not supported
function, err = NewFunction(mock.NewContext(), ast.Cast, types.NewFieldType(mysql.TypeFloat), intColumn)
c.Assert(err, IsNil)
exprs = append(exprs, function)

// Cast to invalid Decimal Type: not supported
function, err = NewFunction(mock.NewContext(), ast.Cast, types.NewFieldType(mysql.TypeNewDecimal), intColumn)
c.Assert(err, IsNil)
exprs = append(exprs, function)

// cast Int32 to UInt32
unsignedInt32Type := types.NewFieldType(mysql.TypeLong)
unsignedInt32Type.Flag = mysql.UnsignedFlag
function, err = NewFunction(mock.NewContext(), ast.Cast, unsignedInt32Type, int32Column)
c.Assert(err, IsNil)
exprs = append(exprs, function)

pushed, remained := PushDownExprs(sc, exprs, client, kv.TiFlash)
c.Assert(len(pushed), Equals, 0)
c.Assert(len(remained), Equals, len(exprs))
Expand Down
34 changes: 26 additions & 8 deletions expression/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,13 @@ func scalarExprSupportedByTiKV(sf *ScalarFunction) bool {
return false
}

func isValidTiFlashDecimalType(tp *types.FieldType) bool {
if tp.Tp != mysql.TypeNewDecimal {
return false
}
return tp.Flen > 0 && tp.Flen <= 65 && tp.Decimal >= 0 && tp.Decimal <= 30 && tp.Flen >= tp.Decimal
}

func scalarExprSupportedByFlash(function *ScalarFunction) bool {
switch function.FuncName.L {
case
Expand All @@ -1018,16 +1025,27 @@ func scalarExprSupportedByFlash(function *ScalarFunction) bool {
return true
}
case ast.Cast:
sourceType := function.GetArgs()[0].GetType()
retType := function.RetType
switch function.Function.PbCode() {
case tipb.ScalarFuncSig_CastIntAsTime:
case tipb.ScalarFuncSig_CastDecimalAsInt, tipb.ScalarFuncSig_CastIntAsInt, tipb.ScalarFuncSig_CastRealAsInt, tipb.ScalarFuncSig_CastTimeAsInt,
tipb.ScalarFuncSig_CastStringAsInt /*, tipb.ScalarFuncSig_CastDurationAsInt, tipb.ScalarFuncSig_CastJsonAsInt*/ :
// TiFlash cast only support cast to Int64 or the source type is the same as the target type
return (sourceType.Tp == retType.Tp && mysql.HasUnsignedFlag(sourceType.Flag) == mysql.HasUnsignedFlag(retType.Flag)) || retType.Tp == mysql.TypeLonglong
case tipb.ScalarFuncSig_CastIntAsReal, tipb.ScalarFuncSig_CastRealAsReal, tipb.ScalarFuncSig_CastStringAsReal: /*, tipb.ScalarFuncSig_CastDecimalAsReal,
tipb.ScalarFuncSig_CastDurationAsReal, tipb.ScalarFuncSig_CastTimeAsReal, tipb.ScalarFuncSig_CastJsonAsReal*/
// TiFlash cast only support cast to Float64 or the source type is the same as the target type
return sourceType.Tp == retType.Tp || retType.Tp == mysql.TypeDouble
case tipb.ScalarFuncSig_CastDecimalAsDecimal, tipb.ScalarFuncSig_CastIntAsDecimal, tipb.ScalarFuncSig_CastRealAsDecimal, tipb.ScalarFuncSig_CastTimeAsDecimal,
tipb.ScalarFuncSig_CastStringAsDecimal /*, tipb.ScalarFuncSig_CastDurationAsDecimal, tipb.ScalarFuncSig_CastJsonAsDecimal*/ :
return isValidTiFlashDecimalType(function.RetType)
case tipb.ScalarFuncSig_CastDecimalAsString, tipb.ScalarFuncSig_CastIntAsString, tipb.ScalarFuncSig_CastRealAsString, tipb.ScalarFuncSig_CastTimeAsString,
tipb.ScalarFuncSig_CastStringAsString /*, tipb.ScalarFuncSig_CastDurationAsString, tipb.ScalarFuncSig_CastJsonAsString*/ :
return true
case tipb.ScalarFuncSig_CastDecimalAsTime, tipb.ScalarFuncSig_CastIntAsTime, tipb.ScalarFuncSig_CastRealAsTime, tipb.ScalarFuncSig_CastTimeAsTime,
tipb.ScalarFuncSig_CastStringAsTime /*, tipb.ScalarFuncSig_CastDurationAsTime, tipb.ScalarFuncSig_CastJsonAsTime*/ :
// ban the function of casting year type as time type pushing down to tiflash because of https://github.com/pingcap/tidb/issues/26215
return function.GetArgs()[0].GetType().Tp != mysql.TypeYear
case tipb.ScalarFuncSig_CastIntAsInt, tipb.ScalarFuncSig_CastIntAsReal, tipb.ScalarFuncSig_CastIntAsDecimal, tipb.ScalarFuncSig_CastIntAsString,
tipb.ScalarFuncSig_CastRealAsInt, tipb.ScalarFuncSig_CastRealAsReal, tipb.ScalarFuncSig_CastRealAsDecimal, tipb.ScalarFuncSig_CastRealAsString, tipb.ScalarFuncSig_CastRealAsTime,
tipb.ScalarFuncSig_CastStringAsInt, tipb.ScalarFuncSig_CastStringAsReal, tipb.ScalarFuncSig_CastStringAsDecimal, tipb.ScalarFuncSig_CastStringAsString, tipb.ScalarFuncSig_CastStringAsTime,
tipb.ScalarFuncSig_CastDecimalAsInt /*, tipb.ScalarFuncSig_CastDecimalAsReal*/, tipb.ScalarFuncSig_CastDecimalAsDecimal, tipb.ScalarFuncSig_CastDecimalAsString, tipb.ScalarFuncSig_CastDecimalAsTime,
tipb.ScalarFuncSig_CastTimeAsInt /*, tipb.ScalarFuncSig_CastTimeAsReal*/, tipb.ScalarFuncSig_CastTimeAsDecimal, tipb.ScalarFuncSig_CastTimeAsTime, tipb.ScalarFuncSig_CastTimeAsString:
return true
}
case ast.DateAdd, ast.AddDate:
switch function.Function.PbCode() {
Expand Down Expand Up @@ -1161,7 +1179,7 @@ func canScalarFuncPushDown(scalarFunc *ScalarFunction, pc PbConverter, storeType
if storeType == kv.UnSpecified {
storageName = "storage layer"
}
pc.sc.AppendWarning(errors.New("Scalar function '" + scalarFunc.FuncName.L + "'(signature: " + scalarFunc.Function.PbCode().String() + ") can not be pushed to " + storageName))
pc.sc.AppendWarning(errors.New("Scalar function '" + scalarFunc.FuncName.L + "'(signature: " + scalarFunc.Function.PbCode().String() + ", return type: " + scalarFunc.RetType.CompactStr() + ") can not be pushed to " + storageName))
}
return false
}
Expand Down
6 changes: 3 additions & 3 deletions planner/core/testdata/enforce_mpp_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -352,13 +352,13 @@
" └─TableFullScan_10 10000.00 cop[tiflash] table:t keep order:false, stats:pseudo"
],
"Warn": [
"Scalar function 'md5'(signature: MD5) can not be pushed to tiflash",
"Scalar function 'md5'(signature: MD5, return type: var_string(32)) can not be pushed to tiflash",
"MPP mode may be blocked because groupByItems contain unsupported exprs",
"Aggregation can not be pushed to tiflash because groupByItems contain unsupported exprs",
"Scalar function 'md5'(signature: MD5) can not be pushed to tiflash",
"Scalar function 'md5'(signature: MD5, return type: var_string(32)) can not be pushed to tiflash",
"MPP mode may be blocked because groupByItems contain unsupported exprs",
"Aggregation can not be pushed to tiflash because groupByItems contain unsupported exprs",
"Scalar function 'md5'(signature: MD5) can not be pushed to tiflash",
"Scalar function 'md5'(signature: MD5, return type: var_string(32)) can not be pushed to tiflash",
"MPP mode may be blocked because groupByItems contain unsupported exprs",
"Aggregation can not be pushed to tiflash because groupByItems contain unsupported exprs"
]
Expand Down
1 change: 1 addition & 0 deletions planner/core/testdata/integration_serial_suite_in.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"name": "TestSelPushDownTiFlash",
"cases": [
"explain format = 'brief' select * from t where t.a > 1 and t.b = \"flash\" or t.a + 3 * t.a = 5",
"explain format = 'brief' select * from t where cast(t.a as double) + 3 = 5.1",
"explain format = 'brief' select * from t where b > 'a' order by convert(b, unsigned) limit 2",
"explain format = 'brief' select * from t where b > 'a' order by b limit 2"
]
Expand Down
8 changes: 8 additions & 0 deletions planner/core/testdata/integration_serial_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@
" └─TableFullScan 10000.00 cop[tiflash] table:t keep order:false, stats:pseudo"
]
},
{
"SQL": "explain format = 'brief' select * from t where cast(t.a as double) + 3 = 5.1",
"Plan": [
"TableReader 8000.00 root data:Selection",
"└─Selection 8000.00 cop[tiflash] eq(plus(cast(test.t.a), 3), 5.1)",
" └─TableFullScan 10000.00 cop[tiflash] table:t keep order:false, stats:pseudo"
]
},
{
"SQL": "explain format = 'brief' select * from t where b > 'a' order by convert(b, unsigned) limit 2",
"Plan": [
Expand Down
2 changes: 1 addition & 1 deletion planner/core/testdata/plan_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -1508,7 +1508,7 @@
" └─IndexFullScan 1.00 cop[tikv] table:tn, index:a(a, b, c, d) keep order:true, stats:pseudo"
],
"Warning": [
"Scalar function 'mod'(signature: ModInt) can not be pushed to storage layer",
"Scalar function 'mod'(signature: ModInt, return type: bigint(20)) can not be pushed to storage layer",
"[planner:1815]Optimizer Hint LIMIT_TO_COP is inapplicable"
]
},
Expand Down

0 comments on commit 7fae4e7

Please sign in to comment.