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

Code before:
	"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 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 := *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
}

// SampleCollector will collect Samples and calculate the count and ndv of an attribute.
type SampleCollector struct {
	FMSketch      *FMSketch
	CMSketch      *CMSketch

Review comment (suggestion):
The comment claims this function returns a "deep copy" but it now performs a shallow copy of the Value pointers. After changing Value to a pointer type, multiple SampleItems will share the same underlying Datum. Update the comment to reflect that this is a shallow copy of the Value field, or implement true deep copying by also copying the Datum objects if needed.

Code after:
	"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 {
				return errors.Errorf("sample item value is nil")
			}
		}
	}