Repository: pingcap/tidb (Go)

Issue:
Can't read from some information_schema tables when cascades planner is enabled
## Bug Report

Please answer these questions before submitting your issue. Thanks!

1. What did you do?

Not a big deal, but wanted to file a bug so you can track it:

```
mysql> set tidb_enable_cascades_planner = 1;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from information_schema.slow_query;
ERROR 1815 (HY000): Internal : Can't find a proper physical plan for this query
```

This is also the case for information_schema.processlist. cluster_processlist and cluster_slow_query return zero results which is worse / inconsistent.

2. What did you expect to see?

Query should succeed.

3. What did you see instead?

Error or no results.

4. What version of TiDB are you using (`tidb-server -V` or run `select tidb_version();` on TiDB)?

```
mysql> select tidb_version()\G
*************************** 1. row ***************************
tidb_version(): Release Version: v4.0.0-alpha-1334-g07e642c92
Git Commit Hash: 07e642c9230ccb7c1537b27442f1fe8433e65f8a
Git Branch: master
UTC Build Time: 2020-01-08 08:32:04
GoVersion: go1.13
Race Enabled: false
TiKV Min Version: v3.0.0-60965b006877ca7234adaced7890d7b029ed1306
Check Table Before Drop: false
1 row in set (0.00 sec)

```


Discussion:
Certain diagnostics commands also fail, like  `ADMIN SHOW DDL JOBS`.
The cascades planner is under development now, you can see the progress through this project: [cascades planner](https://github.com/pingcap/tidb/projects/16). Not generally available yet.

Please turn it off to test or use TiDB.



Patch:
diff --git a/planner/cascades/implementation_rules.go b/planner/cascades/implementation_rules.go
index 970d457a7a1d2..3d0e10ff39148 100644
--- a/planner/cascades/implementation_rules.go
+++ b/planner/cascades/implementation_rules.go
@@ -36,6 +36,9 @@ var defaultImplementationMap = map[memo.Operand][]ImplementationRule{
 	memo.OperandTableDual: {
 		&ImplTableDual{},
 	},
+	memo.OperandMemTableScan: {
+		&ImplMemTableScan{},
+	},
 	memo.OperandProjection: {
 		&ImplProjection{},
 	},
@@ -107,6 +110,35 @@ func (r *ImplTableDual) OnImplement(expr *memo.GroupExpr, reqProp *property.Phys
 	return []memo.Implementation{impl.NewTableDualImpl(dual)}, nil
 }
 
+// ImplMemTableScan implements LogicalMemTable as PhysicalMemTable.
+type ImplMemTableScan struct {
+}
+
+// Match implements ImplementationRule Match interface.
+func (r *ImplMemTableScan) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
+	if !prop.IsEmpty() {
+		return false
+	}
+	return true
+}
+
+// OnImplement implements ImplementationRule OnImplement interface.
+func (r *ImplMemTableScan) OnImplement(
+	expr *memo.GroupExpr,
+	reqProp *property.PhysicalProperty,
+) ([]memo.Implementation, error) {
+	logic := expr.ExprNode.(*plannercore.LogicalMemTable)
+	logicProp := expr.Group.Prop
+	physical := plannercore.PhysicalMemTable{
+		DBName:    logic.DBName,
+		Table:     logic.TableInfo,
+		Columns:   logic.TableInfo.Columns,
+		Extractor: logic.Extractor,
+	}.Init(logic.SCtx(), logicProp.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt), logic.SelectBlockOffset())
+	physical.SetSchema(logicProp.Schema)
+	return []memo.Implementation{impl.NewMemTableScanImpl(physical)}, nil
+}
+
 // ImplProjection implements LogicalProjection as PhysicalProjection.
 type ImplProjection struct {
 }
diff --git a/planner/core/find_best_task.go b/planner/core/find_best_task.go
index 041637093ec2a..90e84ccf51bb9 100644
--- a/planner/core/find_best_task.go
+++ b/planner/core/find_best_task.go
@@ -196,9 +196,9 @@ func (p *LogicalMemTable) findBestTask(prop *property.PhysicalProperty) (t task,
 		return invalidTask, nil
 	}
 	memTable := PhysicalMemTable{
-		DBName:    p.dbName,
-		Table:     p.tableInfo,
-		Columns:   p.tableInfo.Columns,
+		DBName:    p.DBName,
+		Table:     p.TableInfo,
+		Columns:   p.TableInfo.Columns,
 		Extractor: p.Extractor,
 	}.Init(p.ctx, p.stats, p.blockOffset)
 	memTable.SetSchema(p.schema)
diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go
index d3e138800a816..bda7da337dd4a 100644
--- a/planner/core/logical_plan_builder.go
+++ b/planner/core/logical_plan_builder.go
@@ -2717,8 +2717,8 @@ func (b *PlanBuilder) buildMemTable(ctx context.Context, dbName model.CIStr, tab
 
 	// NOTE: Add a `LogicalUnionScan` if we support update memory table in the future
 	p := LogicalMemTable{
-		dbName:    dbName,
-		tableInfo: tableInfo,
+		DBName:    dbName,
+		TableInfo: tableInfo,
 	}.Init(b.ctx, b.getSelectOffset())
 	p.SetSchema(schema)
 	p.names = names
diff --git a/planner/core/logical_plans.go b/planner/core/logical_plans.go
index b4bf7684ff690..b13f69c09bee0 100644
--- a/planner/core/logical_plans.go
+++ b/planner/core/logical_plans.go
@@ -381,8 +381,8 @@ type LogicalMemTable struct {
 	logicalSchemaProducer
 
 	Extractor MemTablePredicateExtractor
-	dbName    model.CIStr
-	tableInfo *model.TableInfo
+	DBName    model.CIStr
+	TableInfo *model.TableInfo
 }
 
 // LogicalUnionScan is only used in non read-only txn.
diff --git a/planner/core/stats.go b/planner/core/stats.go
index 64e5a62a41c0d..f0aaf4cda1bca 100644
--- a/planner/core/stats.go
+++ b/planner/core/stats.go
@@ -48,14 +48,14 @@ func (p *LogicalTableDual) DeriveStats(childStats []*property.StatsInfo, selfSch
 
 // DeriveStats implement LogicalPlan DeriveStats interface.
 func (p *LogicalMemTable) DeriveStats(childStats []*property.StatsInfo, selfSchema *expression.Schema, childSchema []*expression.Schema) (*property.StatsInfo, error) {
-	statsTable := statistics.PseudoTable(p.tableInfo)
+	statsTable := statistics.PseudoTable(p.TableInfo)
 	stats := &property.StatsInfo{
 		RowCount:     float64(statsTable.Count),
-		Cardinality:  make([]float64, len(p.tableInfo.Columns)),
-		HistColl:     statsTable.GenerateHistCollFromColumnInfo(p.tableInfo.Columns, p.schema.Columns),
+		Cardinality:  make([]float64, len(p.TableInfo.Columns)),
+		HistColl:     statsTable.GenerateHistCollFromColumnInfo(p.TableInfo.Columns, p.schema.Columns),
 		StatsVersion: statistics.PseudoVersion,
 	}
-	for i := range p.tableInfo.Columns {
+	for i := range p.TableInfo.Columns {
 		stats.Cardinality[i] = float64(statsTable.Count)
 	}
 	p.stats = stats
diff --git a/planner/implementation/datasource.go b/planner/implementation/datasource.go
index e56dbb58b2539..8c5e14a6b7607 100644
--- a/planner/implementation/datasource.go
+++ b/planner/implementation/datasource.go
@@ -14,12 +14,13 @@
 package implementation
 
 import (
+	"math"
+
 	"github.com/pingcap/tidb/expression"
 	"github.com/pingcap/tidb/kv"
 	plannercore "github.com/pingcap/tidb/planner/core"
 	"github.com/pingcap/tidb/planner/memo"
 	"github.com/pingcap/tidb/statistics"
-	"math"
 )
 
 // TableDualImpl implementation of PhysicalTableDual.
@@ -37,6 +38,21 @@ func (impl *TableDualImpl) CalcCost(outCount float64, children ...memo.Implement
 	return 0
 }
 
+// MemTableScanImpl implementation of PhysicalTableDual.
+type MemTableScanImpl struct {
+	baseImpl
+}
+
+// NewMemTableScanImpl creates a new table dual Implementation.
+func NewMemTableScanImpl(dual *plannercore.PhysicalMemTable) *MemTableScanImpl {
+	return &MemTableScanImpl{baseImpl{plan: dual}}
+}
+
+// CalcCost calculates the cost of the table dual Implementation.
+func (impl *MemTableScanImpl) CalcCost(outCount float64, children ...memo.Implementation) float64 {
+	return 0
+}
+
 // TableReaderImpl implementation of PhysicalTableReader.
 type TableReaderImpl struct {
 	baseImpl
diff --git a/planner/memo/pattern.go b/planner/memo/pattern.go
index de0422ee43473..d13072887839a 100644
--- a/planner/memo/pattern.go
+++ b/planner/memo/pattern.go
@@ -57,6 +57,8 @@ const (
 	OperandLimit
 	// OperandTiKVSingleGather is the operand for TiKVSingleGather.
 	OperandTiKVSingleGather
+	// OperandMemTableScan is the operand for MemTableScan.
+	OperandMemTableScan
 	// OperandTableScan is the operand for TableScan.
 	OperandTableScan
 	// OperandIndexScan is the operand for IndexScan.
@@ -104,6 +106,8 @@ func GetOperand(p plannercore.LogicalPlan) Operand {
 		return OperandTiKVSingleGather
 	case *plannercore.LogicalTableScan:
 		return OperandTableScan
+	case *plannercore.LogicalMemTable:
+		return OperandMemTableScan
 	case *plannercore.LogicalIndexScan:
 		return OperandIndexScan
 	case *plannercore.LogicalShow:


Test patch:
diff --git a/planner/cascades/integration_test.go b/planner/cascades/integration_test.go
index 197a92977f8bd..7ec3a74dd86d3 100644
--- a/planner/cascades/integration_test.go
+++ b/planner/cascades/integration_test.go
@@ -247,3 +247,24 @@ func (s *testIntegrationSuite) TestApply(c *C) {
 		tk.MustQuery(sql).Check(testkit.Rows(output[i].Result...))
 	}
 }
+
+func (s *testIntegrationSuite) TestMemTableScan(c *C) {
+	tk := testkit.NewTestKitWithInit(c, s.store)
+	tk.MustExec("set session tidb_enable_cascades_planner = 1")
+	var input []string
+	var output []struct {
+		SQL    string
+		Plan   []string
+		Result []string
+	}
+	s.testData.GetTestCases(c, &input, &output)
+	for i, sql := range input {
+		s.testData.OnRecord(func() {
+			output[i].SQL = sql
+			output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery("explain " + sql).Rows())
+			output[i].Result = s.testData.ConvertRowsToStrings(tk.MustQuery(sql).Rows())
+		})
+		tk.MustQuery("explain " + sql).Check(testkit.Rows(output[i].Plan...))
+		tk.MustQuery(sql).Check(testkit.Rows(output[i].Result...))
+	}
+}
diff --git a/planner/cascades/testdata/integration_suite_in.json b/planner/cascades/testdata/integration_suite_in.json
index f3cd4f93f0d2d..bd3e77a2f55b6 100644
--- a/planner/cascades/testdata/integration_suite_in.json
+++ b/planner/cascades/testdata/integration_suite_in.json
@@ -71,5 +71,11 @@
       "select a = (select a from t2 where t1.b = t2.b order by a limit 1) from t1",
       "select sum(a), (select t1.a from t1 where t1.a = t2.a limit 1), (select t1.b from t1 where t1.b = t2.b limit 1) from t2"
     ]
+  },
+  {
+    "name": "TestMemTableScan",
+    "cases": [
+      "select * from information_schema.processlist"
+    ]
   }
 ]
diff --git a/planner/cascades/testdata/integration_suite_out.json b/planner/cascades/testdata/integration_suite_out.json
index c6d574f80f2ce..b7cd2764969d0 100644
--- a/planner/cascades/testdata/integration_suite_out.json
+++ b/planner/cascades/testdata/integration_suite_out.json
@@ -570,5 +570,17 @@
         ]
       }
     ]
+  },
+  {
+    "Name": "TestMemTableScan",
+    "Cases": [
+      {
+        "SQL": "select * from information_schema.processlist",
+        "Plan": [
+          "MemTableScan_3 10000.00 root "
+        ],
+        "Result": null
+      }
+    ]
   }
 ]