Files
tidb/pkg/executor/infoschema_reader_test.go

1348 lines
68 KiB
Go

// Copyright 2020 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package executor_test
import (
"context"
"encoding/json"
"fmt"
"math/rand"
"os"
"strconv"
"strings"
"sync/atomic"
"testing"
"time"
"github.com/pingcap/failpoint"
"github.com/pingcap/kvproto/pkg/keyspacepb"
"github.com/pingcap/kvproto/pkg/kvrpcpb"
"github.com/pingcap/tidb/pkg/config"
"github.com/pingcap/tidb/pkg/domain/infosync"
"github.com/pingcap/tidb/pkg/meta/model"
"github.com/pingcap/tidb/pkg/parser/auth"
"github.com/pingcap/tidb/pkg/parser/mysql"
"github.com/pingcap/tidb/pkg/sessionctx/variable"
statstestutil "github.com/pingcap/tidb/pkg/statistics/handle/ddl/testutil"
"github.com/pingcap/tidb/pkg/store/mockstore"
"github.com/pingcap/tidb/pkg/testkit"
"github.com/pingcap/tidb/pkg/testkit/testfailpoint"
"github.com/pingcap/tidb/pkg/util/logutil"
"github.com/stretchr/testify/require"
"github.com/tikv/client-go/v2/tikv"
"github.com/tikv/client-go/v2/tikvrpc"
"go.uber.org/zap"
)
func TestInspectionTables(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
instances := []string{
"pd,127.0.0.1:11080,127.0.0.1:10080,mock-version,mock-githash,0",
"tidb,127.0.0.1:11080,127.0.0.1:10080,mock-version,mock-githash,1001",
"tikv,127.0.0.1:11080,127.0.0.1:10080,mock-version,mock-githash,0",
"tiproxy,127.0.0.1:6000,127.0.0.1:3380,mock-version,mock-githash,0",
"ticdc,127.0.0.1:8300,127.0.0.1:8301,mock-version,mock-githash,0",
"tso,127.0.0.1:3379,127.0.0.1:3379,mock-version,mock-githash,0",
"scheduling,127.0.0.1:4379,127.0.0.1:4379,mock-version,mock-githash,0",
}
fpName := "github.com/pingcap/tidb/pkg/infoschema/mockClusterInfo"
fpExpr := `return("` + strings.Join(instances, ";") + `")`
require.NoError(t, failpoint.Enable(fpName, fpExpr))
defer func() { require.NoError(t, failpoint.Disable(fpName)) }()
tk.MustQuery("select type, instance, status_address, version, git_hash, server_id from information_schema.cluster_info").Check(testkit.Rows(
"pd 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash 0",
"tidb 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash 1001",
"tikv 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash 0",
"tiproxy 127.0.0.1:6000 127.0.0.1:3380 mock-version mock-githash 0",
"ticdc 127.0.0.1:8300 127.0.0.1:8301 mock-version mock-githash 0",
"tso 127.0.0.1:3379 127.0.0.1:3379 mock-version mock-githash 0",
"scheduling 127.0.0.1:4379 127.0.0.1:4379 mock-version mock-githash 0",
))
// enable inspection mode
inspectionTableCache := map[string]variable.TableSnapshot{}
tk.Session().GetSessionVars().InspectionTableCache = inspectionTableCache
tk.MustQuery("select type, instance, status_address, version, git_hash, server_id from information_schema.cluster_info").Check(testkit.Rows(
"pd 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash 0",
"tidb 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash 1001",
"tikv 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash 0",
"tiproxy 127.0.0.1:6000 127.0.0.1:3380 mock-version mock-githash 0",
"ticdc 127.0.0.1:8300 127.0.0.1:8301 mock-version mock-githash 0",
"tso 127.0.0.1:3379 127.0.0.1:3379 mock-version mock-githash 0",
"scheduling 127.0.0.1:4379 127.0.0.1:4379 mock-version mock-githash 0",
))
require.NoError(t, inspectionTableCache["cluster_info"].Err)
require.Len(t, inspectionTableCache["cluster_info"].Rows, 7)
// check whether is obtain data from cache at the next time
inspectionTableCache["cluster_info"].Rows[0][0].SetString("modified-pd", mysql.DefaultCollationName)
tk.MustQuery("select type, instance, status_address, version, git_hash, server_id from information_schema.cluster_info").Check(testkit.Rows(
"modified-pd 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash 0",
"tidb 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash 1001",
"tikv 127.0.0.1:11080 127.0.0.1:10080 mock-version mock-githash 0",
"tiproxy 127.0.0.1:6000 127.0.0.1:3380 mock-version mock-githash 0",
"ticdc 127.0.0.1:8300 127.0.0.1:8301 mock-version mock-githash 0",
"tso 127.0.0.1:3379 127.0.0.1:3379 mock-version mock-githash 0",
"scheduling 127.0.0.1:4379 127.0.0.1:4379 mock-version mock-githash 0",
))
tk.Session().GetSessionVars().InspectionTableCache = nil
}
func TestUserPrivileges(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
// test the privilege of new user for information_schema.table_constraints
tk.MustExec("create user constraints_tester")
constraintsTester := testkit.NewTestKit(t, store)
constraintsTester.MustExec("use information_schema")
require.NoError(t, constraintsTester.Session().Auth(&auth.UserIdentity{
Username: "constraints_tester",
Hostname: "127.0.0.1",
}, nil, nil, nil))
constraintsTester.MustQuery("select * from information_schema.TABLE_CONSTRAINTS WHERE TABLE_NAME != 'CLUSTER_SLOW_QUERY';").Check([][]any{})
// test the privilege of user with privilege of mysql.gc_delete_range for information_schema.table_constraints
tk.MustExec("CREATE ROLE r_gc_delete_range ;")
tk.MustExec("GRANT ALL PRIVILEGES ON mysql.gc_delete_range TO r_gc_delete_range;")
tk.MustExec("GRANT r_gc_delete_range TO constraints_tester;")
constraintsTester.MustExec("set role r_gc_delete_range")
rows := constraintsTester.MustQuery("select * from information_schema.TABLE_CONSTRAINTS where TABLE_NAME='gc_delete_range';").Rows()
require.Greater(t, len(rows), 0)
constraintsTester.MustQuery("select * from information_schema.TABLE_CONSTRAINTS where TABLE_NAME='tables_priv';").Check([][]any{})
// test the privilege of new user for information_schema
tk.MustExec("create user tester1")
tk1 := testkit.NewTestKit(t, store)
tk1.MustExec("use information_schema")
require.NoError(t, tk1.Session().Auth(&auth.UserIdentity{
Username: "tester1",
Hostname: "127.0.0.1",
}, nil, nil, nil))
tk1.MustQuery("select * from information_schema.STATISTICS WHERE TABLE_NAME != 'CLUSTER_SLOW_QUERY';").Check([][]any{})
// test the privilege of user with some privilege for information_schema
tk.MustExec("create user tester2")
tk.MustExec("CREATE ROLE r_columns_priv;")
tk.MustExec("GRANT ALL PRIVILEGES ON mysql.columns_priv TO r_columns_priv;")
tk.MustExec("GRANT r_columns_priv TO tester2;")
tk2 := testkit.NewTestKit(t, store)
tk2.MustExec("use information_schema")
require.NoError(t, tk2.Session().Auth(&auth.UserIdentity{
Username: "tester2",
Hostname: "127.0.0.1",
}, nil, nil, nil))
tk2.MustExec("set role r_columns_priv")
rows = tk2.MustQuery("select * from information_schema.STATISTICS where TABLE_NAME='columns_priv' and COLUMN_NAME='Host';").Rows()
require.Greater(t, len(rows), 0)
tk2.MustQuery("select * from information_schema.STATISTICS where TABLE_NAME='tables_priv' and COLUMN_NAME='Host';").Check(
[][]any{})
// test the privilege of user with all privilege for information_schema
tk.MustExec("create user tester3")
tk.MustExec("CREATE ROLE r_all_priv;")
tk.MustExec("GRANT ALL PRIVILEGES ON mysql.* TO r_all_priv;")
tk.MustExec("GRANT r_all_priv TO tester3;")
tk3 := testkit.NewTestKit(t, store)
tk3.MustExec("use information_schema")
require.NoError(t, tk3.Session().Auth(&auth.UserIdentity{
Username: "tester3",
Hostname: "127.0.0.1",
}, nil, nil, nil))
tk3.MustExec("set role r_all_priv")
rows = tk3.MustQuery("select * from information_schema.STATISTICS where TABLE_NAME='columns_priv' and COLUMN_NAME='Host';").Rows()
require.Greater(t, len(rows), 0)
rows = tk3.MustQuery("select * from information_schema.STATISTICS where TABLE_NAME='tables_priv' and COLUMN_NAME='Host';").Rows()
require.Greater(t, len(rows), 0)
}
func TestDataForTableStatsField(t *testing.T) {
store, dom := testkit.CreateMockStoreAndDomain(t)
h := dom.StatsHandle()
h.Clear()
is := dom.InfoSchema()
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t (c int, d int, e char(5), index idx(e))")
err := statstestutil.HandleNextDDLEventWithTxn(h)
require.NoError(t, err)
tk.MustQuery("select table_rows, avg_row_length, data_length, index_length from information_schema.tables where table_name='t'").Check(
testkit.Rows("0 0 0 0"))
tk.MustExec(`insert into t(c, d, e) values(1, 2, "c"), (2, 3, "d"), (3, 4, "e")`)
require.NoError(t, h.DumpStatsDeltaToKV(true))
require.NoError(t, h.Update(context.Background(), is))
tk.MustQuery("select table_rows, avg_row_length, data_length, index_length from information_schema.tables where table_name='t'").Check(
testkit.Rows("3 16 48 0"))
tk.MustExec(`insert into t(c, d, e) values(4, 5, "f")`)
require.NoError(t, h.DumpStatsDeltaToKV(true))
require.NoError(t, h.Update(context.Background(), is))
tk.MustQuery("select table_rows, avg_row_length, data_length, index_length from information_schema.tables where table_name='t'").Check(
testkit.Rows("4 16 64 0"))
tk.MustExec("delete from t where c >= 3")
require.NoError(t, h.DumpStatsDeltaToKV(true))
require.NoError(t, h.Update(context.Background(), is))
tk.MustQuery("select table_rows, avg_row_length, data_length, index_length from information_schema.tables where table_name='t'").Check(
testkit.Rows("2 16 32 0"))
tk.MustExec("delete from t where c=3")
require.NoError(t, h.DumpStatsDeltaToKV(true))
require.NoError(t, h.Update(context.Background(), is))
tk.MustQuery("select table_rows, avg_row_length, data_length, index_length from information_schema.tables where table_name='t'").Check(
testkit.Rows("2 16 32 0"))
tk.MustExec("analyze table t all columns")
tk.MustQuery("select table_rows, avg_row_length, data_length, index_length from information_schema.tables where table_name='t'").Check(
testkit.Rows("2 18 36 4"))
// Test partition table.
tk.MustExec("drop table if exists t")
tk.MustExec(`CREATE TABLE t (a int, b int, c varchar(5), primary key(a), index idx(c)) PARTITION BY RANGE (a) (PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11), PARTITION p2 VALUES LESS THAN (16))`)
err = statstestutil.HandleNextDDLEventWithTxn(h)
require.NoError(t, err)
tk.MustExec(`insert into t(a, b, c) values(1, 2, "c"), (7, 3, "d"), (12, 4, "e")`)
require.NoError(t, h.DumpStatsDeltaToKV(true))
require.NoError(t, h.Update(context.Background(), is))
tk.MustQuery("select table_rows, avg_row_length, data_length, index_length from information_schema.tables where table_name='t'").Check(
testkit.Rows("3 16 48 0"))
tk.MustExec("analyze table t all columns")
tk.MustQuery("select table_rows, avg_row_length, data_length, index_length from information_schema.tables where table_name='t'").Check(
testkit.Rows("3 18 54 6"))
}
func TestPartitionsTable(t *testing.T) {
store, dom := testkit.CreateMockStoreAndDomain(t)
h := dom.StatsHandle()
h.Clear()
is := dom.InfoSchema()
tk := testkit.NewTestKit(t, store)
tk.MustExec("USE test;")
testkit.WithPruneMode(tk, variable.Static, func() {
tk.MustExec("DROP TABLE IF EXISTS `test_partitions`;")
tk.MustExec(`CREATE TABLE test_partitions (a int, b int, c varchar(5), primary key(a), index idx(c)) PARTITION BY RANGE (a) (PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11), PARTITION p2 VALUES LESS THAN (16));`)
err := statstestutil.HandleNextDDLEventWithTxn(h)
require.NoError(t, err)
tk.MustExec(`insert into test_partitions(a, b, c) values(1, 2, "c"), (7, 3, "d"), (12, 4, "e");`)
tk.MustQuery("select PARTITION_NAME, PARTITION_DESCRIPTION from information_schema.PARTITIONS where table_name='test_partitions';").Check(
testkit.Rows("p0 6", "p1 11", "p2 16"))
tk.MustQuery("select table_rows, avg_row_length, data_length, index_length from information_schema.PARTITIONS where table_name='test_partitions';").Check(
testkit.Rows(
"0 0 0 0",
"0 0 0 0",
"0 0 0 0",
),
)
require.NoError(t, h.DumpStatsDeltaToKV(true))
require.NoError(t, h.Update(context.Background(), is))
tk.MustQuery("select table_rows, avg_row_length, data_length, index_length from information_schema.PARTITIONS where table_name='test_partitions';").Check(
testkit.Rows(
"1 16 16 0",
"1 16 16 0",
"1 16 16 0",
),
)
})
// Test for table has no partitions.
tk.MustExec("DROP TABLE IF EXISTS `test_partitions_1`;")
tk.MustExec(`CREATE TABLE test_partitions_1 (a int, b int, c varchar(5), primary key(a), index idx(c));`)
err := statstestutil.HandleNextDDLEventWithTxn(h)
require.NoError(t, err)
tk.MustExec(`insert into test_partitions_1(a, b, c) values(1, 2, "c"), (7, 3, "d"), (12, 4, "e");`)
require.NoError(t, h.DumpStatsDeltaToKV(true))
require.NoError(t, h.Update(context.Background(), is))
tk.MustQuery("select PARTITION_NAME, TABLE_ROWS, AVG_ROW_LENGTH, DATA_LENGTH, INDEX_LENGTH from information_schema.PARTITIONS where table_name='test_partitions_1';").Check(
testkit.Rows("<nil> 3 16 48 0"))
tk.MustExec("DROP TABLE IF EXISTS `test_partitions`;")
tk.MustExec(`CREATE TABLE test_partitions1 (id int, b int, c varchar(5), primary key(id), index idx(c)) PARTITION BY RANGE COLUMNS(id) (PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11), PARTITION p2 VALUES LESS THAN (16));`)
tk.MustQuery("select PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION from information_schema.partitions where table_name = 'test_partitions1';").Check(testkit.Rows("p0 RANGE COLUMNS `id`", "p1 RANGE COLUMNS `id`", "p2 RANGE COLUMNS `id`"))
tk.MustExec("DROP TABLE test_partitions1")
tk.MustExec(`CREATE TABLE test_partitions (id int, b int, c varchar(5), primary key(id,b), index idx(c)) PARTITION BY RANGE COLUMNS(id,b) (PARTITION p0 VALUES LESS THAN (6,1), PARTITION p1 VALUES LESS THAN (11,9), PARTITION p2 VALUES LESS THAN (16,MAXVALUE))`)
tk.MustQuery("select PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION from information_schema.partitions where table_name = 'test_partitions';").Check(testkit.Rows("p0 RANGE COLUMNS `id`,`b`", "p1 RANGE COLUMNS `id`,`b`", "p2 RANGE COLUMNS `id`,`b`"))
tk.MustExec("DROP TABLE test_partitions")
tk.MustExec(`create table test_partitions (a varchar(255), b int, c datetime) partition by list columns (b,a) (partition p0 values in ((1,"1"), (3,"3")), partition p1 values in ((2, "2")))`)
tk.MustQuery("select PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION from information_schema.partitions where table_name = 'test_partitions'").Check(testkit.Rows("p0 LIST COLUMNS `b`,`a`", "p1 LIST COLUMNS `b`,`a`"))
tk.MustExec("drop table test_partitions")
tk.MustExec("create table test_partitions (a varchar(3)) partition by list columns (a) (partition p0 values in ('1'), partition p1 values in ('2'))")
tk.MustQuery("select PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION from information_schema.partitions where table_name = 'test_partitions'").Check(testkit.Rows("p0 LIST COLUMNS `a`", "p1 LIST COLUMNS `a`"))
tk.MustExec("drop table test_partitions")
tk.MustExec("create table test_partitions (a int) partition by list (a) (partition p0 values in (1), partition p1 values in (2));")
tk.MustQuery("select PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION from information_schema.partitions where table_name = 'test_partitions';").Check(testkit.Rows("p0 LIST `a`", "p1 LIST `a`"))
tk.MustExec("drop table test_partitions")
tk.MustExec("create table test_partitions (a date) partition by list (year(a)) (partition p0 values in (1), partition p1 values in (2));")
tk.MustQuery("select PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION from information_schema.partitions where table_name = 'test_partitions';").Check(testkit.Rows("p0 LIST YEAR(`a`)", "p1 LIST YEAR(`a`)"))
tk.MustExec("drop table test_partitions")
tk.MustExec("create table test_partitions (a bigint, b date) partition by list columns (a,b) (partition p0 values in ((1,'2020-09-28'),(1,'2020-09-29')));")
tk.MustQuery("select PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION from information_schema.partitions where table_name = 'test_partitions';").Check(testkit.Rows("p0 LIST COLUMNS `a`,`b`"))
pid, err := strconv.Atoi(tk.MustQuery("select TIDB_PARTITION_ID from information_schema.partitions where table_name = 'test_partitions';").Rows()[0][0].(string))
require.NoError(t, err)
require.Greater(t, pid, 0)
tk.MustExec("drop table test_partitions")
}
func TestForAnalyzeStatus(t *testing.T) {
store, dom := testkit.CreateMockStoreAndDomain(t)
tk := testkit.NewTestKit(t, store)
analyzeStatusTable := "CREATE TABLE `ANALYZE_STATUS` (\n" +
" `TABLE_SCHEMA` varchar(64) DEFAULT NULL,\n" +
" `TABLE_NAME` varchar(64) DEFAULT NULL,\n" +
" `PARTITION_NAME` varchar(64) DEFAULT NULL,\n" +
" `JOB_INFO` longtext DEFAULT NULL,\n" +
" `PROCESSED_ROWS` bigint(21) unsigned DEFAULT NULL,\n" +
" `START_TIME` datetime DEFAULT NULL,\n" +
" `END_TIME` datetime DEFAULT NULL,\n" +
" `STATE` varchar(64) DEFAULT NULL,\n" +
" `FAIL_REASON` longtext DEFAULT NULL,\n" +
" `INSTANCE` varchar(512) DEFAULT NULL,\n" +
" `PROCESS_ID` bigint(21) unsigned DEFAULT NULL,\n" +
" `REMAINING_SECONDS` varchar(512) DEFAULT NULL,\n" +
" `PROGRESS` double(22,6) DEFAULT NULL,\n" +
" `ESTIMATED_TOTAL_ROWS` bigint(21) unsigned DEFAULT NULL\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"
tk.MustQuery("show create table information_schema.analyze_status").Check(testkit.Rows("ANALYZE_STATUS " + analyzeStatusTable))
tk.MustExec("delete from mysql.analyze_jobs")
tk.MustExec("use test")
tk.MustExec("drop table if exists analyze_test")
tk.MustExec("create table analyze_test (a int, b int, index idx(a))")
tk.MustExec("insert into analyze_test values (1,2),(3,4)")
tk.MustQuery("select distinct TABLE_NAME from information_schema.analyze_status where TABLE_NAME='analyze_test'").Check([][]any{})
tk.MustExec("analyze table analyze_test all columns")
tk.MustQuery("select distinct TABLE_NAME from information_schema.analyze_status where TABLE_NAME='analyze_test'").Check(testkit.Rows("analyze_test"))
// test the privilege of new user for information_schema.analyze_status
tk.MustExec("create user analyze_tester")
analyzeTester := testkit.NewTestKit(t, store)
analyzeTester.MustExec("use information_schema")
require.NoError(t, analyzeTester.Session().Auth(&auth.UserIdentity{
Username: "analyze_tester",
Hostname: "127.0.0.1",
}, nil, nil, nil))
analyzeTester.MustQuery("show analyze status").Check([][]any{})
analyzeTester.MustQuery("select * from information_schema.ANALYZE_STATUS;").Check([][]any{})
// test the privilege of user with privilege of test.t1 for information_schema.analyze_status
tk.MustExec("create table t1 (a int, b int, index idx(a))")
tk.MustExec("insert into t1 values (1,2),(3,4)")
tk.MustExec("analyze table t1 all columns")
tk.MustQuery("show warnings").Check(testkit.Rows("Note 1105 Analyze use auto adjusted sample rate 1.000000 for table test.t1, reason to use this rate is \"use min(1, 110000/10000) as the sample-rate=1\"")) // 1 note.
require.NoError(t, dom.StatsHandle().LoadNeededHistograms(dom.InfoSchema()))
tk.MustExec("CREATE ROLE r_t1 ;")
tk.MustExec("GRANT ALL PRIVILEGES ON test.t1 TO r_t1;")
tk.MustExec("GRANT r_t1 TO analyze_tester;")
analyzeTester.MustExec("set role r_t1")
rows := tk.MustQuery("select * from information_schema.analyze_status where TABLE_NAME='t1'").Sort().Rows()
require.Greater(t, len(rows), 0)
for _, row := range rows {
require.Len(t, row, 14) // test length of row
// test `End_time` field
str, ok := row[6].(string)
require.True(t, ok)
_, err := time.Parse(time.DateTime, str)
require.NoError(t, err)
}
rows2 := tk.MustQuery("show analyze status where TABLE_NAME='t1'").Sort().Rows()
require.Equal(t, len(rows), len(rows2))
for i, row := range rows {
for j, r := range row {
require.Equal(t, r, rows2[i][j])
}
}
}
func TestForServersInfo(t *testing.T) {
globalCfg := config.GetGlobalConfig()
t.Cleanup(func() {
config.StoreGlobalConfig(globalCfg)
})
newCfg := *globalCfg
newCfg.Labels = map[string]string{"dc": "dc1"}
config.StoreGlobalConfig(&newCfg)
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
ctx := context.Background()
sql := "select * from information_schema.TIDB_SERVERS_INFO"
comment := fmt.Sprintf("sql:%s", sql)
rs, err := tk.ExecWithContext(ctx, sql)
require.NoError(t, err)
require.NotNil(t, rs)
fields := rs.Fields()
require.Len(t, fields, 8)
require.Equal(t, fields[0].ColumnAsName.L, "ddl_id")
require.Equal(t, fields[1].ColumnAsName.L, "ip")
require.Equal(t, fields[2].ColumnAsName.L, "port")
require.Equal(t, fields[3].ColumnAsName.L, "status_port")
require.Equal(t, fields[4].ColumnAsName.L, "lease")
require.Equal(t, fields[5].ColumnAsName.L, "version")
require.Equal(t, fields[6].ColumnAsName.L, "git_hash")
require.Equal(t, fields[7].ColumnAsName.L, "labels")
res := tk.ResultSetToResultWithCtx(ctx, rs, comment)
rows := res.Rows()
require.Len(t, rows, 1)
require.Len(t, rows[0], 8)
info, err := infosync.GetServerInfo()
require.NoError(t, err)
require.NotNil(t, info)
require.Equal(t, info.ID, rows[0][0])
require.Equal(t, info.IP, rows[0][1])
require.Equal(t, strconv.FormatInt(int64(info.Port), 10), rows[0][2])
require.Equal(t, strconv.FormatInt(int64(info.StatusPort), 10), rows[0][3])
require.Equal(t, info.Lease, rows[0][4])
require.Equal(t, info.Version, rows[0][5])
require.Equal(t, info.GitHash, rows[0][6])
require.Equal(t, "dc=dc1", rows[0][7])
}
func TestTiFlashSystemTableWithTiFlashV620(t *testing.T) {
instances := []string{
"tiflash,127.0.0.1:3933,127.0.0.1:7777,,",
"tikv,127.0.0.1:11080,127.0.0.1:10080,,",
}
fpName := "github.com/pingcap/tidb/pkg/infoschema/mockStoreServerInfo"
fpExpr := `return("` + strings.Join(instances, ";") + `")`
require.NoError(t, failpoint.Enable(fpName, fpExpr))
defer func() { require.NoError(t, failpoint.Disable(fpName)) }()
mocker := newGetTiFlashSystemTableRequestMocker(t)
mocker.MockQuery(`SELECT * FROM system.dt_segments LIMIT 0, 1024`, func(req *kvrpcpb.TiFlashSystemTableRequest) (*kvrpcpb.TiFlashSystemTableResponse, error) {
require.EqualValues(t, req.Sql, "SELECT * FROM system.dt_segments LIMIT 0, 1024")
data, err := os.ReadFile("testdata/tiflash_v620_dt_segments.json")
require.NoError(t, err)
return &kvrpcpb.TiFlashSystemTableResponse{
Data: data,
}, nil
})
mocker.MockQuery(`SELECT * FROM system.dt_tables LIMIT 0, 1024`, func(req *kvrpcpb.TiFlashSystemTableRequest) (*kvrpcpb.TiFlashSystemTableResponse, error) {
require.EqualValues(t, req.Sql, "SELECT * FROM system.dt_tables LIMIT 0, 1024")
data, err := os.ReadFile("testdata/tiflash_v620_dt_tables.json")
require.NoError(t, err)
return &kvrpcpb.TiFlashSystemTableResponse{
Data: data,
}, nil
})
// When try to parse the result from old version tiflash instance with the latest columns name, some columns may not exist.
// The missing columns will be filled with <nil> value.
store := testkit.CreateMockStore(t, withMockTiFlash(1), mocker.AsOpt())
tk := testkit.NewTestKit(t, store)
tk.MustQuery("select * from information_schema.TIFLASH_SEGMENTS;").Check(testkit.Rows(
"mysql tables_priv 10 0 1 [-9223372036854775808,9223372036854775807) <nil> 0 0 <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> 0 <nil> 2032 <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> 127.0.0.1:3933",
"mysql db 8 0 1 [-9223372036854775808,9223372036854775807) <nil> 0 0 <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> 0 <nil> 2032 <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> 127.0.0.1:3933",
"test segment 70 0 1 [01,FA) <nil> 30511 50813627 0.6730359542460096 <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> 3578860 <nil> 409336 <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> 127.0.0.1:3933",
))
tk.MustQuery("show warnings").Check(testkit.Rows())
tk.MustQuery("select * from information_schema.TIFLASH_TABLES;").Check(testkit.Rows(
"mysql tables_priv 10 0 <nil> 1 0 0 0 <nil> 0 <nil> 0 <nil> <nil> <nil> 0 0 0 0 0 0 <nil> <nil> <nil> 0 0 0 0 <nil> <nil> 0 <nil> <nil> <nil> <nil> 0 <nil> <nil> <nil> 0 0 0 0 0 0 0 0 0 0 127.0.0.1:3933",
"mysql db 8 0 <nil> 1 0 0 0 <nil> 0 <nil> 0 <nil> <nil> <nil> 0 0 0 0 0 0 <nil> <nil> <nil> 0 0 0 0 <nil> <nil> 0 <nil> <nil> <nil> <nil> 0 <nil> <nil> <nil> 0 0 0 0 0 0 0 0 0 0 127.0.0.1:3933",
"test segment 70 0 <nil> 1 102000 169873868 0 0 0 <nil> 0 <nil> <nil> <nil> 0 102000 169873868 0 0 0 <nil> <nil> <nil> 1 102000 169873868 43867622 102000 169873868 0 <nil> <nil> <nil> <nil> 13 13 7846.153846153846 13067220.615384616 0 0 0 0 0 0 0 0 0 0 127.0.0.1:3933",
))
tk.MustQuery("show warnings").Check(testkit.Rows())
}
func TestTiFlashSystemTableWithTiFlashV630(t *testing.T) {
instances := []string{
"tiflash,127.0.0.1:3933,127.0.0.1:7777,,",
"tikv,127.0.0.1:11080,127.0.0.1:10080,,",
}
fpName := "github.com/pingcap/tidb/pkg/infoschema/mockStoreServerInfo"
fpExpr := `return("` + strings.Join(instances, ";") + `")`
require.NoError(t, failpoint.Enable(fpName, fpExpr))
defer func() { require.NoError(t, failpoint.Disable(fpName)) }()
mocker := newGetTiFlashSystemTableRequestMocker(t)
mocker.MockQuery(`SELECT * FROM system.dt_segments LIMIT 0, 1024`, func(req *kvrpcpb.TiFlashSystemTableRequest) (*kvrpcpb.TiFlashSystemTableResponse, error) {
require.EqualValues(t, req.Sql, "SELECT * FROM system.dt_segments LIMIT 0, 1024")
data, err := os.ReadFile("testdata/tiflash_v630_dt_segments.json")
require.NoError(t, err)
return &kvrpcpb.TiFlashSystemTableResponse{
Data: data,
}, nil
})
// When try to parse the result from old version tiflash instance with the latest columns name, some columns may not exist.
// The missing columns will be filled with <nil> value.
store := testkit.CreateMockStore(t, withMockTiFlash(1), mocker.AsOpt())
tk := testkit.NewTestKit(t, store)
tk.MustQuery("select * from information_schema.TIFLASH_SEGMENTS;").Check(testkit.Rows(
"mysql tables_priv 10 0 1 [-9223372036854775808,9223372036854775807) 0 0 0 <nil> 0 0 0 0 2 0 0 0 0 0 <nil> 2032 3 0 0 1 1 0 0 0 0 127.0.0.1:3933",
"test segment 70 436272981189328904 1 [01,FA) 5 102000 169874232 0 0 0 0 0 2 0 0 0 0 0 <nil> 2032 3 102000 169874232 1 68 102000 169874232 43951837 20 127.0.0.1:3933",
"test segment 75 0 1 [01,013130303030393535FF61653666642D6136FF61382D343032382DFF616436312D663736FF3062323736643461FF3600000000000000F8) 2 0 0 <nil> 0 0 1 1 110 0 0 4 4 0 <nil> 2032 111 0 0 1 70 0 0 0 0 127.0.0.1:3933",
"test segment 75 0 113 [013130303030393535FF61653666642D6136FF61382D343032382DFF616436312D663736FF3062323736643461FF3600000000000000F8,013139393938363264FF33346535382D3735FF31382D343661612DFF626235392D636264FF3139333434623736FF3100000000000000F9) 2 10167 16932617 0.4887380741615029 0 0 0 0 114 4969 8275782 2 0 0 <nil> 63992 112 5198 8656835 1 71 5198 8656835 2254100 1 127.0.0.1:3933",
"test segment 75 0 116 [013139393938363264FF33346535382D3735FF31382D343661612DFF626235392D636264FF3139333434623736FF3100000000000000F9,013330303131383034FF61323537662D6638FF63302D346466622DFF383235632D353361FF3236306338616662FF3400000000000000F8) 3 8 13322 0.5 3 4986 1 0 117 1 1668 4 3 4986 <nil> 2032 115 4 6668 1 78 4 6668 6799 1 127.0.0.1:3933",
"test segment 75 0 125 [013330303131383034FF61323537662D6638FF63302D346466622DFF383235632D353361FF3236306338616662FF3400000000000000F8,013339393939613861FF30663062332D6537FF32372D346234642DFF396535632D363865FF3336323066383431FF6300000000000000F9) 2 8677 14451079 0.4024432407514118 3492 5816059 3 0 126 0 0 0 0 5816059 <nil> 2032 124 5185 8635020 1 79 5185 8635020 2247938 1 127.0.0.1:3933",
"test segment 75 0 128 [013339393939613861FF30663062332D6537FF32372D346234642DFF396535632D363865FF3336323066383431FF6300000000000000F9,013730303031636230FF32663330652D3539FF62352D346134302DFF613539312D383930FF6132316364633466FF3200000000000000F8) 0 1 1668 1 0 0 0 0 129 1 1668 5 4 0 <nil> 2032 127 0 0 1 78 4 6668 6799 1 127.0.0.1:3933",
"test segment 75 0 119 [013730303031636230FF32663330652D3539FF62352D346134302DFF613539312D383930FF6132316364633466FF3200000000000000F8,013739393939386561FF36393566612D3534FF64302D346437642DFF383136612D646335FF6432613130353533FF3200000000000000F9) 2 10303 17158730 0.489372027564787 0 0 0 0 120 5042 8397126 2 0 0 <nil> 63992 118 5261 8761604 1 77 5261 8761604 2280506 1 127.0.0.1:3933",
"test segment 75 0 122 [013739393939386561FF36393566612D3534FF64302D346437642DFF383136612D646335FF6432613130353533FF3200000000000000F9,FA) 0 1 1663 1 0 0 0 0 123 1 1663 4 3 0 <nil> 2032 121 0 0 1 78 4 6668 6799 1 127.0.0.1:3933",
))
tk.MustQuery("show warnings").Check(testkit.Rows())
}
func TestTiFlashSystemTableWithTiFlashV640(t *testing.T) {
instances := []string{
"tiflash,127.0.0.1:3933,127.0.0.1:7777,,",
"tikv,127.0.0.1:11080,127.0.0.1:10080,,",
}
fpName := "github.com/pingcap/tidb/pkg/infoschema/mockStoreServerInfo"
fpExpr := `return("` + strings.Join(instances, ";") + `")`
require.NoError(t, failpoint.Enable(fpName, fpExpr))
defer func() { require.NoError(t, failpoint.Disable(fpName)) }()
mocker := newGetTiFlashSystemTableRequestMocker(t)
mocker.MockQuery(`SELECT * FROM system.dt_tables LIMIT 0, 1024`, func(req *kvrpcpb.TiFlashSystemTableRequest) (*kvrpcpb.TiFlashSystemTableResponse, error) {
require.EqualValues(t, req.Sql, "SELECT * FROM system.dt_tables LIMIT 0, 1024")
data, err := os.ReadFile("testdata/tiflash_v640_dt_tables.json")
require.NoError(t, err)
return &kvrpcpb.TiFlashSystemTableResponse{
Data: data,
}, nil
})
// When try to parse the result from old version tiflash instance with the latest columns name, some columns may not exist.
// The missing columns will be filled with <nil> value.
store := testkit.CreateMockStore(t, withMockTiFlash(1), mocker.AsOpt())
tk := testkit.NewTestKit(t, store)
tk.MustQuery("select * from information_schema.TIFLASH_TABLES;").Check(testkit.Rows(
"tpcc customer 135 0 <nil> 4 3528714 2464079200 0 0.002329177144988231 1 0 929227 <nil> 0.16169850346757514 0 8128 882178.5 616019800 4 8219 5747810 2054.75 1436952.5 0 4 3520495 2458331390 1601563417 880123.75 614582847.5 24 8 6 342.4583333333333 239492.08333333334 482 120.5 7303.9315352697095 5100272.593360996 0 0 0 0 0 0 0 0 0 0 127.0.0.1:3933",
"tpcc district 137 0 <nil> 1 7993 1346259 0 0.8748905292130614 1 0.8055198055198055 252168 <nil> 0.21407121407121407 0 147272 7993 1346259 1 6993 1178050 6993 1178050 0 1 1000 168209 91344 1000 168209 6 6 6 1165.5 196341.66666666666 10 10 100 16820.9 0 0 0 0 0 0 0 0 0 0 127.0.0.1:3933",
"tpcc history 139 0 <nil> 19 19379697 1629276978 0 0.0006053758219233252 0.5789473684210527 0.4626662120695534 253640 <nil> 0.25434708489601093 0 293544 1019984.052631579 85751419.89473684 11 11732 997220 1066.5454545454545 90656.36363636363 0 19 19367965 1628279758 625147717 1019366.5789473684 85698934.63157895 15 4 1.3636363636363635 782.1333333333333 66481.33333333333 2378 125.15789473684211 8144.644659377628 684726.559293524 0 0 0 0 0 0 0 0 0 0 127.0.0.1:3933",
"tpcc item 141 0 <nil> 1 100000 10799081 0 0 0 <nil> 0 <nil> <nil> <nil> 0 100000 10799081 0 0 0 <nil> <nil> <nil> 1 100000 10799081 7357726 100000 10799081 0 0 <nil> <nil> <nil> 13 13 7692.307692307692 830698.5384615385 0 0 0 0 0 0 0 0 0 0 127.0.0.1:3933",
"tpcc new_order 143 0 <nil> 4 2717707 78813503 0 0.02266763856442214 1 0.9678592299201351 52809 <nil> 0.029559768846178818 0 1434208 679426.75 19703375.75 4 61604 1786516 15401 446629 0 3 2656103 77026987 40906492 885367.6666666666 25675662.333333332 37 24 9.25 1664.972972972973 48284.21621621621 380 126.66666666666667 6989.744736842105 202702.59736842106 0 0 0 0 0 0 0 0 0 0 127.0.0.1:3933",
"tpcc order_line 145 0 <nil> 203 210607202 20007684190 0 0.0054566462546708164 0.5862068965517241 0.7810067620424135 620065 <nil> 0.005679558722564825 0 22607144 1037473.9014778325 98560020.64039409 119 1149209 109174855 9657.218487394957 917435.756302521 0 203 209457993 19898509335 8724002804 1031812.7733990147 98022213.47290641 893 39 7.504201680672269 1286.9081746920492 122256.27659574468 31507 155.20689655172413 6647.982765734599 631558.3627447869 0 0 0 0 0 0 0 0 0 0 127.0.0.1:3933",
"tpcc orders 147 0 <nil> 22 21903301 1270391458 0 0.02021357420052804 0.7272727272727273 0.9239944527763222 260536 <nil> 0.010145817899282655 0 10025264 995604.5909090909 57745066.27272727 16 442744 25679152 27671.5 1604947 0 22 21460557 1244712306 452173775 975479.8636363636 56577832.09090909 242 34 15.125 1829.5206611570247 106112.19834710743 2973 135.13636363636363 7218.485368314833 418672.15136226034 0 0 0 0 0 0 0 0 0 0 127.0.0.1:3933",
"tpcc stock 149 0 <nil> 42 11112720 4811805131 0 0.028085203262567582 0.9761904761904762 0.8463391893060944 10227093 <nil> 0.07567373591410528 0 6719064 264588.5714285714 114566788.83333333 41 312103 135131097 7612.268292682927 3295880.4146341463 0 42 10800617 4676674034 3231872509 257157.54761904763 111349381.76190476 238 26 5.804878048780488 1311.357142857143 567777.718487395 1644 39.142857142857146 6569.718369829684 2844692.234793187 0 0 0 0 0 0 0 0 0 0 127.0.0.1:3933",
"tpcc warehouse 151 0 <nil> 1 5842 923615 0 0.9828825744608011 1 0.9669104841518634 70220 <nil> 0.07732497387669801 0 133048 5842 923615 1 5742 907807 5742 907807 0 1 100 15808 11642 100 15808 5 5 5 1148.4 181561.4 5 5 20 3161.6 0 0 0 0 0 0 0 0 0 0 127.0.0.1:3933",
))
tk.MustQuery("show warnings").Check(testkit.Rows())
}
func TestTablesTable(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
type tableMeta struct {
schema string
table string
id string
}
toString := func(tm *tableMeta) string {
return fmt.Sprintf("%s %s %s", tm.schema, tm.table, tm.id)
}
// prepare data
tableMetas := []*tableMeta{}
schemaNames := []string{"db1", "db2"}
tableNames := []string{"t1", "t2"}
tk.MustExec("create database db1")
tk.MustExec("create database db2")
for _, schemaName := range schemaNames {
for _, tableName := range tableNames {
tk.MustExec(fmt.Sprintf("create table %s.%s (a int)", schemaName, tableName))
res := tk.MustQuery(fmt.Sprintf("select tidb_table_id from information_schema.tables where table_schema = '%s' and table_name = '%s'", schemaName, tableName))
// [db1 t1 id0, db1 t2 id1, db2 t1 id2, db2 t2 id3]
tableMetas = append(tableMetas, &tableMeta{schema: schemaName, table: tableName, id: res.String()})
}
}
// test table mode
tk.MustQuery(`select tidb_table_mode from information_schema.tables where table_schema = 'db1' and
table_name = 't1'`).Check(testkit.Rows("Normal"))
// Predicates are extracted in CNF, so we separate the test cases by the number of disjunctions in the predicate.
// predicate covers one disjunction
tk.MustQuery(`select table_schema, table_name, tidb_table_id from information_schema.tables
where table_schema = 'db1'`).Sort().Check(testkit.Rows(toString(tableMetas[0]), toString(tableMetas[1])))
tk.MustQuery(`select table_schema, table_name, tidb_table_id from information_schema.tables
where table_name = 't2'`).Sort().Check(testkit.Rows(toString(tableMetas[1]), toString(tableMetas[3])))
tk.MustQuery(fmt.Sprintf("select table_schema, table_name, tidb_table_id from information_schema.tables where tidb_table_id = %s", tableMetas[2].id)).Check(
testkit.Rows(toString(tableMetas[2])))
// cover two disjunctions
tk.MustQuery(`select table_schema, table_name, tidb_table_id from information_schema.tables
where table_schema = 'db1' and table_name = 't2'`).Check(testkit.Rows(toString(tableMetas[1])))
tk.MustQuery(`select table_schema, table_name, tidb_table_id from information_schema.tables
where table_schema in ('db1', 'db2') and table_name = 't2'`).Sort().Check(testkit.Rows(toString(tableMetas[1]), toString(tableMetas[3])))
tk.MustQuery(`select table_schema, table_name, tidb_table_id from information_schema.tables
where (table_schema = 'db1' or table_schema = 'db2' ) and table_name = 't2'`).Sort().Check(testkit.Rows(toString(tableMetas[1]), toString(tableMetas[3])))
tk.MustQuery(`select table_schema, table_name, tidb_table_id from information_schema.tables
where (table_schema = 'db1' or table_schema = 'db2' ) and table_name = 't3'`).Check(testkit.Rows())
tk.MustQuery(fmt.Sprintf("select table_schema, table_name, tidb_table_id from information_schema.tables where table_schema = 'db1' and tidb_table_id = %s", tableMetas[0].id)).Check(
testkit.Rows(toString(tableMetas[0])))
tk.MustQuery(fmt.Sprintf("select table_schema, table_name, tidb_table_id from information_schema.tables where table_name = 't2' and tidb_table_id = %s", tableMetas[1].id)).Check(
testkit.Rows(toString(tableMetas[1])))
tk.MustQuery(fmt.Sprintf("select table_schema, table_name, tidb_table_id from information_schema.tables where table_schema = 'db2' and tidb_table_id = %s", tableMetas[1].id)).Check(
testkit.Rows())
// cover three disjunctions
tk.MustQuery(fmt.Sprintf("select table_schema, table_name, tidb_table_id from information_schema.tables where table_schema = 'db1' and table_name = 't1' and tidb_table_id = %s", tableMetas[0].id)).Check(
testkit.Rows(toString(tableMetas[0])))
tk.MustQuery(fmt.Sprintf("select table_schema, table_name, tidb_table_id from information_schema.tables where table_schema = 'db1' and table_name = 't1' and tidb_table_id = %s", tableMetas[1].id)).Check(
testkit.Rows())
tk.MustQuery(fmt.Sprintf("select table_schema, table_name, tidb_table_id from information_schema.tables where table_schema = 'db1' and table_name = 't1' and tidb_table_id in (%s,%s)", tableMetas[0].id, tableMetas[1].id)).Check(
testkit.Rows(toString(tableMetas[0])))
selectTables, err := strconv.Atoi(tk.MustQuery("select count(*) from information_schema.tables where upper(table_name) = 'T1'").Rows()[0][0].(string))
require.NoError(t, err)
totalTables, err := strconv.Atoi(tk.MustQuery("select count(*) from information_schema.tables").Rows()[0][0].(string))
require.NoError(t, err)
remainTables, err := strconv.Atoi(tk.MustQuery("select count(*) from information_schema.tables where upper(table_name) != 'T1'").Rows()[0][0].(string))
require.NoError(t, err)
require.Equal(t, 2, selectTables)
require.Equal(t, totalTables, remainTables+selectTables)
}
func TestColumnTable(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create table tbl1(col_1 int primary key, col_2 int, col_4 int);")
tk.MustExec("create table tbl2(col_1 int primary key, col_2 int, col_3 int);")
tk.MustExec("create view view1 as select min(col_1), col_2, max(col_4) as max4 from tbl1 group by col_2;")
tk.MustQuery("select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME from information_schema.columns where TABLE_SCHEMA = 'test';").Sort().Check(
testkit.RowsWithSep("|",
"test|tbl1|col_1",
"test|tbl1|col_2",
"test|tbl1|col_4",
"test|tbl2|col_1",
"test|tbl2|col_2",
"test|tbl2|col_3",
"test|view1|col_2",
"test|view1|max4",
"test|view1|min(col_1)"))
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME from information_schema.columns
where TABLE_NAME = 'view1' or TABLE_NAME = 'tbl1'`).Check(
testkit.RowsWithSep("|",
"test|tbl1|col_1",
"test|tbl1|col_2",
"test|tbl1|col_4",
"test|view1|min(col_1)",
"test|view1|col_2",
"test|view1|max4"))
tk.MustQuery("select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME from information_schema.columns where COLUMN_NAME = \"col_2\";").Sort().Check(
testkit.RowsWithSep("|",
"test|tbl1|col_2",
"test|tbl2|col_2",
"test|view1|col_2"))
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME from information_schema.columns
where TABLE_SCHEMA = 'test' and TABLE_NAME = 'tbl2';`).Check(
testkit.RowsWithSep("|",
"test|tbl2|col_1",
"test|tbl2|col_2",
"test|tbl2|col_3"))
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME from information_schema.columns
where TABLE_SCHEMA = 'test' and COLUMN_NAME = 'col_4'`).Check(
testkit.RowsWithSep("|",
"test|tbl1|col_4"))
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME from information_schema.columns
where TABLE_NAME = 'view1' and COLUMN_NAME like 'm%%';`).Check(
testkit.RowsWithSep("|",
"test|view1|min(col_1)",
"test|view1|max4"))
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME from information_schema.columns
where TABLE_SCHEMA = 'test' and TABLE_NAME = 'tbl1' and COLUMN_NAME = 'col_2';`).Check(
testkit.RowsWithSep("|",
"test|tbl1|col_2"))
tk.MustQuery(`select count(*) from information_schema.columns
where TABLE_SCHEMA = 'test' and TABLE_NAME in ('tbl1', 'tbl2', 'view1');`).Check(
testkit.RowsWithSep("|", "9"))
}
func TestIndexUsageTable(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create table idt1(col_1 int primary key, col_2 int, index idx_1(col_1), index idx_2(col_2), index idx_3(col_1, col_2));")
tk.MustExec("create table idt2(col_1 int primary key, col_2 int, index idx_1(col_1), index idx_2(col_2), index idx_4(col_2, col_1));")
tk.MustExec("create table idt3(col_1 varchar(255) primary key);")
tk.MustExec("create table idt4(col_1 varchar(255) primary key NONCLUSTERED);")
tk.MustExec("create table idt5(col_1 int);")
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage
where TABLE_SCHEMA = 'test';`).Sort().Check(
testkit.RowsWithSep("|",
"test|idt1|idx_1",
"test|idt1|idx_2",
"test|idt1|idx_3",
"test|idt1|primary",
"test|idt2|idx_1",
"test|idt2|idx_2",
"test|idt2|idx_4",
"test|idt2|primary",
"test|idt3|primary",
"test|idt4|primary"))
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage where TABLE_NAME = 'idt1'`).Sort().Check(
testkit.RowsWithSep("|",
"test|idt1|idx_1",
"test|idt1|idx_2",
"test|idt1|idx_3",
"test|idt1|primary"))
tk.MustQuery("select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage where INDEX_NAME = 'IDX_3'").Check(
testkit.RowsWithSep("|",
"test|idt1|idx_3"))
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage
where TABLE_SCHEMA = 'test' and TABLE_NAME = 'idt1';`).Sort().Check(
testkit.RowsWithSep("|",
"test|idt1|idx_1",
"test|idt1|idx_2",
"test|idt1|idx_3",
"test|idt1|primary"))
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage
where TABLE_SCHEMA = 'test' and INDEX_NAME = 'idx_2';`).Sort().Check(
testkit.RowsWithSep("|",
"test|idt1|idx_2",
"test|idt2|idx_2"))
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage
where TABLE_NAME = 'idt1' and INDEX_NAME = 'idx_1';`).Check(
testkit.RowsWithSep("|",
"test|idt1|idx_1"))
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage
where TABLE_SCHEMA = 'test' and TABLE_NAME = 'idt2' and INDEX_NAME = 'idx_4';`).Check(
testkit.RowsWithSep("|",
"test|idt2|idx_4"))
tk.MustQuery(`select count(*) from information_schema.tidb_index_usage
where TABLE_SCHEMA = 'test' and TABLE_NAME in ('idt1', 'idt2');`).Check(
testkit.RowsWithSep("|", "8"))
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage
where TABLE_SCHEMA = 'test1';`).Check(testkit.Rows())
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage
where TABLE_NAME = 'idt3';`).Check(testkit.Rows("test idt3 primary"))
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage
where INDEX_NAME = 'IDX_5';`).Check(testkit.Rows())
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage
where TABLE_SCHEMA = 'test' and TABLE_NAME = 'idt0';`).Check(testkit.Rows())
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage
where TABLE_SCHEMA = 'test1' and INDEX_NAME = 'idx_2';`).Check(testkit.Rows())
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage
where TABLE_NAME = 'idt2' and INDEX_NAME = 'idx_3';`).Check(testkit.Rows())
tk.MustQuery(`select TABLE_SCHEMA, TABLE_NAME, INDEX_NAME from information_schema.tidb_index_usage
where TABLE_SCHEMA = 'test' and TABLE_NAME = 'idt1' and INDEX_NAME = 'idx_4';`).Check(testkit.Rows())
}
// https://github.com/pingcap/tidb/issues/32459.
func TestJoinSystemTableContainsView(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create table t (a timestamp, b int);")
tk.MustExec("insert into t values (null, 100);")
tk.MustExec("create view v as select * from t;")
// This is used by grafana when TiDB is specified as the data source.
// See https://github.com/grafana/grafana/blob/e86b6662a187c77656f72bef3b0022bf5ced8b98/public/app/plugins/datasource/mysql/meta_query.ts#L31
for range 10 {
tk.MustQueryWithContext(context.Background(), `
SELECT
table_name as table_name,
( SELECT
column_name as column_name
FROM information_schema.columns c
WHERE
c.table_schema = t.table_schema AND
c.table_name = t.table_name AND
c.data_type IN ('timestamp', 'datetime')
ORDER BY ordinal_position LIMIT 1
) AS time_column,
( SELECT
column_name AS column_name
FROM information_schema.columns c
WHERE
c.table_schema = t.table_schema AND
c.table_name = t.table_name AND
c.data_type IN('float', 'int', 'bigint')
ORDER BY ordinal_position LIMIT 1
) AS value_column
FROM information_schema.tables t
WHERE
t.table_schema = database() AND
EXISTS
( SELECT 1
FROM information_schema.columns c
WHERE
c.table_schema = t.table_schema AND
c.table_name = t.table_name AND
c.data_type IN ('timestamp', 'datetime')
) AND
EXISTS
( SELECT 1
FROM information_schema.columns c
WHERE
c.table_schema = t.table_schema AND
c.table_name = t.table_name AND
c.data_type IN('float', 'int', 'bigint')
)
LIMIT 1
;
`)
}
}
// https://github.com/pingcap/tidb/issues/36426.
func TestShowColumnsWithSubQueryView(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("set @@global.tidb_schema_cache_size = 0;")
t.Cleanup(func() {
tk.MustExec("set @@global.tidb_schema_cache_size = default;")
})
tk.MustExec("CREATE TABLE added (`id` int(11), `name` text, `some_date` timestamp);")
tk.MustExec("CREATE TABLE incremental (`id` int(11), `name`text, `some_date` timestamp);")
tk.MustExec("create view temp_view as (select * from `added` where id > (select max(id) from `incremental`));")
// Show columns should not send coprocessor request to the storage.
testfailpoint.Enable(t, "tikvclient/tikvStoreSendReqResult", `return("timeout")`)
testfailpoint.Enable(t, "github.com/pingcap/tidb/pkg/planner/core/BuildDataSourceFailed", "panic")
tk.MustQuery("show columns from temp_view;").Check(testkit.Rows(
"id int(11) YES <nil> ",
"name text YES <nil> ",
"some_date timestamp YES <nil> "))
tk.MustQuery("select COLUMN_NAME from information_schema.columns where table_name = 'temp_view';").Check(testkit.Rows("id", "name", "some_date"))
}
// Code below are helper utilities for the test cases.
type getTiFlashSystemTableRequestMocker struct {
tikv.Client
t *testing.T
handlers map[string]func(req *kvrpcpb.TiFlashSystemTableRequest) (*kvrpcpb.TiFlashSystemTableResponse, error)
}
func (client *getTiFlashSystemTableRequestMocker) SendRequest(ctx context.Context, addr string, req *tikvrpc.Request, timeout time.Duration) (*tikvrpc.Response, error) {
if req.Type == tikvrpc.CmdGetTiFlashSystemTable {
if handler, ok := client.handlers[req.Req.(*kvrpcpb.TiFlashSystemTableRequest).Sql]; ok {
resp, err := handler(req.GetTiFlashSystemTable())
if err != nil {
return nil, err
}
return &tikvrpc.Response{Resp: resp}, nil
}
// If we enter here, it means no handler is matching. We should fail!
require.Fail(client.t, fmt.Sprintf("Received request %s but no matching handler, maybe caused by unexpected query", req.Req.(*kvrpcpb.TiFlashSystemTableRequest).Sql))
}
return client.Client.SendRequest(ctx, addr, req, timeout)
}
func (client *getTiFlashSystemTableRequestMocker) MockQuery(query string, fn func(req *kvrpcpb.TiFlashSystemTableRequest) (*kvrpcpb.TiFlashSystemTableResponse, error)) *getTiFlashSystemTableRequestMocker {
client.handlers[query] = fn
return client
}
func (client *getTiFlashSystemTableRequestMocker) AsOpt() mockstore.MockTiKVStoreOption {
return mockstore.WithClientHijacker(func(kvClient tikv.Client) tikv.Client {
client.Client = kvClient
return client
})
}
func newGetTiFlashSystemTableRequestMocker(t *testing.T) *getTiFlashSystemTableRequestMocker {
return &getTiFlashSystemTableRequestMocker{
handlers: make(map[string]func(req *kvrpcpb.TiFlashSystemTableRequest) (*kvrpcpb.TiFlashSystemTableResponse, error), 0),
t: t,
}
}
// https://github.com/pingcap/tidb/issues/52350
func TestReferencedTableSchemaWithForeignKey(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("create database if not exists test;")
tk.MustExec("create database if not exists test2;")
tk.MustExec("drop table if exists test.t1;")
tk.MustExec("drop table if exists test2.t2;")
tk.MustExec("create table test.t1(id int primary key);")
tk.MustExec("create table test2.t2(i int, id int, foreign key (id) references test.t1(id));")
tk.MustQuery(`SELECT column_name, referenced_column_name, referenced_table_name, table_schema, referenced_table_schema
FROM information_schema.key_column_usage
WHERE table_name = 't2' AND table_schema = 'test2';`).Check(testkit.Rows(
"id id t1 test2 test"))
}
func TestSameTableNameInTwoSchemas(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("create database test1;")
tk.MustExec("create database test2;")
tk.MustExec("create table test1.t (a int);")
tk.MustExec("create table test2.t (a int);")
rs := tk.MustQuery("select tidb_table_id from information_schema.tables where table_name = 't' and table_schema = 'test1';").Rows()
t1ID, err := strconv.Atoi(rs[0][0].(string))
require.NoError(t, err)
rs = tk.MustQuery("select tidb_table_id from information_schema.tables where table_name = 't' and table_schema = 'test2';").Rows()
t2ID, err := strconv.Atoi(rs[0][0].(string))
require.NoError(t, err)
tk.MustQuery(fmt.Sprintf("select table_schema, table_name, tidb_table_id from information_schema.tables where tidb_table_id = %d;", t1ID)).
Check(testkit.Rows(fmt.Sprintf("test1 t %d", t1ID)))
tk.MustQuery(fmt.Sprintf("select table_schema, table_name, tidb_table_id from information_schema.tables where tidb_table_id = %d;", t2ID)).
Check(testkit.Rows(fmt.Sprintf("test2 t %d", t2ID)))
tk.MustQuery(fmt.Sprintf("select table_schema, table_name, tidb_table_id from information_schema.tables where table_name = 't' and tidb_table_id = %d;", t1ID)).
Check(testkit.Rows(fmt.Sprintf("test1 t %d", t1ID)))
tk.MustQuery(fmt.Sprintf("select table_schema, table_name, tidb_table_id from information_schema.tables where table_schema = 'test1' and tidb_table_id = %d;", t1ID)).
Check(testkit.Rows(fmt.Sprintf("test1 t %d", t1ID)))
tk.MustQuery(fmt.Sprintf("select table_schema, table_name, tidb_table_id from information_schema.tables where table_name = 'unknown' and tidb_table_id = %d;", t1ID)).
Check(testkit.Rows())
tk.MustQuery(fmt.Sprintf("select table_schema, table_name, tidb_table_id from information_schema.tables where table_schema = 'unknown' and tidb_table_id = %d;", t1ID)).
Check(testkit.Rows())
}
func TestInfoSchemaDDLJobs(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
for i := range 2 {
tk.MustExec(fmt.Sprintf("create database d%d", i))
tk.MustExec(fmt.Sprintf("use d%d", i))
for j := range 4 {
tk.MustExec(fmt.Sprintf("create table t%d(id int, col1 int, col2 int)", j))
tk.MustExec(fmt.Sprintf("alter table t%d add index (col1)", j))
}
}
tk2 := testkit.NewTestKit(t, store)
tk2.MustQuery(`SELECT JOB_ID, JOB_TYPE, SCHEMA_STATE, SCHEMA_ID, TABLE_ID, table_name, STATE
FROM information_schema.ddl_jobs WHERE table_name = "t1";`).Check(testkit.RowsWithSep("|",
"135|add index|public|128|133|t1|synced",
"134|create table|public|128|133|t1|synced",
"121|add index|public|114|119|t1|synced",
"120|create table|public|114|119|t1|synced",
))
tk2.MustQuery(`SELECT JOB_ID, JOB_TYPE, SCHEMA_STATE, SCHEMA_ID, TABLE_ID, table_name, STATE
FROM information_schema.ddl_jobs WHERE db_name = "d1" and JOB_TYPE LIKE "add index%%";`).Check(testkit.RowsWithSep("|",
"141|add index|public|128|139|t3|synced",
"138|add index|public|128|136|t2|synced",
"135|add index|public|128|133|t1|synced",
"132|add index|public|128|130|t0|synced",
))
tk2.MustQuery(`SELECT JOB_ID, JOB_TYPE, SCHEMA_STATE, SCHEMA_ID, TABLE_ID, table_name, STATE
FROM information_schema.ddl_jobs WHERE db_name = "d0" and table_name = "t3";`).Check(testkit.RowsWithSep("|",
"127|add index|public|114|125|t3|synced",
"126|create table|public|114|125|t3|synced",
))
tk2.MustQuery(`SELECT JOB_ID, JOB_TYPE, SCHEMA_STATE, SCHEMA_ID, TABLE_ID, table_name, STATE
FROM information_schema.ddl_jobs WHERE state = "running";`).Check(testkit.Rows())
// Test running job
loaded := atomic.Bool{}
testfailpoint.EnableCall(t, "github.com/pingcap/tidb/pkg/ddl/beforeRunOneJobStep", func(job *model.Job) {
if job.SchemaState == model.StateWriteOnly && loaded.CompareAndSwap(false, true) {
tk2.MustQuery(`SELECT JOB_ID, JOB_TYPE, SCHEMA_STATE, SCHEMA_ID, TABLE_ID, table_name, STATE
FROM information_schema.ddl_jobs WHERE table_name = "t0" and state = "running";`).Check(testkit.RowsWithSep("|",
"142 add index write only 114 116 t0 running",
))
tk2.MustQuery(`SELECT JOB_ID, JOB_TYPE, SCHEMA_STATE, SCHEMA_ID, TABLE_ID, table_name, STATE
FROM information_schema.ddl_jobs WHERE db_name = "d0" and state = "running";`).Check(testkit.RowsWithSep("|",
"142 add index write only 114 116 t0 running",
))
tk2.MustQuery(`SELECT JOB_ID, JOB_TYPE, SCHEMA_STATE, SCHEMA_ID, TABLE_ID, table_name, STATE
FROM information_schema.ddl_jobs WHERE state = "running";`).Check(testkit.RowsWithSep("|",
"142 add index write only 114 116 t0 running",
))
}
})
tk.MustExec("use d0")
tk.MustExec("alter table t0 add index (col2)")
// Test search history jobs
tk.MustExec("create database test2")
tk.MustExec("create table test2.t1(id int)")
tk.MustExec("drop database test2")
tk.MustExec("create database test2")
tk.MustExec("create table test2.t1(id int)")
tk.MustQuery(`SELECT JOB_ID, JOB_TYPE, SCHEMA_STATE, SCHEMA_ID, TABLE_ID, table_name, STATE
FROM information_schema.ddl_jobs WHERE db_name = "test2" and table_name = "t1"`).Check(testkit.RowsWithSep("|",
"151|create table|public|148|150|t1|synced",
"146|create table|public|143|145|t1|synced",
))
// Test explain output, since the output may change in future.
tk.MustQuery(`EXPLAIN FORMAT='brief' SELECT * FROM information_schema.ddl_jobs where db_name = "test2" limit 10;`).Check(testkit.Rows(
`Limit 10.00 root offset:0, count:10`,
`└─Selection 10.00 root eq(Column#2, "test2")`,
` └─MemTableScan 10000.00 root table:DDL_JOBS db_name:["test2"]`,
))
}
func TestInfoSchemaConditionWorks(t *testing.T) {
// this test creates table in different schema with different index name, and check
// the condition in the following columns whether work as expected.
//
// - "table_schema"
// - "constraint_schema"
// - "table_name"
// - "constraint_name"
// - "partition_name"
// - "schema_name"
// - "index_name"
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
for db := range 2 {
for table := range 2 {
tk.MustExec(fmt.Sprintf("create database if not exists Db%d;", db))
tk.MustExec(fmt.Sprintf(`create table Db%d.Table%d (id int primary key, data0 varchar(255), data1 varchar(255))
partition by range (id) (
partition p0 values less than (10),
partition p1 values less than (20)
);`, db, table))
for index := range 2 {
tk.MustExec(fmt.Sprintf("create unique index Idx%d on Db%d.Table%d (id, data%d);", index, db, table, index))
}
}
}
testColumns := map[string]string{
"table_schema": "db",
"constraint_schema": "db",
"table_name": "table",
"constraint_name": "idx",
"partition_name": "p",
"schema_name": "db",
"index_name": "idx",
}
testTables := []string{}
for _, row := range tk.MustQuery("show tables in information_schema").Rows() {
tableName := row[0].(string)
// exclude some tables which cannot run without TiKV.
if strings.HasPrefix(tableName, "CLUSTER_") ||
strings.HasPrefix(tableName, "INSPECTION_") ||
strings.HasPrefix(tableName, "METRICS_") ||
strings.HasPrefix(tableName, "TIFLASH_") ||
strings.HasPrefix(tableName, "TIKV_") ||
strings.HasPrefix(tableName, "USER_") ||
tableName == "TABLE_STORAGE_STATS" ||
strings.Contains(tableName, "REGION") {
continue
}
testTables = append(testTables, row[0].(string))
}
for _, table := range testTables {
rs, err := tk.Exec(fmt.Sprintf("select * from information_schema.%s", table))
require.NoError(t, err)
cols := rs.Fields()
chk := rs.NewChunk(nil)
rowCount := 0
for {
err := rs.Next(context.Background(), chk)
require.NoError(t, err)
if chk.NumRows() == 0 {
break
}
rowCount += chk.NumRows()
}
if rowCount == 0 {
// TODO: find a way to test the table without any rows by adding some rows to them.
continue
}
for i := range cols {
colName := cols[i].Column.Name.L
if valPrefix, ok := testColumns[colName]; ok {
for j := range 2 {
sql := fmt.Sprintf("select * from information_schema.%s where %s = '%s%d';",
table, colName, valPrefix, j)
rows := tk.MustQuery(sql).Rows()
rowCountWithCondition := len(rows)
require.Less(t, rowCountWithCondition, rowCount, "%s has no effect on %s. SQL: %s", colName, table, sql)
// check the condition works as expected
for _, row := range rows {
require.Equal(t, fmt.Sprintf("%s%d", valPrefix, j), strings.ToLower(row[i].(string)),
"%s has no effect on %s. SQL: %s", colName, table, sql)
}
}
}
}
}
// Test the PRIMARY constraint filter
rows := tk.MustQuery("select constraint_name, table_schema from information_schema.table_constraints where constraint_name = 'PRIMARY' and table_schema = 'db0';").Rows()
require.Equal(t, 2, len(rows))
for _, row := range rows {
require.Equal(t, "PRIMARY", row[0].(string))
require.Equal(t, "Db0", row[1].(string))
}
rows = tk.MustQuery("select constraint_name, table_schema from information_schema.key_column_usage where constraint_name = 'PRIMARY' and table_schema = 'db1';").Rows()
require.Equal(t, 2, len(rows))
for _, row := range rows {
require.Equal(t, "PRIMARY", row[0].(string))
require.Equal(t, "Db1", row[1].(string))
}
// Test the `partition_name` filter
tk.MustExec("create database if not exists db_no_partition;")
tk.MustExec("create table db_no_partition.t_no_partition (id int primary key, data0 varchar(255), data1 varchar(255));")
tk.MustExec(`create table db_no_partition.t_partition (id int primary key, data0 varchar(255), data1 varchar(255))
partition by range (id) (
partition p0 values less than (10),
partition p1 values less than (20)
);`)
rows = tk.MustQuery("select * from information_schema.partitions where table_schema = 'db_no_partition' and partition_name is NULL;").Rows()
require.Equal(t, 1, len(rows))
rows = tk.MustQuery("select * from information_schema.partitions where table_schema = 'db_no_partition' and (partition_name is NULL or partition_name = 'p0');").Rows()
require.Equal(t, 2, len(rows))
}
func TestInfoschemaTablesSpecialOptimizationCovered(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("set @@global.tidb_schema_cache_size = default")
for _, testCase := range []struct {
sql string
expect bool
}{
{"select table_name, table_schema from information_schema.tables", true},
{"select table_name from information_schema.tables", true},
{"select table_name from information_schema.tables where table_schema = 'test'", true},
{"select table_name, table_schema from information_schema.tables where table_name = 't'", true},
{"select table_schema from information_schema.tables", true},
{"select table_schema from information_schema.tables where tidb_table_id = 4611686018427387967", false},
{"select count(table_schema) from information_schema.tables", true},
{"select count(table_name) from information_schema.tables", true},
{"select count(table_rows) from information_schema.tables", false},
{"select count(1) from information_schema.tables", true},
{"select count(*) from information_schema.tables", true},
{"select count(*) from information_schema.tables where tidb_table_id = 4611686018427387967", false},
{"select count(1) from (select table_name from information_schema.tables) t", true},
{"select * from information_schema.tables", false},
{"select table_name, table_catalog from information_schema.tables", true},
{"select table_name, table_catalog from information_schema.tables where table_catalog = 'normal'", true},
{"select table_name, table_rows from information_schema.tables", false},
{"select table_name, table_schema, tidb_table_id from information_schema.tables where tidb_table_id = 4611686018427387967", false},
} {
var covered bool
ctx := context.WithValue(context.Background(), "cover-check", &covered)
tk.MustQueryWithContext(ctx, testCase.sql)
require.Equal(t, testCase.expect, covered, testCase.sql)
}
}
func TestIndexUsageWithData(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
// Some bad tests will set the global variable to 0, and they don't set it back. So even if the default value for this variable is 1,
// we'll need to set it to 1 here.
tk.MustExec("set global tidb_enable_collect_execution_info=1;")
tk.RefreshSession()
insertDataAndScanToT := func(indexName string) {
// insert 1000 rows
tk.MustExec("INSERT into t WITH RECURSIVE cte AS (select 1 as n UNION ALL select n+1 FROM cte WHERE n < 1000) select n from cte;")
tk.MustExec("ANALYZE TABLE t")
// full scan
sql := fmt.Sprintf("SELECT * FROM t use index(%s) ORDER BY a", indexName)
rows := tk.MustQuery(sql).Rows()
require.Len(t, rows, 1000)
for i, r := range rows {
require.Equal(t, r[0], strconv.Itoa(i+1))
}
logutil.BgLogger().Info("execute with plan",
zap.String("sql", sql),
zap.String("plan", tk.MustQuery("explain "+sql).String()))
// scan 1/4 of the rows
sql = fmt.Sprintf("SELECT * FROM t use index(%s) WHERE a <= 250 ORDER BY a", indexName)
rows = tk.MustQuery(sql).Rows()
require.Len(t, rows, 250)
for i, r := range rows {
require.Equal(t, r[0], strconv.Itoa(i+1))
}
logutil.BgLogger().Info("execute with plan",
zap.String("sql", sql),
zap.String("plan", tk.MustQuery("explain "+sql).String()))
}
checkIndexUsage := func(startQuery time.Time, endQuery time.Time) {
require.Eventually(t, func() bool {
rows := tk.MustQuery("select QUERY_TOTAL,PERCENTAGE_ACCESS_20_50,PERCENTAGE_ACCESS_100,LAST_ACCESS_TIME from information_schema.tidb_index_usage where table_schema = 'test'").Rows()
if len(rows) != 1 {
return false
}
if rows[0][0] != "2" || rows[0][1] != "1" || rows[0][2] != "1" {
return false
}
lastAccessTime, err := time.ParseInLocation(time.DateTime, rows[0][3].(string), time.Local)
if err != nil {
return false
}
if lastAccessTime.Unix() < startQuery.Unix() || lastAccessTime.Unix() > endQuery.Unix() {
return false
}
return true
}, 5*time.Second, 100*time.Millisecond)
}
t.Run("test index usage with normal index", func(t *testing.T) {
tk.MustExec("use test")
tk.MustExec("create table t (a int, index idx(a));")
defer tk.MustExec("drop table t")
tk.MustQuery("select * from information_schema.tidb_index_usage where table_schema = 'test'").Check(testkit.Rows(
"test t idx 0 0 0 0 0 0 0 0 0 0 <nil>",
))
startQuery := time.Now()
insertDataAndScanToT("idx")
endQuery := time.Now()
checkIndexUsage(startQuery, endQuery)
})
t.Run("test index usage with integer primary key", func(t *testing.T) {
tk.MustExec("use test")
tk.MustExec("create table t (a int primary key);")
defer tk.MustExec("drop table t")
tk.MustQuery("select * from information_schema.tidb_index_usage where table_schema = 'test'").Check(testkit.Rows(
"test t primary 0 0 0 0 0 0 0 0 0 0 <nil>",
))
startQuery := time.Now()
insertDataAndScanToT("primary")
endQuery := time.Now()
checkIndexUsage(startQuery, endQuery)
})
t.Run("test index usage with integer clustered primary key", func(t *testing.T) {
tk.MustExec("use test")
tk.MustExec("create table t (a bigint primary key clustered);")
defer tk.MustExec("drop table t")
tk.MustQuery("select * from information_schema.tidb_index_usage where table_schema = 'test'").Check(testkit.Rows(
"test t primary 0 0 0 0 0 0 0 0 0 0 <nil>",
))
startQuery := time.Now()
insertDataAndScanToT("primary")
endQuery := time.Now()
checkIndexUsage(startQuery, endQuery)
})
t.Run("test index usage with string primary key", func(t *testing.T) {
tk.MustExec("use test")
tk.MustExec("create table t (a varchar(16) primary key clustered);")
defer tk.MustExec("drop table t")
tk.MustQuery("select * from information_schema.tidb_index_usage where table_schema = 'test'").Check(testkit.Rows(
"test t primary 0 0 0 0 0 0 0 0 0 0 <nil>",
))
tk.MustExec("INSERT into t WITH RECURSIVE cte AS (select 1 as n UNION ALL select n+1 FROM cte WHERE n < 1000) select n from cte;")
tk.MustExec("ANALYZE TABLE t")
// full scan
rows := tk.MustQuery("SELECT * FROM t ORDER BY a").Rows()
require.Len(t, rows, 1000)
// scan 1/4 of the rows
startQuery := time.Now()
rows = tk.MustQuery("select * from t where a < '3'").Rows()
require.Len(t, rows, 223)
endQuery := time.Now()
checkIndexUsage(startQuery, endQuery)
})
t.Run("test index usage with nonclustered primary key", func(t *testing.T) {
tk.MustExec("use test")
tk.MustExec("create table t (a int primary key nonclustered);")
defer tk.MustExec("drop table t")
tk.MustQuery("select * from information_schema.tidb_index_usage where table_schema = 'test'").Check(testkit.Rows(
"test t primary 0 0 0 0 0 0 0 0 0 0 <nil>",
))
startQuery := time.Now()
insertDataAndScanToT("primary")
endQuery := time.Now()
checkIndexUsage(startQuery, endQuery)
})
}
func TestKeyspaceMeta(t *testing.T) {
keyspaceID := rand.Uint32() >> 8
keyspaceName := fmt.Sprintf("keyspace-%d", keyspaceID)
cfg := map[string]string{
"key_a": "a",
"key_b": "b",
}
keyspaceMeta := &keyspacepb.KeyspaceMeta{
Id: keyspaceID,
Name: keyspaceName,
Config: cfg,
}
store := testkit.CreateMockStore(t, mockstore.WithKeyspaceMeta(keyspaceMeta))
tk := testkit.NewTestKit(t, store)
rows := tk.MustQuery("select * from information_schema.keyspace_meta").Rows()
require.Equal(t, 1, len(rows))
require.Equal(t, keyspaceMeta.Name, rows[0][0])
require.Equal(t, fmt.Sprintf("%d", keyspaceMeta.Id), rows[0][1])
actualCfg := make(map[string]string)
err := json.Unmarshal([]byte(rows[0][2].(string)), &actualCfg)
require.Nil(t, err)
require.Equal(t, cfg, actualCfg)
}
func TestStatisticShowPublicIndexes(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create table t (a int, b int);")
tk.MustExec("insert into t values (1, 1);")
tk1 := testkit.NewTestKit(t, store)
tk1.MustExec("use test")
testfailpoint.EnableCall(t, "github.com/pingcap/tidb/pkg/ddl/afterWaitSchemaSynced", func(job *model.Job) {
if job.Type != model.ActionAddIndex || job.SchemaState == model.StatePublic {
return
}
rs := tk1.MustQuery(`SELECT count(1) FROM INFORMATION_SCHEMA.STATISTICS where
TABLE_SCHEMA = 'test' and table_name = 't' and index_name = 'idx';`).Rows()
require.Equal(t, "0", rs[0][0].(string))
})
tk.MustExec("alter table t add index idx(b);")
}