diff --git a/distsql/request_builder.go b/distsql/request_builder.go index 98d58eb023217..dcae06ea677c0 100644 --- a/distsql/request_builder.go +++ b/distsql/request_builder.go @@ -82,6 +82,13 @@ func (builder *RequestBuilder) SetTableHandles(tid int64, handles []kv.Handle) * return builder } +// SetPartitionsAndHandles sets "KeyRanges" for "kv.Request" by converting ParitionHandles to KeyRanges. +// handles in slice must be kv.PartitionHandle. +func (builder *RequestBuilder) SetPartitionsAndHandles(handles []kv.Handle) *RequestBuilder { + builder.Request.KeyRanges = PartitionHandlesToKVRanges(handles) + return builder +} + const estimatedRegionRowCount = 100000 // SetDAGRequest sets the request type to "ReqTypeDAG" and construct request data. @@ -299,6 +306,44 @@ func TableHandlesToKVRanges(tid int64, handles []kv.Handle) []kv.KeyRange { return krs } +// PartitionHandlesToKVRanges convert ParitionHandles to kv ranges. +// Handle in slices must be kv.PartitionHandle +func PartitionHandlesToKVRanges(handles []kv.Handle) []kv.KeyRange { + krs := make([]kv.KeyRange, 0, len(handles)) + i := 0 + for i < len(handles) { + ph := handles[i].(kv.PartitionHandle) + h := ph.Handle + pid := ph.PartitionID + if commonHandle, ok := h.(*kv.CommonHandle); ok { + ran := kv.KeyRange{ + StartKey: tablecodec.EncodeRowKey(pid, commonHandle.Encoded()), + EndKey: tablecodec.EncodeRowKey(pid, append(commonHandle.Encoded(), 0)), + } + krs = append(krs, ran) + i++ + continue + } + j := i + 1 + for ; j < len(handles) && handles[j-1].IntValue() != math.MaxInt64; j++ { + if handles[j].IntValue() != handles[j-1].IntValue()+1 { + break + } + if handles[j].(kv.PartitionHandle).PartitionID != pid { + break + } + } + low := codec.EncodeInt(nil, handles[i].IntValue()) + high := codec.EncodeInt(nil, handles[j-1].IntValue()) + high = kv.Key(high).PrefixNext() + startKey := tablecodec.EncodeRowKey(pid, low) + endKey := tablecodec.EncodeRowKey(pid, high) + krs = append(krs, kv.KeyRange{StartKey: startKey, EndKey: endKey}) + i = j + } + return krs +} + // IndexRangesToKVRanges converts index ranges to "KeyRange". func IndexRangesToKVRanges(sc *stmtctx.StatementContext, tid, idxID int64, ranges []*ranger.Range, fb *statistics.QueryFeedback) ([]kv.KeyRange, error) { if fb == nil || fb.Hist == nil { diff --git a/executor/builder.go b/executor/builder.go index 93f283c7b734e..5f6154c1ee6d3 100644 --- a/executor/builder.go +++ b/executor/builder.go @@ -2670,6 +2670,10 @@ func (b *executorBuilder) buildIndexReader(v *plannercore.PhysicalIndexReader) E return ret } + if is.Index.Global { + return ret + } + nextPartition := nextPartitionForIndexReader{exec: ret} exec, err := buildPartitionTable(b, is.Table, &v.PartitionInfo, ret, nextPartition) if err != nil { @@ -2713,7 +2717,17 @@ func buildIndexReq(b *executorBuilder, schemaLen, handleLen int, plans []planner func buildNoRangeIndexLookUpReader(b *executorBuilder, v *plannercore.PhysicalIndexLookUpReader) (*IndexLookUpExecutor, error) { is := v.IndexPlans[0].(*plannercore.PhysicalIndexScan) - indexReq, indexStreaming, err := buildIndexReq(b, len(is.Index.Columns), len(v.CommonHandleCols), v.IndexPlans) + var handleLen int + if len(v.CommonHandleCols) != 0 { + handleLen = len(v.CommonHandleCols) + } else { + handleLen = 1 + } + if is.Index.Global { + // Should output pid col. + handleLen++ + } + indexReq, indexStreaming, err := buildIndexReq(b, len(is.Index.Columns), handleLen, v.IndexPlans) if err != nil { return nil, err } @@ -2806,6 +2820,10 @@ func (b *executorBuilder) buildIndexLookUpReader(v *plannercore.PhysicalIndexLoo return ret } + if is.Index.Global { + return ret + } + nextPartition := nextPartitionForIndexLookUp{exec: ret} exec, err := buildPartitionTable(b, ts.Table, &v.PartitionInfo, ret, nextPartition) if err != nil { @@ -3100,7 +3118,11 @@ func (builder *dataReaderBuilder) buildTableReaderFromHandles(ctx context.Contex }) } var b distsql.RequestBuilder - b.SetTableHandles(getPhysicalTableID(e.table), handles) + if _, ok := handles[0].(kv.PartitionHandle); ok { + b.SetPartitionsAndHandles(handles) + } else { + b.SetTableHandles(getPhysicalTableID(e.table), handles) + } return builder.buildTableReaderBase(ctx, e, b) } diff --git a/executor/distsql.go b/executor/distsql.go index fe5810b8b92cd..347735c49594e 100644 --- a/executor/distsql.go +++ b/executor/distsql.go @@ -459,6 +459,9 @@ func (e *IndexLookUpExecutor) getRetTpsByHandle() []*types.FieldType { } else { tps = []*types.FieldType{types.NewFieldType(mysql.TypeLonglong)} } + if e.index.Global { + tps = append(tps, types.NewFieldType(mysql.TypeLonglong)) + } if e.checkIndexValue != nil { tps = e.idxColTps } @@ -714,11 +717,15 @@ func (w *indexWorker) fetchHandles(ctx context.Context, result distsql.SelectRes func (w *indexWorker) extractTaskHandles(ctx context.Context, chk *chunk.Chunk, idxResult distsql.SelectResult, count uint64) ( handles []kv.Handle, retChk *chunk.Chunk, scannedKeys uint64, err error) { var handleOffset []int + numColsWithoutPid := chk.NumCols() + if w.idxLookup.index.Global { + numColsWithoutPid = numColsWithoutPid - 1 + } for i := range w.idxLookup.handleCols { - handleOffset = append(handleOffset, chk.NumCols()-len(w.idxLookup.handleCols)+i) + handleOffset = append(handleOffset, numColsWithoutPid-len(w.idxLookup.handleCols)+i) } if len(handleOffset) == 0 { - handleOffset = []int{chk.NumCols() - 1} + handleOffset = []int{numColsWithoutPid - 1} } handles = make([]kv.Handle, 0, w.batchSize) // PushedLimit would always be nil for CheckIndex or CheckTable, we add this check just for insurance. @@ -895,6 +902,11 @@ func (e *IndexLookUpExecutor) getHandle(row chunk.Row, handleIdx []int, handle = kv.IntHandle(row.GetInt64(handleIdx[0])) } } + if e.index.Global { + pidOffset := row.Len() - 1 + pid := row.GetInt64(pidOffset) + handle = kv.NewPartitionHandle(pid, handle) + } return } diff --git a/executor/executor_test.go b/executor/executor_test.go index 998602c4a4ce8..1bb12cb2dbd10 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -130,6 +130,7 @@ var _ = SerialSuites(&testSerialSuite1{&baseTestSuite{}}) var _ = SerialSuites(&testSlowQuery{&baseTestSuite{}}) var _ = Suite(&partitionTableSuite{&baseTestSuite{}}) var _ = SerialSuites(&tiflashTestSuite{}) +var _ = SerialSuites(&globalIndexSuite{&baseTestSuite{}}) var _ = SerialSuites(&testSerialSuite{&baseTestSuite{}}) type testSuite struct{ *baseTestSuite } @@ -142,6 +143,7 @@ type testSuiteWithData struct { } type testSlowQuery struct{ *baseTestSuite } type partitionTableSuite struct{ *baseTestSuite } +type globalIndexSuite struct{ *baseTestSuite } type testSerialSuite struct{ *baseTestSuite } type baseTestSuite struct { @@ -196,6 +198,13 @@ func (s *baseTestSuite) TearDownSuite(c *C) { s.store.Close() } +func (s *globalIndexSuite) SetUpSuite(c *C) { + s.baseTestSuite.SetUpSuite(c) + config.UpdateGlobal(func(conf *config.Config) { + conf.EnableGlobalIndex = true + }) +} + func (s *testSuiteP1) TestPessimisticSelectForUpdate(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") diff --git a/executor/partition_table_test.go b/executor/partition_table_test.go index 4856ce290bdd3..920fa09a5acef 100644 --- a/executor/partition_table_test.go +++ b/executor/partition_table_test.go @@ -176,3 +176,27 @@ PRIMARY KEY (pk1,pk2)) partition by hash(pk2) partitions 4;`) tk.MustQuery("select /*+ INL_JOIN(dt, rr) */ * from coverage_dt dt join coverage_rr rr on (dt.pk1 = rr.pk1 and dt.pk2 = rr.pk2);").Sort().Check(testkit.Rows("ios 3 ios 3 2", "linux 5 linux 5 1")) tk.MustQuery("select /*+ INL_MERGE_JOIN(dt, rr) */ * from coverage_dt dt join coverage_rr rr on (dt.pk1 = rr.pk1 and dt.pk2 = rr.pk2);").Sort().Check(testkit.Rows("ios 3 ios 3 2", "linux 5 linux 5 1")) } + +func (s *globalIndexSuite) TestGlobalIndexScan(c *C) { + tk := testkit.NewTestKitWithInit(c, s.store) + tk.MustExec("drop table if exists p") + tk.MustExec(`create table p (id int, c int) partition by range (c) ( +partition p0 values less than (4), +partition p1 values less than (7), +partition p2 values less than (10))`) + tk.MustExec("alter table p add unique idx(id)") + tk.MustExec("insert into p values (1,3), (3,4), (5,6), (7,9)") + tk.MustQuery("select id from p use index (idx)").Check(testkit.Rows("1", "3", "5", "7")) +} + +func (s *globalIndexSuite) TestGlobalIndexDoubleRead(c *C) { + tk := testkit.NewTestKitWithInit(c, s.store) + tk.MustExec("drop table if exists p") + tk.MustExec(`create table p (id int, c int) partition by range (c) ( +partition p0 values less than (4), +partition p1 values less than (7), +partition p2 values less than (10))`) + tk.MustExec("alter table p add unique idx(id)") + tk.MustExec("insert into p values (1,3), (3,4), (5,6), (7,9)") + tk.MustQuery("select * from p use index (idx)").Check(testkit.Rows("1 3", "3 4", "5 6", "7 9")) +} diff --git a/go.sum b/go.sum index c768dc7728ab3..a1d1e6f0a3302 100644 --- a/go.sum +++ b/go.sum @@ -406,14 +406,11 @@ github.com/ngaut/unistore v0.0.0-20200918091209-68a2db6bb775/go.mod h1:ZR3NH+Hzq github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= -github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34= @@ -425,7 +422,6 @@ github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsq github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.3.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= @@ -439,7 +435,6 @@ github.com/pingcap-incubator/tidb-dashboard v0.0.0-20200710045508-523e95bc5ec9/g github.com/pingcap-incubator/tidb-dashboard v0.0.0-20200715070228-47f5de8a6992/go.mod h1:9yaAM77sPfa5/f6sdxr3jSkKfIz463KRHyiFHiGjdes= github.com/pingcap-incubator/tidb-dashboard v0.0.0-20200807020752-01f0abe88e93/go.mod h1:9yaAM77sPfa5/f6sdxr3jSkKfIz463KRHyiFHiGjdes= github.com/pingcap/badger v1.5.1-0.20200604041313-19c397305fcc/go.mod h1:LyrqUOHZrUDf9oGi1yoz1+qw9ckSIhQb5eMa1acOLNQ= -github.com/pingcap/badger v1.5.1-0.20200714132513-80ba2000f159 h1:cmZSuRbdfOJd3kJjRIClrLbt3nD0xi4oqYR1c/ZrPKg= github.com/pingcap/badger v1.5.1-0.20200714132513-80ba2000f159/go.mod h1:LyrqUOHZrUDf9oGi1yoz1+qw9ckSIhQb5eMa1acOLNQ= github.com/pingcap/badger v1.5.1-0.20200810065601-8c92a97807f9/go.mod h1:LyrqUOHZrUDf9oGi1yoz1+qw9ckSIhQb5eMa1acOLNQ= github.com/pingcap/badger v1.5.1-0.20200908111422-2e78ee155d19 h1:IXpGy7y9HyoShAFmzW2OPF0xCA5EOoSTyZHwsgYk9Ro= @@ -451,7 +446,6 @@ github.com/pingcap/br v0.0.0-20200617120402-56e151ad8b67/go.mod h1:/3QzpDG7YTPrD github.com/pingcap/br v0.0.0-20200727092753-a475692725db/go.mod h1:4iTqZAMbEPmjBggYixqIg2FwIHBQtyImTM/QYlpTBGk= github.com/pingcap/br v0.0.0-20200803052654-e6f63fc1807a/go.mod h1:8j7vGUfHCETYbeBfASLTDywC3NFSx90z9nuk0PV9rpo= github.com/pingcap/br v0.0.0-20200805121136-181c081ba6ac/go.mod h1:9P24mNzNmXjggYBm4pnb08slSbua8FA6QIyg68GpuhQ= -github.com/pingcap/br v0.0.0-20200820083933-d9d6207c0aa7 h1:7YWkuK/QY7/nz819lnxb0qDXqLrApDjZHjYPo+tduGA= github.com/pingcap/br v0.0.0-20200820083933-d9d6207c0aa7/go.mod h1:5ri8663t7CtJuG0kiOKKoBmwk9HOCX5MoKpmh1fW4CE= github.com/pingcap/br v0.0.0-20200923023944-7456456854e4 h1:f1e1xbBAMc6mOrnBtrPRke52Zxv8zVlyr5g0Tz/pySQ= github.com/pingcap/br v0.0.0-20200923023944-7456456854e4/go.mod h1:DGsMcZVYt2haeDF/xGerf77c2RpTymgYY5+bMg8uArA= @@ -460,15 +454,11 @@ github.com/pingcap/check v0.0.0-20191107115940-caf2b9e6ccf4/go.mod h1:PYMCGwN0JH github.com/pingcap/check v0.0.0-20191216031241-8a5a85928f12/go.mod h1:PYMCGwN0JHjoqGr3HrZoD+b8Tgx8bKnArhSq8YVzUMc= github.com/pingcap/check v0.0.0-20200212061837-5e12011dc712 h1:R8gStypOBmpnHEx1qi//SaqxJVI4inOqljg/Aj5/390= github.com/pingcap/check v0.0.0-20200212061837-5e12011dc712/go.mod h1:PYMCGwN0JHjoqGr3HrZoD+b8Tgx8bKnArhSq8YVzUMc= -github.com/pingcap/errcode v0.0.0-20180921232412-a1a7271709d9 h1:KH4f4Si9XK6/IW50HtoaiLIFHGkapOM6w83za47UYik= github.com/pingcap/errcode v0.0.0-20180921232412-a1a7271709d9/go.mod h1:4b2X8xSqxIroj/IZ9MX/VGZhAwc11wB9wRIzHvz6SeM= github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= -github.com/pingcap/errors v0.11.5-0.20190809092503-95897b64e011 h1:58naV4XMEqm0hl9LcYo6cZoGBGiLtefMQMF/vo3XLgQ= github.com/pingcap/errors v0.11.5-0.20190809092503-95897b64e011/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= -github.com/pingcap/errors v0.11.5-0.20200729012136-4e113ddee29e h1:/EGWHNOyEgizEBuAujWsb9vXrPZtt1b7ooDPyjEkjDw= github.com/pingcap/errors v0.11.5-0.20200729012136-4e113ddee29e/go.mod h1:g4vx//d6VakjJ0mk7iLBlKA8LFavV/sAVINT/1PFxeQ= -github.com/pingcap/errors v0.11.5-0.20200902104258-eba4f1d8f6de h1:mW8hC2yXTpflfyTeJgcN4aJQfwcYODde8YgjBgAy6do= github.com/pingcap/errors v0.11.5-0.20200902104258-eba4f1d8f6de/go.mod h1:g4vx//d6VakjJ0mk7iLBlKA8LFavV/sAVINT/1PFxeQ= github.com/pingcap/errors v0.11.5-0.20200917111840-a15ef68f753d h1:TH18wFO5Nq/zUQuWu9ms2urgZnLP69XJYiI2JZAkUGc= github.com/pingcap/errors v0.11.5-0.20200917111840-a15ef68f753d/go.mod h1:g4vx//d6VakjJ0mk7iLBlKA8LFavV/sAVINT/1PFxeQ= @@ -548,7 +538,6 @@ github.com/pingcap/tidb-tools v4.0.0-rc.1.0.20200421113014-507d2bb3a15e+incompat github.com/pingcap/tidb-tools v4.0.0-rc.1.0.20200514040632-f76b3e428e19+incompatible/go.mod h1:XGdcy9+yqlDSEMTpOXnwf3hiTeqrV6MN/u1se9N8yIM= github.com/pingcap/tidb-tools v4.0.0+incompatible/go.mod h1:XGdcy9+yqlDSEMTpOXnwf3hiTeqrV6MN/u1se9N8yIM= github.com/pingcap/tidb-tools v4.0.1+incompatible/go.mod h1:XGdcy9+yqlDSEMTpOXnwf3hiTeqrV6MN/u1se9N8yIM= -github.com/pingcap/tidb-tools v4.0.5-0.20200820082341-afeaaaaaa153+incompatible h1:OozchEPztWQsTdLxPSPs6P+Cowbr35J7uy5oRpjbV9E= github.com/pingcap/tidb-tools v4.0.5-0.20200820082341-afeaaaaaa153+incompatible/go.mod h1:XGdcy9+yqlDSEMTpOXnwf3hiTeqrV6MN/u1se9N8yIM= github.com/pingcap/tidb-tools v4.0.5-0.20200820092506-34ea90c93237+incompatible h1:qPppnsXVh3KswqRZdSAShGLLPd7dB+5w4lXDnpYn0SQ= github.com/pingcap/tidb-tools v4.0.5-0.20200820092506-34ea90c93237+incompatible/go.mod h1:XGdcy9+yqlDSEMTpOXnwf3hiTeqrV6MN/u1se9N8yIM= @@ -597,7 +586,6 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sergi/go-diff v1.0.1-0.20180205163309-da645544ed44 h1:tB9NOR21++IjLyVx3/PCPhWMwqGNCMQEH96A6dMZ/gc= github.com/sergi/go-diff v1.0.1-0.20180205163309-da645544ed44/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shirou/gopsutil v2.19.10+incompatible h1:lA4Pi29JEVIQIgATSeftHSY0rMGI9CLrl2ZvDLiahto= github.com/shirou/gopsutil v2.19.10+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= diff --git a/kv/key.go b/kv/key.go index c5397993a0566..53eacf05a8a3d 100644 --- a/kv/key.go +++ b/kv/key.go @@ -429,3 +429,41 @@ func BuildHandleFromDatumRow(sctx *stmtctx.StatementContext, row []types.Datum, } return handle, nil } + +// PartitionHandle combines a handle and a PartitionID, used to location a row in partioned table. +// Now only used in global index. +// TODO: support PartitionHandle in HandleMap. +type PartitionHandle struct { + Handle + PartitionID int64 +} + +// NewPartitionHandle creates a PartitionHandle from a normal handle and a pid. +func NewPartitionHandle(pid int64, h Handle) PartitionHandle { + return PartitionHandle{ + Handle: h, + PartitionID: pid, + } +} + +// Equal implements the Handle interface. +func (ph PartitionHandle) Equal(h Handle) bool { + if ph2, ok := h.(PartitionHandle); ok { + return ph.PartitionID == ph2.PartitionID && ph.Handle.Equal(ph2.Handle) + } + return false +} + +// Compare implements the Handle interface. +func (ph PartitionHandle) Compare(h Handle) int { + if ph2, ok := h.(PartitionHandle); ok { + if ph.PartitionID < ph2.PartitionID { + return -1 + } + if ph.PartitionID > ph2.PartitionID { + return 1 + } + return ph.Handle.Compare(ph2.Handle) + } + panic("PartitonHandle compares to non-parition Handle") +} diff --git a/planner/core/find_best_task.go b/planner/core/find_best_task.go index 8919acda79fb7..2cb6483328955 100644 --- a/planner/core/find_best_task.go +++ b/planner/core/find_best_task.go @@ -1073,8 +1073,6 @@ func (is *PhysicalIndexScan) initSchema(idxExprCols []*expression.Column, isDoub for i := len(is.Index.Columns); i < len(idxExprCols); i++ { indexCols = append(indexCols, idxExprCols[i]) } - is.SetSchema(expression.NewSchema(indexCols...)) - return } setHandle := len(indexCols) > len(is.Index.Columns) if !setHandle { @@ -1086,13 +1084,24 @@ func (is *PhysicalIndexScan) initSchema(idxExprCols []*expression.Column, isDoub } } } - // If it's double read case, the first index must return handle. So we should add extra handle column - // if there isn't a handle column. - if isDoubleRead && !setHandle { - if !is.Table.IsCommonHandle { + + if isDoubleRead { + // If it's double read case, the first index must return handle. So we should add extra handle column + // if there isn't a handle column. + if !setHandle { + if !is.Table.IsCommonHandle { + indexCols = append(indexCols, &expression.Column{ + RetType: types.NewFieldType(mysql.TypeLonglong), + ID: model.ExtraHandleID, + UniqueID: is.ctx.GetSessionVars().AllocPlanColumnID(), + }) + } + } + // If index is global, we should add extra column for pid. + if is.Index.Global { indexCols = append(indexCols, &expression.Column{ RetType: types.NewFieldType(mysql.TypeLonglong), - ID: model.ExtraHandleID, + ID: model.ExtraPidColID, UniqueID: is.ctx.GetSessionVars().AllocPlanColumnID(), }) } diff --git a/planner/core/plan_to_pb.go b/planner/core/plan_to_pb.go index bccaacce3aa22..5e6a2b948db1b 100644 --- a/planner/core/plan_to_pb.go +++ b/planner/core/plan_to_pb.go @@ -202,6 +202,8 @@ func (p *PhysicalIndexScan) ToPB(ctx sessionctx.Context, _ kv.StoreType) (*tipb. for _, col := range p.schema.Columns { if col.ID == model.ExtraHandleID { columns = append(columns, model.NewExtraHandleColInfo()) + } else if col.ID == model.ExtraPidColID { + columns = append(columns, model.NewExtraPartitionIDColInfo()) } else { columns = append(columns, findColumnInfoByID(tableColumns, col.ID)) } diff --git a/store/mockstore/unistore/cophandler/closure_exec.go b/store/mockstore/unistore/cophandler/closure_exec.go index e0d72ed421ef7..60b4f4e617f91 100644 --- a/store/mockstore/unistore/cophandler/closure_exec.go +++ b/store/mockstore/unistore/cophandler/closure_exec.go @@ -168,8 +168,11 @@ func (e *closureExecutor) initIdxScanCtx(idxScan *tipb.IndexScan) { e.idxScanCtx.pkStatus = pkColNotExists e.idxScanCtx.primaryColumnIds = idxScan.PrimaryColumnIds - lastColumn := e.columnInfos[len(e.columnInfos)-1] + if lastColumn.GetColumnId() == model.ExtraPidColID { + lastColumn = e.columnInfos[len(e.columnInfos)-2] + e.idxScanCtx.columnLen-- + } if len(e.idxScanCtx.primaryColumnIds) == 0 { if lastColumn.GetPkHandle() {