github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/optimizer/plan/range.go (about)

     1  // Copyright 2015 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package plan
    15  
    16  import (
    17  	"fmt"
    18  	"math"
    19  	"sort"
    20  
    21  	"github.com/insionng/yougam/libraries/juju/errors"
    22  	"github.com/insionng/yougam/libraries/pingcap/tidb/ast"
    23  	"github.com/insionng/yougam/libraries/pingcap/tidb/parser/opcode"
    24  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/types"
    25  )
    26  
    27  type rangePoint struct {
    28  	value types.Datum
    29  	excl  bool // exclude
    30  	start bool
    31  }
    32  
    33  func (rp rangePoint) String() string {
    34  	val := rp.value.GetValue()
    35  	if rp.value.Kind() == types.KindMinNotNull {
    36  		val = "-inf"
    37  	} else if rp.value.Kind() == types.KindMaxValue {
    38  		val = "+inf"
    39  	}
    40  	if rp.start {
    41  		symbol := "["
    42  		if rp.excl {
    43  			symbol = "("
    44  		}
    45  		return fmt.Sprintf("%s%v", symbol, val)
    46  	}
    47  	symbol := "]"
    48  	if rp.excl {
    49  		symbol = ")"
    50  	}
    51  	return fmt.Sprintf("%v%s", val, symbol)
    52  }
    53  
    54  type rangePointSorter struct {
    55  	points []rangePoint
    56  	err    error
    57  }
    58  
    59  func (r *rangePointSorter) Len() int {
    60  	return len(r.points)
    61  }
    62  
    63  func (r *rangePointSorter) Less(i, j int) bool {
    64  	a := r.points[i]
    65  	b := r.points[j]
    66  	cmp, err := a.value.CompareDatum(b.value)
    67  	if err != nil {
    68  		r.err = err
    69  		return true
    70  	}
    71  	if cmp == 0 {
    72  		return r.equalValueLess(a, b)
    73  	}
    74  	return cmp < 0
    75  }
    76  
    77  func (r *rangePointSorter) equalValueLess(a, b rangePoint) bool {
    78  	if a.start && b.start {
    79  		return !a.excl && b.excl
    80  	} else if a.start {
    81  		return !b.excl
    82  	} else if b.start {
    83  		return a.excl || b.excl
    84  	}
    85  	return a.excl && !b.excl
    86  }
    87  
    88  func (r *rangePointSorter) Swap(i, j int) {
    89  	r.points[i], r.points[j] = r.points[j], r.points[i]
    90  }
    91  
    92  type rangeBuilder struct {
    93  	err error
    94  }
    95  
    96  func (r *rangeBuilder) build(expr ast.ExprNode) []rangePoint {
    97  	switch x := expr.(type) {
    98  	case *ast.BinaryOperationExpr:
    99  		return r.buildFromBinop(x)
   100  	case *ast.PatternInExpr:
   101  		return r.buildFromIn(x)
   102  	case *ast.ParenthesesExpr:
   103  		return r.build(x.Expr)
   104  	case *ast.BetweenExpr:
   105  		return r.buildFromBetween(x)
   106  	case *ast.IsNullExpr:
   107  		return r.buildFromIsNull(x)
   108  	case *ast.IsTruthExpr:
   109  		return r.buildFromIsTruth(x)
   110  	case *ast.PatternLikeExpr:
   111  		rans := r.buildFromPatternLike(x)
   112  		return rans
   113  	case *ast.ColumnNameExpr:
   114  		return r.buildFromColumnName(x)
   115  	}
   116  	return fullRange
   117  }
   118  
   119  func (r *rangeBuilder) buildFromBinop(x *ast.BinaryOperationExpr) []rangePoint {
   120  	if x.Op == opcode.OrOr {
   121  		return r.union(r.build(x.L), r.build(x.R))
   122  	} else if x.Op == opcode.AndAnd {
   123  		return r.intersection(r.build(x.L), r.build(x.R))
   124  	}
   125  	// This has been checked that the binary operation is comparison operation, and one of
   126  	// the operand is column name expression.
   127  	var value types.Datum
   128  	var op opcode.Op
   129  	if _, ok := x.L.(*ast.ValueExpr); ok {
   130  		value = types.NewDatum(x.L.GetValue())
   131  		switch x.Op {
   132  		case opcode.GE:
   133  			op = opcode.LE
   134  		case opcode.GT:
   135  			op = opcode.LT
   136  		case opcode.LT:
   137  			op = opcode.GT
   138  		case opcode.LE:
   139  			op = opcode.GE
   140  		default:
   141  			op = x.Op
   142  		}
   143  	} else {
   144  		value = types.NewDatum(x.R.GetValue())
   145  		op = x.Op
   146  	}
   147  	if value.Kind() == types.KindNull {
   148  		return nil
   149  	}
   150  	switch op {
   151  	case opcode.EQ:
   152  		startPoint := rangePoint{value: value, start: true}
   153  		endPoint := rangePoint{value: value}
   154  		return []rangePoint{startPoint, endPoint}
   155  	case opcode.NE:
   156  		startPoint1 := rangePoint{value: types.MinNotNullDatum(), start: true}
   157  		endPoint1 := rangePoint{value: value, excl: true}
   158  		startPoint2 := rangePoint{value: value, start: true, excl: true}
   159  		endPoint2 := rangePoint{value: types.MaxValueDatum()}
   160  		return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2}
   161  	case opcode.LT:
   162  		startPoint := rangePoint{value: types.MinNotNullDatum(), start: true}
   163  		endPoint := rangePoint{value: value, excl: true}
   164  		return []rangePoint{startPoint, endPoint}
   165  	case opcode.LE:
   166  		startPoint := rangePoint{value: types.MinNotNullDatum(), start: true}
   167  		endPoint := rangePoint{value: value}
   168  		return []rangePoint{startPoint, endPoint}
   169  	case opcode.GT:
   170  		startPoint := rangePoint{value: value, start: true, excl: true}
   171  		endPoint := rangePoint{value: types.MaxValueDatum()}
   172  		return []rangePoint{startPoint, endPoint}
   173  	case opcode.GE:
   174  		startPoint := rangePoint{value: value, start: true}
   175  		endPoint := rangePoint{value: types.MaxValueDatum()}
   176  		return []rangePoint{startPoint, endPoint}
   177  	}
   178  	return nil
   179  }
   180  
   181  func (r *rangeBuilder) buildFromIn(x *ast.PatternInExpr) []rangePoint {
   182  	if x.Not {
   183  		r.err = ErrUnsupportedType.Gen("NOT IN is not supported")
   184  		return fullRange
   185  	}
   186  	var rangePoints []rangePoint
   187  	for _, v := range x.List {
   188  		startPoint := rangePoint{value: types.NewDatum(v.GetValue()), start: true}
   189  		endPoint := rangePoint{value: types.NewDatum(v.GetValue())}
   190  		rangePoints = append(rangePoints, startPoint, endPoint)
   191  	}
   192  	sorter := rangePointSorter{points: rangePoints}
   193  	sort.Sort(&sorter)
   194  	if sorter.err != nil {
   195  		r.err = sorter.err
   196  	}
   197  	// check duplicates
   198  	hasDuplicate := false
   199  	isStart := false
   200  	for _, v := range rangePoints {
   201  		if isStart == v.start {
   202  			hasDuplicate = true
   203  			break
   204  		}
   205  		isStart = v.start
   206  	}
   207  	if !hasDuplicate {
   208  		return rangePoints
   209  	}
   210  	// remove duplicates
   211  	distinctRangePoints := make([]rangePoint, 0, len(rangePoints))
   212  	isStart = false
   213  	for i := 0; i < len(rangePoints); i++ {
   214  		current := rangePoints[i]
   215  		if isStart == current.start {
   216  			continue
   217  		}
   218  		distinctRangePoints = append(distinctRangePoints, current)
   219  		isStart = current.start
   220  	}
   221  	return distinctRangePoints
   222  }
   223  
   224  func (r *rangeBuilder) buildFromBetween(x *ast.BetweenExpr) []rangePoint {
   225  	if x.Not {
   226  		binop1 := &ast.BinaryOperationExpr{Op: opcode.LT, L: x.Expr, R: x.Left}
   227  		binop2 := &ast.BinaryOperationExpr{Op: opcode.GT, L: x.Expr, R: x.Right}
   228  		range1 := r.buildFromBinop(binop1)
   229  		range2 := r.buildFromBinop(binop2)
   230  		return r.union(range1, range2)
   231  	}
   232  	binop1 := &ast.BinaryOperationExpr{Op: opcode.GE, L: x.Expr, R: x.Left}
   233  	binop2 := &ast.BinaryOperationExpr{Op: opcode.LE, L: x.Expr, R: x.Right}
   234  	range1 := r.buildFromBinop(binop1)
   235  	range2 := r.buildFromBinop(binop2)
   236  	return r.intersection(range1, range2)
   237  }
   238  
   239  func (r *rangeBuilder) buildFromIsNull(x *ast.IsNullExpr) []rangePoint {
   240  	if x.Not {
   241  		startPoint := rangePoint{value: types.MinNotNullDatum(), start: true}
   242  		endPoint := rangePoint{value: types.MaxValueDatum()}
   243  		return []rangePoint{startPoint, endPoint}
   244  	}
   245  	startPoint := rangePoint{start: true}
   246  	endPoint := rangePoint{}
   247  	return []rangePoint{startPoint, endPoint}
   248  }
   249  
   250  func (r *rangeBuilder) buildFromIsTruth(x *ast.IsTruthExpr) []rangePoint {
   251  	if x.True != 0 {
   252  		if x.Not {
   253  			// NOT TRUE range is {[null null] [0, 0]}
   254  			startPoint1 := rangePoint{start: true}
   255  			endPoint1 := rangePoint{}
   256  			startPoint2 := rangePoint{start: true}
   257  			startPoint2.value.SetInt64(0)
   258  			endPoint2 := rangePoint{}
   259  			endPoint2.value.SetInt64(0)
   260  			return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2}
   261  		}
   262  		// TRUE range is {[-inf 0) (0 +inf]}
   263  		startPoint1 := rangePoint{value: types.MinNotNullDatum(), start: true}
   264  		endPoint1 := rangePoint{excl: true}
   265  		endPoint1.value.SetInt64(0)
   266  		startPoint2 := rangePoint{excl: true, start: true}
   267  		startPoint2.value.SetInt64(0)
   268  		endPoint2 := rangePoint{value: types.MaxValueDatum()}
   269  		return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2}
   270  	}
   271  	if x.Not {
   272  		startPoint1 := rangePoint{start: true}
   273  		endPoint1 := rangePoint{excl: true}
   274  		endPoint1.value.SetInt64(0)
   275  		startPoint2 := rangePoint{start: true, excl: true}
   276  		startPoint2.value.SetInt64(0)
   277  		endPoint2 := rangePoint{value: types.MaxValueDatum()}
   278  		return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2}
   279  	}
   280  	startPoint := rangePoint{start: true}
   281  	startPoint.value.SetInt64(0)
   282  	endPoint := rangePoint{}
   283  	endPoint.value.SetInt64(0)
   284  	return []rangePoint{startPoint, endPoint}
   285  }
   286  
   287  func (r *rangeBuilder) buildFromPatternLike(x *ast.PatternLikeExpr) []rangePoint {
   288  	if x.Not {
   289  		// Pattern not like is not supported.
   290  		r.err = ErrUnsupportedType.Gen("NOT LIKE is not supported.")
   291  		return fullRange
   292  	}
   293  	pattern, err := types.ToString(x.Pattern.GetValue())
   294  	if err != nil {
   295  		r.err = errors.Trace(err)
   296  		return fullRange
   297  	}
   298  	lowValue := make([]byte, 0, len(pattern))
   299  	// unscape the pattern
   300  	var exclude bool
   301  	for i := 0; i < len(pattern); i++ {
   302  		if pattern[i] == x.Escape {
   303  			i++
   304  			if i < len(pattern) {
   305  				lowValue = append(lowValue, pattern[i])
   306  			} else {
   307  				lowValue = append(lowValue, x.Escape)
   308  			}
   309  			continue
   310  		}
   311  		if pattern[i] == '%' {
   312  			break
   313  		} else if pattern[i] == '_' {
   314  			exclude = true
   315  			break
   316  		}
   317  		lowValue = append(lowValue, pattern[i])
   318  	}
   319  	if len(lowValue) == 0 {
   320  		return []rangePoint{{value: types.MinNotNullDatum(), start: true}, {value: types.MaxValueDatum()}}
   321  	}
   322  	startPoint := rangePoint{start: true, excl: exclude}
   323  	startPoint.value.SetBytesAsString(lowValue)
   324  	highValue := make([]byte, len(lowValue))
   325  	copy(highValue, lowValue)
   326  	endPoint := rangePoint{excl: true}
   327  	for i := len(highValue) - 1; i >= 0; i-- {
   328  		highValue[i]++
   329  		if highValue[i] != 0 {
   330  			endPoint.value.SetBytesAsString(highValue)
   331  			break
   332  		}
   333  		if i == 0 {
   334  			endPoint.value = types.MaxValueDatum()
   335  			break
   336  		}
   337  	}
   338  	ranges := make([]rangePoint, 2)
   339  	ranges[0] = startPoint
   340  	ranges[1] = endPoint
   341  	return ranges
   342  }
   343  
   344  func (r *rangeBuilder) buildFromColumnName(x *ast.ColumnNameExpr) []rangePoint {
   345  	// column name expression is equivalent to column name is true.
   346  	startPoint1 := rangePoint{value: types.MinNotNullDatum(), start: true}
   347  	endPoint1 := rangePoint{excl: true}
   348  	endPoint1.value.SetInt64(0)
   349  	startPoint2 := rangePoint{excl: true, start: true}
   350  	startPoint2.value.SetInt64(0)
   351  	endPoint2 := rangePoint{value: types.MaxValueDatum()}
   352  	return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2}
   353  }
   354  
   355  func (r *rangeBuilder) intersection(a, b []rangePoint) []rangePoint {
   356  	return r.merge(a, b, false)
   357  }
   358  
   359  func (r *rangeBuilder) union(a, b []rangePoint) []rangePoint {
   360  	return r.merge(a, b, true)
   361  }
   362  
   363  func (r *rangeBuilder) merge(a, b []rangePoint, union bool) []rangePoint {
   364  	sorter := rangePointSorter{points: append(a, b...)}
   365  	sort.Sort(&sorter)
   366  	if sorter.err != nil {
   367  		r.err = sorter.err
   368  		return nil
   369  	}
   370  	var (
   371  		merged               []rangePoint
   372  		inRangeCount         int
   373  		requiredInRangeCount int
   374  	)
   375  	if union {
   376  		requiredInRangeCount = 1
   377  	} else {
   378  		requiredInRangeCount = 2
   379  	}
   380  	for _, val := range sorter.points {
   381  		if val.start {
   382  			inRangeCount++
   383  			if inRangeCount == requiredInRangeCount {
   384  				// just reached the required in range count, a new range started.
   385  				merged = append(merged, val)
   386  			}
   387  		} else {
   388  			if inRangeCount == requiredInRangeCount {
   389  				// just about to leave the required in range count, the range is ended.
   390  				merged = append(merged, val)
   391  			}
   392  			inRangeCount--
   393  		}
   394  	}
   395  	return merged
   396  }
   397  
   398  // buildIndexRanges build index ranges from range points.
   399  // Only the first column in the index is built, extra column ranges will be appended by
   400  // appendIndexRanges.
   401  func (r *rangeBuilder) buildIndexRanges(rangePoints []rangePoint) []*IndexRange {
   402  	indexRanges := make([]*IndexRange, 0, len(rangePoints)/2)
   403  	for i := 0; i < len(rangePoints); i += 2 {
   404  		startPoint := rangePoints[i]
   405  		endPoint := rangePoints[i+1]
   406  		ir := &IndexRange{
   407  			LowVal:      []types.Datum{startPoint.value},
   408  			LowExclude:  startPoint.excl,
   409  			HighVal:     []types.Datum{endPoint.value},
   410  			HighExclude: endPoint.excl,
   411  		}
   412  		indexRanges = append(indexRanges, ir)
   413  	}
   414  	return indexRanges
   415  }
   416  
   417  // appendIndexRanges appends additional column ranges for multi-column index.
   418  // The additional column ranges can only be appended to point ranges.
   419  // for example we have an index (a, b), if the condition is (a > 1 and b = 2)
   420  // then we can not build a conjunctive ranges for this index.
   421  func (r *rangeBuilder) appendIndexRanges(origin []*IndexRange, rangePoints []rangePoint) []*IndexRange {
   422  	var newIndexRanges []*IndexRange
   423  	for i := 0; i < len(origin); i++ {
   424  		oRange := origin[i]
   425  		if !oRange.IsPoint() {
   426  			newIndexRanges = append(newIndexRanges, oRange)
   427  		} else {
   428  			newIndexRanges = append(newIndexRanges, r.appendIndexRange(oRange, rangePoints)...)
   429  		}
   430  	}
   431  	return newIndexRanges
   432  }
   433  
   434  func (r *rangeBuilder) appendIndexRange(origin *IndexRange, rangePoints []rangePoint) []*IndexRange {
   435  	newRanges := make([]*IndexRange, 0, len(rangePoints)/2)
   436  	for i := 0; i < len(rangePoints); i += 2 {
   437  		startPoint := rangePoints[i]
   438  		lowVal := make([]types.Datum, len(origin.LowVal)+1)
   439  		copy(lowVal, origin.LowVal)
   440  		lowVal[len(origin.LowVal)] = startPoint.value
   441  
   442  		endPoint := rangePoints[i+1]
   443  		highVal := make([]types.Datum, len(origin.HighVal)+1)
   444  		copy(highVal, origin.HighVal)
   445  		highVal[len(origin.HighVal)] = endPoint.value
   446  
   447  		ir := &IndexRange{
   448  			LowVal:      lowVal,
   449  			LowExclude:  startPoint.excl,
   450  			HighVal:     highVal,
   451  			HighExclude: endPoint.excl,
   452  		}
   453  		newRanges = append(newRanges, ir)
   454  	}
   455  	return newRanges
   456  }
   457  
   458  func (r *rangeBuilder) buildTableRanges(rangePoints []rangePoint) []TableRange {
   459  	tableRanges := make([]TableRange, 0, len(rangePoints)/2)
   460  	for i := 0; i < len(rangePoints); i += 2 {
   461  		startPoint := rangePoints[i]
   462  		if startPoint.value.Kind() == types.KindNull || startPoint.value.Kind() == types.KindMinNotNull {
   463  			startPoint.value.SetInt64(math.MinInt64)
   464  		}
   465  		startInt, err := types.ToInt64(startPoint.value.GetValue())
   466  		if err != nil {
   467  			r.err = errors.Trace(err)
   468  			return tableRanges
   469  		}
   470  		startDatum := types.NewDatum(startInt)
   471  		cmp, err := startDatum.CompareDatum(startPoint.value)
   472  		if err != nil {
   473  			r.err = errors.Trace(err)
   474  			return tableRanges
   475  		}
   476  		if cmp < 0 || (cmp == 0 && startPoint.excl) {
   477  			startInt++
   478  		}
   479  		endPoint := rangePoints[i+1]
   480  		if endPoint.value.Kind() == types.KindNull {
   481  			endPoint.value.SetInt64(math.MinInt64)
   482  		} else if endPoint.value.Kind() == types.KindMaxValue {
   483  			endPoint.value.SetInt64(math.MaxInt64)
   484  		}
   485  		endInt, err := types.ToInt64(endPoint.value.GetValue())
   486  		if err != nil {
   487  			r.err = errors.Trace(err)
   488  			return tableRanges
   489  		}
   490  		endDatum := types.NewDatum(endInt)
   491  		cmp, err = endDatum.CompareDatum(endPoint.value)
   492  		if err != nil {
   493  			r.err = errors.Trace(err)
   494  			return tableRanges
   495  		}
   496  		if cmp > 0 || (cmp == 0 && endPoint.excl) {
   497  			endInt--
   498  		}
   499  		if startInt > endInt {
   500  			continue
   501  		}
   502  		tableRanges = append(tableRanges, TableRange{LowVal: startInt, HighVal: endInt})
   503  	}
   504  	return tableRanges
   505  }