-
Notifications
You must be signed in to change notification settings - Fork 5.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
expression, planner: push cast down to control function with enum type. #24542
Changes from 5 commits
ad10d0b
5b2db24
7531af5
a37d37b
d29f678
a19bd12
84e3acd
471a890
42adbcc
b276a15
2a44f22
4958693
3133cc3
66f9a47
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1804,6 +1804,12 @@ func BuildCastFunction4Union(ctx sessionctx.Context, expr Expression, tp *types. | |
|
||
// BuildCastFunction builds a CAST ScalarFunction from the Expression. | ||
func BuildCastFunction(ctx sessionctx.Context, expr Expression, tp *types.FieldType) (res Expression) { | ||
if res, success := TryPushCastDownToControlFunctionForHybridType(ctx, expr, tp); success { | ||
if tp.EvalType() != types.ETJson { | ||
res = FoldConstant(res) | ||
} | ||
return res | ||
} | ||
var fc functionClass | ||
switch tp.EvalType() { | ||
case types.ETInt: | ||
|
@@ -1983,3 +1989,85 @@ func WrapWithCastAsJSON(ctx sessionctx.Context, expr Expression) Expression { | |
} | ||
return BuildCastFunction(ctx, expr, tp) | ||
} | ||
|
||
// TryPushCastDownToControlFunctionForHybridType try to push cast down to control function for Hybrid Type. | ||
wshwsh12 marked this conversation as resolved.
Show resolved
Hide resolved
wshwsh12 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// If necessary, it will rebuild control function using changed args. | ||
func TryPushCastDownToControlFunctionForHybridType(ctx sessionctx.Context, expr Expression, tp *types.FieldType) (res Expression, success bool) { | ||
sf, ok := expr.(*ScalarFunction) | ||
if !ok { | ||
return expr, false | ||
} | ||
|
||
var wrapCastFunc func(ctx sessionctx.Context, expr Expression) Expression | ||
switch tp.EvalType() { | ||
case types.ETInt: | ||
wrapCastFunc = WrapWithCastAsInt | ||
case types.ETReal: | ||
wrapCastFunc = WrapWithCastAsReal | ||
case types.ETString: | ||
wrapCastFunc = WrapWithCastAsString | ||
default: | ||
return expr, false | ||
} | ||
|
||
args := sf.GetArgs() | ||
switch sf.FuncName.L { | ||
case ast.If: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a test. In mysql, |
||
if args[1].GetType().Hybrid() || args[2].GetType().Hybrid() { | ||
args[1] = wrapCastFunc(ctx, args[1]) | ||
args[2] = wrapCastFunc(ctx, args[2]) | ||
f, err := funcs[ast.If].getFunction(ctx, args) | ||
if err != nil { | ||
return expr, false | ||
} | ||
sf.RetType, sf.Function = f.getRetTp(), f | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
return sf, true | ||
} | ||
case ast.Case: | ||
hasHybrid := false | ||
for i := 0; i < len(args)-1; i += 2 { | ||
hasHybrid = hasHybrid || args[i+1].GetType().Hybrid() | ||
} | ||
if len(args)%2 == 1 { | ||
hasHybrid = hasHybrid || args[len(args)-1].GetType().Hybrid() | ||
} | ||
if !hasHybrid { | ||
return expr, false | ||
} | ||
|
||
for i := 0; i < len(args)-1; i += 2 { | ||
args[i+1] = wrapCastFunc(ctx, args[i+1]) | ||
} | ||
if len(args)%2 == 1 { | ||
args[len(args)-1] = wrapCastFunc(ctx, args[len(args)-1]) | ||
} | ||
f, err := funcs[ast.Case].getFunction(ctx, args) | ||
if err != nil { | ||
return expr, false | ||
} | ||
sf.RetType, sf.Function = f.getRetTp(), f | ||
return sf, true | ||
case ast.Elt: | ||
hasHybrid := false | ||
for i := 1; i < len(args); i++ { | ||
hasHybrid = hasHybrid || args[i].GetType().Hybrid() | ||
} | ||
if !hasHybrid { | ||
return expr, false | ||
} | ||
|
||
for i := 1; i < len(args); i++ { | ||
args[i] = wrapCastFunc(ctx, args[i]) | ||
} | ||
f, err := funcs[ast.Elt].getFunction(ctx, args) | ||
if err != nil { | ||
return expr, false | ||
} | ||
sf.RetType, sf.Function = f.getRetTp(), f | ||
// Elt only supports ETString, so we need add extra cast to keep retType right. | ||
return wrapCastFunc(ctx, sf), true | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The invoker will wrap a cast, why do we need to do this here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I remove this. |
||
default: | ||
return expr, false | ||
} | ||
return expr, false | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -975,6 +975,18 @@ func (b *PlanBuilder) buildSelection(ctx context.Context, p LogicalPlan, where a | |
if len(cnfExpres) == 0 { | ||
return p, nil | ||
} | ||
// check expr field types. | ||
for i, expr := range cnfExpres { | ||
if expr.GetType().EvalType() == types.ETString { | ||
tp := types.NewFieldType(mysql.TypeDouble) | ||
wshwsh12 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tp.Flen, tp.Decimal = mysql.MaxRealWidth, types.UnspecifiedLength | ||
types.SetBinChsClnFlag(tp) | ||
tp.Flag |= expr.GetType().Flag & mysql.UnsignedFlag | ||
if res, ok := expression.TryPushCastDownToControlFunctionForHybridType(b.ctx, expr, tp); ok { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It will push cast as string into if function. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I got it wrong... |
||
cnfExpres[i] = res | ||
} | ||
} | ||
} | ||
selection.Conditions = cnfExpres | ||
selection.SetChildren(p) | ||
return selection, nil | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BuildCastFunc
will also be used for explicitcast
, if we return here, we may build a wrong scalar function.e.g.
select cast(if ()) from t ;