Repository: pingcap/tidb
File: pkg/planner/core/stats.go (Go)

Code before:
}

// fixTiCIIndexRangesForIntHandle fixes the TiCI index ranges for int handle.
// For normal index range, its min value is NULL or the MinNotNull, and max value is MaxValue.
// But for TiCI index range which directly uses table's int pk range, we should set the min value to the min int value and max value to max int value.
// And unlike the normal index, the code converting the int pk's range to the final kv.KeyRange doesn't handle the NULL.
// So after calling the function of extract normal index ranges, we need to fix the ranges for TiCI index with int handle.
func fixTiCIIndexRangesForIntHandle(ranges []*ranger.Range, isUnsigned bool) []*ranger.Range {
	var minDatum, maxDatum types.Datum
	// isUnsigned indicates whether the handle is unsigned.
	// Now we just cast the unsigned int to int and then store the int value inside the Datum.
	// We wrap the uint64/int64 with Datum here to keep us untouched with Datum's internal representation.
	if isUnsigned {
		minDatum = types.NewUintDatum(0)
		maxDatum = types.NewUintDatum(math.MaxUint64)
	} else {
		minDatum = types.NewIntDatum(math.MinInt64)
		maxDatum = types.NewIntDatum(math.MaxInt64)
	}
	for i := len(ranges) - 1; i >= 0; i-- {
		ran := ranges[i]
		// Remove the [NULL, NULL] which is invalid when generating int handle's kv.KeyRange.
		if ran.HighVal[0].IsNull() {
			ranges = slices.Delete(ranges, i, i+1)
			continue
		}
		// Convert the min and max value to the int min/max value.
		if ran.LowVal[0].IsNull() || ran.LowVal[0].Kind() == types.KindMinNotNull {
			ran.LowVal[0].SetInt64(minDatum.GetInt64())
			ran.LowExclude = false
		}
		if ran.HighVal[0].Kind() == types.KindMaxValue {
			ran.HighVal[0].SetInt64(maxDatum.GetInt64())
		}
	}
	return ranges
}

func getGeneralAttributesFromPaths(paths []*util.AccessPath, totalRowCount float64) (float64, bool) {
	minSelectivity := 1.0
	indexForce := false
	for _, path := range paths {
		// For table path and index merge path, AccessPath.CountAfterIndex is not set and meaningless,
		// but we still consider their AccessPath.CountAfterAccess.
		if totalRowCount > 0 {
			if path.IsTablePath() || path.PartialIndexPaths != nil {
				minSelectivity = min(minSelectivity, path.CountAfterAccess/totalRowCount)
			} else {
				minSelectivity = min(minSelectivity, path.CountAfterIndex/totalRowCount)
			}
		}

Review comment (suggestion):
This is not about correctness.
Avoid potential display issue: `[0, -1]`.

Code after:
}

// fixTiCIIndexRangesForIntHandle fixes the TiCI index ranges for int handle.
// For normal index range, its min value is NULL or the MinNotNull, and max value is MaxValue.
// But for TiCI index range which directly uses table's int pk range, we should set the min value to the min int value and max value to max int value.
// And unlike the normal index, the code converting the int pk's range to the final kv.KeyRange doesn't handle the NULL.
// So after calling the function of extract normal index ranges, we need to fix the ranges for TiCI index with int handle.
func fixTiCIIndexRangesForIntHandle(ranges []*ranger.Range, isUnsigned bool) []*ranger.Range {
	// isUnsigned indicates whether the handle is unsigned.
	// Now we just cast the unsigned int to int and then store the int value inside the Datum.
	// We wrap the uint64/int64 with Datum here to keep us untouched with Datum's internal representation.
	var setMin, setMax func(ran *ranger.Range)
	if isUnsigned {
		setMin = func(ran *ranger.Range) {
			ran.LowVal[0].SetUint64(0)
		}
		setMax = func(ran *ranger.Range) {
			ran.HighVal[0].SetUint64(math.MaxUint64)
		}
	} else {
		setMin = func(ran *ranger.Range) {
			ran.LowVal[0].SetInt64(math.MinInt64)
		}
		setMax = func(ran *ranger.Range) {
			ran.HighVal[0].SetInt64(math.MaxInt64)
		}
	}
	for i := len(ranges) - 1; i >= 0; i-- {
		ran := ranges[i]
		// Remove the [NULL, NULL] which is invalid when generating int handle's kv.KeyRange.
		if ran.HighVal[0].IsNull() {
			ranges = slices.Delete(ranges, i, i+1)
			continue
		}
		// Convert the min and max value to the int min/max value.
		if ran.LowVal[0].IsNull() || ran.LowVal[0].Kind() == types.KindMinNotNull {
			setMin(ran)
			ran.LowExclude = false
		}
		if ran.HighVal[0].Kind() == types.KindMaxValue {
			setMax(ran)
		}
	}
	return ranges
}

func getGeneralAttributesFromPaths(paths []*util.AccessPath, totalRowCount float64) (float64, bool) {
	minSelectivity := 1.0
	indexForce := false
	for _, path := range paths {
		// For table path and index merge path, AccessPath.CountAfterIndex is not set and meaningless,