github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/internal/table/scanner/scanner_test.go (about)

     1  package scanner
     2  
     3  import (
     4  	"encoding/binary"
     5  	"encoding/json"
     6  	"math"
     7  	"strconv"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/google/uuid"
    12  	"github.com/stretchr/testify/require"
    13  	"github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
    14  
    15  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
    16  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xrand"
    17  	"github.com/ydb-platform/ydb-go-sdk/v3/table/result/indexed"
    18  	"github.com/ydb-platform/ydb-go-sdk/v3/table/result/named"
    19  	"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
    20  )
    21  
    22  //nolint:gocyclo
    23  func valueFromPrimitiveTypeID(c *column, r xrand.Rand) (*Ydb.Value, interface{}) {
    24  	rv := r.Int64(math.MaxInt16)
    25  	switch c.typeID {
    26  	case Ydb.Type_BOOL:
    27  		v := rv%2 == 1
    28  		ydbval := &Ydb.Value{
    29  			Value: &Ydb.Value_BoolValue{
    30  				BoolValue: v,
    31  			},
    32  		}
    33  		if c.optional && !c.testDefault {
    34  			vp := &v
    35  
    36  			return ydbval, &vp
    37  		}
    38  
    39  		return ydbval, &v
    40  	case Ydb.Type_INT8:
    41  		v := int8(rv)
    42  		ydbval := &Ydb.Value{
    43  			Value: &Ydb.Value_Int32Value{
    44  				Int32Value: int32(v),
    45  			},
    46  		}
    47  		if c.optional && !c.testDefault {
    48  			vp := &v
    49  
    50  			return ydbval, &vp
    51  		}
    52  
    53  		return ydbval, &v
    54  	case Ydb.Type_UINT8:
    55  		if c.nilValue {
    56  			ydbval := &Ydb.Value{
    57  				Value: &Ydb.Value_NullFlagValue{},
    58  			}
    59  			if c.testDefault {
    60  				var dv uint8
    61  
    62  				return ydbval, &dv
    63  			}
    64  			var dv *uint8
    65  
    66  			return ydbval, &dv
    67  		}
    68  		v := uint8(rv)
    69  		ydbval := &Ydb.Value{
    70  			Value: &Ydb.Value_Uint32Value{
    71  				Uint32Value: uint32(v),
    72  			},
    73  		}
    74  		if c.optional && !c.testDefault {
    75  			vp := &v
    76  
    77  			return ydbval, &vp
    78  		}
    79  
    80  		return ydbval, &v
    81  	case Ydb.Type_INT16:
    82  		v := int16(rv)
    83  		ydbval := &Ydb.Value{
    84  			Value: &Ydb.Value_Int32Value{
    85  				Int32Value: int32(v),
    86  			},
    87  		}
    88  		if c.optional && !c.testDefault {
    89  			vp := &v
    90  
    91  			return ydbval, &vp
    92  		}
    93  
    94  		return ydbval, &v
    95  	case Ydb.Type_UINT16:
    96  		v := uint16(rv)
    97  		ydbval := &Ydb.Value{
    98  			Value: &Ydb.Value_Uint32Value{
    99  				Uint32Value: uint32(v),
   100  			},
   101  		}
   102  		if c.optional && !c.testDefault {
   103  			vp := &v
   104  
   105  			return ydbval, &vp
   106  		}
   107  
   108  		return ydbval, &v
   109  	case Ydb.Type_INT32:
   110  		if c.nilValue {
   111  			ydbval := &Ydb.Value{
   112  				Value: &Ydb.Value_NullFlagValue{},
   113  			}
   114  			if c.testDefault {
   115  				var dv int32
   116  
   117  				return ydbval, &dv
   118  			}
   119  			var dv *int32
   120  
   121  			return ydbval, &dv
   122  		}
   123  		v := int32(rv)
   124  		ydbval := &Ydb.Value{
   125  			Value: &Ydb.Value_Int32Value{
   126  				Int32Value: v,
   127  			},
   128  		}
   129  		if c.optional && !c.testDefault {
   130  			vp := &v
   131  
   132  			return ydbval, &vp
   133  		}
   134  
   135  		return ydbval, &v
   136  	case Ydb.Type_UINT32:
   137  		v := uint32(rv)
   138  		ydbval := &Ydb.Value{
   139  			Value: &Ydb.Value_Uint32Value{
   140  				Uint32Value: v,
   141  			},
   142  		}
   143  		if c.optional && !c.testDefault {
   144  			vp := &v
   145  
   146  			return ydbval, &vp
   147  		}
   148  
   149  		return ydbval, &v
   150  	case Ydb.Type_INT64:
   151  		v := rv
   152  		ydbval := &Ydb.Value{
   153  			Value: &Ydb.Value_Int64Value{
   154  				Int64Value: v,
   155  			},
   156  		}
   157  		if c.ydbvalue {
   158  			vp := types.Int64Value(v)
   159  
   160  			return ydbval, &vp
   161  		}
   162  		if c.scanner {
   163  			s := intIncScanner(v + 10)
   164  
   165  			return ydbval, &s
   166  		}
   167  		if c.optional && !c.testDefault {
   168  			vp := &v
   169  
   170  			return ydbval, &vp
   171  		}
   172  
   173  		return ydbval, &v
   174  	case Ydb.Type_UINT64:
   175  		v := uint64(rv)
   176  		ydbval := &Ydb.Value{
   177  			Value: &Ydb.Value_Uint64Value{
   178  				Uint64Value: v,
   179  			},
   180  		}
   181  		if c.optional && !c.testDefault {
   182  			vp := &v
   183  
   184  			return ydbval, &vp
   185  		}
   186  
   187  		return ydbval, &v
   188  	case Ydb.Type_FLOAT:
   189  		v := float32(rv)
   190  		ydbval := &Ydb.Value{
   191  			Value: &Ydb.Value_FloatValue{
   192  				FloatValue: v,
   193  			},
   194  		}
   195  		if c.ydbvalue {
   196  			vp := types.FloatValue(v)
   197  
   198  			return ydbval, &vp
   199  		}
   200  		if c.optional && !c.testDefault {
   201  			vp := &v
   202  
   203  			return ydbval, &vp
   204  		}
   205  
   206  		return ydbval, &v
   207  	case Ydb.Type_DOUBLE:
   208  		v := float64(rv)
   209  		ydbval := &Ydb.Value{
   210  			Value: &Ydb.Value_DoubleValue{
   211  				DoubleValue: v,
   212  			},
   213  		}
   214  		if c.optional && !c.testDefault {
   215  			vp := &v
   216  
   217  			return ydbval, &vp
   218  		}
   219  
   220  		return ydbval, &v
   221  	case Ydb.Type_DATE:
   222  		v := uint32(rv)
   223  		ydbval := &Ydb.Value{
   224  			Value: &Ydb.Value_Uint32Value{
   225  				Uint32Value: v,
   226  			},
   227  		}
   228  		src := value.DateToTime(v)
   229  		if c.scanner {
   230  			s := dateScanner(src)
   231  
   232  			return ydbval, &s
   233  		}
   234  		if c.optional && !c.testDefault {
   235  			vp := &src
   236  
   237  			return ydbval, &vp
   238  		}
   239  
   240  		return ydbval, &src
   241  	case Ydb.Type_DATETIME:
   242  		v := uint32(rv)
   243  		ydbval := &Ydb.Value{
   244  			Value: &Ydb.Value_Uint32Value{
   245  				Uint32Value: v,
   246  			},
   247  		}
   248  		src := value.DatetimeToTime(v)
   249  		if c.optional && !c.testDefault {
   250  			vp := &src
   251  
   252  			return ydbval, &vp
   253  		}
   254  
   255  		return ydbval, &src
   256  	case Ydb.Type_TIMESTAMP:
   257  		v := uint64(rv)
   258  		ydbval := &Ydb.Value{
   259  			Value: &Ydb.Value_Uint64Value{
   260  				Uint64Value: v,
   261  			},
   262  		}
   263  		src := value.TimestampToTime(v)
   264  		if c.optional && !c.testDefault {
   265  			vp := &src
   266  
   267  			return ydbval, &vp
   268  		}
   269  
   270  		return ydbval, &src
   271  	case Ydb.Type_INTERVAL:
   272  		if c.nilValue {
   273  			ydbval := &Ydb.Value{
   274  				Value: &Ydb.Value_NullFlagValue{},
   275  			}
   276  			if c.testDefault {
   277  				var dv time.Duration
   278  
   279  				return ydbval, &dv
   280  			}
   281  			var dv *time.Duration
   282  
   283  			return ydbval, &dv
   284  		}
   285  		rv %= time.Now().Unix()
   286  		v := rv
   287  		ydbval := &Ydb.Value{
   288  			Value: &Ydb.Value_Int64Value{
   289  				Int64Value: v,
   290  			},
   291  		}
   292  		src := value.IntervalToDuration(v)
   293  		if c.optional && !c.testDefault {
   294  			vp := &src
   295  
   296  			return ydbval, &vp
   297  		}
   298  
   299  		return ydbval, &src
   300  	case Ydb.Type_TZ_DATE:
   301  		v := time.Now().Format(value.LayoutDate) + ",Europe/Berlin"
   302  		ydbval := &Ydb.Value{
   303  			Value: &Ydb.Value_TextValue{
   304  				TextValue: v,
   305  			},
   306  		}
   307  		src, _ := value.TzDateToTime(v)
   308  		if c.optional && !c.testDefault {
   309  			vp := &src
   310  
   311  			return ydbval, &vp
   312  		}
   313  
   314  		return ydbval, &src
   315  	case Ydb.Type_TZ_DATETIME:
   316  		if c.nilValue {
   317  			ydbval := &Ydb.Value{
   318  				Value: &Ydb.Value_NullFlagValue{},
   319  			}
   320  			if c.testDefault {
   321  				var dv time.Time
   322  
   323  				return ydbval, &dv
   324  			}
   325  			var dv *time.Time
   326  
   327  			return ydbval, &dv
   328  		}
   329  		rv %= time.Now().Unix()
   330  		v := value.DatetimeToTime(uint32(rv)).Format(value.LayoutTzDatetime) + ",Europe/Berlin"
   331  		ydbval := &Ydb.Value{
   332  			Value: &Ydb.Value_TextValue{
   333  				TextValue: v,
   334  			},
   335  		}
   336  		src, _ := value.TzDatetimeToTime(v)
   337  		if c.optional && !c.testDefault {
   338  			vp := &src
   339  
   340  			return ydbval, &vp
   341  		}
   342  
   343  		return ydbval, &src
   344  	case Ydb.Type_TZ_TIMESTAMP:
   345  		rv %= time.Now().Unix()
   346  		v := value.TimestampToTime(uint64(rv)).Format(value.LayoutTzTimestamp) + ",Europe/Berlin"
   347  		ydbval := &Ydb.Value{
   348  			Value: &Ydb.Value_TextValue{
   349  				TextValue: v,
   350  			},
   351  		}
   352  		src, _ := value.TzTimestampToTime(v)
   353  		if c.optional && !c.testDefault {
   354  			vp := &src
   355  
   356  			return ydbval, &vp
   357  		}
   358  
   359  		return ydbval, &src
   360  	case Ydb.Type_STRING:
   361  		if c.nilValue {
   362  			ydbval := &Ydb.Value{
   363  				Value: &Ydb.Value_NullFlagValue{},
   364  			}
   365  			if c.testDefault {
   366  				var dv []byte
   367  
   368  				return ydbval, &dv
   369  			}
   370  			var dv *[]byte
   371  
   372  			return ydbval, &dv
   373  		}
   374  		v := make([]byte, 16)
   375  		binary.BigEndian.PutUint64(v[0:8], uint64(rv))
   376  		binary.BigEndian.PutUint64(v[8:16], uint64(rv))
   377  		ydbval := &Ydb.Value{
   378  			Value: &Ydb.Value_BytesValue{
   379  				BytesValue: v,
   380  			},
   381  		}
   382  		src := v
   383  		if c.optional && !c.testDefault {
   384  			vp := &src
   385  
   386  			return ydbval, &vp
   387  		}
   388  
   389  		return ydbval, &src
   390  	case Ydb.Type_UTF8:
   391  		v := strconv.FormatUint(uint64(rv), 10)
   392  		ydbval := &Ydb.Value{
   393  			Value: &Ydb.Value_TextValue{
   394  				TextValue: v,
   395  			},
   396  		}
   397  		if c.optional && !c.testDefault {
   398  			vp := &v
   399  
   400  			return ydbval, &vp
   401  		}
   402  
   403  		return ydbval, &v
   404  	case Ydb.Type_YSON:
   405  		if c.nilValue {
   406  			ydbval := &Ydb.Value{
   407  				Value: &Ydb.Value_NullFlagValue{},
   408  			}
   409  			if c.testDefault {
   410  				var dv []byte
   411  
   412  				return ydbval, &dv
   413  			}
   414  			var dv *[]byte
   415  
   416  			return ydbval, &dv
   417  		}
   418  		v := strconv.FormatUint(uint64(rv), 10)
   419  		ydbval := &Ydb.Value{
   420  			Value: &Ydb.Value_TextValue{
   421  				TextValue: v,
   422  			},
   423  		}
   424  		src := []byte(v)
   425  		if c.optional && !c.testDefault {
   426  			vp := &src
   427  
   428  			return ydbval, &vp
   429  		}
   430  
   431  		return ydbval, &src
   432  	case Ydb.Type_JSON:
   433  		v := strconv.FormatUint(uint64(rv), 10)
   434  		ydbval := &Ydb.Value{
   435  			Value: &Ydb.Value_TextValue{
   436  				TextValue: v,
   437  			},
   438  		}
   439  		if c.ydbvalue {
   440  			vp := types.JSONValue(v)
   441  
   442  			return ydbval, &vp
   443  		}
   444  		src := []byte(v)
   445  		if c.optional && !c.testDefault {
   446  			vp := &src
   447  
   448  			return ydbval, &vp
   449  		}
   450  
   451  		return ydbval, &src
   452  	case Ydb.Type_UUID:
   453  		if c.nilValue {
   454  			ydbval := &Ydb.Value{
   455  				Value: &Ydb.Value_NullFlagValue{},
   456  			}
   457  			if c.testDefault {
   458  				var dv uuid.UUID
   459  
   460  				return ydbval, &dv
   461  			}
   462  			var dv *uuid.UUID
   463  
   464  			return ydbval, &dv
   465  		}
   466  		v := uuid.UUID{}
   467  
   468  		binary.LittleEndian.PutUint64(v[0:8], uint64(rv))
   469  		binary.LittleEndian.PutUint64(v[8:16], uint64(rv))
   470  		low, high := value.UUIDToHiLoPair(v)
   471  		ydbval := &Ydb.Value{
   472  			High_128: high,
   473  			Value: &Ydb.Value_Low_128{
   474  				Low_128: low,
   475  			},
   476  		}
   477  		if c.optional && !c.testDefault {
   478  			vp := &v
   479  
   480  			return ydbval, &vp
   481  		}
   482  
   483  		return ydbval, &v
   484  	case Ydb.Type_JSON_DOCUMENT:
   485  		v := strconv.FormatUint(uint64(rv), 10)
   486  		ydbval := &Ydb.Value{
   487  			Value: &Ydb.Value_TextValue{
   488  				TextValue: v,
   489  			},
   490  		}
   491  		src := []byte(v)
   492  		if c.optional && !c.testDefault {
   493  			vp := &src
   494  
   495  			return ydbval, &vp
   496  		}
   497  
   498  		return ydbval, &src
   499  	case Ydb.Type_DYNUMBER:
   500  		v := strconv.FormatUint(uint64(rv), 10)
   501  		ydbval := &Ydb.Value{
   502  			Value: &Ydb.Value_TextValue{
   503  				TextValue: v,
   504  			},
   505  		}
   506  		if c.optional && !c.testDefault {
   507  			vp := &v
   508  
   509  			return ydbval, &vp
   510  		}
   511  
   512  		return ydbval, &v
   513  	default:
   514  		panic("ydb: unexpected types")
   515  	}
   516  }
   517  
   518  func getResultSet(count int, col []*column) (result *Ydb.ResultSet, testValues [][]indexed.RequiredOrOptional) {
   519  	result = &Ydb.ResultSet{}
   520  	for _, c := range col {
   521  		t := &Ydb.Type{
   522  			Type: &Ydb.Type_TypeId{
   523  				TypeId: c.typeID,
   524  			},
   525  		}
   526  		if c.optional {
   527  			t = &Ydb.Type{
   528  				Type: &Ydb.Type_OptionalType{
   529  					OptionalType: &Ydb.OptionalType{
   530  						Item: t,
   531  					},
   532  				},
   533  			}
   534  		}
   535  		result.Columns = append(
   536  			result.GetColumns(),
   537  			&Ydb.Column{
   538  				Name: c.name,
   539  				Type: t,
   540  			},
   541  		)
   542  	}
   543  
   544  	r := xrand.New(xrand.WithLock())
   545  	testValues = make([][]indexed.RequiredOrOptional, count)
   546  	for i := 0; i < count; i++ {
   547  		var items []*Ydb.Value
   548  		var vals []indexed.RequiredOrOptional
   549  		for j := range result.GetColumns() {
   550  			v, val := valueFromPrimitiveTypeID(col[j], r)
   551  			vals = append(vals, val)
   552  			items = append(items, v)
   553  		}
   554  		result.Rows = append(result.GetRows(), &Ydb.Value{
   555  			Items: items,
   556  		})
   557  		testValues[i] = vals
   558  	}
   559  
   560  	return result, testValues
   561  }
   562  
   563  func TestScanSqlTypes(t *testing.T) {
   564  	s := initScanner()
   565  	for _, test := range scannerData {
   566  		t.Run(test.name, func(t *testing.T) {
   567  			set, expected := getResultSet(test.count, test.columns)
   568  			s.reset(set, test.setColumns...)
   569  			for s.NextRow() {
   570  				if test.columns[0].testDefault {
   571  					if err := s.ScanWithDefaults(func() (values []indexed.Required) {
   572  						for _, v := range test.values {
   573  							values = append(values, v)
   574  						}
   575  
   576  						return values
   577  					}()...); err != nil {
   578  						t.Fatalf("test: %s; error: %s", test.name, err)
   579  					}
   580  				} else {
   581  					if err := s.Scan(test.values...); err != nil {
   582  						t.Fatalf("test: %s; error: %s", test.name, err)
   583  					}
   584  				}
   585  				if test.setColumnIndexes != nil {
   586  					for i, v := range test.setColumnIndexes {
   587  						require.Equal(t, expected[0][v], test.values[i])
   588  					}
   589  				} else {
   590  					require.Equal(t, expected[0], test.values)
   591  				}
   592  				expected = expected[1:]
   593  			}
   594  		})
   595  	}
   596  }
   597  
   598  func TestScanNamed(t *testing.T) {
   599  	s := initScanner()
   600  	or := func(columns []string, i int, defaultValue string) string {
   601  		if columns == nil {
   602  			return defaultValue
   603  		}
   604  
   605  		return columns[i]
   606  	}
   607  	for _, test := range scannerData {
   608  		t.Run(test.name, func(t *testing.T) {
   609  			set, expected := getResultSet(test.count, test.columns)
   610  			s.reset(set)
   611  			for s.NextRow() {
   612  				values := make([]named.Value, 0, len(test.values))
   613  				//nolint:nestif
   614  				if test.columns[0].testDefault {
   615  					for i := range test.values {
   616  						values = append(
   617  							values,
   618  							named.OptionalWithDefault(
   619  								or(test.setColumns, i, test.columns[i].name),
   620  								test.values[i],
   621  							),
   622  						)
   623  					}
   624  					if err := s.ScanNamed(values...); err != nil {
   625  						t.Fatalf("test: %s; error: %s", test.name, err)
   626  					}
   627  				} else {
   628  					for i := range test.values {
   629  						if test.columns[i].optional {
   630  							if test.columns[i].testDefault {
   631  								values = append(
   632  									values,
   633  									named.OptionalWithDefault(
   634  										or(test.setColumns, i, test.columns[i].name),
   635  										test.values[i],
   636  									),
   637  								)
   638  							} else {
   639  								values = append(
   640  									values,
   641  									named.Optional(
   642  										or(test.setColumns, i, test.columns[i].name),
   643  										test.values[i],
   644  									),
   645  								)
   646  							}
   647  						} else {
   648  							values = append(
   649  								values,
   650  								named.Required(
   651  									or(test.setColumns, i, test.columns[i].name),
   652  									test.values[i],
   653  								),
   654  							)
   655  						}
   656  					}
   657  					if err := s.ScanNamed(values...); err != nil {
   658  						t.Fatalf("test: %s; error: %s", test.name, err)
   659  					}
   660  				}
   661  				if test.setColumnIndexes != nil {
   662  					for i, v := range test.setColumnIndexes {
   663  						require.Equal(t, expected[0][v], test.values[i])
   664  					}
   665  				} else {
   666  					require.Equal(t, expected[0], test.values)
   667  				}
   668  				expected = expected[1:]
   669  			}
   670  		})
   671  	}
   672  }
   673  
   674  type jsonUnmarshaller struct {
   675  	bytes []byte
   676  }
   677  
   678  func (json *jsonUnmarshaller) UnmarshalJSON(bytes []byte) error {
   679  	json.bytes = bytes
   680  
   681  	return nil
   682  }
   683  
   684  var _ json.Unmarshaler = &jsonUnmarshaller{}
   685  
   686  func TestScanToJsonUnmarshaller(t *testing.T) {
   687  	s := initScanner()
   688  	for _, test := range []struct {
   689  		name    string
   690  		count   int
   691  		columns []*column
   692  		values  []indexed.RequiredOrOptional
   693  	}{
   694  		{
   695  			name:  "<optional JSONDocument, required JSON> to json.Unmarshaller",
   696  			count: 2,
   697  			columns: []*column{{
   698  				name:     "jsondocument",
   699  				typeID:   Ydb.Type_JSON_DOCUMENT,
   700  				optional: true,
   701  			}, {
   702  				name:   "json",
   703  				typeID: Ydb.Type_JSON,
   704  			}},
   705  			values: []indexed.RequiredOrOptional{
   706  				new(jsonUnmarshaller),
   707  				new(jsonUnmarshaller),
   708  			},
   709  		}, {
   710  			name:  "<required JSONDocument, optional JSON> to json.Unmarshaller",
   711  			count: 2,
   712  			columns: []*column{{
   713  				name:   "jsondocument",
   714  				typeID: Ydb.Type_JSON_DOCUMENT,
   715  			}, {
   716  				name:     "json",
   717  				typeID:   Ydb.Type_JSON,
   718  				optional: true,
   719  			}},
   720  			values: []indexed.RequiredOrOptional{
   721  				new(jsonUnmarshaller),
   722  				new(jsonUnmarshaller),
   723  			},
   724  		}, {
   725  			name:  "<optional JSONDocument, optional JSON> to json.Unmarshaller",
   726  			count: 2,
   727  			columns: []*column{{
   728  				name:     "jsondocument",
   729  				typeID:   Ydb.Type_JSON_DOCUMENT,
   730  				optional: true,
   731  			}, {
   732  				name:     "json",
   733  				typeID:   Ydb.Type_JSON,
   734  				optional: true,
   735  			}},
   736  			values: []indexed.RequiredOrOptional{
   737  				new(jsonUnmarshaller),
   738  				new(jsonUnmarshaller),
   739  			},
   740  		}, {
   741  			name:  "<required JSONDocument, required JSON> to json.Unmarshaller",
   742  			count: 2,
   743  			columns: []*column{{
   744  				name:   "jsondocument",
   745  				typeID: Ydb.Type_JSON_DOCUMENT,
   746  			}, {
   747  				name:   "json",
   748  				typeID: Ydb.Type_JSON,
   749  			}},
   750  			values: []indexed.RequiredOrOptional{
   751  				new(jsonUnmarshaller),
   752  				new(jsonUnmarshaller),
   753  			},
   754  		},
   755  	} {
   756  		set, _ := getResultSet(test.count, test.columns)
   757  		s.reset(set)
   758  		for s.NextRow() {
   759  			values := make([]indexed.RequiredOrOptional, 0, len(test.values))
   760  			for i, col := range test.columns {
   761  				if col.optional {
   762  					values = append(
   763  						values,
   764  						indexed.Optional(
   765  							test.values[i],
   766  						),
   767  					)
   768  				} else {
   769  					values = append(
   770  						values,
   771  						indexed.Required(
   772  							test.values[i],
   773  						),
   774  					)
   775  				}
   776  			}
   777  			if err := s.Scan(values...); err != nil {
   778  				t.Fatalf("test: %s; error: %s", test.name, err)
   779  			}
   780  		}
   781  	}
   782  }