diff --git a/pkg/executor/import_into.go b/pkg/executor/import_into.go index 7d9a4f92efd95..c41d708d705cb 100644 --- a/pkg/executor/import_into.go +++ b/pkg/executor/import_into.go @@ -151,7 +151,7 @@ func (e *ImportIntoExec) fillJobInfo(ctx context.Context, jobID int64, req *chun }); err != nil { return err } - fillOneImportJobInfo(info, req, unknownImportedRowCount) + FillOneImportJobInfo(info, req, unknownImportedRowCount) return nil } diff --git a/pkg/executor/show.go b/pkg/executor/show.go index d13c2259e1968..d1b59699b77c9 100644 --- a/pkg/executor/show.go +++ b/pkg/executor/show.go @@ -494,6 +494,67 @@ func (*ShowExec) fetchShowOpenTables() error { return nil } +// showInfo represents the result of `SHOW TABLES`. +type showInfo struct { + Name model.CIStr + // only used for show full tables + TableType string +} + +// getTableType returns the type of the table. +func (e *ShowExec) getTableType(tb *model.TableInfo) string { + switch { + case tb.IsView(): + return "VIEW" + case tb.IsSequence(): + return "SEQUENCE" + case util.IsSystemView(e.DBName.L): + return "SYSTEM VIEW" + default: + return "BASE TABLE" + } +} + +// fetchShowInfoByName fetches the show info for `SHOW TABLES like 'xxx'` +func (e *ShowExec) fetchShowInfoByName(ctx context.Context, name string) ([]*showInfo, error) { + tb, err := e.is.TableByName(ctx, e.DBName, model.NewCIStr(name)) + if err != nil { + // do nothing if table not exists + if infoschema.ErrTableNotExists.Equal(err) { + return nil, nil + } + return nil, errors.Trace(err) + } + return []*showInfo{{Name: tb.Meta().Name, TableType: e.getTableType(tb.Meta())}}, nil +} + +// fetchShowSimpleTables fetches the table info for `SHOW TABLE`. +func (e *ShowExec) fetchShowSimpleTables(ctx context.Context) ([]*showInfo, error) { + tb, err := e.is.SchemaSimpleTableInfos(ctx, e.DBName) + if err != nil { + return nil, errors.Trace(err) + } + showInfos := make([]*showInfo, 0, len(tb)) + for _, v := range tb { + // TODO: consider add type info to TableNameInfo + showInfos = append(showInfos, &showInfo{Name: v.Name}) + } + return showInfos, nil +} + +// fetchShowFullTables fetches the table info for `SHOW FULL TABLES`. +func (e *ShowExec) fetchShowFullTables(ctx context.Context) ([]*showInfo, error) { + tb, err := e.is.SchemaTableInfos(ctx, e.DBName) + if err != nil { + return nil, errors.Trace(err) + } + showInfos := make([]*showInfo, 0, len(tb)) + for _, v := range tb { + showInfos = append(showInfos, &showInfo{Name: v.Name, TableType: e.getTableType(v)}) + } + return showInfos, nil +} + func (e *ShowExec) fetchShowTables(ctx context.Context) error { checker := privilege.GetPrivilegeManager(e.Ctx()) if checker != nil && e.Ctx().GetSessionVars().User != nil { @@ -504,12 +565,11 @@ func (e *ShowExec) fetchShowTables(ctx context.Context) error { if !e.is.SchemaExists(e.DBName) { return exeerrors.ErrBadDB.GenWithStackByArgs(e.DBName) } - // sort for tables - schemaTables, err := e.is.SchemaTableInfos(ctx, e.DBName) - if err != nil { - return errors.Trace(err) - } - tableNames := make([]string, 0, len(schemaTables)) + var ( + tableNames = make([]string, 0) + showInfos []*showInfo + err error + ) activeRoles := e.Ctx().GetSessionVars().ActiveRoles var ( tableTypes = make(map[string]string) @@ -521,7 +581,18 @@ func (e *ShowExec) fetchShowTables(ctx context.Context) error { fieldFilter = e.Extractor.Field() fieldPatternsLike = e.Extractor.FieldPatternLike() } - for _, v := range schemaTables { + + if fieldFilter != "" { + showInfos, err = e.fetchShowInfoByName(ctx, fieldFilter) + } else if e.Full { + showInfos, err = e.fetchShowFullTables(ctx) + } else { + showInfos, err = e.fetchShowSimpleTables(ctx) + } + if err != nil { + return errors.Trace(err) + } + for _, v := range showInfos { // Test with mysql.AllPrivMask means any privilege would be OK. // TODO: Should consider column privileges, which also make a table visible. if checker != nil && !checker.RequestVerification(activeRoles, e.DBName.O, v.Name.O, "", mysql.AllPrivMask) { @@ -532,14 +603,8 @@ func (e *ShowExec) fetchShowTables(ctx context.Context) error { continue } tableNames = append(tableNames, v.Name.O) - if v.IsView() { - tableTypes[v.Name.O] = "VIEW" - } else if v.IsSequence() { - tableTypes[v.Name.O] = "SEQUENCE" - } else if util.IsSystemView(e.DBName.L) { - tableTypes[v.Name.O] = "SYSTEM VIEW" - } else { - tableTypes[v.Name.O] = "BASE TABLE" + if e.Full { + tableTypes[v.Name.O] = v.TableType } } slices.Sort(tableNames) @@ -2258,7 +2323,8 @@ func (e *ShowExec) fetchShowSessionStates(ctx context.Context) error { return nil } -func fillOneImportJobInfo(info *importer.JobInfo, result *chunk.Chunk, importedRowCount int64) { +// FillOneImportJobInfo is exported for testing. +func FillOneImportJobInfo(info *importer.JobInfo, result *chunk.Chunk, importedRowCount int64) { fullTableName := utils.EncloseDBAndTable(info.TableSchema, info.TableName) result.AppendInt64(0, info.ID) result.AppendString(1, info.Parameters.FileLocation) @@ -2299,7 +2365,7 @@ func handleImportJobInfo(ctx context.Context, info *importer.JobInfo, result *ch } importedRowCount = int64(rows) } - fillOneImportJobInfo(info, result, importedRowCount) + FillOneImportJobInfo(info, result, importedRowCount) return nil } diff --git a/pkg/executor/show_test.go b/pkg/executor/show_test.go index 17c44771cea84..2b6ee9f89c9fb 100644 --- a/pkg/executor/show_test.go +++ b/pkg/executor/show_test.go @@ -12,14 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -package executor +package executor_test import ( "testing" "time" + "github.com/pingcap/tidb/pkg/errno" + "github.com/pingcap/tidb/pkg/executor" "github.com/pingcap/tidb/pkg/executor/importer" "github.com/pingcap/tidb/pkg/parser/mysql" + "github.com/pingcap/tidb/pkg/testkit" "github.com/pingcap/tidb/pkg/types" "github.com/pingcap/tidb/pkg/util/chunk" "github.com/stretchr/testify/require" @@ -44,12 +47,12 @@ func Test_fillOneImportJobInfo(t *testing.T) { jobInfo := &importer.JobInfo{ Parameters: importer.ImportParameters{}, } - fillOneImportJobInfo(jobInfo, c, -1) + executor.FillOneImportJobInfo(jobInfo, c, -1) require.True(t, c.GetRow(0).IsNull(7)) require.True(t, c.GetRow(0).IsNull(10)) require.True(t, c.GetRow(0).IsNull(11)) - fillOneImportJobInfo(jobInfo, c, 0) + executor.FillOneImportJobInfo(jobInfo, c, 0) require.False(t, c.GetRow(1).IsNull(7)) require.Equal(t, uint64(0), c.GetRow(1).GetUint64(7)) require.True(t, c.GetRow(1).IsNull(10)) @@ -58,9 +61,32 @@ func Test_fillOneImportJobInfo(t *testing.T) { jobInfo.Summary = &importer.JobSummary{ImportedRows: 123} jobInfo.StartTime = types.NewTime(types.FromGoTime(time.Now()), mysql.TypeTimestamp, 0) jobInfo.EndTime = types.NewTime(types.FromGoTime(time.Now()), mysql.TypeTimestamp, 0) - fillOneImportJobInfo(jobInfo, c, 0) + executor.FillOneImportJobInfo(jobInfo, c, 0) require.False(t, c.GetRow(2).IsNull(7)) require.Equal(t, uint64(123), c.GetRow(2).GetUint64(7)) require.False(t, c.GetRow(2).IsNull(10)) require.False(t, c.GetRow(2).IsNull(11)) } + +func TestShow(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + + tk.MustExec("use test") + tk.MustExec("create table t(id int, abclmn int);") + tk.MustExec("create table abclmn(a int);") + + tk.MustGetErrCode("show columns from t like id", errno.ErrBadField) + tk.MustGetErrCode("show columns from t like `id`", errno.ErrBadField) + + tk.MustQuery("show tables").Check(testkit.Rows("abclmn", "t")) + tk.MustQuery("show full tables").Check(testkit.Rows("abclmn BASE TABLE", "t BASE TABLE")) + tk.MustQuery("show tables like 't'").Check(testkit.Rows("t")) + tk.MustQuery("show tables like 'T'").Check(testkit.Rows("t")) + tk.MustQuery("show tables like 'ABCLMN'").Check(testkit.Rows("abclmn")) + tk.MustQuery("show tables like 'ABC%'").Check(testkit.Rows("abclmn")) + tk.MustQuery("show tables like '%lmn'").Check(testkit.Rows("abclmn")) + tk.MustQuery("show full tables like '%lmn'").Check(testkit.Rows("abclmn BASE TABLE")) + tk.MustGetErrCode("show tables like T", errno.ErrBadField) + tk.MustGetErrCode("show tables like `T`", errno.ErrBadField) +}