Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

show: prefilter table name with like pattern and show full tables #55396

Merged
merged 10 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/executor/import_into.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
100 changes: 83 additions & 17 deletions pkg/executor/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 <FULL> 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 {
Expand All @@ -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)
Expand All @@ -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) {
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
}

Expand Down
34 changes: 30 additions & 4 deletions pkg/executor/show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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))
Expand All @@ -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)
}