Skip to content

Commit

Permalink
This is an automated cherry-pick of pingcap#48413
Browse files Browse the repository at this point in the history
Signed-off-by: ti-chi-bot <ti-community-prow-bot@tidb.io>
  • Loading branch information
qw4990 authored and ti-chi-bot committed Nov 9, 2023
1 parent 38cb4f3 commit 8e92932
Show file tree
Hide file tree
Showing 4 changed files with 1,507 additions and 14 deletions.
25 changes: 15 additions & 10 deletions expression/builtin_compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -1621,7 +1621,7 @@ func allowCmpArgsRefining4PlanCache(ctx sessionctx.Context, args []Expression) (
// 3. It also handles comparing datetime/timestamp column with numeric constant, try to cast numeric constant as timestamp type, do nothing if failed.
// This refining operation depends on the values of these args, but these values can change when using plan-cache.
// So we have to skip this operation or mark the plan as over-optimized when using plan-cache.
func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Expression) []Expression {
func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Expression) ([]Expression, error) {
arg0Type, arg1Type := args[0].GetType(), args[1].GetType()
arg0EvalType, arg1EvalType := arg0Type.EvalType(), arg1Type.EvalType()
arg0IsInt := arg0EvalType == types.ETInt
Expand All @@ -1632,17 +1632,19 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express
isPositiveInfinite, isNegativeInfinite := false, false

if !allowCmpArgsRefining4PlanCache(ctx, args) {
return args
return args, nil
}
// We should remove the mutable constant for correctness, because its value may be changed.
RemoveMutableConst(ctx, args)
if err := RemoveMutableConst(ctx, args); err != nil {
return nil, err
}

if arg0IsCon && !arg1IsCon && matchRefineRule3Pattern(arg0EvalType, arg1Type) {
return c.refineNumericConstantCmpDatetime(ctx, args, arg0, 0)
return c.refineNumericConstantCmpDatetime(ctx, args, arg0, 0), nil
}

if !arg0IsCon && arg1IsCon && matchRefineRule3Pattern(arg1EvalType, arg0Type) {
return c.refineNumericConstantCmpDatetime(ctx, args, arg1, 1)
return c.refineNumericConstantCmpDatetime(ctx, args, arg1, 1), nil
}

// int non-constant [cmp] non-int constant
Expand Down Expand Up @@ -1708,24 +1710,24 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express
}
if isExceptional && (c.op == opcode.EQ || c.op == opcode.NullEQ) {
// This will always be false.
return []Expression{NewZero(), NewOne()}
return []Expression{NewZero(), NewOne()}, nil
}
if isPositiveInfinite {
// If the op is opcode.LT, opcode.LE
// This will always be true.
// If the op is opcode.GT, opcode.GE
// This will always be false.
return []Expression{NewZero(), NewOne()}
return []Expression{NewZero(), NewOne()}, nil
}
if isNegativeInfinite {
// If the op is opcode.GT, opcode.GE
// This will always be true.
// If the op is opcode.LT, opcode.LE
// This will always be false.
return []Expression{NewOne(), NewZero()}
return []Expression{NewOne(), NewZero()}, nil
}

return c.refineArgsByUnsignedFlag(ctx, []Expression{finalArg0, finalArg1})
return c.refineArgsByUnsignedFlag(ctx, []Expression{finalArg0, finalArg1}), nil
}

// see https://github.com/pingcap/tidb/issues/38361 for more details
Expand Down Expand Up @@ -1818,7 +1820,10 @@ func (c *compareFunctionClass) getFunction(ctx sessionctx.Context, rawArgs []Exp
if err = c.verifyArgs(rawArgs); err != nil {
return nil, err
}
args := c.refineArgs(ctx, rawArgs)
args, err := c.refineArgs(ctx, rawArgs)
if err != nil {
return nil, err
}
cmpType := GetAccurateCmpType(args[0], args[1])
sig, err = c.generateCmpSigs(ctx, args, cmpType)
return sig, err
Expand Down
15 changes: 12 additions & 3 deletions expression/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -1496,16 +1496,25 @@ func containMutableConst(ctx sessionctx.Context, exprs []Expression) bool {
}

// RemoveMutableConst used to remove the `ParamMarker` and `DeferredExpr` in the `Constant` expr.
func RemoveMutableConst(ctx sessionctx.Context, exprs []Expression) {
func RemoveMutableConst(ctx sessionctx.Context, exprs []Expression) (err error) {
for _, expr := range exprs {
switch v := expr.(type) {
case *Constant:
v.ParamMarker = nil
v.DeferredExpr = nil
if v.DeferredExpr != nil { // evaluate and update v.Value to convert v to a complete immutable constant.
// TODO: remove or hide DefferedExpr since it's too dangerous (hard to be consistent with v.Value all the time).
v.Value, err = v.DeferredExpr.Eval(chunk.Row{})
if err != nil {
return err
}
v.DeferredExpr = nil
}
v.DeferredExpr = nil // do nothing since v.Value has already been evaluated in this case.
case *ScalarFunction:
RemoveMutableConst(ctx, v.GetArgs())
return RemoveMutableConst(ctx, v.GetArgs())
}
}
return nil
}

const (
Expand Down
Loading

0 comments on commit 8e92932

Please sign in to comment.