From e2a05cb39417714f4d61fd1270d9e4b6b1261e2d Mon Sep 17 00:00:00 2001
From: Kenan Yao <cauchy1992@gmail.com>
Date: Tue, 21 Apr 2020 20:04:23 +0800
Subject: [PATCH] =?UTF-8?q?expression:=20avoid=20`Order=20By`=20constant?=
 =?UTF-8?q?=20expression=20error=20when=20pl=E2=80=A6=20(#16261)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 expression/expression.go            |  2 +-
 expression/function_traits.go       |  6 ++----
 expression/integration_test.go      | 22 ++++++++++++++++++++++
 expression/util.go                  | 21 +++++++++++++++++++++
 planner/core/rule_column_pruning.go |  2 +-
 5 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/expression/expression.go b/expression/expression.go
index f81dcc919492d..cca14125c5740 100644
--- a/expression/expression.go
+++ b/expression/expression.go
@@ -131,9 +131,9 @@ type Expression interface {
 	IsCorrelated() bool
 
 	// ConstItem checks if this expression is constant item, regardless of query evaluation state.
-	// A constant item can be eval() when build a plan.
 	// An expression is constant item if it:
 	// refers no tables.
+	// refers no correlated column.
 	// refers no subqueries that refers any tables.
 	// refers no non-deterministic functions.
 	// refers no statement parameters.
diff --git a/expression/function_traits.go b/expression/function_traits.go
index 528414ba3b373..f1f00ba4aa8a2 100644
--- a/expression/function_traits.go
+++ b/expression/function_traits.go
@@ -102,7 +102,8 @@ var IllegalFunctions4GeneratedColumns = map[string]struct{}{
 	ast.ReleaseAllLocks:  {},
 }
 
-// DeferredFunctions stores non-deterministic functions, which can be deferred only when the plan cache is enabled.
+// DeferredFunctions stores functions which are foldable but should be deferred as well when plan cache is enabled.
+// Note that, these functions must be foldable at first place, i.e, they are not in `unFoldableFunctions`.
 var DeferredFunctions = map[string]struct{}{
 	ast.Now:              {},
 	ast.RandomBytes:      {},
@@ -112,12 +113,9 @@ var DeferredFunctions = map[string]struct{}{
 	ast.CurrentTime:      {},
 	ast.UTCTimestamp:     {},
 	ast.UnixTimestamp:    {},
-	ast.Sysdate:          {},
 	ast.Curdate:          {},
 	ast.CurrentDate:      {},
 	ast.UTCDate:          {},
-	ast.Rand:             {},
-	ast.UUID:             {},
 }
 
 // inequalFunctions stores functions which cannot be propagated from column equal condition.
diff --git a/expression/integration_test.go b/expression/integration_test.go
index 6469f26b1b21f..55e2b81f28cb7 100755
--- a/expression/integration_test.go
+++ b/expression/integration_test.go
@@ -5544,6 +5544,28 @@ func (s *testIntegrationSuite) TestCacheRefineArgs(c *C) {
 	tk.MustQuery("execute stmt using @p0").Check(testkit.Rows("0"))
 }
 
+func (s *testIntegrationSuite) TestOrderByFuncPlanCache(c *C) {
+	tk := testkit.NewTestKit(c, s.store)
+	orgEnable := plannercore.PreparedPlanCacheEnabled()
+	defer func() {
+		plannercore.SetPreparedPlanCache(orgEnable)
+	}()
+	plannercore.SetPreparedPlanCache(true)
+	var err error
+	tk.Se, err = session.CreateSession4TestWithOpt(s.store, &session.Opt{
+		PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64),
+	})
+	c.Assert(err, IsNil)
+
+	tk.MustExec("use test")
+	tk.MustExec("drop table if exists t")
+	tk.MustExec("create table t(a int)")
+	tk.MustExec("prepare stmt from 'SELECT * FROM t order by rand()'")
+	tk.MustQuery("execute stmt").Check(testkit.Rows())
+	tk.MustExec("prepare stmt from 'SELECT * FROM t order by now()'")
+	tk.MustQuery("execute stmt").Check(testkit.Rows())
+}
+
 func (s *testIntegrationSuite) TestCollation(c *C) {
 	tk := testkit.NewTestKit(c, s.store)
 	tk.MustExec("use test")
diff --git a/expression/util.go b/expression/util.go
index 41218b1bdb423..455477c59ff01 100644
--- a/expression/util.go
+++ b/expression/util.go
@@ -748,6 +748,27 @@ func BuildNotNullExpr(ctx sessionctx.Context, expr Expression) Expression {
 	return notNull
 }
 
+// IsRuntimeConstExpr checks if a expr can be treated as a constant in **executor**.
+func IsRuntimeConstExpr(expr Expression) bool {
+	switch x := expr.(type) {
+	case *ScalarFunction:
+		if _, ok := unFoldableFunctions[x.FuncName.L]; ok {
+			return false
+		}
+		for _, arg := range x.GetArgs() {
+			if !IsRuntimeConstExpr(arg) {
+				return false
+			}
+		}
+		return true
+	case *Column:
+		return false
+	case *Constant, *CorrelatedColumn:
+		return true
+	}
+	return false
+}
+
 // IsMutableEffectsExpr checks if expr contains function which is mutable or has side effects.
 func IsMutableEffectsExpr(expr Expression) bool {
 	switch x := expr.(type) {
diff --git a/planner/core/rule_column_pruning.go b/planner/core/rule_column_pruning.go
index c35f17a6a0cdf..0f27ba8a697d6 100644
--- a/planner/core/rule_column_pruning.go
+++ b/planner/core/rule_column_pruning.go
@@ -138,7 +138,7 @@ func (ls *LogicalSort) PruneColumns(parentUsedCols []*expression.Column) error {
 	for i := len(ls.ByItems) - 1; i >= 0; i-- {
 		cols := expression.ExtractColumns(ls.ByItems[i].Expr)
 		if len(cols) == 0 {
-			if expression.IsMutableEffectsExpr(ls.ByItems[i].Expr) {
+			if !expression.IsRuntimeConstExpr(ls.ByItems[i].Expr) {
 				continue
 			}
 			ls.ByItems = append(ls.ByItems[:i], ls.ByItems[i+1:]...)