vitess.io/vitess@v0.16.2/go/mysql/binlog_event_rbr.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package mysql
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/binary"
    22  	"fmt"
    23  	"math"
    24  	"strconv"
    25  	"strings"
    26  	"time"
    27  
    28  	"vitess.io/vitess/go/sqltypes"
    29  	"vitess.io/vitess/go/vt/proto/vtrpc"
    30  	"vitess.io/vitess/go/vt/vterrors"
    31  
    32  	querypb "vitess.io/vitess/go/vt/proto/query"
    33  )
    34  
    35  // ZeroTimestamp is the special value 0 for a timestamp.
    36  var ZeroTimestamp = []byte("0000-00-00 00:00:00")
    37  
    38  // TableMap implements BinlogEvent.TableMap().
    39  //
    40  // Expected format (L = total length of event data):
    41  //
    42  //	# bytes   field
    43  //	4/6       table id
    44  //	2         flags
    45  //	1         schema name length sl
    46  //	sl        schema name
    47  //	1         [00]
    48  //	1         table name length tl
    49  //	tl        table name
    50  //	1         [00]
    51  //	<var>     column count cc (var-len encoded)
    52  //	cc        column-def, one byte per column
    53  //	<var>     column-meta-def (var-len encoded string)
    54  //	n         NULL-bitmask, length: (cc + 7) / 8
    55  func (ev binlogEvent) TableMap(f BinlogFormat) (*TableMap, error) {
    56  	data := ev.Bytes()[f.HeaderLength:]
    57  
    58  	result := &TableMap{}
    59  	pos := 6
    60  	if f.HeaderSize(eTableMapEvent) == 6 {
    61  		pos = 4
    62  	}
    63  	result.Flags = binary.LittleEndian.Uint16(data[pos : pos+2])
    64  	pos += 2
    65  
    66  	l := int(data[pos])
    67  	result.Database = string(data[pos+1 : pos+1+l])
    68  	pos += 1 + l + 1
    69  
    70  	l = int(data[pos])
    71  	result.Name = string(data[pos+1 : pos+1+l])
    72  	pos += 1 + l + 1
    73  
    74  	columnCount, read, ok := readLenEncInt(data, pos)
    75  	if !ok {
    76  		return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "expected column count at position %v (data=%v)", pos, data)
    77  	}
    78  	pos = read
    79  
    80  	result.Types = data[pos : pos+int(columnCount)]
    81  	pos += int(columnCount)
    82  
    83  	metaLen, read, ok := readLenEncInt(data, pos)
    84  	if !ok {
    85  		return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "expected metadata length at position %v (data=%v)", pos, data)
    86  	}
    87  	pos = read
    88  
    89  	// Allocate and parse / copy Metadata.
    90  	result.Metadata = make([]uint16, columnCount)
    91  	expectedEnd := pos + int(metaLen)
    92  	for c := uint64(0); c < columnCount; c++ {
    93  		var err error
    94  		result.Metadata[c], pos, err = metadataRead(data, pos, result.Types[c])
    95  		if err != nil {
    96  			return nil, err
    97  		}
    98  	}
    99  	if pos != expectedEnd {
   100  		return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected metadata end: got %v was expecting %v (data=%v)", pos, expectedEnd, data)
   101  	}
   102  
   103  	// A bit array that says if each column can be NULL.
   104  	result.CanBeNull, _ = newBitmap(data, pos, int(columnCount))
   105  
   106  	return result, nil
   107  }
   108  
   109  // metadataLength returns how many bytes are used for metadata, based on a type.
   110  func metadataLength(typ byte) int {
   111  	switch typ {
   112  	case TypeDecimal, TypeTiny, TypeShort, TypeLong, TypeNull, TypeTimestamp, TypeLongLong, TypeInt24, TypeDate, TypeTime, TypeDateTime, TypeYear, TypeNewDate:
   113  		// No data here.
   114  		return 0
   115  
   116  	case TypeFloat, TypeDouble, TypeTimestamp2, TypeDateTime2, TypeTime2, TypeJSON, TypeTinyBlob, TypeMediumBlob, TypeLongBlob, TypeBlob, TypeGeometry:
   117  		// One byte.
   118  		return 1
   119  
   120  	case TypeNewDecimal, TypeEnum, TypeSet, TypeString:
   121  		// Two bytes, Big Endian because of crazy encoding.
   122  		return 2
   123  
   124  	case TypeVarchar, TypeBit, TypeVarString:
   125  		// Two bytes, Little Endian
   126  		return 2
   127  
   128  	default:
   129  		// Unknown type. This is used in tests only, so panic.
   130  		panic(vterrors.Errorf(vtrpc.Code_INTERNAL, "metadataLength: unhandled data type: %v", typ))
   131  	}
   132  }
   133  
   134  // metadataTotalLength returns the total size of the metadata for an
   135  // array of types.
   136  func metadataTotalLength(types []byte) int {
   137  	sum := 0
   138  	for _, t := range types {
   139  		sum += metadataLength(t)
   140  	}
   141  	return sum
   142  }
   143  
   144  // metadataRead reads a single value from the metadata string.
   145  func metadataRead(data []byte, pos int, typ byte) (uint16, int, error) {
   146  	switch typ {
   147  
   148  	case TypeDecimal, TypeTiny, TypeShort, TypeLong, TypeNull, TypeTimestamp, TypeLongLong, TypeInt24, TypeDate, TypeTime, TypeDateTime, TypeYear, TypeNewDate:
   149  		// No data here.
   150  		return 0, pos, nil
   151  
   152  	case TypeFloat, TypeDouble, TypeTimestamp2, TypeDateTime2, TypeTime2, TypeJSON, TypeTinyBlob, TypeMediumBlob, TypeLongBlob, TypeBlob, TypeGeometry:
   153  		// One byte.
   154  		return uint16(data[pos]), pos + 1, nil
   155  
   156  	case TypeNewDecimal, TypeEnum, TypeSet, TypeString:
   157  		// Two bytes, Big Endian because of crazy encoding.
   158  		return uint16(data[pos])<<8 + uint16(data[pos+1]), pos + 2, nil
   159  
   160  	case TypeVarchar, TypeBit, TypeVarString:
   161  		// Two bytes, Little Endian
   162  		return uint16(data[pos]) + uint16(data[pos+1])<<8, pos + 2, nil
   163  
   164  	default:
   165  		// Unknown types, we can't go on.
   166  		return 0, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "metadataRead: unhandled data type: %v", typ)
   167  	}
   168  }
   169  
   170  // metadataWrite writes a single value into the metadata string.
   171  func metadataWrite(data []byte, pos int, typ byte, value uint16) int {
   172  	switch typ {
   173  
   174  	case TypeDecimal, TypeTiny, TypeShort, TypeLong, TypeNull, TypeTimestamp, TypeLongLong, TypeInt24, TypeDate, TypeTime, TypeDateTime, TypeYear, TypeNewDate:
   175  		// No data here.
   176  		return pos
   177  
   178  	case TypeFloat, TypeDouble, TypeTimestamp2, TypeDateTime2, TypeTime2, TypeJSON, TypeTinyBlob, TypeMediumBlob, TypeLongBlob, TypeBlob, TypeGeometry:
   179  		// One byte.
   180  		data[pos] = byte(value)
   181  		return pos + 1
   182  
   183  	case TypeNewDecimal, TypeEnum, TypeSet, TypeString:
   184  		// Two bytes, Big Endian because of crazy encoding.
   185  		data[pos] = byte(value >> 8)
   186  		data[pos+1] = byte(value)
   187  		return pos + 2
   188  
   189  	case TypeVarchar, TypeBit, TypeVarString:
   190  		// Two bytes, Little Endian
   191  		data[pos] = byte(value)
   192  		data[pos+1] = byte(value >> 8)
   193  		return pos + 2
   194  
   195  	default:
   196  		// Unknown type. This is used in tests only, so panic.
   197  		panic(vterrors.Errorf(vtrpc.Code_INTERNAL, "metadataRead: unhandled data type: %v", typ))
   198  	}
   199  }
   200  
   201  var dig2bytes = []int{0, 1, 1, 2, 2, 3, 3, 4, 4, 4}
   202  
   203  // cellLength returns the new position after the field with the given
   204  // type is read.
   205  func cellLength(data []byte, pos int, typ byte, metadata uint16) (int, error) {
   206  	switch typ {
   207  	case TypeNull:
   208  		return 0, nil
   209  	case TypeTiny, TypeYear:
   210  		return 1, nil
   211  	case TypeShort:
   212  		return 2, nil
   213  	case TypeInt24:
   214  		return 3, nil
   215  	case TypeLong, TypeFloat, TypeTimestamp:
   216  		return 4, nil
   217  	case TypeLongLong, TypeDouble:
   218  		return 8, nil
   219  	case TypeDate, TypeTime, TypeNewDate:
   220  		return 3, nil
   221  	case TypeDateTime:
   222  		return 8, nil
   223  	case TypeVarchar, TypeVarString:
   224  		// Length is encoded in 1 or 2 bytes.
   225  		if metadata > 255 {
   226  			l := int(uint64(data[pos]) |
   227  				uint64(data[pos+1])<<8)
   228  			return l + 2, nil
   229  		}
   230  		l := int(data[pos])
   231  		return l + 1, nil
   232  	case TypeBit:
   233  		// bitmap length is in metadata, as:
   234  		// upper 8 bits: bytes length
   235  		// lower 8 bits: bit length
   236  		nbits := ((metadata >> 8) * 8) + (metadata & 0xFF)
   237  		return (int(nbits) + 7) / 8, nil
   238  	case TypeTimestamp2:
   239  		// metadata has number of decimals. One byte encodes
   240  		// two decimals.
   241  		return 4 + (int(metadata)+1)/2, nil
   242  	case TypeDateTime2:
   243  		// metadata has number of decimals. One byte encodes
   244  		// two decimals.
   245  		return 5 + (int(metadata)+1)/2, nil
   246  	case TypeTime2:
   247  		// metadata has number of decimals. One byte encodes
   248  		// two decimals.
   249  		return 3 + (int(metadata)+1)/2, nil
   250  	case TypeNewDecimal:
   251  		precision := int(metadata >> 8)
   252  		scale := int(metadata & 0xff)
   253  		// Example:
   254  		//   NNNNNNNNNNNN.MMMMMM
   255  		//     12 bytes     6 bytes
   256  		// precision is 18
   257  		// scale is 6
   258  		// storage is done by groups of 9 digits:
   259  		// - 32 bits are used to store groups of 9 digits.
   260  		// - any leftover digit is stored in:
   261  		//   - 1 byte for 1 and 2 digits
   262  		//   - 2 bytes for 3 and 4 digits
   263  		//   - 3 bytes for 5 and 6 digits
   264  		//   - 4 bytes for 7 and 8 digits (would also work for 9)
   265  		// both sides of the dot are stored separately.
   266  		// In this example, we'd have:
   267  		// - 2 bytes to store the first 3 full digits.
   268  		// - 4 bytes to store the next 9 full digits.
   269  		// - 3 bytes to store the 6 fractional digits.
   270  		intg := precision - scale
   271  		intg0 := intg / 9
   272  		frac0 := scale / 9
   273  		intg0x := intg - intg0*9
   274  		frac0x := scale - frac0*9
   275  		return intg0*4 + dig2bytes[intg0x] + frac0*4 + dig2bytes[frac0x], nil
   276  	case TypeEnum, TypeSet:
   277  		return int(metadata & 0xff), nil
   278  	case TypeJSON, TypeTinyBlob, TypeMediumBlob, TypeLongBlob, TypeBlob, TypeGeometry:
   279  		// Of the Blobs, only TypeBlob is used in binary logs,
   280  		// but supports others just in case.
   281  		switch metadata {
   282  		case 1:
   283  			return 1 + int(uint32(data[pos])), nil
   284  		case 2:
   285  			return 2 + int(uint32(data[pos])|
   286  				uint32(data[pos+1])<<8), nil
   287  		case 3:
   288  			return 3 + int(uint32(data[pos])|
   289  				uint32(data[pos+1])<<8|
   290  				uint32(data[pos+2])<<16), nil
   291  		case 4:
   292  			return 4 + int(uint32(data[pos])|
   293  				uint32(data[pos+1])<<8|
   294  				uint32(data[pos+2])<<16|
   295  				uint32(data[pos+3])<<24), nil
   296  		default:
   297  			return 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unsupported blob/geometry metadata value %v (data: %v pos: %v)", metadata, data, pos)
   298  		}
   299  	case TypeString:
   300  		// This may do String, Enum, and Set. The type is in
   301  		// metadata. If it's a string, then there will be more bits.
   302  		// This will give us the maximum length of the field.
   303  		t := metadata >> 8
   304  		if t == TypeEnum || t == TypeSet {
   305  			return int(metadata & 0xff), nil
   306  		}
   307  		max := int((((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0xff))
   308  		// Length is encoded in 1 or 2 bytes.
   309  		if max > 255 {
   310  			l := int(uint64(data[pos]) |
   311  				uint64(data[pos+1])<<8)
   312  			return l + 2, nil
   313  		}
   314  		l := int(data[pos])
   315  		return l + 1, nil
   316  
   317  	default:
   318  		return 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unsupported type %v (data: %v pos: %v)", typ, data, pos)
   319  	}
   320  }
   321  
   322  // printTimestamp is a helper method to append a timestamp into a bytes.Buffer,
   323  // and return the Buffer.
   324  func printTimestamp(v uint32) *bytes.Buffer {
   325  	if v == 0 {
   326  		return bytes.NewBuffer(ZeroTimestamp)
   327  	}
   328  
   329  	t := time.Unix(int64(v), 0).UTC()
   330  	year, month, day := t.Date()
   331  	hour, minute, second := t.Clock()
   332  
   333  	result := &bytes.Buffer{}
   334  	fmt.Fprintf(result, "%04d-%02d-%02d %02d:%02d:%02d", year, int(month), day, hour, minute, second)
   335  	return result
   336  }
   337  
   338  // CellValue returns the data for a cell as a sqltypes.Value, and how
   339  // many bytes it takes. It uses source type in querypb.Type and vitess type
   340  // byte to determine general shared aspects of types and the querypb.Field to
   341  // determine other info specifically about its underlying column (SQL column
   342  // type, column length, charset, etc)
   343  func CellValue(data []byte, pos int, typ byte, metadata uint16, field *querypb.Field) (sqltypes.Value, int, error) {
   344  	switch typ {
   345  	case TypeTiny:
   346  		if sqltypes.IsSigned(field.Type) {
   347  			return sqltypes.MakeTrusted(querypb.Type_INT8,
   348  				strconv.AppendInt(nil, int64(int8(data[pos])), 10)), 1, nil
   349  		}
   350  		return sqltypes.MakeTrusted(querypb.Type_UINT8,
   351  			strconv.AppendUint(nil, uint64(data[pos]), 10)), 1, nil
   352  	case TypeYear:
   353  		val := data[pos]
   354  		if val == 0 {
   355  			return sqltypes.MakeTrusted(querypb.Type_YEAR,
   356  				[]byte{'0', '0', '0', '0'}), 1, nil
   357  		}
   358  		return sqltypes.MakeTrusted(querypb.Type_YEAR,
   359  			strconv.AppendUint(nil, uint64(data[pos])+1900, 10)), 1, nil
   360  	case TypeShort:
   361  		val := binary.LittleEndian.Uint16(data[pos : pos+2])
   362  		if sqltypes.IsSigned(field.Type) {
   363  			return sqltypes.MakeTrusted(querypb.Type_INT16,
   364  				strconv.AppendInt(nil, int64(int16(val)), 10)), 2, nil
   365  		}
   366  		return sqltypes.MakeTrusted(querypb.Type_UINT16,
   367  			strconv.AppendUint(nil, uint64(val), 10)), 2, nil
   368  	case TypeInt24:
   369  		if sqltypes.IsSigned(field.Type) && data[pos+2]&128 > 0 {
   370  			// Negative number, have to extend the sign.
   371  			val := int32(uint32(data[pos]) +
   372  				uint32(data[pos+1])<<8 +
   373  				uint32(data[pos+2])<<16 +
   374  				uint32(255)<<24)
   375  			return sqltypes.MakeTrusted(querypb.Type_INT24,
   376  				strconv.AppendInt(nil, int64(val), 10)), 3, nil
   377  		}
   378  		// Positive number.
   379  		val := uint64(data[pos]) +
   380  			uint64(data[pos+1])<<8 +
   381  			uint64(data[pos+2])<<16
   382  		return sqltypes.MakeTrusted(querypb.Type_UINT24,
   383  			strconv.AppendUint(nil, val, 10)), 3, nil
   384  	case TypeLong:
   385  		val := binary.LittleEndian.Uint32(data[pos : pos+4])
   386  		if sqltypes.IsSigned(field.Type) {
   387  			return sqltypes.MakeTrusted(querypb.Type_INT32,
   388  				strconv.AppendInt(nil, int64(int32(val)), 10)), 4, nil
   389  		}
   390  		return sqltypes.MakeTrusted(querypb.Type_UINT32,
   391  			strconv.AppendUint(nil, uint64(val), 10)), 4, nil
   392  	case TypeFloat:
   393  		val := binary.LittleEndian.Uint32(data[pos : pos+4])
   394  		fval := math.Float32frombits(val)
   395  		return sqltypes.MakeTrusted(querypb.Type_FLOAT32,
   396  			strconv.AppendFloat(nil, float64(fval), 'E', -1, 32)), 4, nil
   397  	case TypeDouble:
   398  		val := binary.LittleEndian.Uint64(data[pos : pos+8])
   399  		fval := math.Float64frombits(val)
   400  		return sqltypes.MakeTrusted(querypb.Type_FLOAT64,
   401  			strconv.AppendFloat(nil, fval, 'E', -1, 64)), 8, nil
   402  	case TypeTimestamp:
   403  		val := binary.LittleEndian.Uint32(data[pos : pos+4])
   404  		txt := printTimestamp(val)
   405  		return sqltypes.MakeTrusted(querypb.Type_TIMESTAMP,
   406  			txt.Bytes()), 4, nil
   407  	case TypeLongLong:
   408  		val := binary.LittleEndian.Uint64(data[pos : pos+8])
   409  		if sqltypes.IsSigned(field.Type) {
   410  			return sqltypes.MakeTrusted(querypb.Type_INT64,
   411  				strconv.AppendInt(nil, int64(val), 10)), 8, nil
   412  		}
   413  		return sqltypes.MakeTrusted(querypb.Type_UINT64,
   414  			strconv.AppendUint(nil, val, 10)), 8, nil
   415  	case TypeDate, TypeNewDate:
   416  		val := uint32(data[pos]) +
   417  			uint32(data[pos+1])<<8 +
   418  			uint32(data[pos+2])<<16
   419  		day := val & 31
   420  		month := val >> 5 & 15
   421  		year := val >> 9
   422  		return sqltypes.MakeTrusted(querypb.Type_DATE,
   423  			[]byte(fmt.Sprintf("%04d-%02d-%02d", year, month, day))), 3, nil
   424  	case TypeTime:
   425  		var hour, minute, second int32
   426  		if data[pos+2]&128 > 0 {
   427  			// Negative number, have to extend the sign.
   428  			val := int32(uint32(data[pos]) +
   429  				uint32(data[pos+1])<<8 +
   430  				uint32(data[pos+2])<<16 +
   431  				uint32(255)<<24)
   432  			hour = val / 10000
   433  			minute = -((val % 10000) / 100)
   434  			second = -(val % 100)
   435  		} else {
   436  			val := int32(data[pos]) +
   437  				int32(data[pos+1])<<8 +
   438  				int32(data[pos+2])<<16
   439  			hour = val / 10000
   440  			minute = (val % 10000) / 100
   441  			second = val % 100
   442  		}
   443  		return sqltypes.MakeTrusted(querypb.Type_TIME,
   444  			[]byte(fmt.Sprintf("%02d:%02d:%02d", hour, minute, second))), 3, nil
   445  	case TypeDateTime:
   446  		val := binary.LittleEndian.Uint64(data[pos : pos+8])
   447  		d := val / 1000000
   448  		t := val % 1000000
   449  		year := d / 10000
   450  		month := (d % 10000) / 100
   451  		day := d % 100
   452  		hour := t / 10000
   453  		minute := (t % 10000) / 100
   454  		second := t % 100
   455  		return sqltypes.MakeTrusted(querypb.Type_DATETIME,
   456  			[]byte(fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second))), 8, nil
   457  	case TypeVarchar, TypeVarString:
   458  		// We trust that typ is compatible with the field.Type
   459  		// Length is encoded in 1 or 2 bytes.
   460  		typeToUse := querypb.Type_VARCHAR
   461  		if field.Type == querypb.Type_VARBINARY || field.Type == querypb.Type_BINARY || field.Type == querypb.Type_BLOB {
   462  			typeToUse = field.Type
   463  		}
   464  		if metadata > 255 {
   465  			l := int(uint64(data[pos]) |
   466  				uint64(data[pos+1])<<8)
   467  			return sqltypes.MakeTrusted(typeToUse,
   468  				data[pos+2:pos+2+l]), l + 2, nil
   469  		}
   470  		l := int(data[pos])
   471  		return sqltypes.MakeTrusted(typeToUse,
   472  			data[pos+1:pos+1+l]), l + 1, nil
   473  	case TypeBit:
   474  		// The contents is just the bytes, quoted.
   475  		nbits := ((metadata >> 8) * 8) + (metadata & 0xFF)
   476  		l := (int(nbits) + 7) / 8
   477  		return sqltypes.MakeTrusted(querypb.Type_BIT,
   478  			data[pos:pos+l]), l, nil
   479  	case TypeTimestamp2:
   480  		second := binary.BigEndian.Uint32(data[pos : pos+4])
   481  		txt := printTimestamp(second)
   482  		switch metadata {
   483  		case 1:
   484  			decimals := int(data[pos+4])
   485  			fmt.Fprintf(txt, ".%01d", decimals/10)
   486  			return sqltypes.MakeTrusted(querypb.Type_TIMESTAMP,
   487  				txt.Bytes()), 5, nil
   488  		case 2:
   489  			decimals := int(data[pos+4])
   490  			fmt.Fprintf(txt, ".%02d", decimals)
   491  			return sqltypes.MakeTrusted(querypb.Type_TIMESTAMP,
   492  				txt.Bytes()), 5, nil
   493  		case 3:
   494  			decimals := int(data[pos+4])<<8 +
   495  				int(data[pos+5])
   496  			fmt.Fprintf(txt, ".%03d", decimals/10)
   497  			return sqltypes.MakeTrusted(querypb.Type_TIMESTAMP,
   498  				txt.Bytes()), 6, nil
   499  		case 4:
   500  			decimals := int(data[pos+4])<<8 +
   501  				int(data[pos+5])
   502  			fmt.Fprintf(txt, ".%04d", decimals)
   503  			return sqltypes.MakeTrusted(querypb.Type_TIMESTAMP,
   504  				txt.Bytes()), 6, nil
   505  		case 5:
   506  			decimals := int(data[pos+4])<<16 +
   507  				int(data[pos+5])<<8 +
   508  				int(data[pos+6])
   509  			fmt.Fprintf(txt, ".%05d", decimals/10)
   510  			return sqltypes.MakeTrusted(querypb.Type_TIMESTAMP,
   511  				txt.Bytes()), 7, nil
   512  		case 6:
   513  			decimals := int(data[pos+4])<<16 +
   514  				int(data[pos+5])<<8 +
   515  				int(data[pos+6])
   516  			fmt.Fprintf(txt, ".%06d", decimals)
   517  			return sqltypes.MakeTrusted(querypb.Type_TIMESTAMP,
   518  				txt.Bytes()), 7, nil
   519  		}
   520  		return sqltypes.MakeTrusted(querypb.Type_TIMESTAMP,
   521  			txt.Bytes()), 4, nil
   522  	case TypeDateTime2:
   523  		ymdhms := (uint64(data[pos])<<32 |
   524  			uint64(data[pos+1])<<24 |
   525  			uint64(data[pos+2])<<16 |
   526  			uint64(data[pos+3])<<8 |
   527  			uint64(data[pos+4])) - uint64(0x8000000000)
   528  		ymd := ymdhms >> 17
   529  		ym := ymd >> 5
   530  		hms := ymdhms % (1 << 17)
   531  
   532  		day := ymd % (1 << 5)
   533  		month := ym % 13
   534  		year := ym / 13
   535  
   536  		second := hms % (1 << 6)
   537  		minute := (hms >> 6) % (1 << 6)
   538  		hour := hms >> 12
   539  
   540  		txt := &bytes.Buffer{}
   541  		fmt.Fprintf(txt, "%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
   542  
   543  		switch metadata {
   544  		case 1:
   545  			decimals := int(data[pos+5])
   546  			fmt.Fprintf(txt, ".%01d", decimals/10)
   547  			return sqltypes.MakeTrusted(querypb.Type_DATETIME,
   548  				txt.Bytes()), 6, nil
   549  		case 2:
   550  			decimals := int(data[pos+5])
   551  			fmt.Fprintf(txt, ".%02d", decimals)
   552  			return sqltypes.MakeTrusted(querypb.Type_DATETIME,
   553  				txt.Bytes()), 6, nil
   554  		case 3:
   555  			decimals := int(data[pos+5])<<8 +
   556  				int(data[pos+6])
   557  			fmt.Fprintf(txt, ".%03d", decimals/10)
   558  			return sqltypes.MakeTrusted(querypb.Type_DATETIME,
   559  				txt.Bytes()), 7, nil
   560  		case 4:
   561  			decimals := int(data[pos+5])<<8 +
   562  				int(data[pos+6])
   563  			fmt.Fprintf(txt, ".%04d", decimals)
   564  			return sqltypes.MakeTrusted(querypb.Type_DATETIME,
   565  				txt.Bytes()), 7, nil
   566  		case 5:
   567  			decimals := int(data[pos+5])<<16 +
   568  				int(data[pos+6])<<8 +
   569  				int(data[pos+7])
   570  			fmt.Fprintf(txt, ".%05d", decimals/10)
   571  			return sqltypes.MakeTrusted(querypb.Type_DATETIME,
   572  				txt.Bytes()), 8, nil
   573  		case 6:
   574  			decimals := int(data[pos+5])<<16 +
   575  				int(data[pos+6])<<8 +
   576  				int(data[pos+7])
   577  			fmt.Fprintf(txt, ".%06d", decimals)
   578  			return sqltypes.MakeTrusted(querypb.Type_DATETIME,
   579  				txt.Bytes()), 8, nil
   580  		}
   581  		return sqltypes.MakeTrusted(querypb.Type_DATETIME,
   582  			txt.Bytes()), 5, nil
   583  	case TypeTime2:
   584  		hms := (int64(data[pos])<<16 |
   585  			int64(data[pos+1])<<8 |
   586  			int64(data[pos+2])) - 0x800000
   587  		sign := ""
   588  		if hms < 0 {
   589  			hms = -hms
   590  			sign = "-"
   591  		}
   592  
   593  		fracStr := ""
   594  		switch metadata {
   595  		case 1:
   596  			frac := int(data[pos+3])
   597  			if sign == "-" && frac != 0 {
   598  				hms--
   599  				frac = 0x100 - frac
   600  			}
   601  			fracStr = fmt.Sprintf(".%.1d", frac/10)
   602  		case 2:
   603  			frac := int(data[pos+3])
   604  			if sign == "-" && frac != 0 {
   605  				hms--
   606  				frac = 0x100 - frac
   607  			}
   608  			fracStr = fmt.Sprintf(".%.2d", frac)
   609  		case 3:
   610  			frac := int(data[pos+3])<<8 |
   611  				int(data[pos+4])
   612  			if sign == "-" && frac != 0 {
   613  				hms--
   614  				frac = 0x10000 - frac
   615  			}
   616  			fracStr = fmt.Sprintf(".%.3d", frac/10)
   617  		case 4:
   618  			frac := int(data[pos+3])<<8 |
   619  				int(data[pos+4])
   620  			if sign == "-" && frac != 0 {
   621  				hms--
   622  				frac = 0x10000 - frac
   623  			}
   624  			fracStr = fmt.Sprintf(".%.4d", frac)
   625  		case 5:
   626  			frac := int(data[pos+3])<<16 |
   627  				int(data[pos+4])<<8 |
   628  				int(data[pos+5])
   629  			if sign == "-" && frac != 0 {
   630  				hms--
   631  				frac = 0x1000000 - frac
   632  			}
   633  			fracStr = fmt.Sprintf(".%.5d", frac/10)
   634  		case 6:
   635  			frac := int(data[pos+3])<<16 |
   636  				int(data[pos+4])<<8 |
   637  				int(data[pos+5])
   638  			if sign == "-" && frac != 0 {
   639  				hms--
   640  				frac = 0x1000000 - frac
   641  			}
   642  			fracStr = fmt.Sprintf(".%.6d", frac)
   643  		}
   644  
   645  		hour := (hms >> 12) % (1 << 10)
   646  		minute := (hms >> 6) % (1 << 6)
   647  		second := hms % (1 << 6)
   648  		return sqltypes.MakeTrusted(querypb.Type_TIME,
   649  			[]byte(fmt.Sprintf("%v%02d:%02d:%02d%v", sign, hour, minute, second, fracStr))), 3 + (int(metadata)+1)/2, nil
   650  
   651  	case TypeNewDecimal:
   652  		precision := int(metadata >> 8) // total digits number
   653  		scale := int(metadata & 0xff)   // number of fractional digits
   654  		intg := precision - scale       // number of full digits
   655  		intg0 := intg / 9               // number of 32-bits digits
   656  		intg0x := intg - intg0*9        // leftover full digits
   657  		frac0 := scale / 9              // number of 32 bits fractionals
   658  		frac0x := scale - frac0*9       // leftover fractionals
   659  
   660  		l := intg0*4 + dig2bytes[intg0x] + frac0*4 + dig2bytes[frac0x]
   661  
   662  		// Copy the data so we can change it. Otherwise
   663  		// decoding is just too hard.
   664  		d := make([]byte, l)
   665  		copy(d, data[pos:pos+l])
   666  
   667  		txt := &bytes.Buffer{}
   668  
   669  		isNegative := (d[0] & 0x80) == 0
   670  		d[0] ^= 0x80 // First bit is inverted.
   671  		if isNegative {
   672  			// Negative numbers are just inverted bytes.
   673  			txt.WriteByte('-')
   674  			for i := range d {
   675  				d[i] ^= 0xff
   676  			}
   677  		}
   678  
   679  		// first we have the leftover full digits
   680  		var val uint32
   681  		switch dig2bytes[intg0x] {
   682  		case 0:
   683  			// nothing to do
   684  		case 1:
   685  			// one byte, up to two digits
   686  			val = uint32(d[0])
   687  		case 2:
   688  			// two bytes, up to 4 digits
   689  			val = uint32(d[0])<<8 +
   690  				uint32(d[1])
   691  		case 3:
   692  			// 3 bytes, up to 6 digits
   693  			val = uint32(d[0])<<16 +
   694  				uint32(d[1])<<8 +
   695  				uint32(d[2])
   696  		case 4:
   697  			// 4 bytes, up to 8 digits (9 digits would be a full)
   698  			val = uint32(d[0])<<24 +
   699  				uint32(d[1])<<16 +
   700  				uint32(d[2])<<8 +
   701  				uint32(d[3])
   702  		}
   703  		pos = dig2bytes[intg0x]
   704  		if val > 0 {
   705  			txt.Write(strconv.AppendUint(nil, uint64(val), 10))
   706  		}
   707  
   708  		// now the full digits, 32 bits each, 9 digits
   709  		for i := 0; i < intg0; i++ {
   710  			val = binary.BigEndian.Uint32(d[pos : pos+4])
   711  			fmt.Fprintf(txt, "%09d", val)
   712  			pos += 4
   713  		}
   714  
   715  		// now see if we have a fraction
   716  		if scale == 0 {
   717  			// When the field is a DECIMAL using a scale of 0, e.g.
   718  			// DECIMAL(5,0), a binlogged value of 0 is almost treated
   719  			// like the NULL byte and we get a 0 byte length value.
   720  			// In this case let's return the correct value of 0.
   721  			if txt.Len() == 0 {
   722  				txt.WriteRune('0')
   723  			}
   724  
   725  			return sqltypes.MakeTrusted(querypb.Type_DECIMAL,
   726  				txt.Bytes()), l, nil
   727  		}
   728  		txt.WriteByte('.')
   729  
   730  		// now the full fractional digits
   731  		for i := 0; i < frac0; i++ {
   732  			val = binary.BigEndian.Uint32(d[pos : pos+4])
   733  			fmt.Fprintf(txt, "%09d", val)
   734  			pos += 4
   735  		}
   736  
   737  		// then the partial fractional digits
   738  		switch dig2bytes[frac0x] {
   739  		case 0:
   740  			// Nothing to do
   741  			return sqltypes.MakeTrusted(querypb.Type_DECIMAL,
   742  				txt.Bytes()), l, nil
   743  		case 1:
   744  			// one byte, 1 or 2 digits
   745  			val = uint32(d[pos])
   746  			if frac0x == 1 {
   747  				fmt.Fprintf(txt, "%1d", val)
   748  			} else {
   749  				fmt.Fprintf(txt, "%02d", val)
   750  			}
   751  		case 2:
   752  			// two bytes, 3 or 4 digits
   753  			val = uint32(d[pos])<<8 +
   754  				uint32(d[pos+1])
   755  			if frac0x == 3 {
   756  				fmt.Fprintf(txt, "%03d", val)
   757  			} else {
   758  				fmt.Fprintf(txt, "%04d", val)
   759  			}
   760  		case 3:
   761  			// 3 bytes, 5 or 6 digits
   762  			val = uint32(d[pos])<<16 +
   763  				uint32(d[pos+1])<<8 +
   764  				uint32(d[pos+2])
   765  			if frac0x == 5 {
   766  				fmt.Fprintf(txt, "%05d", val)
   767  			} else {
   768  				fmt.Fprintf(txt, "%06d", val)
   769  			}
   770  		case 4:
   771  			// 4 bytes, 7 or 8 digits (9 digits would be a full)
   772  			val = uint32(d[pos])<<24 +
   773  				uint32(d[pos+1])<<16 +
   774  				uint32(d[pos+2])<<8 +
   775  				uint32(d[pos+3])
   776  			if frac0x == 7 {
   777  				fmt.Fprintf(txt, "%07d", val)
   778  			} else {
   779  				fmt.Fprintf(txt, "%08d", val)
   780  			}
   781  		}
   782  
   783  		// remove preceding 0s from the integral part, otherwise we get "000000000001.23" instead of "1.23"
   784  		trimPrecedingZeroes := func(b []byte) []byte {
   785  			s := string(b)
   786  			isNegative := false
   787  			if s[0] == '-' {
   788  				isNegative = true
   789  				s = s[1:]
   790  			}
   791  			s = strings.TrimLeft(s, "0")
   792  			if isNegative {
   793  				s = fmt.Sprintf("-%s", s)
   794  			}
   795  			return []byte(s)
   796  		}
   797  		return sqltypes.MakeTrusted(querypb.Type_DECIMAL, trimPrecedingZeroes(txt.Bytes())), l, nil
   798  
   799  	case TypeEnum:
   800  		switch metadata & 0xff {
   801  		case 1:
   802  			// One byte storage.
   803  			return sqltypes.MakeTrusted(querypb.Type_ENUM,
   804  				strconv.AppendUint(nil, uint64(data[pos]), 10)), 1, nil
   805  		case 2:
   806  			// Two bytes storage.
   807  			val := binary.LittleEndian.Uint16(data[pos : pos+2])
   808  			return sqltypes.MakeTrusted(querypb.Type_ENUM,
   809  				strconv.AppendUint(nil, uint64(val), 10)), 2, nil
   810  		default:
   811  			return sqltypes.NULL, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected enum size: %v", metadata&0xff)
   812  		}
   813  
   814  	case TypeSet:
   815  		l := int(metadata & 0xff)
   816  		return sqltypes.MakeTrusted(querypb.Type_SET,
   817  			data[pos:pos+l]), l, nil
   818  
   819  	case TypeJSON, TypeTinyBlob, TypeMediumBlob, TypeLongBlob, TypeBlob:
   820  		// Only TypeBlob is used in binary logs,
   821  		// but supports others just in case.
   822  		l := 0
   823  		switch metadata {
   824  		case 1:
   825  			l = int(uint32(data[pos]))
   826  		case 2:
   827  			l = int(uint32(data[pos]) |
   828  				uint32(data[pos+1])<<8)
   829  		case 3:
   830  			l = int(uint32(data[pos]) |
   831  				uint32(data[pos+1])<<8 |
   832  				uint32(data[pos+2])<<16)
   833  		case 4:
   834  			l = int(uint32(data[pos]) |
   835  				uint32(data[pos+1])<<8 |
   836  				uint32(data[pos+2])<<16 |
   837  				uint32(data[pos+3])<<24)
   838  		default:
   839  			return sqltypes.NULL, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unsupported blob metadata value %v (data: %v pos: %v)", metadata, data, pos)
   840  		}
   841  		pos += int(metadata)
   842  
   843  		var limitArray = func(data []byte, limit int) []byte {
   844  			if len(data) > limit {
   845  				return data[:limit]
   846  			}
   847  			return data
   848  		}
   849  		// For JSON, we parse the data, and emit SQL.
   850  		if typ == TypeJSON {
   851  			var err error
   852  			jsonData := data[pos : pos+l]
   853  			s, err := getJSONValue(jsonData)
   854  			if err != nil {
   855  				return sqltypes.NULL, 0, vterrors.Wrapf(err, "error stringifying JSON data %v", limitArray(jsonData, 100))
   856  			}
   857  			d := []byte(s)
   858  			return sqltypes.MakeTrusted(sqltypes.Expression,
   859  				d), l + int(metadata), nil
   860  		}
   861  
   862  		return sqltypes.MakeTrusted(querypb.Type_VARBINARY,
   863  			data[pos:pos+l]), l + int(metadata), nil
   864  
   865  	case TypeString:
   866  		// This may do String, Enum, and Set. The type is in
   867  		// metadata. If it's a string, then there will be more bits.
   868  		t := metadata >> 8
   869  		if t == TypeEnum {
   870  			// We don't know the string values. So just use the
   871  			// numbers.
   872  			switch metadata & 0xff {
   873  			case 1:
   874  				// One byte storage.
   875  				return sqltypes.MakeTrusted(querypb.Type_UINT8,
   876  					strconv.AppendUint(nil, uint64(data[pos]), 10)), 1, nil
   877  			case 2:
   878  				// Two bytes storage.
   879  				val := binary.LittleEndian.Uint16(data[pos : pos+2])
   880  				return sqltypes.MakeTrusted(querypb.Type_UINT16,
   881  					strconv.AppendUint(nil, uint64(val), 10)), 2, nil
   882  			default:
   883  				return sqltypes.NULL, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected enum size: %v", metadata&0xff)
   884  			}
   885  		}
   886  		if t == TypeSet {
   887  			// We don't know the set values. So just use the
   888  			// numbers.
   889  			l := int(metadata & 0xff)
   890  			var val uint64
   891  			for i := 0; i < l; i++ {
   892  				val += uint64(data[pos+i]) << (uint(i) * 8)
   893  			}
   894  			return sqltypes.MakeTrusted(querypb.Type_UINT64,
   895  				strconv.AppendUint(nil, uint64(val), 10)), l, nil
   896  		}
   897  		// This is a real string. The length is weird.
   898  		max := int((((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0xff))
   899  		// Length is encoded in 1 or 2 bytes.
   900  		if max > 255 {
   901  			// This code path exists due to https://bugs.mysql.com/bug.php?id=37426.
   902  			// CHAR types need to allocate 3 bytes per char. So, the length for CHAR(255)
   903  			// cannot be represented in 1 byte. This also means that this rule does not
   904  			// apply to BINARY data.
   905  			l := int(uint64(data[pos]) |
   906  				uint64(data[pos+1])<<8)
   907  			return sqltypes.MakeTrusted(querypb.Type_VARCHAR,
   908  				data[pos+2:pos+2+l]), l + 2, nil
   909  		}
   910  		l := int(data[pos])
   911  		mdata := data[pos+1 : pos+1+l]
   912  		if sqltypes.IsBinary(field.Type) {
   913  			// For binary(n) column types, mysql pads the data on the right with nulls. However the binlog event contains
   914  			// the data without this padding. This causes several issues:
   915  			//    * if a binary(n) column is part of the sharding key, the keyspace_id() returned during the copy phase
   916  			//      (where the value is the result of a mysql query) is different from the one during replication
   917  			//      (where the value is the one from the binlogs)
   918  			//    * mysql where clause comparisons do not do the right thing without padding
   919  			// So for fixed length BINARY columns we right-pad it with nulls if necessary to match what MySQL returns.
   920  			// Because CHAR columns with a binary collation (e.g. utf8mb4_bin) have the same metadata as a BINARY column
   921  			// in binlog events, we also need to check for this case based on the underlying column type.
   922  			if l < max && strings.HasPrefix(strings.ToLower(field.ColumnType), "binary") {
   923  				paddedData := make([]byte, max)
   924  				copy(paddedData[:l], mdata)
   925  				mdata = paddedData
   926  			}
   927  			return sqltypes.MakeTrusted(querypb.Type_BINARY, mdata), l + 1, nil
   928  		}
   929  		return sqltypes.MakeTrusted(querypb.Type_VARCHAR, mdata), l + 1, nil
   930  
   931  	case TypeGeometry:
   932  		l := 0
   933  		switch metadata {
   934  		case 1:
   935  			l = int(uint32(data[pos]))
   936  		case 2:
   937  			l = int(uint32(data[pos]) |
   938  				uint32(data[pos+1])<<8)
   939  		case 3:
   940  			l = int(uint32(data[pos]) |
   941  				uint32(data[pos+1])<<8 |
   942  				uint32(data[pos+2])<<16)
   943  		case 4:
   944  			l = int(uint32(data[pos]) |
   945  				uint32(data[pos+1])<<8 |
   946  				uint32(data[pos+2])<<16 |
   947  				uint32(data[pos+3])<<24)
   948  		default:
   949  			return sqltypes.NULL, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unsupported geometry metadata value %v (data: %v pos: %v)", metadata, data, pos)
   950  		}
   951  		pos += int(metadata)
   952  		return sqltypes.MakeTrusted(querypb.Type_GEOMETRY,
   953  			data[pos:pos+l]), l + int(metadata), nil
   954  
   955  	default:
   956  		return sqltypes.NULL, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unsupported type %v", typ)
   957  	}
   958  }
   959  
   960  // Rows implements BinlogEvent.TableMap().
   961  //
   962  // Expected format (L = total length of event data):
   963  //
   964  //	# bytes   field
   965  //	4/6       table id
   966  //	2         flags
   967  //	-- if version == 2
   968  //	2         extra data length edl
   969  //	edl       extra data
   970  //	-- endif
   971  //
   972  // <var>      number of columns (var-len encoded)
   973  // <var>      identify bitmap
   974  // <var>      data bitmap
   975  // -- for each row
   976  // <var>      null bitmap for identify for present rows
   977  // <var>      values for each identify field
   978  // <var>      null bitmap for data for present rows
   979  // <var>      values for each data field
   980  // --
   981  func (ev binlogEvent) Rows(f BinlogFormat, tm *TableMap) (Rows, error) {
   982  	typ := ev.Type()
   983  	data := ev.Bytes()[f.HeaderLength:]
   984  	hasIdentify := typ == eUpdateRowsEventV1 || typ == eUpdateRowsEventV2 ||
   985  		typ == eDeleteRowsEventV1 || typ == eDeleteRowsEventV2
   986  	hasData := typ == eWriteRowsEventV1 || typ == eWriteRowsEventV2 ||
   987  		typ == eUpdateRowsEventV1 || typ == eUpdateRowsEventV2
   988  
   989  	result := Rows{}
   990  	pos := 6
   991  	if f.HeaderSize(typ) == 6 {
   992  		pos = 4
   993  	}
   994  	result.Flags = binary.LittleEndian.Uint16(data[pos : pos+2])
   995  	pos += 2
   996  
   997  	// version=2 have extra data here.
   998  	if typ == eWriteRowsEventV2 || typ == eUpdateRowsEventV2 || typ == eDeleteRowsEventV2 {
   999  		// This extraDataLength contains the 2 bytes length.
  1000  		extraDataLength := binary.LittleEndian.Uint16(data[pos : pos+2])
  1001  		pos += int(extraDataLength)
  1002  	}
  1003  
  1004  	columnCount, read, ok := readLenEncInt(data, pos)
  1005  	if !ok {
  1006  		return result, vterrors.Errorf(vtrpc.Code_INTERNAL, "expected column count at position %v (data=%v)", pos, data)
  1007  	}
  1008  	pos = read
  1009  
  1010  	numIdentifyColumns := 0
  1011  	numDataColumns := 0
  1012  
  1013  	if hasIdentify {
  1014  		// Bitmap of the columns used for identify.
  1015  		result.IdentifyColumns, pos = newBitmap(data, pos, int(columnCount))
  1016  		numIdentifyColumns = result.IdentifyColumns.BitCount()
  1017  	}
  1018  
  1019  	if hasData {
  1020  		// Bitmap of columns that are present.
  1021  		result.DataColumns, pos = newBitmap(data, pos, int(columnCount))
  1022  		numDataColumns = result.DataColumns.BitCount()
  1023  	}
  1024  
  1025  	// One row at a time.
  1026  	for pos < len(data) {
  1027  		row := Row{}
  1028  
  1029  		if hasIdentify {
  1030  			// Bitmap of identify columns that are null (amongst the ones that are present).
  1031  			row.NullIdentifyColumns, pos = newBitmap(data, pos, numIdentifyColumns)
  1032  
  1033  			// Get the identify values.
  1034  			startPos := pos
  1035  			valueIndex := 0
  1036  			for c := 0; c < int(columnCount); c++ {
  1037  				if !result.IdentifyColumns.Bit(c) {
  1038  					// This column is not represented.
  1039  					continue
  1040  				}
  1041  
  1042  				if row.NullIdentifyColumns.Bit(valueIndex) {
  1043  					// This column is represented, but its value is NULL.
  1044  					valueIndex++
  1045  					continue
  1046  				}
  1047  
  1048  				// This column is represented now. We need to skip its length.
  1049  				l, err := cellLength(data, pos, tm.Types[c], tm.Metadata[c])
  1050  				if err != nil {
  1051  					return result, err
  1052  				}
  1053  				pos += l
  1054  				valueIndex++
  1055  			}
  1056  			row.Identify = data[startPos:pos]
  1057  		}
  1058  
  1059  		if hasData {
  1060  			// Bitmap of columns that are null (amongst the ones that are present).
  1061  			row.NullColumns, pos = newBitmap(data, pos, numDataColumns)
  1062  
  1063  			// Get the values.
  1064  			startPos := pos
  1065  			valueIndex := 0
  1066  			for c := 0; c < int(columnCount); c++ {
  1067  				if !result.DataColumns.Bit(c) {
  1068  					// This column is not represented.
  1069  					continue
  1070  				}
  1071  
  1072  				if row.NullColumns.Bit(valueIndex) {
  1073  					// This column is represented, but its value is NULL.
  1074  					valueIndex++
  1075  					continue
  1076  				}
  1077  
  1078  				// This column is represented now. We need to skip its length.
  1079  				l, err := cellLength(data, pos, tm.Types[c], tm.Metadata[c])
  1080  				if err != nil {
  1081  					return result, err
  1082  				}
  1083  				pos += l
  1084  				valueIndex++
  1085  			}
  1086  			row.Data = data[startPos:pos]
  1087  		}
  1088  
  1089  		result.Rows = append(result.Rows, row)
  1090  	}
  1091  
  1092  	return result, nil
  1093  }
  1094  
  1095  // StringValuesForTests is a helper method to return the string value
  1096  // of all columns in a row in a Row. Only use it in tests, as the
  1097  // returned values cannot be interpreted correctly without the schema.
  1098  // We assume everything is unsigned in this method.
  1099  func (rs *Rows) StringValuesForTests(tm *TableMap, rowIndex int) ([]string, error) {
  1100  	var result []string
  1101  
  1102  	valueIndex := 0
  1103  	data := rs.Rows[rowIndex].Data
  1104  	pos := 0
  1105  	for c := 0; c < rs.DataColumns.Count(); c++ {
  1106  		if !rs.DataColumns.Bit(c) {
  1107  			continue
  1108  		}
  1109  
  1110  		if rs.Rows[rowIndex].NullColumns.Bit(valueIndex) {
  1111  			// This column is represented, but its value is NULL.
  1112  			result = append(result, "NULL")
  1113  			valueIndex++
  1114  			continue
  1115  		}
  1116  
  1117  		// We have real data
  1118  		value, l, err := CellValue(data, pos, tm.Types[c], tm.Metadata[c], &querypb.Field{Type: querypb.Type_UINT64})
  1119  		if err != nil {
  1120  			return nil, err
  1121  		}
  1122  		result = append(result, value.ToString())
  1123  		pos += l
  1124  		valueIndex++
  1125  	}
  1126  
  1127  	return result, nil
  1128  }
  1129  
  1130  // StringIdentifiesForTests is a helper method to return the string
  1131  // identify of all columns in a row in a Row. Only use it in tests, as the
  1132  // returned values cannot be interpreted correctly without the schema.
  1133  // We assume everything is unsigned in this method.
  1134  func (rs *Rows) StringIdentifiesForTests(tm *TableMap, rowIndex int) ([]string, error) {
  1135  	var result []string
  1136  
  1137  	valueIndex := 0
  1138  	data := rs.Rows[rowIndex].Identify
  1139  	pos := 0
  1140  	for c := 0; c < rs.IdentifyColumns.Count(); c++ {
  1141  		if !rs.IdentifyColumns.Bit(c) {
  1142  			continue
  1143  		}
  1144  
  1145  		if rs.Rows[rowIndex].NullIdentifyColumns.Bit(valueIndex) {
  1146  			// This column is represented, but its value is NULL.
  1147  			result = append(result, "NULL")
  1148  			valueIndex++
  1149  			continue
  1150  		}
  1151  
  1152  		// We have real data
  1153  		value, l, err := CellValue(data, pos, tm.Types[c], tm.Metadata[c], &querypb.Field{Type: querypb.Type_UINT64})
  1154  		if err != nil {
  1155  			return nil, err
  1156  		}
  1157  		result = append(result, value.ToString())
  1158  		pos += l
  1159  		valueIndex++
  1160  	}
  1161  
  1162  	return result, nil
  1163  }