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

     1  package scanner
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"time"
     7  
     8  	"github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
     9  
    10  	"github.com/ydb-platform/ydb-go-sdk/v3/table/result/indexed"
    11  	"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
    12  )
    13  
    14  type column struct {
    15  	name        string
    16  	typeID      Ydb.Type_PrimitiveTypeId
    17  	optional    bool
    18  	scanner     bool
    19  	ydbvalue    bool
    20  	testDefault bool
    21  	nilValue    bool
    22  }
    23  
    24  type intIncScanner int64
    25  
    26  func (s *intIncScanner) Scan(src interface{}) error {
    27  	v, ok := src.(int64)
    28  	if !ok {
    29  		return fmt.Errorf("wrong type: %T, exp: int64", src)
    30  	}
    31  	*s = intIncScanner(v + 10)
    32  
    33  	return nil
    34  }
    35  
    36  type dateScanner time.Time
    37  
    38  func (s *dateScanner) Scan(src interface{}) error {
    39  	v, ok := src.(time.Time)
    40  	if !ok {
    41  		return fmt.Errorf("wrong type: %T, exp: time.Time", src)
    42  	}
    43  	*s = dateScanner(v)
    44  
    45  	return nil
    46  }
    47  
    48  var scannerData = []struct {
    49  	name             string
    50  	count            int
    51  	columns          []*column
    52  	values           []indexed.RequiredOrOptional
    53  	setColumns       []string
    54  	setColumnIndexes []int
    55  }{
    56  	{
    57  		name:  "Scan UUID, DATE",
    58  		count: 10,
    59  		columns: []*column{{
    60  			name:   "uuid",
    61  			typeID: Ydb.Type_UUID,
    62  		}, {
    63  			name:   "date",
    64  			typeID: Ydb.Type_DATE,
    65  		}},
    66  		values: []indexed.RequiredOrOptional{new([16]byte), new(time.Time)},
    67  	},
    68  	{
    69  		name:  "Scan JSON, DOUBLE",
    70  		count: 20,
    71  		columns: []*column{{
    72  			name:   "json",
    73  			typeID: Ydb.Type_JSON,
    74  		}, {
    75  			name:   "double",
    76  			typeID: Ydb.Type_DOUBLE,
    77  		}},
    78  		values: []indexed.RequiredOrOptional{new([]byte), new(float64)},
    79  	},
    80  	{
    81  		name:  "Scan INT8, INT16, INT32",
    82  		count: 210,
    83  		columns: []*column{{
    84  			name:   "int8",
    85  			typeID: Ydb.Type_INT8,
    86  		}, {
    87  			name:   "int16",
    88  			typeID: Ydb.Type_INT16,
    89  		}, {
    90  			name:   "int32",
    91  			typeID: Ydb.Type_INT32,
    92  		}},
    93  		values:     []indexed.RequiredOrOptional{new(int8), new(int16), new(int32)},
    94  		setColumns: []string{"int8", "int16", "int32"},
    95  	},
    96  	{
    97  		name:  "Scan YSON, DOUBLE. Zero rows in the result",
    98  		count: 0,
    99  		columns: []*column{{
   100  			name:   "yson",
   101  			typeID: Ydb.Type_YSON,
   102  		}, {
   103  			name:   "double",
   104  			typeID: Ydb.Type_DOUBLE,
   105  		}},
   106  		values: []indexed.RequiredOrOptional{new([]byte), new(float64)},
   107  	},
   108  	{
   109  		name:  "Scan JSON, FLOAT",
   110  		count: 1000,
   111  		columns: []*column{{
   112  			name:   "jsondocument",
   113  			typeID: Ydb.Type_JSON_DOCUMENT,
   114  		}, {
   115  			name:   "float",
   116  			typeID: Ydb.Type_FLOAT,
   117  		}},
   118  		values: []indexed.RequiredOrOptional{new([]byte), new(float32)},
   119  	},
   120  	{
   121  		name:  "Scan UINT8, UINT16, UINT32",
   122  		count: 200,
   123  		columns: []*column{{
   124  			name:   "uint8",
   125  			typeID: Ydb.Type_UINT8,
   126  		}, {
   127  			name:   "uint16",
   128  			typeID: Ydb.Type_UINT16,
   129  		}, {
   130  			name:   "uint32",
   131  			typeID: Ydb.Type_UINT32,
   132  		}},
   133  		values: []indexed.RequiredOrOptional{new(uint8), new(uint16), new(uint32)},
   134  	},
   135  	{
   136  		name:  "Scan DYNUMBER, Type_UTF8, Type_STRING",
   137  		count: 5,
   138  		columns: []*column{{
   139  			name:   "dynumber",
   140  			typeID: Ydb.Type_DYNUMBER,
   141  		}, {
   142  			name:   "utf8",
   143  			typeID: Ydb.Type_UTF8,
   144  		}, {
   145  			name:   "string",
   146  			typeID: Ydb.Type_STRING,
   147  		}},
   148  		values: []indexed.RequiredOrOptional{new(string), new(string), new([]byte)},
   149  	},
   150  	{
   151  		name:  "Scan float32, int64, uint64 and skip other columns",
   152  		count: 15,
   153  		columns: []*column{{
   154  			name:   "float32",
   155  			typeID: Ydb.Type_FLOAT,
   156  		}, {
   157  			name:   "utf8",
   158  			typeID: Ydb.Type_UTF8,
   159  		}, {
   160  			name:   "int64",
   161  			typeID: Ydb.Type_INT64,
   162  		}, {
   163  			name:   "string",
   164  			typeID: Ydb.Type_STRING,
   165  		}, {
   166  			name:   "uint64",
   167  			typeID: Ydb.Type_UINT64,
   168  		}},
   169  		values:           []indexed.RequiredOrOptional{new(float32), new(int64), new(uint64)},
   170  		setColumns:       []string{"float32", "int64", "uint64"},
   171  		setColumnIndexes: []int{0, 2, 4},
   172  	},
   173  	{
   174  		name:  "Scan TIMESTAMP, BOOL, INTERVAL in a different order",
   175  		count: 20,
   176  		columns: []*column{{
   177  			name:   "timestamp",
   178  			typeID: Ydb.Type_TIMESTAMP,
   179  		}, {
   180  			name:   "bool",
   181  			typeID: Ydb.Type_BOOL,
   182  		}, {
   183  			name:   "interval",
   184  			typeID: Ydb.Type_INTERVAL,
   185  		}},
   186  		values:           []indexed.RequiredOrOptional{new(bool), new(time.Duration), new(time.Time)},
   187  		setColumns:       []string{"bool", "interval", "timestamp"},
   188  		setColumnIndexes: []int{1, 2, 0},
   189  	},
   190  	{
   191  		name:  "ScanWithDefaults for required columns TZ_TIMESTAMP, TZ_DATE, TZ_DATETIME in a different order",
   192  		count: 300,
   193  		columns: []*column{{
   194  			name:        "tztimestamp",
   195  			typeID:      Ydb.Type_TZ_TIMESTAMP,
   196  			testDefault: true,
   197  		}, {
   198  			name:        "tzdate",
   199  			typeID:      Ydb.Type_TZ_DATE,
   200  			testDefault: true,
   201  		}, {
   202  			name:        "tzdatetime",
   203  			typeID:      Ydb.Type_TZ_DATETIME,
   204  			testDefault: true,
   205  		}},
   206  		values:           []indexed.RequiredOrOptional{new(time.Time), new(time.Time), new(time.Time)},
   207  		setColumns:       []string{"tztimestamp", "tzdatetime", "tzdate"},
   208  		setColumnIndexes: []int{0, 2, 1},
   209  	},
   210  	{
   211  		name:  "Scan int64, float, json as ydb.valueType",
   212  		count: 100,
   213  		columns: []*column{{
   214  			name:     "valueint64",
   215  			typeID:   Ydb.Type_INT64,
   216  			ydbvalue: true,
   217  		}, {
   218  			name:     "valuefloat",
   219  			typeID:   Ydb.Type_FLOAT,
   220  			ydbvalue: true,
   221  		}, {
   222  			name:     "valuejson",
   223  			typeID:   Ydb.Type_JSON,
   224  			ydbvalue: true,
   225  		}},
   226  		values: []indexed.RequiredOrOptional{
   227  			new(types.Value),
   228  			new(types.Value),
   229  			new(types.Value),
   230  		},
   231  	},
   232  	{
   233  		name:  "Scan table with single column",
   234  		count: 10,
   235  		columns: []*column{{
   236  			name:   "datetime",
   237  			typeID: Ydb.Type_DATETIME,
   238  		}},
   239  		values: []indexed.RequiredOrOptional{new(time.Time)},
   240  	},
   241  	{
   242  		name:  "Scan optional values",
   243  		count: 500,
   244  		columns: []*column{{
   245  			name:     "otzdatetime",
   246  			typeID:   Ydb.Type_TZ_DATETIME,
   247  			optional: true,
   248  		}, {
   249  			name:     "ouint16",
   250  			typeID:   Ydb.Type_UINT16,
   251  			optional: true,
   252  		}, {
   253  			name:     "ostring",
   254  			typeID:   Ydb.Type_STRING,
   255  			optional: true,
   256  		}},
   257  		values: []indexed.RequiredOrOptional{new(*time.Time), new(*uint16), new(*[]byte)},
   258  	},
   259  	{
   260  		name:  "Scan optional values",
   261  		count: 30,
   262  		columns: []*column{{
   263  			name:     "ointerval",
   264  			typeID:   Ydb.Type_INTERVAL,
   265  			optional: true,
   266  		}, {
   267  			name:     "ouuid",
   268  			typeID:   Ydb.Type_UUID,
   269  			optional: true,
   270  		}, {
   271  			name:     "odouble",
   272  			typeID:   Ydb.Type_DOUBLE,
   273  			optional: true,
   274  		}},
   275  		values: []indexed.RequiredOrOptional{new(*time.Duration), new(*[16]byte), new(*float64)},
   276  	},
   277  	{
   278  		name:  "Scan int64, date, string as ydb.Scanner",
   279  		count: 4,
   280  		columns: []*column{{
   281  			name:    "sint64",
   282  			typeID:  Ydb.Type_INT64,
   283  			scanner: true,
   284  		}, {
   285  			name:    "sdate",
   286  			typeID:  Ydb.Type_DATE,
   287  			scanner: true,
   288  		}, {
   289  			name:    "sstring",
   290  			typeID:  Ydb.Type_STRING,
   291  			scanner: true,
   292  		}},
   293  		values: []indexed.RequiredOrOptional{new(intIncScanner), new(dateScanner), new([]byte)},
   294  	},
   295  	{
   296  		name:  "Scan optional int64, date, string as ydb.Scanner",
   297  		count: 30,
   298  		columns: []*column{{
   299  			name:     "sint64",
   300  			typeID:   Ydb.Type_INT64,
   301  			optional: true,
   302  			scanner:  true,
   303  		}, {
   304  			name:     "sdate",
   305  			typeID:   Ydb.Type_DATE,
   306  			optional: true,
   307  			scanner:  true,
   308  		}, {
   309  			name:     "sstring",
   310  			typeID:   Ydb.Type_STRING,
   311  			optional: true,
   312  		}},
   313  		values: []indexed.RequiredOrOptional{new(intIncScanner), new(dateScanner), new(*[]byte)},
   314  	},
   315  	{
   316  		name:  "ScanWithDefaults optional int64, date, string with null values as ydb.Scanner",
   317  		count: 30,
   318  		columns: []*column{{
   319  			name:     "sint64",
   320  			typeID:   Ydb.Type_INT64,
   321  			optional: true,
   322  			scanner:  true,
   323  		}, {
   324  			name:     "sdate",
   325  			typeID:   Ydb.Type_DATE,
   326  			optional: true,
   327  			scanner:  true,
   328  		}, {
   329  			name:     "sstring",
   330  			typeID:   Ydb.Type_STRING,
   331  			optional: true,
   332  			scanner:  true,
   333  			nilValue: true,
   334  		}},
   335  		values: []indexed.RequiredOrOptional{new(intIncScanner), new(dateScanner), new(*[]byte)},
   336  	},
   337  	{
   338  		name:  "ScanWithDefaults optional int32, time interval, string",
   339  		count: 30,
   340  		columns: []*column{{
   341  			name:        "oint32",
   342  			typeID:      Ydb.Type_INT32,
   343  			optional:    true,
   344  			testDefault: true,
   345  		}, {
   346  			name:        "otimeinterval",
   347  			typeID:      Ydb.Type_INTERVAL,
   348  			optional:    true,
   349  			testDefault: true,
   350  		}, {
   351  			name:        "ostring",
   352  			typeID:      Ydb.Type_STRING,
   353  			optional:    true,
   354  			testDefault: true,
   355  		}},
   356  		values: []indexed.RequiredOrOptional{new(int32), new(time.Duration), new([]byte)},
   357  	},
   358  	{
   359  		name:  "ScanWithDefaults optional int32, time interval, string, nil values applied as default value types",
   360  		count: 14,
   361  		columns: []*column{{
   362  			name:        "oint32",
   363  			typeID:      Ydb.Type_INT32,
   364  			optional:    true,
   365  			testDefault: true,
   366  			nilValue:    true,
   367  		}, {
   368  			name:        "otimeinterval",
   369  			typeID:      Ydb.Type_INTERVAL,
   370  			optional:    true,
   371  			testDefault: true,
   372  			nilValue:    true,
   373  		}, {
   374  			name:        "ostring",
   375  			typeID:      Ydb.Type_STRING,
   376  			optional:    true,
   377  			testDefault: true,
   378  			nilValue:    true,
   379  		}},
   380  		values: []indexed.RequiredOrOptional{new(int32), new(time.Duration), new([]byte)},
   381  	},
   382  	{
   383  		name:  "Scan optional int32, time interval, string. All values are null",
   384  		count: 15,
   385  		columns: []*column{{
   386  			name:     "oint32",
   387  			typeID:   Ydb.Type_INT32,
   388  			optional: true,
   389  			nilValue: true,
   390  		}, {
   391  			name:     "otimeinterval",
   392  			typeID:   Ydb.Type_INTERVAL,
   393  			optional: true,
   394  			nilValue: true,
   395  		}, {
   396  			name:     "ostring",
   397  			typeID:   Ydb.Type_STRING,
   398  			optional: true,
   399  			nilValue: true,
   400  		}},
   401  		values: []indexed.RequiredOrOptional{new(*int32), new(*time.Duration), new(*[]byte)},
   402  	},
   403  	{
   404  		name:  "Scan optional uint8, yson, tzdatetime, uuid. All values are null",
   405  		count: 15,
   406  		columns: []*column{{
   407  			name:     "ouint8",
   408  			typeID:   Ydb.Type_UINT8,
   409  			optional: true,
   410  			nilValue: true,
   411  		}, {
   412  			name:     "oyson",
   413  			typeID:   Ydb.Type_YSON,
   414  			optional: true,
   415  			nilValue: true,
   416  		}, {
   417  			name:     "otzdatetime",
   418  			typeID:   Ydb.Type_TZ_DATETIME,
   419  			optional: true,
   420  			nilValue: true,
   421  		}, {
   422  			name:     "ouuid",
   423  			typeID:   Ydb.Type_UUID,
   424  			optional: true,
   425  			nilValue: true,
   426  		}},
   427  		values: []indexed.RequiredOrOptional{new(*uint8), new(*[]byte), new(*time.Time), new(*[16]byte)},
   428  	},
   429  	{
   430  		name:  "Scan string as byte array.",
   431  		count: 19,
   432  		columns: []*column{{
   433  			name:   "string",
   434  			typeID: Ydb.Type_STRING,
   435  		}},
   436  		values: []indexed.RequiredOrOptional{new([]byte)},
   437  	},
   438  	{
   439  		name:  "Scan optional string as byte array.",
   440  		count: 18,
   441  		columns: []*column{{
   442  			name:     "string",
   443  			typeID:   Ydb.Type_STRING,
   444  			optional: true,
   445  		}},
   446  		values: []indexed.RequiredOrOptional{new(*[]byte)},
   447  	},
   448  	{
   449  		name:  "Scan optional null string as byte array.",
   450  		count: 17,
   451  		columns: []*column{{
   452  			name:     "string",
   453  			typeID:   Ydb.Type_STRING,
   454  			optional: true,
   455  			nilValue: true,
   456  		}},
   457  		values: []indexed.RequiredOrOptional{new(*[]byte)},
   458  	},
   459  	{
   460  		name:  "Scan optional default string as byte array.",
   461  		count: 16,
   462  		columns: []*column{{
   463  			name:        "string",
   464  			typeID:      Ydb.Type_STRING,
   465  			optional:    true,
   466  			nilValue:    true,
   467  			testDefault: true,
   468  		}},
   469  		values: []indexed.RequiredOrOptional{new([]byte)},
   470  	},
   471  }
   472  
   473  func initScanner() *valueScanner {
   474  	res := valueScanner{
   475  		set: &Ydb.ResultSet{
   476  			Columns:   nil,
   477  			Rows:      nil,
   478  			Truncated: false,
   479  		},
   480  		row: nil,
   481  		stack: scanStack{
   482  			v: nil,
   483  			p: 0,
   484  		},
   485  		nextRow:       0,
   486  		nextItem:      0,
   487  		columnIndexes: nil,
   488  		err:           nil,
   489  	}
   490  
   491  	return &res
   492  }
   493  
   494  func PrepareScannerPerformanceTest(count int) *valueScanner {
   495  	res := initScanner()
   496  	res.set.Columns = []*Ydb.Column{{
   497  		Name: "series_id",
   498  		Type: &Ydb.Type{
   499  			Type: &Ydb.Type_TypeId{
   500  				TypeId: Ydb.Type_UINT64,
   501  			},
   502  		},
   503  	}, {
   504  		Name: "title",
   505  		Type: &Ydb.Type{
   506  			Type: &Ydb.Type_OptionalType{
   507  				OptionalType: &Ydb.OptionalType{
   508  					Item: &Ydb.Type{
   509  						Type: &Ydb.Type_TypeId{
   510  							TypeId: Ydb.Type_UTF8,
   511  						},
   512  					},
   513  				},
   514  			},
   515  		},
   516  	}, {
   517  		Name: "release_date",
   518  		Type: &Ydb.Type{
   519  			Type: &Ydb.Type_OptionalType{
   520  				OptionalType: &Ydb.OptionalType{
   521  					Item: &Ydb.Type{
   522  						Type: &Ydb.Type_TypeId{
   523  							TypeId: Ydb.Type_DATETIME,
   524  						},
   525  					},
   526  				},
   527  			},
   528  		},
   529  	}}
   530  	res.set.Rows = []*Ydb.Value{}
   531  	for i := 0; i < count; i++ {
   532  		res.set.Rows = append(res.set.GetRows(), &Ydb.Value{
   533  			Items: []*Ydb.Value{{
   534  				Value: &Ydb.Value_Uint64Value{
   535  					Uint64Value: uint64(i),
   536  				},
   537  			}, {
   538  				Value: &Ydb.Value_TextValue{
   539  					TextValue: strconv.Itoa(i) + "a",
   540  				},
   541  			}, {
   542  				Value: &Ydb.Value_Uint32Value{
   543  					Uint32Value: uint32(i),
   544  				},
   545  			}},
   546  		})
   547  	}
   548  	res.converter = &rawConverter{res}
   549  
   550  	return res
   551  }