code: func PushDownNot(ctx sessionctx.Context, expr Expression, not bool) Expression {
  	if f, ok := expr.(*ScalarFunction); ok {
  		switch f.FuncName.L {
  		case ast.UnaryNot:
  			return PushDownNot(f.GetCtx(), f.GetArgs()[0], !not)
  		case ast.LT, ast.GE, ast.GT, ast.LE, ast.EQ, ast.NE:
  			if not {
  				return NewFunctionInternal(f.GetCtx(), oppositeOp[f.FuncName.L], f.GetType(), f.GetArgs()...)
  			}
  			for i, arg := range f.GetArgs() {
  				f.GetArgs()[i] = PushDownNot(f.GetCtx(), arg, false)
  			}
  			return f
  		case ast.LogicAnd:
  			if not {
  				args := f.GetArgs()
  				for i, a := range args {
  					args[i] = PushDownNot(f.GetCtx(), a, true)
  				}
  				return NewFunctionInternal(f.GetCtx(), ast.LogicOr, f.GetType(), args...)
  			}
  			for i, arg := range f.GetArgs() {
  				f.GetArgs()[i] = PushDownNot(f.GetCtx(), arg, false)
  			}
  			return f
  		case ast.LogicOr:
  			if not {
  				args := f.GetArgs()
  				for i, a := range args {
  					args[i] = PushDownNot(f.GetCtx(), a, true)
  				}
  				return NewFunctionInternal(f.GetCtx(), ast.LogicAnd, f.GetType(), args...)
  			}
  			for i, arg := range f.GetArgs() {
  				f.GetArgs()[i] = PushDownNot(f.GetCtx(), arg, false)
  			}
  			return f
  		}
  	}
  	if not {
  		expr = NewFunctionInternal(ctx, ast.UnaryNot, types.NewFieldType(mysql.TypeTiny), expr)
  	}
  	return expr
  }
docs: // PushDownNot pushes the `not` function down to the expression's arguments.