func (conv *Conv) SampleBadRows(n int) []string {
	var l []string
	for _, x := range conv.sampleBadRows.rows {
		l = append(l, fmt.Sprintf("table=%s cols=%v data=%v\n", x.table, x.cols, x.vals))
		if len(l) > n {
			break
		}
	}
	return l
}
SampleBadRows returns a string-formatted list of rows that generated errors.
Returns at most n rows.
package internal
import (
	"fmt"
	"time"
	"github.com/cloudspannerecosystem/harbourbridge/schema"
	"github.com/cloudspannerecosystem/harbourbridge/spanner/ddl"
)
type Conv struct {
	mode           mode                                 
	SpSchema       ddl.Schema                           
	SyntheticPKeys map[string]SyntheticPKey             
	SrcSchema      map[string]schema.Table              
	Issues         map[string]map[string][]SchemaIssue  
	ToSpanner      map[string]NameAndCols               
	ToSource       map[string]NameAndCols               
	UsedNames      map[string]bool                      
	dataSink       func(table string, cols []string, values []interface{})
	Location       *time.Location  
	sampleBadRows  rowSamples      
	Stats          stats
	TimezoneOffset string  
	TargetDb       string  
}
type mode int
const (
	schemaOnly mode = iota
	dataOnly
)
type SyntheticPKey struct {
	Col      string
	Sequence int64
}
type SchemaIssue int
const (
	DefaultValue SchemaIssue = iota
	ForeignKey
	MissingPrimaryKey
	MultiDimensionalArray
	NoGoodType
	Numeric
	NumericThatFits
	Decimal
	DecimalThatFits
	Serial
	AutoIncrement
	Timestamp
	Datetime
	Widened
	Time
)
type NameAndCols struct {
	Name string
	Cols map[string]string
}
type rowSamples struct {
	rows       []*row
	bytes      int64  
	bytesLimit int64  
}
type row struct {
	table string
	cols  []string
	vals  []string
}
type stats struct {
	Rows       map[string]int64           
	GoodRows   map[string]int64           
	BadRows    map[string]int64           
	Statement  map[string]*statementStat  
	Unexpected map[string]int64           
	Reparsed   int64                      
}
type statementStat struct {
	Schema int64
	Data   int64
	Skip   int64
	Error  int64
}
func MakeConv() *Conv {
	return &Conv{
		SpSchema:       ddl.NewSchema(),
		SyntheticPKeys: make(map[string]SyntheticPKey),
		SrcSchema:      make(map[string]schema.Table),
		Issues:         make(map[string]map[string][]SchemaIssue),
		ToSpanner:      make(map[string]NameAndCols),
		ToSource:       make(map[string]NameAndCols),
		UsedNames:      make(map[string]bool),
		Location:       time.Local,  
		sampleBadRows:  rowSamples{bytesLimit: 10 * 1000 * 1000},
		Stats: stats{
			Rows:       make(map[string]int64),
			GoodRows:   make(map[string]int64),
			BadRows:    make(map[string]int64),
			Statement:  make(map[string]*statementStat),
			Unexpected: make(map[string]int64),
		},
		TimezoneOffset: "+00:00",  
	}
}
func (conv *Conv) SetDataSink(ds func(table string, cols []string, values []interface{})) {
	conv.dataSink = ds
}
func (conv *Conv) SetSchemaMode() {
	conv.mode = schemaOnly
}
func (conv *Conv) SetDataMode() {
	conv.mode = dataOnly
}
func (conv *Conv) WriteRow(srcTable, spTable string, spCols []string, spVals []interface{}) {
	if conv.dataSink == nil {
		msg := "Internal error: ProcessDataRow called but dataSink not configured"
		VerbosePrintf("%s\n", msg)
		conv.Unexpected(msg)
		conv.StatsAddBadRow(srcTable, conv.DataMode())
	} else {
		conv.dataSink(spTable, spCols, spVals)
		conv.statsAddGoodRow(srcTable, conv.DataMode())
	}
}
func (conv *Conv) Rows() int64 {
	n := int64(0)
	for _, c := range conv.Stats.Rows {
		n += c
	}
	return n
}
func (conv *Conv) BadRows() int64 {
	n := int64(0)
	for _, c := range conv.Stats.BadRows {
		n += c
	}
	return n
}
func (conv *Conv) Statements() int64 {
	n := int64(0)
	for _, x := range conv.Stats.Statement {
		n += x.Schema + x.Data + x.Skip + x.Error
	}
	return n
}
func (conv *Conv) StatementErrors() int64 {
	n := int64(0)
	for _, x := range conv.Stats.Statement {
		n += x.Error
	}
	return n
}
func (conv *Conv) Unexpecteds() int64 {
	return int64(len(conv.Stats.Unexpected))
}
func (conv *Conv) CollectBadRow(srcTable string, srcCols, vals []string) {
	r := &row{table: srcTable, cols: srcCols, vals: vals}
	bytes := byteSize(r)
	if len(conv.sampleBadRows.rows) == 0 || bytes+conv.sampleBadRows.bytes < conv.sampleBadRows.bytesLimit {
		conv.sampleBadRows.rows = append(conv.sampleBadRows.rows, r)
		conv.sampleBadRows.bytes += bytes
	}
}