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 }