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

planner: make (*AccessPath).OnlyPointRange more succinct #30520

Merged
merged 7 commits into from
Dec 13, 2021
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
26 changes: 6 additions & 20 deletions planner/util/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,35 +151,21 @@ func isColEqCorColOrConstant(ctx sessionctx.Context, filter expression.Expressio

// OnlyPointRange checks whether each range is a point(no interval range exists).
func (path *AccessPath) OnlyPointRange(sctx sessionctx.Context) bool {
qw4990 marked this conversation as resolved.
Show resolved Hide resolved
noIntervalRange := true
if path.IsIntHandlePath {
for _, ran := range path.Ranges {
if !ran.IsPoint(sctx) {
noIntervalRange = false
break
if !ran.IsPointNullable(sctx.GetSessionVars().StmtCtx) {
return false
}
}
return noIntervalRange
return true
}
haveNullVal := false
for _, ran := range path.Ranges {
// Not point or the not full matched.
if !ran.IsPoint(sctx) || len(ran.HighVal) != len(path.Index.Columns) {
noIntervalRange = false
break
}
// Check whether there's null value.
for i := 0; i < len(path.Index.Columns); i++ {
if ran.HighVal[i].IsNull() {
haveNullVal = true
break
}
}
if haveNullVal {
break
if !ran.IsPointNonNullable(sctx) || len(ran.HighVal) != len(path.Index.Columns) {
return false
}
}
return noIntervalRange && !haveNullVal
return true
}

// Col2Len maps expression.Column.UniqueID to column length
Expand Down
74 changes: 58 additions & 16 deletions planner/util/path_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,61 +12,103 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package util
package util_test

import (
"testing"

"github.com/pingcap/tidb/parser/model"
"github.com/pingcap/tidb/planner/core"
"github.com/pingcap/tidb/planner/util"
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util/ranger"
"github.com/stretchr/testify/require"
)

func TestCompareCol2Len(t *testing.T) {
tests := []struct {
c1 Col2Len
c2 Col2Len
c1 util.Col2Len
c2 util.Col2Len
res int
comparable bool
}{
{
c1: Col2Len{1: -1, 2: -1, 3: -1},
c2: Col2Len{1: -1, 2: 10},
c1: util.Col2Len{1: -1, 2: -1, 3: -1},
c2: util.Col2Len{1: -1, 2: 10},
res: 1,
comparable: true,
},
{
c1: Col2Len{1: 5},
c2: Col2Len{1: 10, 2: -1},
c1: util.Col2Len{1: 5},
c2: util.Col2Len{1: 10, 2: -1},
res: -1,
comparable: true,
},
{
c1: Col2Len{1: -1, 2: -1},
c2: Col2Len{1: -1, 2: 5, 3: -1},
c1: util.Col2Len{1: -1, 2: -1},
c2: util.Col2Len{1: -1, 2: 5, 3: -1},
res: 0,
comparable: false,
},
{
c1: Col2Len{1: -1, 2: 10},
c2: Col2Len{1: -1, 2: 5, 3: -1},
c1: util.Col2Len{1: -1, 2: 10},
c2: util.Col2Len{1: -1, 2: 5, 3: -1},
res: 0,
comparable: false,
},
{
c1: Col2Len{1: -1, 2: 10},
c2: Col2Len{1: -1, 2: 10},
c1: util.Col2Len{1: -1, 2: 10},
c2: util.Col2Len{1: -1, 2: 10},
res: 0,
comparable: true,
},
{
c1: Col2Len{1: -1, 2: -1},
c2: Col2Len{1: -1, 2: 10},
c1: util.Col2Len{1: -1, 2: -1},
c2: util.Col2Len{1: -1, 2: 10},
res: 0,
comparable: false,
},
}
for _, tt := range tests {
res, comparable := CompareCol2Len(tt.c1, tt.c2)
res, comparable := util.CompareCol2Len(tt.c1, tt.c2)
require.Equal(t, tt.res, res)
require.Equal(t, tt.comparable, comparable)
}
}

func TestOnlyPointRange(t *testing.T) {
t.Parallel()
sctx := core.MockContext()
nullDatum := types.MinNotNullDatum()
nullDatum.SetNull()
nullPointRange := ranger.Range{
LowVal: []types.Datum{*nullDatum.Clone()},
HighVal: []types.Datum{*nullDatum.Clone()},
}
onePointRange := ranger.Range{
LowVal: []types.Datum{types.NewIntDatum(1)},
HighVal: []types.Datum{types.NewIntDatum(1)},
}
one2TwoRange := ranger.Range{
LowVal: []types.Datum{types.NewIntDatum(1)},
HighVal: []types.Datum{types.NewIntDatum(2)},
}

intHandlePath := &util.AccessPath{IsIntHandlePath: true}
intHandlePath.Ranges = []*ranger.Range{&nullPointRange, &onePointRange}
require.True(t, intHandlePath.OnlyPointRange(sctx))
intHandlePath.Ranges = []*ranger.Range{&onePointRange, &one2TwoRange}
require.False(t, intHandlePath.OnlyPointRange(sctx))

indexPath := &util.AccessPath{Index: &model.IndexInfo{Columns: make([]*model.IndexColumn, 1)}}
indexPath.Ranges = []*ranger.Range{&onePointRange}
require.True(t, indexPath.OnlyPointRange(sctx))
indexPath.Ranges = []*ranger.Range{&nullPointRange, &onePointRange}
require.False(t, indexPath.OnlyPointRange(sctx))
indexPath.Ranges = []*ranger.Range{&onePointRange, &one2TwoRange}
require.False(t, indexPath.OnlyPointRange(sctx))

indexPath.Index.Columns = make([]*model.IndexColumn, 2)
indexPath.Ranges = []*ranger.Range{&onePointRange}
require.False(t, indexPath.OnlyPointRange(sctx))
}