forked from forgejo/forgejo
Integrate public as bindata optionally (#293)
* Dropped unused codekit config * Integrated dynamic and static bindata for public * Ignore public bindata * Add a general generate make task * Integrated flexible public assets into web command * Updated vendoring, added all missiong govendor deps * Made the linter happy with the bindata and dynamic code * Moved public bindata definition to modules directory * Ignoring the new bindata path now * Updated to the new public modules import path * Updated public bindata command and drop the new prefix
This commit is contained in:
parent
4680c349dd
commit
b6a95a8cb3
691 changed files with 305318 additions and 1272 deletions
505
vendor/github.com/pingcap/tidb/optimizer/plan/range.go
generated
vendored
Normal file
505
vendor/github.com/pingcap/tidb/optimizer/plan/range.go
generated
vendored
Normal file
|
@ -0,0 +1,505 @@
|
|||
// Copyright 2015 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,
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package plan
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
"github.com/juju/errors"
|
||||
"github.com/pingcap/tidb/ast"
|
||||
"github.com/pingcap/tidb/parser/opcode"
|
||||
"github.com/pingcap/tidb/util/types"
|
||||
)
|
||||
|
||||
type rangePoint struct {
|
||||
value types.Datum
|
||||
excl bool // exclude
|
||||
start bool
|
||||
}
|
||||
|
||||
func (rp rangePoint) String() string {
|
||||
val := rp.value.GetValue()
|
||||
if rp.value.Kind() == types.KindMinNotNull {
|
||||
val = "-inf"
|
||||
} else if rp.value.Kind() == types.KindMaxValue {
|
||||
val = "+inf"
|
||||
}
|
||||
if rp.start {
|
||||
symbol := "["
|
||||
if rp.excl {
|
||||
symbol = "("
|
||||
}
|
||||
return fmt.Sprintf("%s%v", symbol, val)
|
||||
}
|
||||
symbol := "]"
|
||||
if rp.excl {
|
||||
symbol = ")"
|
||||
}
|
||||
return fmt.Sprintf("%v%s", val, symbol)
|
||||
}
|
||||
|
||||
type rangePointSorter struct {
|
||||
points []rangePoint
|
||||
err error
|
||||
}
|
||||
|
||||
func (r *rangePointSorter) Len() int {
|
||||
return len(r.points)
|
||||
}
|
||||
|
||||
func (r *rangePointSorter) Less(i, j int) bool {
|
||||
a := r.points[i]
|
||||
b := r.points[j]
|
||||
cmp, err := a.value.CompareDatum(b.value)
|
||||
if err != nil {
|
||||
r.err = err
|
||||
return true
|
||||
}
|
||||
if cmp == 0 {
|
||||
return r.equalValueLess(a, b)
|
||||
}
|
||||
return cmp < 0
|
||||
}
|
||||
|
||||
func (r *rangePointSorter) equalValueLess(a, b rangePoint) bool {
|
||||
if a.start && b.start {
|
||||
return !a.excl && b.excl
|
||||
} else if a.start {
|
||||
return !b.excl
|
||||
} else if b.start {
|
||||
return a.excl || b.excl
|
||||
}
|
||||
return a.excl && !b.excl
|
||||
}
|
||||
|
||||
func (r *rangePointSorter) Swap(i, j int) {
|
||||
r.points[i], r.points[j] = r.points[j], r.points[i]
|
||||
}
|
||||
|
||||
type rangeBuilder struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (r *rangeBuilder) build(expr ast.ExprNode) []rangePoint {
|
||||
switch x := expr.(type) {
|
||||
case *ast.BinaryOperationExpr:
|
||||
return r.buildFromBinop(x)
|
||||
case *ast.PatternInExpr:
|
||||
return r.buildFromIn(x)
|
||||
case *ast.ParenthesesExpr:
|
||||
return r.build(x.Expr)
|
||||
case *ast.BetweenExpr:
|
||||
return r.buildFromBetween(x)
|
||||
case *ast.IsNullExpr:
|
||||
return r.buildFromIsNull(x)
|
||||
case *ast.IsTruthExpr:
|
||||
return r.buildFromIsTruth(x)
|
||||
case *ast.PatternLikeExpr:
|
||||
rans := r.buildFromPatternLike(x)
|
||||
return rans
|
||||
case *ast.ColumnNameExpr:
|
||||
return r.buildFromColumnName(x)
|
||||
}
|
||||
return fullRange
|
||||
}
|
||||
|
||||
func (r *rangeBuilder) buildFromBinop(x *ast.BinaryOperationExpr) []rangePoint {
|
||||
if x.Op == opcode.OrOr {
|
||||
return r.union(r.build(x.L), r.build(x.R))
|
||||
} else if x.Op == opcode.AndAnd {
|
||||
return r.intersection(r.build(x.L), r.build(x.R))
|
||||
}
|
||||
// This has been checked that the binary operation is comparison operation, and one of
|
||||
// the operand is column name expression.
|
||||
var value types.Datum
|
||||
var op opcode.Op
|
||||
if _, ok := x.L.(*ast.ValueExpr); ok {
|
||||
value = types.NewDatum(x.L.GetValue())
|
||||
switch x.Op {
|
||||
case opcode.GE:
|
||||
op = opcode.LE
|
||||
case opcode.GT:
|
||||
op = opcode.LT
|
||||
case opcode.LT:
|
||||
op = opcode.GT
|
||||
case opcode.LE:
|
||||
op = opcode.GE
|
||||
default:
|
||||
op = x.Op
|
||||
}
|
||||
} else {
|
||||
value = types.NewDatum(x.R.GetValue())
|
||||
op = x.Op
|
||||
}
|
||||
if value.Kind() == types.KindNull {
|
||||
return nil
|
||||
}
|
||||
switch op {
|
||||
case opcode.EQ:
|
||||
startPoint := rangePoint{value: value, start: true}
|
||||
endPoint := rangePoint{value: value}
|
||||
return []rangePoint{startPoint, endPoint}
|
||||
case opcode.NE:
|
||||
startPoint1 := rangePoint{value: types.MinNotNullDatum(), start: true}
|
||||
endPoint1 := rangePoint{value: value, excl: true}
|
||||
startPoint2 := rangePoint{value: value, start: true, excl: true}
|
||||
endPoint2 := rangePoint{value: types.MaxValueDatum()}
|
||||
return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2}
|
||||
case opcode.LT:
|
||||
startPoint := rangePoint{value: types.MinNotNullDatum(), start: true}
|
||||
endPoint := rangePoint{value: value, excl: true}
|
||||
return []rangePoint{startPoint, endPoint}
|
||||
case opcode.LE:
|
||||
startPoint := rangePoint{value: types.MinNotNullDatum(), start: true}
|
||||
endPoint := rangePoint{value: value}
|
||||
return []rangePoint{startPoint, endPoint}
|
||||
case opcode.GT:
|
||||
startPoint := rangePoint{value: value, start: true, excl: true}
|
||||
endPoint := rangePoint{value: types.MaxValueDatum()}
|
||||
return []rangePoint{startPoint, endPoint}
|
||||
case opcode.GE:
|
||||
startPoint := rangePoint{value: value, start: true}
|
||||
endPoint := rangePoint{value: types.MaxValueDatum()}
|
||||
return []rangePoint{startPoint, endPoint}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *rangeBuilder) buildFromIn(x *ast.PatternInExpr) []rangePoint {
|
||||
if x.Not {
|
||||
r.err = ErrUnsupportedType.Gen("NOT IN is not supported")
|
||||
return fullRange
|
||||
}
|
||||
var rangePoints []rangePoint
|
||||
for _, v := range x.List {
|
||||
startPoint := rangePoint{value: types.NewDatum(v.GetValue()), start: true}
|
||||
endPoint := rangePoint{value: types.NewDatum(v.GetValue())}
|
||||
rangePoints = append(rangePoints, startPoint, endPoint)
|
||||
}
|
||||
sorter := rangePointSorter{points: rangePoints}
|
||||
sort.Sort(&sorter)
|
||||
if sorter.err != nil {
|
||||
r.err = sorter.err
|
||||
}
|
||||
// check duplicates
|
||||
hasDuplicate := false
|
||||
isStart := false
|
||||
for _, v := range rangePoints {
|
||||
if isStart == v.start {
|
||||
hasDuplicate = true
|
||||
break
|
||||
}
|
||||
isStart = v.start
|
||||
}
|
||||
if !hasDuplicate {
|
||||
return rangePoints
|
||||
}
|
||||
// remove duplicates
|
||||
distinctRangePoints := make([]rangePoint, 0, len(rangePoints))
|
||||
isStart = false
|
||||
for i := 0; i < len(rangePoints); i++ {
|
||||
current := rangePoints[i]
|
||||
if isStart == current.start {
|
||||
continue
|
||||
}
|
||||
distinctRangePoints = append(distinctRangePoints, current)
|
||||
isStart = current.start
|
||||
}
|
||||
return distinctRangePoints
|
||||
}
|
||||
|
||||
func (r *rangeBuilder) buildFromBetween(x *ast.BetweenExpr) []rangePoint {
|
||||
if x.Not {
|
||||
binop1 := &ast.BinaryOperationExpr{Op: opcode.LT, L: x.Expr, R: x.Left}
|
||||
binop2 := &ast.BinaryOperationExpr{Op: opcode.GT, L: x.Expr, R: x.Right}
|
||||
range1 := r.buildFromBinop(binop1)
|
||||
range2 := r.buildFromBinop(binop2)
|
||||
return r.union(range1, range2)
|
||||
}
|
||||
binop1 := &ast.BinaryOperationExpr{Op: opcode.GE, L: x.Expr, R: x.Left}
|
||||
binop2 := &ast.BinaryOperationExpr{Op: opcode.LE, L: x.Expr, R: x.Right}
|
||||
range1 := r.buildFromBinop(binop1)
|
||||
range2 := r.buildFromBinop(binop2)
|
||||
return r.intersection(range1, range2)
|
||||
}
|
||||
|
||||
func (r *rangeBuilder) buildFromIsNull(x *ast.IsNullExpr) []rangePoint {
|
||||
if x.Not {
|
||||
startPoint := rangePoint{value: types.MinNotNullDatum(), start: true}
|
||||
endPoint := rangePoint{value: types.MaxValueDatum()}
|
||||
return []rangePoint{startPoint, endPoint}
|
||||
}
|
||||
startPoint := rangePoint{start: true}
|
||||
endPoint := rangePoint{}
|
||||
return []rangePoint{startPoint, endPoint}
|
||||
}
|
||||
|
||||
func (r *rangeBuilder) buildFromIsTruth(x *ast.IsTruthExpr) []rangePoint {
|
||||
if x.True != 0 {
|
||||
if x.Not {
|
||||
// NOT TRUE range is {[null null] [0, 0]}
|
||||
startPoint1 := rangePoint{start: true}
|
||||
endPoint1 := rangePoint{}
|
||||
startPoint2 := rangePoint{start: true}
|
||||
startPoint2.value.SetInt64(0)
|
||||
endPoint2 := rangePoint{}
|
||||
endPoint2.value.SetInt64(0)
|
||||
return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2}
|
||||
}
|
||||
// TRUE range is {[-inf 0) (0 +inf]}
|
||||
startPoint1 := rangePoint{value: types.MinNotNullDatum(), start: true}
|
||||
endPoint1 := rangePoint{excl: true}
|
||||
endPoint1.value.SetInt64(0)
|
||||
startPoint2 := rangePoint{excl: true, start: true}
|
||||
startPoint2.value.SetInt64(0)
|
||||
endPoint2 := rangePoint{value: types.MaxValueDatum()}
|
||||
return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2}
|
||||
}
|
||||
if x.Not {
|
||||
startPoint1 := rangePoint{start: true}
|
||||
endPoint1 := rangePoint{excl: true}
|
||||
endPoint1.value.SetInt64(0)
|
||||
startPoint2 := rangePoint{start: true, excl: true}
|
||||
startPoint2.value.SetInt64(0)
|
||||
endPoint2 := rangePoint{value: types.MaxValueDatum()}
|
||||
return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2}
|
||||
}
|
||||
startPoint := rangePoint{start: true}
|
||||
startPoint.value.SetInt64(0)
|
||||
endPoint := rangePoint{}
|
||||
endPoint.value.SetInt64(0)
|
||||
return []rangePoint{startPoint, endPoint}
|
||||
}
|
||||
|
||||
func (r *rangeBuilder) buildFromPatternLike(x *ast.PatternLikeExpr) []rangePoint {
|
||||
if x.Not {
|
||||
// Pattern not like is not supported.
|
||||
r.err = ErrUnsupportedType.Gen("NOT LIKE is not supported.")
|
||||
return fullRange
|
||||
}
|
||||
pattern, err := types.ToString(x.Pattern.GetValue())
|
||||
if err != nil {
|
||||
r.err = errors.Trace(err)
|
||||
return fullRange
|
||||
}
|
||||
lowValue := make([]byte, 0, len(pattern))
|
||||
// unscape the pattern
|
||||
var exclude bool
|
||||
for i := 0; i < len(pattern); i++ {
|
||||
if pattern[i] == x.Escape {
|
||||
i++
|
||||
if i < len(pattern) {
|
||||
lowValue = append(lowValue, pattern[i])
|
||||
} else {
|
||||
lowValue = append(lowValue, x.Escape)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if pattern[i] == '%' {
|
||||
break
|
||||
} else if pattern[i] == '_' {
|
||||
exclude = true
|
||||
break
|
||||
}
|
||||
lowValue = append(lowValue, pattern[i])
|
||||
}
|
||||
if len(lowValue) == 0 {
|
||||
return []rangePoint{{value: types.MinNotNullDatum(), start: true}, {value: types.MaxValueDatum()}}
|
||||
}
|
||||
startPoint := rangePoint{start: true, excl: exclude}
|
||||
startPoint.value.SetBytesAsString(lowValue)
|
||||
highValue := make([]byte, len(lowValue))
|
||||
copy(highValue, lowValue)
|
||||
endPoint := rangePoint{excl: true}
|
||||
for i := len(highValue) - 1; i >= 0; i-- {
|
||||
highValue[i]++
|
||||
if highValue[i] != 0 {
|
||||
endPoint.value.SetBytesAsString(highValue)
|
||||
break
|
||||
}
|
||||
if i == 0 {
|
||||
endPoint.value = types.MaxValueDatum()
|
||||
break
|
||||
}
|
||||
}
|
||||
ranges := make([]rangePoint, 2)
|
||||
ranges[0] = startPoint
|
||||
ranges[1] = endPoint
|
||||
return ranges
|
||||
}
|
||||
|
||||
func (r *rangeBuilder) buildFromColumnName(x *ast.ColumnNameExpr) []rangePoint {
|
||||
// column name expression is equivalent to column name is true.
|
||||
startPoint1 := rangePoint{value: types.MinNotNullDatum(), start: true}
|
||||
endPoint1 := rangePoint{excl: true}
|
||||
endPoint1.value.SetInt64(0)
|
||||
startPoint2 := rangePoint{excl: true, start: true}
|
||||
startPoint2.value.SetInt64(0)
|
||||
endPoint2 := rangePoint{value: types.MaxValueDatum()}
|
||||
return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2}
|
||||
}
|
||||
|
||||
func (r *rangeBuilder) intersection(a, b []rangePoint) []rangePoint {
|
||||
return r.merge(a, b, false)
|
||||
}
|
||||
|
||||
func (r *rangeBuilder) union(a, b []rangePoint) []rangePoint {
|
||||
return r.merge(a, b, true)
|
||||
}
|
||||
|
||||
func (r *rangeBuilder) merge(a, b []rangePoint, union bool) []rangePoint {
|
||||
sorter := rangePointSorter{points: append(a, b...)}
|
||||
sort.Sort(&sorter)
|
||||
if sorter.err != nil {
|
||||
r.err = sorter.err
|
||||
return nil
|
||||
}
|
||||
var (
|
||||
merged []rangePoint
|
||||
inRangeCount int
|
||||
requiredInRangeCount int
|
||||
)
|
||||
if union {
|
||||
requiredInRangeCount = 1
|
||||
} else {
|
||||
requiredInRangeCount = 2
|
||||
}
|
||||
for _, val := range sorter.points {
|
||||
if val.start {
|
||||
inRangeCount++
|
||||
if inRangeCount == requiredInRangeCount {
|
||||
// just reached the required in range count, a new range started.
|
||||
merged = append(merged, val)
|
||||
}
|
||||
} else {
|
||||
if inRangeCount == requiredInRangeCount {
|
||||
// just about to leave the required in range count, the range is ended.
|
||||
merged = append(merged, val)
|
||||
}
|
||||
inRangeCount--
|
||||
}
|
||||
}
|
||||
return merged
|
||||
}
|
||||
|
||||
// buildIndexRanges build index ranges from range points.
|
||||
// Only the first column in the index is built, extra column ranges will be appended by
|
||||
// appendIndexRanges.
|
||||
func (r *rangeBuilder) buildIndexRanges(rangePoints []rangePoint) []*IndexRange {
|
||||
indexRanges := make([]*IndexRange, 0, len(rangePoints)/2)
|
||||
for i := 0; i < len(rangePoints); i += 2 {
|
||||
startPoint := rangePoints[i]
|
||||
endPoint := rangePoints[i+1]
|
||||
ir := &IndexRange{
|
||||
LowVal: []types.Datum{startPoint.value},
|
||||
LowExclude: startPoint.excl,
|
||||
HighVal: []types.Datum{endPoint.value},
|
||||
HighExclude: endPoint.excl,
|
||||
}
|
||||
indexRanges = append(indexRanges, ir)
|
||||
}
|
||||
return indexRanges
|
||||
}
|
||||
|
||||
// appendIndexRanges appends additional column ranges for multi-column index.
|
||||
// The additional column ranges can only be appended to point ranges.
|
||||
// for example we have an index (a, b), if the condition is (a > 1 and b = 2)
|
||||
// then we can not build a conjunctive ranges for this index.
|
||||
func (r *rangeBuilder) appendIndexRanges(origin []*IndexRange, rangePoints []rangePoint) []*IndexRange {
|
||||
var newIndexRanges []*IndexRange
|
||||
for i := 0; i < len(origin); i++ {
|
||||
oRange := origin[i]
|
||||
if !oRange.IsPoint() {
|
||||
newIndexRanges = append(newIndexRanges, oRange)
|
||||
} else {
|
||||
newIndexRanges = append(newIndexRanges, r.appendIndexRange(oRange, rangePoints)...)
|
||||
}
|
||||
}
|
||||
return newIndexRanges
|
||||
}
|
||||
|
||||
func (r *rangeBuilder) appendIndexRange(origin *IndexRange, rangePoints []rangePoint) []*IndexRange {
|
||||
newRanges := make([]*IndexRange, 0, len(rangePoints)/2)
|
||||
for i := 0; i < len(rangePoints); i += 2 {
|
||||
startPoint := rangePoints[i]
|
||||
lowVal := make([]types.Datum, len(origin.LowVal)+1)
|
||||
copy(lowVal, origin.LowVal)
|
||||
lowVal[len(origin.LowVal)] = startPoint.value
|
||||
|
||||
endPoint := rangePoints[i+1]
|
||||
highVal := make([]types.Datum, len(origin.HighVal)+1)
|
||||
copy(highVal, origin.HighVal)
|
||||
highVal[len(origin.HighVal)] = endPoint.value
|
||||
|
||||
ir := &IndexRange{
|
||||
LowVal: lowVal,
|
||||
LowExclude: startPoint.excl,
|
||||
HighVal: highVal,
|
||||
HighExclude: endPoint.excl,
|
||||
}
|
||||
newRanges = append(newRanges, ir)
|
||||
}
|
||||
return newRanges
|
||||
}
|
||||
|
||||
func (r *rangeBuilder) buildTableRanges(rangePoints []rangePoint) []TableRange {
|
||||
tableRanges := make([]TableRange, 0, len(rangePoints)/2)
|
||||
for i := 0; i < len(rangePoints); i += 2 {
|
||||
startPoint := rangePoints[i]
|
||||
if startPoint.value.Kind() == types.KindNull || startPoint.value.Kind() == types.KindMinNotNull {
|
||||
startPoint.value.SetInt64(math.MinInt64)
|
||||
}
|
||||
startInt, err := types.ToInt64(startPoint.value.GetValue())
|
||||
if err != nil {
|
||||
r.err = errors.Trace(err)
|
||||
return tableRanges
|
||||
}
|
||||
startDatum := types.NewDatum(startInt)
|
||||
cmp, err := startDatum.CompareDatum(startPoint.value)
|
||||
if err != nil {
|
||||
r.err = errors.Trace(err)
|
||||
return tableRanges
|
||||
}
|
||||
if cmp < 0 || (cmp == 0 && startPoint.excl) {
|
||||
startInt++
|
||||
}
|
||||
endPoint := rangePoints[i+1]
|
||||
if endPoint.value.Kind() == types.KindNull {
|
||||
endPoint.value.SetInt64(math.MinInt64)
|
||||
} else if endPoint.value.Kind() == types.KindMaxValue {
|
||||
endPoint.value.SetInt64(math.MaxInt64)
|
||||
}
|
||||
endInt, err := types.ToInt64(endPoint.value.GetValue())
|
||||
if err != nil {
|
||||
r.err = errors.Trace(err)
|
||||
return tableRanges
|
||||
}
|
||||
endDatum := types.NewDatum(endInt)
|
||||
cmp, err = endDatum.CompareDatum(endPoint.value)
|
||||
if err != nil {
|
||||
r.err = errors.Trace(err)
|
||||
return tableRanges
|
||||
}
|
||||
if cmp > 0 || (cmp == 0 && endPoint.excl) {
|
||||
endInt--
|
||||
}
|
||||
if startInt > endInt {
|
||||
continue
|
||||
}
|
||||
tableRanges = append(tableRanges, TableRange{LowVal: startInt, HighVal: endInt})
|
||||
}
|
||||
return tableRanges
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue