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

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