Repository: pingcap/tidb
File: pkg/statistics/sample.go (Go)

Code before:
	"github.com/pingcap/tidb/pkg/parser/terror"
	"github.com/pingcap/tidb/pkg/planner/core/resolve"
	"github.com/pingcap/tidb/pkg/sessionctx/stmtctx"
	"github.com/pingcap/tidb/pkg/tablecodec"
	"github.com/pingcap/tidb/pkg/types"
	"github.com/pingcap/tidb/pkg/util/chunk"
	"github.com/pingcap/tidb/pkg/util/collate"
	"github.com/pingcap/tidb/pkg/util/fastrand"
	"github.com/pingcap/tidb/pkg/util/sqlexec"
	"github.com/pingcap/tipb/go-tipb"
	"github.com/twmb/murmur3"
)

// SampleItem is an item of sampled column value.
type SampleItem struct {
	// Value is the sampled column value.
	Value *types.Datum
	// Handle is the handle of the sample in its key.
	// This property is used to calculate Ordinal in fast analyze.
	Handle kv.Handle
	// Ordinal is original position of this item in SampleCollector before sorting. This
	// is used for computing correlation.
	Ordinal int
}

// EmptySampleItemSize is the size of empty SampleItem, 32 = 8 (datum ptr) + 16(interface) + 8(int).
const EmptySampleItemSize = int64(unsafe.Sizeof(SampleItem{}))

// CopySampleItems returns a deep copy of SampleItem slice.
func CopySampleItems(items []*SampleItem) []*SampleItem {
	n := make([]*SampleItem, len(items))
	for i, item := range items {
		ni := *item
		n[i] = &ni
	}
	return n
}

func sortSampleItems(sc *stmtctx.StatementContext, items []*SampleItem) error {
	var err error
	slices.SortStableFunc(items, func(i, j *SampleItem) int {
		var cmp int
		cmp, err = i.Value.Compare(sc.TypeCtx(), j.Value, collate.GetBinaryCollator())
		if err != nil {
			return -1
		}
		return cmp
	})
	return err
}


Review comment (suggestion):
The comment states "32 = 8 (datum ptr) + 16(interface) + 8(int)" but the actual struct `SampleItem` has three fields: `Value *types.Datum` (8 bytes pointer), `Handle kv.Handle` (interface, which is typically 16 bytes), and `Ordinal int` (8 bytes). This adds up to 32 bytes, which is correct. However, the comment could be clearer by specifying which field corresponds to which size component, e.g., "32 = 8 (Value ptr) + 16 (Handle interface) + 8 (Ordinal int)".
```suggestion
// EmptySampleItemSize is the size of an empty SampleItem on 64-bit platforms: 32 = 8 (Value pointer) + 16 (Handle interface) + 8 (Ordinal int).
```

Code after:
	"github.com/pingcap/tidb/pkg/parser/terror"
	"github.com/pingcap/tidb/pkg/planner/core/resolve"
	"github.com/pingcap/tidb/pkg/sessionctx/stmtctx"
	"github.com/pingcap/tidb/pkg/tablecodec"
	"github.com/pingcap/tidb/pkg/types"
	"github.com/pingcap/tidb/pkg/util/chunk"
	"github.com/pingcap/tidb/pkg/util/collate"
	"github.com/pingcap/tidb/pkg/util/fastrand"
	"github.com/pingcap/tidb/pkg/util/intest"
	"github.com/pingcap/tidb/pkg/util/sqlexec"
	"github.com/pingcap/tipb/go-tipb"
	"github.com/twmb/murmur3"
)

// SampleItem is an item of sampled column value.
type SampleItem struct {
	// Value is the sampled column value.
	Value *types.Datum
	// Handle is the handle of the sample in its key.
	// This property is used to calculate Ordinal in fast analyze.
	Handle kv.Handle
	// Ordinal is original position of this item in SampleCollector before sorting. This
	// is used for computing correlation.
	Ordinal int
}

// EmptySampleItemSize is the size of an empty SampleItem on 64-bit platforms: 32 = 8 (Value pointer) + 16 (Handle interface) + 8 (Ordinal int).
const EmptySampleItemSize = int64(unsafe.Sizeof(SampleItem{}))

// CopySampleItems returns a deep copy of SampleItem slice.
func CopySampleItems(items []*SampleItem) []*SampleItem {
	n := make([]*SampleItem, len(items))
	for i, item := range items {
		ni := &SampleItem{
			Handle:  item.Handle,
			Ordinal: item.Ordinal,
		}
		if item.Value != nil {
			ni.Value = &types.Datum{}
			item.Value.Copy(ni.Value)
		}
		n[i] = ni
	}
	return n
}

func sortSampleItems(sc *stmtctx.StatementContext, items []*SampleItem) error {
	var err error
	if intest.InTest {
		for _, item := range items {
			if item.Value == nil {