diff --git a/expression/expr_to_pb_test.go b/expression/expr_to_pb_test.go index bd2af6c76d227..426a0000ed4a7 100644 --- a/expression/expr_to_pb_test.go +++ b/expression/expr_to_pb_test.go @@ -503,7 +503,7 @@ func TestOtherFunc2Pb(t *testing.T) { } } -func TestExprPushDownToFlash(t *testing.T) { +func TestJsonPushDownToFlash(t *testing.T) { sc := new(stmtctx.StatementContext) client := new(mock.Client) @@ -511,19 +511,10 @@ func TestExprPushDownToFlash(t *testing.T) { jsonColumn := genColumn(mysql.TypeJSON, 1) intColumn := genColumn(mysql.TypeLonglong, 2) - realColumn := genColumn(mysql.TypeDouble, 3) - decimalColumn := genColumn(mysql.TypeNewDecimal, 4) - decimalColumn.RetType.SetDecimal(mysql.MaxDecimalScale) - decimalColumn.RetType.SetFlen(mysql.MaxDecimalWidth) stringColumn := genColumn(mysql.TypeString, 5) - datetimeColumn := genColumn(mysql.TypeDatetime, 6) - binaryStringColumn := genColumn(mysql.TypeString, 7) - binaryStringColumn.RetType.SetCollate(charset.CollationBin) - int32Column := genColumn(mysql.TypeLong, 8) - float32Column := genColumn(mysql.TypeFloat, 9) - enumColumn := genColumn(mysql.TypeEnum, 10) - durationColumn := genColumn(mysql.TypeDuration, 11) + // functions that can be pushdown to tiflash + // json_length function, err := NewFunction(mock.NewContext(), ast.JSONLength, types.NewFieldType(mysql.TypeLonglong), jsonColumn) require.NoError(t, err) exprs = append(exprs, function) @@ -540,8 +531,104 @@ func TestExprPushDownToFlash(t *testing.T) { require.NoError(t, err) exprs = append(exprs, function) + // CastJsonAsString + function, err = NewFunction(mock.NewContext(), ast.Cast, types.NewFieldType(mysql.TypeString), jsonColumn) + require.NoError(t, err) + exprs = append(exprs, function) + + // IfNullJson + function, err = NewFunction(mock.NewContext(), ast.Ifnull, types.NewFieldType(mysql.TypeJSON), jsonColumn, jsonColumn) + require.NoError(t, err) + exprs = append(exprs, function) + + // JsonIsNull is not implement, for function json_col is null, it will be converted to cast(json as string) is null + function, err = NewFunction(mock.NewContext(), ast.IsNull, types.NewFieldType(mysql.TypeLonglong), jsonColumn) + require.NoError(t, err) + exprs = append(exprs, function) + + // CaseWhenJson + function, err = NewFunction(mock.NewContext(), ast.Case, types.NewFieldType(mysql.TypeJSON), intColumn, jsonColumn, intColumn, jsonColumn, jsonColumn) + require.NoError(t, err) + exprs = append(exprs, function) + + // CoalesceJson + function, err = NewFunction(mock.NewContext(), ast.Coalesce, types.NewFieldType(mysql.TypeJSON), jsonColumn, jsonColumn, jsonColumn) + require.NoError(t, err) + exprs = append(exprs, function) + + pushed, remained := PushDownExprs(sc, exprs, client, kv.TiFlash) + require.Len(t, pushed, len(exprs)) + require.Len(t, remained, 0) + + // functions that can not be pushed to tiflash + exprs = exprs[:0] + // LTJson + function, err = NewFunction(mock.NewContext(), ast.LT, types.NewFieldType(mysql.TypeLonglong), jsonColumn, jsonColumn) + require.NoError(t, err) + exprs = append(exprs, function) + + // LEJson + function, err = NewFunction(mock.NewContext(), ast.LE, types.NewFieldType(mysql.TypeLonglong), jsonColumn, jsonColumn) + require.NoError(t, err) + exprs = append(exprs, function) + + // GTJson + function, err = NewFunction(mock.NewContext(), ast.GT, types.NewFieldType(mysql.TypeLonglong), jsonColumn, jsonColumn) + require.NoError(t, err) + exprs = append(exprs, function) + + // GEJson + function, err = NewFunction(mock.NewContext(), ast.GE, types.NewFieldType(mysql.TypeLonglong), jsonColumn, jsonColumn) + require.NoError(t, err) + exprs = append(exprs, function) + + // EQJson + function, err = NewFunction(mock.NewContext(), ast.EQ, types.NewFieldType(mysql.TypeLonglong), jsonColumn, jsonColumn) + require.NoError(t, err) + exprs = append(exprs, function) + + // NEJson + function, err = NewFunction(mock.NewContext(), ast.NE, types.NewFieldType(mysql.TypeLonglong), jsonColumn, jsonColumn) + require.NoError(t, err) + exprs = append(exprs, function) + + // InJson + function, err = NewFunction(mock.NewContext(), ast.In, types.NewFieldType(mysql.TypeLonglong), jsonColumn, jsonColumn, jsonColumn) + require.NoError(t, err) + exprs = append(exprs, function) + + // json_depth + function, err = NewFunction(mock.NewContext(), ast.JSONDepth, types.NewFieldType(mysql.TypeLonglong), jsonColumn) + require.NoError(t, err) + exprs = append(exprs, function) + + pushed, remained = PushDownExprs(sc, exprs, client, kv.TiFlash) + require.Len(t, pushed, 0) + require.Len(t, remained, len(exprs)) +} + +func TestExprPushDownToFlash(t *testing.T) { + sc := new(stmtctx.StatementContext) + client := new(mock.Client) + + exprs := make([]Expression, 0) + + intColumn := genColumn(mysql.TypeLonglong, 2) + realColumn := genColumn(mysql.TypeDouble, 3) + decimalColumn := genColumn(mysql.TypeNewDecimal, 4) + decimalColumn.RetType.SetDecimal(mysql.MaxDecimalScale) + decimalColumn.RetType.SetFlen(mysql.MaxDecimalWidth) + stringColumn := genColumn(mysql.TypeString, 5) + datetimeColumn := genColumn(mysql.TypeDatetime, 6) + binaryStringColumn := genColumn(mysql.TypeString, 7) + binaryStringColumn.RetType.SetCollate(charset.CollationBin) + int32Column := genColumn(mysql.TypeLong, 8) + float32Column := genColumn(mysql.TypeFloat, 9) + enumColumn := genColumn(mysql.TypeEnum, 10) + durationColumn := genColumn(mysql.TypeDuration, 11) + // lpad - function, err = NewFunction(mock.NewContext(), ast.Lpad, types.NewFieldType(mysql.TypeString), stringColumn, int32Column, stringColumn) + function, err := NewFunction(mock.NewContext(), ast.Lpad, types.NewFieldType(mysql.TypeString), stringColumn, int32Column, stringColumn) require.NoError(t, err) exprs = append(exprs, function) @@ -651,11 +738,6 @@ func TestExprPushDownToFlash(t *testing.T) { require.NoError(t, err) exprs = append(exprs, function) - // CastJsonAsString - function, err = NewFunction(mock.NewContext(), ast.Cast, types.NewFieldType(mysql.TypeString), jsonColumn) - require.NoError(t, err) - exprs = append(exprs, function) - // CastIntAsTime function, err = NewFunction(mock.NewContext(), ast.Cast, types.NewFieldType(mysql.TypeDatetime), intColumn) require.NoError(t, err) @@ -990,10 +1072,6 @@ func TestExprPushDownToFlash(t *testing.T) { require.NoError(t, err) exprs = append(exprs, function) - function, err = NewFunction(mock.NewContext(), ast.JSONDepth, types.NewFieldType(mysql.TypeLonglong), jsonColumn) - require.NoError(t, err) - exprs = append(exprs, function) - // ExtractDatetimeFromString: can not be pushed extractDatetimeFromStringUnitCol := new(Constant) extractDatetimeFromStringUnitCol.Value = types.NewStringDatum("day_microsecond") diff --git a/expression/expression.go b/expression/expression.go index db4bdc4ac5dcb..76e584479ca9b 100644 --- a/expression/expression.go +++ b/expression/expression.go @@ -1161,7 +1161,15 @@ func scalarExprSupportedByFlash(function *ScalarFunction) bool { tipb.ScalarFuncSig_CoalesceDuration, tipb.ScalarFuncSig_IfNullDuration, tipb.ScalarFuncSig_IfDuration, - tipb.ScalarFuncSig_CaseWhenDuration: + tipb.ScalarFuncSig_CaseWhenDuration, + tipb.ScalarFuncSig_LTJson, + tipb.ScalarFuncSig_LEJson, + tipb.ScalarFuncSig_GTJson, + tipb.ScalarFuncSig_GEJson, + tipb.ScalarFuncSig_EQJson, + tipb.ScalarFuncSig_NEJson, + tipb.ScalarFuncSig_JsonIsNull, + tipb.ScalarFuncSig_InJson: return false case tipb.ScalarFuncSig_JsonUnquoteSig: // TiFlash json_unquote now only supports json string generated by cast(json as string)