Skip to content

Commit 249ff99

Browse files
authored
infoschema: Migrate the infoschema's retrieving data logic for 'schemata' to executor (#14704)
1 parent e7b1993 commit 249ff99

File tree

6 files changed

+317
-180
lines changed

6 files changed

+317
-180
lines changed

executor/builder.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,7 +1267,7 @@ func (b *executorBuilder) getStartTS() (uint64, error) {
12671267
func (b *executorBuilder) buildMemTable(v *plannercore.PhysicalMemTable) Executor {
12681268
switch v.DBName.L {
12691269
case util.MetricSchemaName.L:
1270-
return &ClusterReaderExec{
1270+
return &MemTableReaderExec{
12711271
baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ExplainID()),
12721272
retriever: &MetricRetriever{
12731273
table: v.Table,
@@ -1277,66 +1277,74 @@ func (b *executorBuilder) buildMemTable(v *plannercore.PhysicalMemTable) Executo
12771277
case util.InformationSchemaName.L:
12781278
switch v.Table.Name.L {
12791279
case strings.ToLower(infoschema.TableClusterConfig):
1280-
return &ClusterReaderExec{
1280+
return &MemTableReaderExec{
12811281
baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ExplainID()),
12821282
retriever: &clusterConfigRetriever{
12831283
extractor: v.Extractor.(*plannercore.ClusterTableExtractor),
12841284
},
12851285
}
12861286
case strings.ToLower(infoschema.TableClusterLoad):
1287-
return &ClusterReaderExec{
1287+
return &MemTableReaderExec{
12881288
baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ExplainID()),
12891289
retriever: &clusterServerInfoRetriever{
12901290
extractor: v.Extractor.(*plannercore.ClusterTableExtractor),
12911291
serverInfoType: diagnosticspb.ServerInfoType_LoadInfo,
12921292
},
12931293
}
12941294
case strings.ToLower(infoschema.TableClusterHardware):
1295-
return &ClusterReaderExec{
1295+
return &MemTableReaderExec{
12961296
baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ExplainID()),
12971297
retriever: &clusterServerInfoRetriever{
12981298
extractor: v.Extractor.(*plannercore.ClusterTableExtractor),
12991299
serverInfoType: diagnosticspb.ServerInfoType_HardwareInfo,
13001300
},
13011301
}
13021302
case strings.ToLower(infoschema.TableClusterSystemInfo):
1303-
return &ClusterReaderExec{
1303+
return &MemTableReaderExec{
13041304
baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ExplainID()),
13051305
retriever: &clusterServerInfoRetriever{
13061306
extractor: v.Extractor.(*plannercore.ClusterTableExtractor),
13071307
serverInfoType: diagnosticspb.ServerInfoType_SystemInfo,
13081308
},
13091309
}
13101310
case strings.ToLower(infoschema.TableClusterLog):
1311-
return &ClusterReaderExec{
1311+
return &MemTableReaderExec{
13121312
baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ExplainID()),
13131313
retriever: &clusterLogRetriever{
13141314
extractor: v.Extractor.(*plannercore.ClusterLogTableExtractor),
13151315
},
13161316
}
13171317
case strings.ToLower(infoschema.TableInspectionResult):
1318-
return &ClusterReaderExec{
1318+
return &MemTableReaderExec{
13191319
baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ExplainID()),
13201320
retriever: &inspectionRetriever{
13211321
extractor: v.Extractor.(*plannercore.InspectionResultTableExtractor),
13221322
},
13231323
}
13241324
case strings.ToLower(infoschema.TableMetricSummary):
1325-
return &ClusterReaderExec{
1325+
return &MemTableReaderExec{
13261326
baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ExplainID()),
13271327
retriever: &MetricSummaryRetriever{
13281328
table: v.Table,
13291329
extractor: v.Extractor.(*plannercore.MetricTableExtractor),
13301330
},
13311331
}
13321332
case strings.ToLower(infoschema.TableMetricSummaryByLabel):
1333-
return &ClusterReaderExec{
1333+
return &MemTableReaderExec{
13341334
baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ExplainID()),
13351335
retriever: &MetricSummaryByLabelRetriever{
13361336
table: v.Table,
13371337
extractor: v.Extractor.(*plannercore.MetricTableExtractor),
13381338
},
13391339
}
1340+
case strings.ToLower(infoschema.TableSchemata), strings.ToLower(infoschema.TableViews):
1341+
return &MemTableReaderExec{
1342+
baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ExplainID()),
1343+
retriever: &memtableRetriever{
1344+
table: v.Table,
1345+
columns: v.Columns,
1346+
},
1347+
}
13401348
}
13411349
}
13421350
tb, _ := b.is.TableByID(v.Table.ID)

executor/cluster_reader.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,19 @@ type dummyCloser struct{}
5353

5454
func (dummyCloser) close() error { return nil }
5555

56-
type clusterRetriever interface {
56+
type memTableRetriever interface {
5757
retrieve(ctx context.Context, sctx sessionctx.Context) ([][]types.Datum, error)
5858
close() error
5959
}
6060

61-
// ClusterReaderExec executes cluster information retrieving from the cluster components
62-
type ClusterReaderExec struct {
61+
// MemTableReaderExec executes memTable information retrieving from the MemTable components
62+
type MemTableReaderExec struct {
6363
baseExecutor
64-
retriever clusterRetriever
64+
retriever memTableRetriever
6565
}
6666

6767
// Next implements the Executor Next interface.
68-
func (e *ClusterReaderExec) Next(ctx context.Context, req *chunk.Chunk) error {
68+
func (e *MemTableReaderExec) Next(ctx context.Context, req *chunk.Chunk) error {
6969
rows, err := e.retriever.retrieve(ctx, e.ctx)
7070
if err != nil {
7171
return err
@@ -86,7 +86,7 @@ func (e *ClusterReaderExec) Next(ctx context.Context, req *chunk.Chunk) error {
8686
}
8787

8888
// Close implements the Executor Close interface.
89-
func (e *ClusterReaderExec) Close() error {
89+
func (e *MemTableReaderExec) Close() error {
9090
return e.retriever.close()
9191
}
9292

@@ -96,7 +96,7 @@ type clusterConfigRetriever struct {
9696
extractor *plannercore.ClusterTableExtractor
9797
}
9898

99-
// retrieve implements the clusterRetriever interface
99+
// retrieve implements the memTableRetriever interface
100100
func (e *clusterConfigRetriever) retrieve(_ context.Context, sctx sessionctx.Context) ([][]types.Datum, error) {
101101
if e.extractor.SkipRequest || e.retrieved {
102102
return nil, nil
@@ -224,7 +224,7 @@ type clusterServerInfoRetriever struct {
224224
retrieved bool
225225
}
226226

227-
// retrieve implements the clusterRetriever interface
227+
// retrieve implements the memTableRetriever interface
228228
func (e *clusterServerInfoRetriever) retrieve(ctx context.Context, sctx sessionctx.Context) ([][]types.Datum, error) {
229229
if e.extractor.SkipRequest || e.retrieved {
230230
return nil, nil

executor/infoschema_reader.go

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// Copyright 2020 PingCAP, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package executor
15+
16+
import (
17+
"context"
18+
"sort"
19+
20+
"github.com/pingcap/parser/model"
21+
"github.com/pingcap/parser/mysql"
22+
"github.com/pingcap/tidb/infoschema"
23+
"github.com/pingcap/tidb/privilege"
24+
"github.com/pingcap/tidb/sessionctx"
25+
"github.com/pingcap/tidb/types"
26+
)
27+
28+
type memtableRetriever struct {
29+
dummyCloser
30+
table *model.TableInfo
31+
columns []*model.ColumnInfo
32+
rows [][]types.Datum
33+
rowIdx int
34+
retrieved bool
35+
initialized bool
36+
}
37+
38+
// retrieve implements the infoschemaRetriever interface
39+
func (e *memtableRetriever) retrieve(ctx context.Context, sctx sessionctx.Context) ([][]types.Datum, error) {
40+
if e.retrieved {
41+
return nil, nil
42+
}
43+
44+
//Cache the ret full rows in schemataRetriever
45+
if !e.initialized {
46+
is := infoschema.GetInfoSchema(sctx)
47+
dbs := is.AllSchemas()
48+
sort.Sort(infoschema.SchemasSorter(dbs))
49+
var err error
50+
switch e.table.Name.O {
51+
case infoschema.TableSchemata:
52+
e.rows = dataForSchemata(sctx, dbs)
53+
case infoschema.TableViews:
54+
e.rows, err = dataForViews(sctx, dbs)
55+
}
56+
if err != nil {
57+
return nil, err
58+
}
59+
e.initialized = true
60+
}
61+
62+
//Adjust the amount of each return
63+
maxCount := 1024
64+
retCount := maxCount
65+
if e.rowIdx+maxCount > len(e.rows) {
66+
retCount = len(e.rows) - e.rowIdx
67+
e.retrieved = true
68+
}
69+
ret := make([][]types.Datum, retCount)
70+
for i := e.rowIdx; i < e.rowIdx+retCount; i++ {
71+
ret[i-e.rowIdx] = e.rows[i]
72+
}
73+
e.rowIdx += retCount
74+
if len(e.columns) == len(e.table.Columns) {
75+
return ret, nil
76+
}
77+
rows := make([][]types.Datum, len(ret))
78+
for i, fullRow := range ret {
79+
row := make([]types.Datum, len(e.columns))
80+
for j, col := range e.columns {
81+
row[j] = fullRow[col.Offset]
82+
}
83+
rows[i] = row
84+
}
85+
return rows, nil
86+
}
87+
88+
func dataForSchemata(ctx sessionctx.Context, schemas []*model.DBInfo) [][]types.Datum {
89+
checker := privilege.GetPrivilegeManager(ctx)
90+
rows := make([][]types.Datum, 0, len(schemas))
91+
92+
for _, schema := range schemas {
93+
94+
charset := mysql.DefaultCharset
95+
collation := mysql.DefaultCollationName
96+
97+
if len(schema.Charset) > 0 {
98+
charset = schema.Charset // Overwrite default
99+
}
100+
101+
if len(schema.Collate) > 0 {
102+
collation = schema.Collate // Overwrite default
103+
}
104+
105+
if checker != nil && !checker.RequestVerification(ctx.GetSessionVars().ActiveRoles, schema.Name.L, "", "", mysql.AllPrivMask) {
106+
continue
107+
}
108+
record := types.MakeDatums(
109+
infoschema.CatalogVal, // CATALOG_NAME
110+
schema.Name.O, // SCHEMA_NAME
111+
charset, // DEFAULT_CHARACTER_SET_NAME
112+
collation, // DEFAULT_COLLATION_NAME
113+
nil,
114+
)
115+
rows = append(rows, record)
116+
}
117+
return rows
118+
}
119+
120+
func dataForViews(ctx sessionctx.Context, schemas []*model.DBInfo) ([][]types.Datum, error) {
121+
checker := privilege.GetPrivilegeManager(ctx)
122+
var rows [][]types.Datum
123+
for _, schema := range schemas {
124+
for _, table := range schema.Tables {
125+
if !table.IsView() {
126+
continue
127+
}
128+
collation := table.Collate
129+
charset := table.Charset
130+
if collation == "" {
131+
collation = mysql.DefaultCollationName
132+
}
133+
if charset == "" {
134+
charset = mysql.DefaultCharset
135+
}
136+
if checker != nil && !checker.RequestVerification(ctx.GetSessionVars().ActiveRoles, schema.Name.L, table.Name.L, "", mysql.AllPrivMask) {
137+
continue
138+
}
139+
record := types.MakeDatums(
140+
infoschema.CatalogVal, // TABLE_CATALOG
141+
schema.Name.O, // TABLE_SCHEMA
142+
table.Name.O, // TABLE_NAME
143+
table.View.SelectStmt, // VIEW_DEFINITION
144+
table.View.CheckOption.String(), // CHECK_OPTION
145+
"NO", // IS_UPDATABLE
146+
table.View.Definer.String(), // DEFINER
147+
table.View.Security.String(), // SECURITY_TYPE
148+
charset, // CHARACTER_SET_CLIENT
149+
collation, // COLLATION_CONNECTION
150+
)
151+
rows = append(rows, record)
152+
}
153+
}
154+
return rows, nil
155+
}

executor/infoschema_reader_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright 2020 PingCAP, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package executor_test
15+
16+
import (
17+
. "github.com/pingcap/check"
18+
"github.com/pingcap/parser/auth"
19+
"github.com/pingcap/tidb/domain"
20+
"github.com/pingcap/tidb/kv"
21+
"github.com/pingcap/tidb/util/testkit"
22+
)
23+
24+
var _ = Suite(&testInfoschemaTableSuite{})
25+
26+
type testInfoschemaTableSuite struct {
27+
store kv.Storage
28+
dom *domain.Domain
29+
}
30+
31+
func (s *testInfoschemaTableSuite) SetUpSuite(c *C) {
32+
store, dom, err := newStoreWithBootstrap()
33+
c.Assert(err, IsNil)
34+
s.store = store
35+
s.dom = dom
36+
}
37+
38+
func (s *testInfoschemaTableSuite) TearDownSuite(c *C) {
39+
s.dom.Close()
40+
s.store.Close()
41+
}
42+
func (s *testInfoschemaTableSuite) TestSchemataTables(c *C) {
43+
tk := testkit.NewTestKit(c, s.store)
44+
45+
tk.MustQuery("select * from information_schema.SCHEMATA where schema_name='mysql';").Check(
46+
testkit.Rows("def mysql utf8mb4 utf8mb4_bin <nil>"))
47+
48+
//test the privilege of new user for information_schema.schemata
49+
tk.MustExec("create user schemata_tester")
50+
schemataTester := testkit.NewTestKit(c, s.store)
51+
schemataTester.MustExec("use information_schema")
52+
c.Assert(schemataTester.Se.Auth(&auth.UserIdentity{
53+
Username: "schemata_tester",
54+
Hostname: "127.0.0.1",
55+
}, nil, nil), IsTrue)
56+
schemataTester.MustQuery("select count(*) from information_schema.SCHEMATA;").Check(testkit.Rows("1"))
57+
schemataTester.MustQuery("select * from information_schema.SCHEMATA where schema_name='mysql';").Check(
58+
[][]interface{}{})
59+
schemataTester.MustQuery("select * from information_schema.SCHEMATA where schema_name='INFORMATION_SCHEMA';").Check(
60+
testkit.Rows("def INFORMATION_SCHEMA utf8mb4 utf8mb4_bin <nil>"))
61+
62+
//test the privilege of user with privilege of mysql for information_schema.schemata
63+
tk.MustExec("CREATE ROLE r_mysql_priv;")
64+
tk.MustExec("GRANT ALL PRIVILEGES ON mysql.* TO r_mysql_priv;")
65+
tk.MustExec("GRANT r_mysql_priv TO schemata_tester;")
66+
schemataTester.MustExec("set role r_mysql_priv")
67+
schemataTester.MustQuery("select count(*) from information_schema.SCHEMATA;").Check(testkit.Rows("2"))
68+
schemataTester.MustQuery("select * from information_schema.SCHEMATA;").Check(
69+
testkit.Rows("def INFORMATION_SCHEMA utf8mb4 utf8mb4_bin <nil>", "def mysql utf8mb4 utf8mb4_bin <nil>"))
70+
}
71+
72+
func (s *testInfoschemaTableSuite) TestSchemataCharacterSet(c *C) {
73+
tk := testkit.NewTestKit(c, s.store)
74+
tk.MustExec("CREATE DATABASE `foo` DEFAULT CHARACTER SET = 'utf8mb4'")
75+
tk.MustQuery("select default_character_set_name, default_collation_name FROM information_schema.SCHEMATA WHERE schema_name = 'foo'").Check(
76+
testkit.Rows("utf8mb4 utf8mb4_bin"))
77+
tk.MustExec("drop database `foo`")
78+
}
79+
80+
func (s *testInfoschemaTableSuite) TestViews(c *C) {
81+
tk := testkit.NewTestKit(c, s.store)
82+
tk.MustExec("CREATE DEFINER='root'@'localhost' VIEW test.v1 AS SELECT 1")
83+
tk.MustQuery("SELECT * FROM information_schema.views WHERE table_schema='test' AND table_name='v1'").Check(testkit.Rows("def test v1 SELECT 1 CASCADED NO root@localhost DEFINER utf8mb4 utf8mb4_bin"))
84+
tk.MustQuery("SELECT table_catalog, table_schema, table_name, table_type, engine, version, row_format, table_rows, avg_row_length, data_length, max_data_length, index_length, data_free, auto_increment, update_time, check_time, table_collation, checksum, create_options, table_comment FROM information_schema.tables WHERE table_schema='test' AND table_name='v1'").Check(testkit.Rows("def test v1 VIEW <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> VIEW"))
85+
}

0 commit comments

Comments
 (0)