1/* 2Copyright 2017 Google LLC 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package spanner 18 19import ( 20 "encoding/base64" 21 "fmt" 22 "reflect" 23 "strconv" 24 "strings" 25 "testing" 26 "time" 27 28 "cloud.google.com/go/civil" 29 "cloud.google.com/go/internal/testutil" 30 proto "github.com/golang/protobuf/proto" 31 proto3 "github.com/golang/protobuf/ptypes/struct" 32 "github.com/google/go-cmp/cmp" 33 sppb "google.golang.org/genproto/googleapis/spanner/v1" 34) 35 36var ( 37 tm = time.Date(2016, 11, 15, 0, 0, 0, 0, time.UTC) 38 dt, _ = civil.ParseDate("2016-11-15") 39 // row contains a column for each unique Cloud Spanner type. 40 row = Row{ 41 []*sppb.StructType_Field{ 42 // STRING / STRING ARRAY 43 {Name: "STRING", Type: stringType()}, 44 {Name: "NULL_STRING", Type: stringType()}, 45 {Name: "STRING_ARRAY", Type: listType(stringType())}, 46 {Name: "NULL_STRING_ARRAY", Type: listType(stringType())}, 47 // BYTES / BYTES ARRAY 48 {Name: "BYTES", Type: bytesType()}, 49 {Name: "NULL_BYTES", Type: bytesType()}, 50 {Name: "BYTES_ARRAY", Type: listType(bytesType())}, 51 {Name: "NULL_BYTES_ARRAY", Type: listType(bytesType())}, 52 // INT64 / INT64 ARRAY 53 {Name: "INT64", Type: intType()}, 54 {Name: "NULL_INT64", Type: intType()}, 55 {Name: "INT64_ARRAY", Type: listType(intType())}, 56 {Name: "NULL_INT64_ARRAY", Type: listType(intType())}, 57 // BOOL / BOOL ARRAY 58 {Name: "BOOL", Type: boolType()}, 59 {Name: "NULL_BOOL", Type: boolType()}, 60 {Name: "BOOL_ARRAY", Type: listType(boolType())}, 61 {Name: "NULL_BOOL_ARRAY", Type: listType(boolType())}, 62 // FLOAT64 / FLOAT64 ARRAY 63 {Name: "FLOAT64", Type: floatType()}, 64 {Name: "NULL_FLOAT64", Type: floatType()}, 65 {Name: "FLOAT64_ARRAY", Type: listType(floatType())}, 66 {Name: "NULL_FLOAT64_ARRAY", Type: listType(floatType())}, 67 // TIMESTAMP / TIMESTAMP ARRAY 68 {Name: "TIMESTAMP", Type: timeType()}, 69 {Name: "NULL_TIMESTAMP", Type: timeType()}, 70 {Name: "TIMESTAMP_ARRAY", Type: listType(timeType())}, 71 {Name: "NULL_TIMESTAMP_ARRAY", Type: listType(timeType())}, 72 // DATE / DATE ARRAY 73 {Name: "DATE", Type: dateType()}, 74 {Name: "NULL_DATE", Type: dateType()}, 75 {Name: "DATE_ARRAY", Type: listType(dateType())}, 76 {Name: "NULL_DATE_ARRAY", Type: listType(dateType())}, 77 78 // STRUCT ARRAY 79 { 80 Name: "STRUCT_ARRAY", 81 Type: listType( 82 structType( 83 mkField("Col1", intType()), 84 mkField("Col2", floatType()), 85 mkField("Col3", stringType()), 86 ), 87 ), 88 }, 89 { 90 Name: "NULL_STRUCT_ARRAY", 91 Type: listType( 92 structType( 93 mkField("Col1", intType()), 94 mkField("Col2", floatType()), 95 mkField("Col3", stringType()), 96 ), 97 ), 98 }, 99 }, 100 []*proto3.Value{ 101 // STRING / STRING ARRAY 102 stringProto("value"), 103 nullProto(), 104 listProto(stringProto("value1"), nullProto(), stringProto("value3")), 105 nullProto(), 106 // BYTES / BYTES ARRAY 107 bytesProto([]byte("value")), 108 nullProto(), 109 listProto(bytesProto([]byte("value1")), nullProto(), bytesProto([]byte("value3"))), 110 nullProto(), 111 // INT64 / INT64 ARRAY 112 intProto(17), 113 nullProto(), 114 listProto(intProto(1), intProto(2), nullProto()), 115 nullProto(), 116 // BOOL / BOOL ARRAY 117 boolProto(true), 118 nullProto(), 119 listProto(nullProto(), boolProto(true), boolProto(false)), 120 nullProto(), 121 // FLOAT64 / FLOAT64 ARRAY 122 floatProto(1.7), 123 nullProto(), 124 listProto(nullProto(), nullProto(), floatProto(1.7)), 125 nullProto(), 126 // TIMESTAMP / TIMESTAMP ARRAY 127 timeProto(tm), 128 nullProto(), 129 listProto(nullProto(), timeProto(tm)), 130 nullProto(), 131 // DATE / DATE ARRAY 132 dateProto(dt), 133 nullProto(), 134 listProto(nullProto(), dateProto(dt)), 135 nullProto(), 136 // STRUCT ARRAY 137 listProto( 138 nullProto(), 139 listProto(intProto(3), floatProto(33.3), stringProto("three")), 140 nullProto(), 141 ), 142 nullProto(), 143 }, 144 } 145) 146 147// Test helpers for getting column values. 148func TestColumnValues(t *testing.T) { 149 vals := []interface{}{} 150 wantVals := []interface{}{} 151 // Test getting column values. 152 for i, wants := range [][]interface{}{ 153 // STRING / STRING ARRAY 154 {"value", NullString{"value", true}}, 155 {NullString{}}, 156 {[]NullString{{"value1", true}, {}, {"value3", true}}}, 157 {[]NullString(nil)}, 158 // BYTES / BYTES ARRAY 159 {[]byte("value")}, 160 {[]byte(nil)}, 161 {[][]byte{[]byte("value1"), nil, []byte("value3")}}, 162 {[][]byte(nil)}, 163 // INT64 / INT64 ARRAY 164 {int64(17), NullInt64{17, true}}, 165 {NullInt64{}}, 166 {[]NullInt64{{1, true}, {2, true}, {}}}, 167 {[]NullInt64(nil)}, 168 // BOOL / BOOL ARRAY 169 {true, NullBool{true, true}}, 170 {NullBool{}}, 171 {[]NullBool{{}, {true, true}, {false, true}}}, 172 {[]NullBool(nil)}, 173 // FLOAT64 / FLOAT64 ARRAY 174 {1.7, NullFloat64{1.7, true}}, 175 {NullFloat64{}}, 176 {[]NullFloat64{{}, {}, {1.7, true}}}, 177 {[]NullFloat64(nil)}, 178 // TIMESTAMP / TIMESTAMP ARRAY 179 {tm, NullTime{tm, true}}, 180 {NullTime{}}, 181 {[]NullTime{{}, {tm, true}}}, 182 {[]NullTime(nil)}, 183 // DATE / DATE ARRAY 184 {dt, NullDate{dt, true}}, 185 {NullDate{}}, 186 {[]NullDate{{}, {dt, true}}}, 187 {[]NullDate(nil)}, 188 // STRUCT ARRAY 189 { 190 []*struct { 191 Col1 NullInt64 192 Col2 NullFloat64 193 Col3 string 194 }{ 195 nil, 196 197 { 198 NullInt64{3, true}, 199 NullFloat64{33.3, true}, 200 "three", 201 }, 202 nil, 203 }, 204 []NullRow{ 205 {}, 206 { 207 Row: Row{ 208 fields: []*sppb.StructType_Field{ 209 mkField("Col1", intType()), 210 mkField("Col2", floatType()), 211 mkField("Col3", stringType()), 212 }, 213 vals: []*proto3.Value{ 214 intProto(3), 215 floatProto(33.3), 216 stringProto("three"), 217 }, 218 }, 219 Valid: true, 220 }, 221 {}, 222 }, 223 }, 224 { 225 []*struct { 226 Col1 NullInt64 227 Col2 NullFloat64 228 Col3 string 229 }(nil), 230 []NullRow(nil), 231 }, 232 } { 233 for j, want := range wants { 234 // Prepare Value vector to test Row.Columns. 235 if j == 0 { 236 vals = append(vals, reflect.New(reflect.TypeOf(want)).Interface()) 237 wantVals = append(wantVals, want) 238 } 239 // Column 240 gotp := reflect.New(reflect.TypeOf(want)) 241 err := row.Column(i, gotp.Interface()) 242 if err != nil { 243 t.Errorf("\t row.Column(%v, %T) returns error: %v, want nil", i, gotp.Interface(), err) 244 } 245 if got := reflect.Indirect(gotp).Interface(); !testEqual(got, want) { 246 t.Errorf("\t row.Column(%v, %T) retrives %v, want %v", i, gotp.Interface(), got, want) 247 } 248 // ColumnByName 249 gotp = reflect.New(reflect.TypeOf(want)) 250 err = row.ColumnByName(row.fields[i].Name, gotp.Interface()) 251 if err != nil { 252 t.Errorf("\t row.ColumnByName(%v, %T) returns error: %v, want nil", row.fields[i].Name, gotp.Interface(), err) 253 } 254 if got := reflect.Indirect(gotp).Interface(); !testEqual(got, want) { 255 t.Errorf("\t row.ColumnByName(%v, %T) retrives %v, want %v", row.fields[i].Name, gotp.Interface(), got, want) 256 } 257 } 258 } 259 // Test Row.Columns. 260 if err := row.Columns(vals...); err != nil { 261 t.Errorf("row.Columns() returns error: %v, want nil", err) 262 } 263 for i, want := range wantVals { 264 if got := reflect.Indirect(reflect.ValueOf(vals[i])).Interface(); !testEqual(got, want) { 265 t.Errorf("\t got %v(%T) for column[%v], want %v(%T)", got, got, row.fields[i].Name, want, want) 266 } 267 } 268} 269 270// Test decoding into nil destination. 271func TestNilDst(t *testing.T) { 272 for i, test := range []struct { 273 r *Row 274 dst interface{} 275 wantErr error 276 structDst interface{} 277 wantToStructErr error 278 }{ 279 { 280 &Row{ 281 []*sppb.StructType_Field{ 282 {Name: "Col0", Type: stringType()}, 283 }, 284 []*proto3.Value{stringProto("value")}, 285 }, 286 nil, 287 errDecodeColumn(0, errNilDst(nil)), 288 nil, 289 errToStructArgType(nil), 290 }, 291 { 292 &Row{ 293 []*sppb.StructType_Field{ 294 {Name: "Col0", Type: stringType()}, 295 }, 296 []*proto3.Value{stringProto("value")}, 297 }, 298 (*string)(nil), 299 errDecodeColumn(0, errNilDst((*string)(nil))), 300 (*struct{ STRING string })(nil), 301 errNilDst((*struct{ STRING string })(nil)), 302 }, 303 { 304 &Row{ 305 []*sppb.StructType_Field{ 306 { 307 Name: "Col0", 308 Type: listType( 309 structType( 310 mkField("Col1", intType()), 311 mkField("Col2", floatType()), 312 ), 313 ), 314 }, 315 }, 316 []*proto3.Value{listProto( 317 listProto(intProto(3), floatProto(33.3)), 318 )}, 319 }, 320 (*[]*struct { 321 Col1 int 322 Col2 float64 323 })(nil), 324 errDecodeColumn(0, errNilDst((*[]*struct { 325 Col1 int 326 Col2 float64 327 })(nil))), 328 (*struct { 329 StructArray []*struct { 330 Col1 int 331 Col2 float64 332 } `spanner:"STRUCT_ARRAY"` 333 })(nil), 334 errNilDst((*struct { 335 StructArray []*struct { 336 Col1 int 337 Col2 float64 338 } `spanner:"STRUCT_ARRAY"` 339 })(nil)), 340 }, 341 } { 342 if gotErr := test.r.Column(0, test.dst); !testEqual(gotErr, test.wantErr) { 343 t.Errorf("%v: test.r.Column() returns error %v, want %v", i, gotErr, test.wantErr) 344 } 345 if gotErr := test.r.ColumnByName("Col0", test.dst); !testEqual(gotErr, test.wantErr) { 346 t.Errorf("%v: test.r.ColumnByName() returns error %v, want %v", i, gotErr, test.wantErr) 347 } 348 // Row.Columns(T) should return nil on T == nil, otherwise, it should return test.wantErr. 349 wantColumnsErr := test.wantErr 350 if test.dst == nil { 351 wantColumnsErr = nil 352 } 353 if gotErr := test.r.Columns(test.dst); !testEqual(gotErr, wantColumnsErr) { 354 t.Errorf("%v: test.r.Columns() returns error %v, want %v", i, gotErr, wantColumnsErr) 355 } 356 if gotErr := test.r.ToStruct(test.structDst); !testEqual(gotErr, test.wantToStructErr) { 357 t.Errorf("%v: test.r.ToStruct() returns error %v, want %v", i, gotErr, test.wantToStructErr) 358 } 359 } 360} 361 362// Test decoding NULL columns using Go types that don't support NULL. 363func TestNullTypeErr(t *testing.T) { 364 var tm time.Time 365 ntoi := func(n string) int { 366 for i, f := range row.fields { 367 if f.Name == n { 368 return i 369 } 370 } 371 t.Errorf("cannot find column name %q in row", n) 372 return 0 373 } 374 for _, test := range []struct { 375 colName string 376 dst interface{} 377 }{ 378 { 379 "NULL_STRING", 380 proto.String(""), 381 }, 382 { 383 "NULL_INT64", 384 proto.Int64(0), 385 }, 386 { 387 "NULL_BOOL", 388 proto.Bool(false), 389 }, 390 { 391 "NULL_FLOAT64", 392 proto.Float64(0.0), 393 }, 394 { 395 "NULL_TIMESTAMP", 396 &tm, 397 }, 398 { 399 "NULL_DATE", 400 &dt, 401 }, 402 } { 403 wantErr := errDecodeColumn(ntoi(test.colName), errDstNotForNull(test.dst)) 404 if gotErr := row.ColumnByName(test.colName, test.dst); !testEqual(gotErr, wantErr) { 405 t.Errorf("row.ColumnByName(%v) returns error %v, want %v", test.colName, gotErr, wantErr) 406 } 407 } 408} 409 410// Test using wrong destination type in column decoders. 411func TestColumnTypeErr(t *testing.T) { 412 // badDst cannot hold any of the column values. 413 badDst := &struct{}{} 414 for i, f := range row.fields { // For each of the columns, try to decode it into badDst. 415 tc := f.Type.Code 416 var etc sppb.TypeCode 417 if strings.Contains(f.Name, "ARRAY") { 418 etc = f.Type.ArrayElementType.Code 419 } 420 wantErr := errDecodeColumn(i, errTypeMismatch(tc, etc, badDst)) 421 if strings.Contains(f.Name, "STRUCT_ARRAY") { 422 wantErr = errDecodeColumn(i, fmt.Errorf("the container is not a slice of struct pointers: %v", errTypeMismatch(tc, etc, badDst))) 423 } 424 if gotErr := row.Column(i, badDst); !testEqual(gotErr, wantErr) { 425 t.Errorf("Column(%v): decoding into destination with wrong type %T returns error %v, want %v", 426 i, badDst, gotErr, wantErr) 427 } 428 if gotErr := row.ColumnByName(f.Name, badDst); !testEqual(gotErr, wantErr) { 429 t.Errorf("ColumnByName(%v): decoding into destination with wrong type %T returns error %v, want %v", 430 f.Name, badDst, gotErr, wantErr) 431 } 432 } 433 wantErr := errDecodeColumn(1, errTypeMismatch(sppb.TypeCode_STRING, sppb.TypeCode_TYPE_CODE_UNSPECIFIED, badDst)) 434 // badDst is used to receive column 1. 435 vals := []interface{}{nil, badDst} // Row.Column() is expected to fail at column 1. 436 // Skip decoding the rest columns by providing nils as the destinations. 437 for i := 2; i < len(row.fields); i++ { 438 vals = append(vals, nil) 439 } 440 if gotErr := row.Columns(vals...); !testEqual(gotErr, wantErr) { 441 t.Errorf("Columns(): decoding column 1 with wrong type %T returns error %v, want %v", 442 badDst, gotErr, wantErr) 443 } 444} 445 446// Test the handling of invalid column decoding requests which cannot be mapped to correct column(s). 447func TestInvalidColumnRequest(t *testing.T) { 448 for _, test := range []struct { 449 desc string 450 f func() error 451 wantErr error 452 }{ 453 { 454 "Request column index is out of range", 455 func() error { 456 return row.Column(10000, &struct{}{}) 457 }, 458 errColIdxOutOfRange(10000, &row), 459 }, 460 { 461 "Cannot find the named column", 462 func() error { 463 return row.ColumnByName("string", &struct{}{}) 464 }, 465 errColNotFound("string"), 466 }, 467 { 468 "Not enough arguments to call row.Columns()", 469 func() error { 470 return row.Columns(nil, nil) 471 }, 472 errNumOfColValue(2, &row), 473 }, 474 { 475 "Call ColumnByName on row with duplicated column names", 476 func() error { 477 var s string 478 r := &Row{ 479 []*sppb.StructType_Field{ 480 {Name: "Val", Type: stringType()}, 481 {Name: "Val", Type: stringType()}, 482 }, 483 []*proto3.Value{stringProto("value1"), stringProto("value2")}, 484 } 485 return r.ColumnByName("Val", &s) 486 }, 487 errDupColName("Val"), 488 }, 489 { 490 "Call ToStruct on row with duplicated column names", 491 func() error { 492 s := &struct { 493 Val string 494 }{} 495 r := &Row{ 496 []*sppb.StructType_Field{ 497 {Name: "Val", Type: stringType()}, 498 {Name: "Val", Type: stringType()}, 499 }, 500 []*proto3.Value{stringProto("value1"), stringProto("value2")}, 501 } 502 return r.ToStruct(s) 503 }, 504 errDupSpannerField("Val", &sppb.StructType{ 505 Fields: []*sppb.StructType_Field{ 506 {Name: "Val", Type: stringType()}, 507 {Name: "Val", Type: stringType()}, 508 }, 509 }), 510 }, 511 { 512 "Call ToStruct on a row with unnamed field", 513 func() error { 514 s := &struct { 515 Val string 516 }{} 517 r := &Row{ 518 []*sppb.StructType_Field{ 519 {Name: "", Type: stringType()}, 520 }, 521 []*proto3.Value{stringProto("value1")}, 522 } 523 return r.ToStruct(s) 524 }, 525 errUnnamedField(&sppb.StructType{Fields: []*sppb.StructType_Field{ 526 {Name: "", Type: stringType()}, 527 }}, 0), 528 }, 529 } { 530 if gotErr := test.f(); !testEqual(gotErr, test.wantErr) { 531 t.Errorf("%v: test.f() returns error %v, want %v", test.desc, gotErr, test.wantErr) 532 } 533 } 534} 535 536// Test decoding the row with row.ToStruct into an invalid destination. 537func TestToStructInvalidDst(t *testing.T) { 538 for _, test := range []struct { 539 desc string 540 dst interface{} 541 wantErr error 542 }{ 543 { 544 "Decode row as STRUCT into int32", 545 proto.Int(1), 546 errToStructArgType(proto.Int(1)), 547 }, 548 { 549 "Decode row as STRUCT to nil Go struct", 550 (*struct{})(nil), 551 errNilDst((*struct{})(nil)), 552 }, 553 { 554 "Decode row as STRUCT to Go struct with duplicated fields for the PK column", 555 &struct { 556 PK1 string `spanner:"STRING"` 557 PK2 string `spanner:"STRING"` 558 }{}, 559 errNoOrDupGoField(&struct { 560 PK1 string `spanner:"STRING"` 561 PK2 string `spanner:"STRING"` 562 }{}, "STRING"), 563 }, 564 { 565 "Decode row as STRUCT to Go struct with no field for the PK column", 566 &struct { 567 PK1 string `spanner:"_STRING"` 568 }{}, 569 errNoOrDupGoField(&struct { 570 PK1 string `spanner:"_STRING"` 571 }{}, "STRING"), 572 }, 573 { 574 "Decode row as STRUCT to Go struct with wrong type for the PK column", 575 &struct { 576 PK1 int64 `spanner:"STRING"` 577 }{}, 578 errDecodeStructField(&sppb.StructType{Fields: row.fields}, "STRING", 579 errTypeMismatch(sppb.TypeCode_STRING, sppb.TypeCode_TYPE_CODE_UNSPECIFIED, proto.Int64(0))), 580 }, 581 } { 582 if gotErr := row.ToStruct(test.dst); !testEqual(gotErr, test.wantErr) { 583 t.Errorf("%v: decoding:\ngot %v\nwant %v", test.desc, gotErr, test.wantErr) 584 } 585 } 586} 587 588// Test decoding a broken row. 589func TestBrokenRow(t *testing.T) { 590 for i, test := range []struct { 591 row *Row 592 dst interface{} 593 wantErr error 594 }{ 595 { 596 // A row with no field. 597 &Row{ 598 []*sppb.StructType_Field{}, 599 []*proto3.Value{stringProto("value")}, 600 }, 601 &NullString{"value", true}, 602 errFieldsMismatchVals(&Row{ 603 []*sppb.StructType_Field{}, 604 []*proto3.Value{stringProto("value")}, 605 }), 606 }, 607 { 608 // A row with nil field. 609 &Row{ 610 []*sppb.StructType_Field{nil}, 611 []*proto3.Value{stringProto("value")}, 612 }, 613 &NullString{"value", true}, 614 errNilColType(0), 615 }, 616 { 617 // Field is not nil, but its type is nil. 618 &Row{ 619 []*sppb.StructType_Field{ 620 {Name: "Col0", Type: nil}, 621 }, 622 []*proto3.Value{listProto(stringProto("value1"), stringProto("value2"))}, 623 }, 624 &[]NullString{}, 625 errDecodeColumn(0, errNilSpannerType()), 626 }, 627 { 628 // Field is not nil, field type is not nil, but it is an array and its array element type is nil. 629 &Row{ 630 []*sppb.StructType_Field{ 631 {Name: "Col0", Type: &sppb.Type{Code: sppb.TypeCode_ARRAY}}, 632 }, 633 []*proto3.Value{listProto(stringProto("value1"), stringProto("value2"))}, 634 }, 635 &[]NullString{}, 636 errDecodeColumn(0, errNilArrElemType(&sppb.Type{Code: sppb.TypeCode_ARRAY})), 637 }, 638 { 639 // Field specifies valid type, value is nil. 640 &Row{ 641 []*sppb.StructType_Field{ 642 {Name: "Col0", Type: intType()}, 643 }, 644 []*proto3.Value{nil}, 645 }, 646 &NullInt64{1, true}, 647 errDecodeColumn(0, errNilSrc()), 648 }, 649 { 650 // Field specifies INT64 type, value is having a nil Kind. 651 &Row{ 652 []*sppb.StructType_Field{ 653 {Name: "Col0", Type: intType()}, 654 }, 655 []*proto3.Value{{Kind: (*proto3.Value_StringValue)(nil)}}, 656 }, 657 &NullInt64{1, true}, 658 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_StringValue)(nil)}, "String")), 659 }, 660 { 661 // Field specifies INT64 type, but value is for Number type. 662 &Row{ 663 []*sppb.StructType_Field{ 664 {Name: "Col0", Type: intType()}, 665 }, 666 []*proto3.Value{floatProto(1.0)}, 667 }, 668 &NullInt64{1, true}, 669 errDecodeColumn(0, errSrcVal(floatProto(1.0), "String")), 670 }, 671 { 672 // Field specifies INT64 type, but value is wrongly encoded. 673 &Row{ 674 []*sppb.StructType_Field{ 675 {Name: "Col0", Type: intType()}, 676 }, 677 []*proto3.Value{stringProto("&1")}, 678 }, 679 proto.Int64(0), 680 errDecodeColumn(0, errBadEncoding(stringProto("&1"), func() error { 681 _, err := strconv.ParseInt("&1", 10, 64) 682 return err 683 }())), 684 }, 685 { 686 // Field specifies INT64 type, but value is wrongly encoded. 687 &Row{ 688 []*sppb.StructType_Field{ 689 {Name: "Col0", Type: intType()}, 690 }, 691 []*proto3.Value{stringProto("&1")}, 692 }, 693 &NullInt64{}, 694 errDecodeColumn(0, errBadEncoding(stringProto("&1"), func() error { 695 _, err := strconv.ParseInt("&1", 10, 64) 696 return err 697 }())), 698 }, 699 { 700 // Field specifies STRING type, but value is having a nil Kind. 701 &Row{ 702 []*sppb.StructType_Field{ 703 {Name: "Col0", Type: stringType()}, 704 }, 705 []*proto3.Value{{Kind: (*proto3.Value_StringValue)(nil)}}, 706 }, 707 &NullString{"value", true}, 708 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_StringValue)(nil)}, "String")), 709 }, 710 { 711 // Field specifies STRING type, but value is for ARRAY type. 712 &Row{ 713 []*sppb.StructType_Field{ 714 {Name: "Col0", Type: stringType()}, 715 }, 716 []*proto3.Value{listProto(stringProto("value"))}, 717 }, 718 &NullString{"value", true}, 719 errDecodeColumn(0, errSrcVal(listProto(stringProto("value")), "String")), 720 }, 721 { 722 // Field specifies FLOAT64 type, value is having a nil Kind. 723 &Row{ 724 []*sppb.StructType_Field{ 725 {Name: "Col0", Type: floatType()}, 726 }, 727 []*proto3.Value{{Kind: (*proto3.Value_NumberValue)(nil)}}, 728 }, 729 &NullFloat64{1.0, true}, 730 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_NumberValue)(nil)}, "Number")), 731 }, 732 { 733 // Field specifies FLOAT64 type, but value is for BOOL type. 734 &Row{ 735 []*sppb.StructType_Field{ 736 {Name: "Col0", Type: floatType()}, 737 }, 738 []*proto3.Value{boolProto(true)}, 739 }, 740 &NullFloat64{1.0, true}, 741 errDecodeColumn(0, errSrcVal(boolProto(true), "Number")), 742 }, 743 { 744 // Field specifies FLOAT64 type, but value is wrongly encoded. 745 &Row{ 746 []*sppb.StructType_Field{ 747 {Name: "Col0", Type: floatType()}, 748 }, 749 []*proto3.Value{stringProto("nan")}, 750 }, 751 &NullFloat64{}, 752 errDecodeColumn(0, errUnexpectedFloat64Str("nan")), 753 }, 754 { 755 // Field specifies FLOAT64 type, but value is wrongly encoded. 756 &Row{ 757 []*sppb.StructType_Field{ 758 {Name: "Col0", Type: floatType()}, 759 }, 760 []*proto3.Value{stringProto("nan")}, 761 }, 762 proto.Float64(0), 763 errDecodeColumn(0, errUnexpectedFloat64Str("nan")), 764 }, 765 { 766 // Field specifies BYTES type, value is having a nil Kind. 767 &Row{ 768 []*sppb.StructType_Field{ 769 {Name: "Col0", Type: bytesType()}, 770 }, 771 []*proto3.Value{{Kind: (*proto3.Value_StringValue)(nil)}}, 772 }, 773 &[]byte{}, 774 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_StringValue)(nil)}, "String")), 775 }, 776 { 777 // Field specifies BYTES type, but value is for BOOL type. 778 &Row{ 779 []*sppb.StructType_Field{ 780 {Name: "Col0", Type: bytesType()}, 781 }, 782 []*proto3.Value{boolProto(false)}, 783 }, 784 &[]byte{}, 785 errDecodeColumn(0, errSrcVal(boolProto(false), "String")), 786 }, 787 { 788 // Field specifies BYTES type, but value is wrongly encoded. 789 &Row{ 790 []*sppb.StructType_Field{ 791 {Name: "Col0", Type: bytesType()}, 792 }, 793 []*proto3.Value{stringProto("&&")}, 794 }, 795 &[]byte{}, 796 errDecodeColumn(0, errBadEncoding(stringProto("&&"), func() error { 797 _, err := base64.StdEncoding.DecodeString("&&") 798 return err 799 }())), 800 }, 801 { 802 // Field specifies BOOL type, value is having a nil Kind. 803 &Row{ 804 []*sppb.StructType_Field{ 805 {Name: "Col0", Type: boolType()}, 806 }, 807 []*proto3.Value{{Kind: (*proto3.Value_BoolValue)(nil)}}, 808 }, 809 &NullBool{false, true}, 810 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_BoolValue)(nil)}, "Bool")), 811 }, 812 { 813 // Field specifies BOOL type, but value is for STRING type. 814 &Row{ 815 []*sppb.StructType_Field{ 816 {Name: "Col0", Type: boolType()}, 817 }, 818 []*proto3.Value{stringProto("false")}, 819 }, 820 &NullBool{false, true}, 821 errDecodeColumn(0, errSrcVal(stringProto("false"), "Bool")), 822 }, 823 { 824 // Field specifies TIMESTAMP type, value is having a nil Kind. 825 &Row{ 826 []*sppb.StructType_Field{ 827 {Name: "Col0", Type: timeType()}, 828 }, 829 []*proto3.Value{{Kind: (*proto3.Value_StringValue)(nil)}}, 830 }, 831 &NullTime{time.Now(), true}, 832 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_StringValue)(nil)}, "String")), 833 }, 834 { 835 // Field specifies TIMESTAMP type, but value is for BOOL type. 836 &Row{ 837 []*sppb.StructType_Field{ 838 {Name: "Col0", Type: timeType()}, 839 }, 840 []*proto3.Value{boolProto(false)}, 841 }, 842 &NullTime{time.Now(), true}, 843 errDecodeColumn(0, errSrcVal(boolProto(false), "String")), 844 }, 845 { 846 // Field specifies TIMESTAMP type, but value is invalid timestamp. 847 &Row{ 848 []*sppb.StructType_Field{ 849 {Name: "Col0", Type: timeType()}, 850 }, 851 []*proto3.Value{stringProto("junk")}, 852 }, 853 &NullTime{time.Now(), true}, 854 errDecodeColumn(0, errBadEncoding(stringProto("junk"), func() error { 855 _, err := time.Parse(time.RFC3339Nano, "junk") 856 return err 857 }())), 858 }, 859 { 860 // Field specifies DATE type, value is having a nil Kind. 861 &Row{ 862 []*sppb.StructType_Field{ 863 {Name: "Col0", Type: dateType()}, 864 }, 865 []*proto3.Value{{Kind: (*proto3.Value_StringValue)(nil)}}, 866 }, 867 &NullDate{civil.Date{}, true}, 868 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_StringValue)(nil)}, "String")), 869 }, 870 { 871 // Field specifies DATE type, but value is for BOOL type. 872 &Row{ 873 []*sppb.StructType_Field{ 874 {Name: "Col0", Type: dateType()}, 875 }, 876 []*proto3.Value{boolProto(false)}, 877 }, 878 &NullDate{civil.Date{}, true}, 879 errDecodeColumn(0, errSrcVal(boolProto(false), "String")), 880 }, 881 { 882 // Field specifies DATE type, but value is invalid timestamp. 883 &Row{ 884 []*sppb.StructType_Field{ 885 {Name: "Col0", Type: dateType()}, 886 }, 887 []*proto3.Value{stringProto("junk")}, 888 }, 889 &NullDate{civil.Date{}, true}, 890 errDecodeColumn(0, errBadEncoding(stringProto("junk"), func() error { 891 _, err := civil.ParseDate("junk") 892 return err 893 }())), 894 }, 895 896 { 897 // Field specifies ARRAY<INT64> type, value is having a nil Kind. 898 &Row{ 899 []*sppb.StructType_Field{ 900 {Name: "Col0", Type: listType(intType())}, 901 }, 902 []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, 903 }, 904 &[]NullInt64{}, 905 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), 906 }, 907 { 908 // Field specifies ARRAY<INT64> type, value is having a nil ListValue. 909 &Row{ 910 []*sppb.StructType_Field{ 911 {Name: "Col0", Type: listType(intType())}, 912 }, 913 []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, 914 }, 915 &[]NullInt64{}, 916 errDecodeColumn(0, errNilListValue("INT64")), 917 }, 918 { 919 // Field specifies ARRAY<INT64> type, but value is for BYTES type. 920 &Row{ 921 []*sppb.StructType_Field{ 922 {Name: "Col0", Type: listType(intType())}, 923 }, 924 []*proto3.Value{bytesProto([]byte("value"))}, 925 }, 926 &[]NullInt64{}, 927 errDecodeColumn(0, errSrcVal(bytesProto([]byte("value")), "List")), 928 }, 929 { 930 // Field specifies ARRAY<INT64> type, but value is for ARRAY<BOOL> type. 931 &Row{ 932 []*sppb.StructType_Field{ 933 {Name: "Col0", Type: listType(intType())}, 934 }, 935 []*proto3.Value{listProto(boolProto(true))}, 936 }, 937 &[]NullInt64{}, 938 errDecodeColumn(0, errDecodeArrayElement(0, boolProto(true), 939 "INT64", errSrcVal(boolProto(true), "String"))), 940 }, 941 { 942 // Field specifies ARRAY<STRING> type, value is having a nil Kind. 943 &Row{ 944 []*sppb.StructType_Field{ 945 {Name: "Col0", Type: listType(stringType())}, 946 }, 947 []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, 948 }, 949 &[]NullString{}, 950 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), 951 }, 952 { 953 // Field specifies ARRAY<STRING> type, value is having a nil ListValue. 954 &Row{ 955 []*sppb.StructType_Field{ 956 {Name: "Col0", Type: listType(stringType())}, 957 }, 958 []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, 959 }, 960 &[]NullString{}, 961 errDecodeColumn(0, errNilListValue("STRING")), 962 }, 963 { 964 // Field specifies ARRAY<STRING> type, but value is for BOOL type. 965 &Row{ 966 []*sppb.StructType_Field{ 967 {Name: "Col0", Type: listType(stringType())}, 968 }, 969 []*proto3.Value{boolProto(true)}, 970 }, 971 &[]NullString{}, 972 errDecodeColumn(0, errSrcVal(boolProto(true), "List")), 973 }, 974 { 975 // Field specifies ARRAY<STRING> type, but value is for ARRAY<BOOL> type. 976 &Row{ 977 []*sppb.StructType_Field{ 978 {Name: "Col0", Type: listType(stringType())}, 979 }, 980 []*proto3.Value{listProto(boolProto(true))}, 981 }, 982 &[]NullString{}, 983 errDecodeColumn(0, errDecodeArrayElement(0, boolProto(true), 984 "STRING", errSrcVal(boolProto(true), "String"))), 985 }, 986 { 987 // Field specifies ARRAY<FLOAT64> type, value is having a nil Kind. 988 &Row{ 989 []*sppb.StructType_Field{ 990 {Name: "Col0", Type: listType(floatType())}, 991 }, 992 []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, 993 }, 994 &[]NullFloat64{}, 995 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), 996 }, 997 { 998 // Field specifies ARRAY<FLOAT64> type, value is having a nil ListValue. 999 &Row{ 1000 []*sppb.StructType_Field{ 1001 {Name: "Col0", Type: listType(floatType())}, 1002 }, 1003 []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, 1004 }, 1005 &[]NullFloat64{}, 1006 errDecodeColumn(0, errNilListValue("FLOAT64")), 1007 }, 1008 { 1009 // Field specifies ARRAY<FLOAT64> type, but value is for STRING type. 1010 &Row{ 1011 []*sppb.StructType_Field{ 1012 {Name: "Col0", Type: listType(floatType())}, 1013 }, 1014 []*proto3.Value{stringProto("value")}, 1015 }, 1016 &[]NullFloat64{}, 1017 errDecodeColumn(0, errSrcVal(stringProto("value"), "List")), 1018 }, 1019 { 1020 // Field specifies ARRAY<FLOAT64> type, but value is for ARRAY<BOOL> type. 1021 &Row{ 1022 []*sppb.StructType_Field{ 1023 {Name: "Col0", Type: listType(floatType())}, 1024 }, 1025 []*proto3.Value{listProto(boolProto(true))}, 1026 }, 1027 &[]NullFloat64{}, 1028 errDecodeColumn(0, errDecodeArrayElement(0, boolProto(true), 1029 "FLOAT64", errSrcVal(boolProto(true), "Number"))), 1030 }, 1031 { 1032 // Field specifies ARRAY<BYTES> type, value is having a nil Kind. 1033 &Row{ 1034 []*sppb.StructType_Field{ 1035 {Name: "Col0", Type: listType(bytesType())}, 1036 }, 1037 []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, 1038 }, 1039 &[][]byte{}, 1040 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), 1041 }, 1042 { 1043 // Field specifies ARRAY<BYTES> type, value is having a nil ListValue. 1044 &Row{ 1045 []*sppb.StructType_Field{ 1046 {Name: "Col0", Type: listType(bytesType())}, 1047 }, 1048 []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, 1049 }, 1050 &[][]byte{}, 1051 errDecodeColumn(0, errNilListValue("BYTES")), 1052 }, 1053 { 1054 // Field specifies ARRAY<BYTES> type, but value is for FLOAT64 type. 1055 &Row{ 1056 []*sppb.StructType_Field{ 1057 {Name: "Col0", Type: listType(bytesType())}, 1058 }, 1059 []*proto3.Value{floatProto(1.0)}, 1060 }, 1061 &[][]byte{}, 1062 errDecodeColumn(0, errSrcVal(floatProto(1.0), "List")), 1063 }, 1064 { 1065 // Field specifies ARRAY<BYTES> type, but value is for ARRAY<FLOAT64> type. 1066 &Row{ 1067 []*sppb.StructType_Field{ 1068 {Name: "Col0", Type: listType(bytesType())}, 1069 }, 1070 []*proto3.Value{listProto(floatProto(1.0))}, 1071 }, 1072 &[][]byte{}, 1073 errDecodeColumn(0, errDecodeArrayElement(0, floatProto(1.0), 1074 "BYTES", errSrcVal(floatProto(1.0), "String"))), 1075 }, 1076 { 1077 // Field specifies ARRAY<BOOL> type, value is having a nil Kind. 1078 &Row{ 1079 []*sppb.StructType_Field{ 1080 {Name: "Col0", Type: listType(boolType())}, 1081 }, 1082 []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, 1083 }, 1084 &[]NullBool{}, 1085 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), 1086 }, 1087 { 1088 // Field specifies ARRAY<BOOL> type, value is having a nil ListValue. 1089 &Row{ 1090 []*sppb.StructType_Field{ 1091 {Name: "Col0", Type: listType(boolType())}, 1092 }, 1093 []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, 1094 }, 1095 &[]NullBool{}, 1096 errDecodeColumn(0, errNilListValue("BOOL")), 1097 }, 1098 { 1099 // Field specifies ARRAY<BOOL> type, but value is for FLOAT64 type. 1100 &Row{ 1101 []*sppb.StructType_Field{ 1102 {Name: "Col0", Type: listType(boolType())}, 1103 }, 1104 []*proto3.Value{floatProto(1.0)}, 1105 }, 1106 &[]NullBool{}, 1107 errDecodeColumn(0, errSrcVal(floatProto(1.0), "List")), 1108 }, 1109 { 1110 // Field specifies ARRAY<BOOL> type, but value is for ARRAY<FLOAT64> type. 1111 &Row{ 1112 []*sppb.StructType_Field{ 1113 {Name: "Col0", Type: listType(boolType())}, 1114 }, 1115 []*proto3.Value{listProto(floatProto(1.0))}, 1116 }, 1117 &[]NullBool{}, 1118 errDecodeColumn(0, errDecodeArrayElement(0, floatProto(1.0), 1119 "BOOL", errSrcVal(floatProto(1.0), "Bool"))), 1120 }, 1121 { 1122 // Field specifies ARRAY<TIMESTAMP> type, value is having a nil Kind. 1123 &Row{ 1124 []*sppb.StructType_Field{ 1125 {Name: "Col0", Type: listType(timeType())}, 1126 }, 1127 []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, 1128 }, 1129 &[]NullTime{}, 1130 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), 1131 }, 1132 { 1133 // Field specifies ARRAY<TIMESTAMP> type, value is having a nil ListValue. 1134 &Row{ 1135 []*sppb.StructType_Field{ 1136 {Name: "Col0", Type: listType(timeType())}, 1137 }, 1138 []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, 1139 }, 1140 &[]NullTime{}, 1141 errDecodeColumn(0, errNilListValue("TIMESTAMP")), 1142 }, 1143 { 1144 // Field specifies ARRAY<TIMESTAMP> type, but value is for FLOAT64 type. 1145 &Row{ 1146 []*sppb.StructType_Field{ 1147 {Name: "Col0", Type: listType(timeType())}, 1148 }, 1149 []*proto3.Value{floatProto(1.0)}, 1150 }, 1151 &[]NullTime{}, 1152 errDecodeColumn(0, errSrcVal(floatProto(1.0), "List")), 1153 }, 1154 { 1155 // Field specifies ARRAY<TIMESTAMP> type, but value is for ARRAY<FLOAT64> type. 1156 &Row{ 1157 []*sppb.StructType_Field{ 1158 {Name: "Col0", Type: listType(timeType())}, 1159 }, 1160 []*proto3.Value{listProto(floatProto(1.0))}, 1161 }, 1162 &[]NullTime{}, 1163 errDecodeColumn(0, errDecodeArrayElement(0, floatProto(1.0), 1164 "TIMESTAMP", errSrcVal(floatProto(1.0), "String"))), 1165 }, 1166 { 1167 // Field specifies ARRAY<DATE> type, value is having a nil Kind. 1168 &Row{ 1169 []*sppb.StructType_Field{ 1170 {Name: "Col0", Type: listType(dateType())}, 1171 }, 1172 []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, 1173 }, 1174 &[]NullDate{}, 1175 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), 1176 }, 1177 { 1178 // Field specifies ARRAY<DATE> type, value is having a nil ListValue. 1179 &Row{ 1180 []*sppb.StructType_Field{ 1181 {Name: "Col0", Type: listType(dateType())}, 1182 }, 1183 []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, 1184 }, 1185 &[]NullDate{}, 1186 errDecodeColumn(0, errNilListValue("DATE")), 1187 }, 1188 { 1189 // Field specifies ARRAY<DATE> type, but value is for FLOAT64 type. 1190 &Row{ 1191 []*sppb.StructType_Field{ 1192 {Name: "Col0", Type: listType(dateType())}, 1193 }, 1194 []*proto3.Value{floatProto(1.0)}, 1195 }, 1196 &[]NullDate{}, 1197 errDecodeColumn(0, errSrcVal(floatProto(1.0), "List")), 1198 }, 1199 { 1200 // Field specifies ARRAY<DATE> type, but value is for ARRAY<FLOAT64> type. 1201 &Row{ 1202 []*sppb.StructType_Field{ 1203 {Name: "Col0", Type: listType(dateType())}, 1204 }, 1205 []*proto3.Value{listProto(floatProto(1.0))}, 1206 }, 1207 &[]NullDate{}, 1208 errDecodeColumn(0, errDecodeArrayElement(0, floatProto(1.0), 1209 "DATE", errSrcVal(floatProto(1.0), "String"))), 1210 }, 1211 { 1212 // Field specifies ARRAY<STRUCT> type, value is having a nil Kind. 1213 &Row{ 1214 []*sppb.StructType_Field{ 1215 {Name: "Col0", Type: listType(structType( 1216 mkField("Col1", intType()), 1217 mkField("Col2", floatType()), 1218 mkField("Col3", stringType()), 1219 ))}, 1220 }, 1221 []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, 1222 }, 1223 &[]*struct { 1224 Col1 int64 1225 Col2 float64 1226 Col3 string 1227 }{}, 1228 errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), 1229 }, 1230 { 1231 // Field specifies ARRAY<STRUCT> type, value is having a nil ListValue. 1232 &Row{ 1233 []*sppb.StructType_Field{ 1234 {Name: "Col0", Type: listType(structType( 1235 mkField("Col1", intType()), 1236 mkField("Col2", floatType()), 1237 mkField("Col3", stringType()), 1238 ))}, 1239 }, 1240 []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, 1241 }, 1242 &[]*struct { 1243 Col1 int64 1244 Col2 float64 1245 Col3 string 1246 }{}, 1247 errDecodeColumn(0, errNilListValue("STRUCT")), 1248 }, 1249 { 1250 // Field specifies ARRAY<STRUCT> type, value is having a nil ListValue. 1251 &Row{ 1252 []*sppb.StructType_Field{ 1253 { 1254 Name: "Col0", 1255 Type: listType( 1256 structType( 1257 mkField("Col1", intType()), 1258 mkField("Col2", floatType()), 1259 mkField("Col3", stringType()), 1260 ), 1261 ), 1262 }, 1263 }, 1264 []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, 1265 }, 1266 &[]NullRow{}, 1267 errDecodeColumn(0, errNilListValue("STRUCT")), 1268 }, 1269 { 1270 // Field specifies ARRAY<STRUCT> type, value is for BYTES type. 1271 &Row{ 1272 []*sppb.StructType_Field{ 1273 { 1274 Name: "Col0", 1275 Type: listType( 1276 structType( 1277 mkField("Col1", intType()), 1278 mkField("Col2", floatType()), 1279 mkField("Col3", stringType()), 1280 ), 1281 ), 1282 }, 1283 }, 1284 []*proto3.Value{bytesProto([]byte("value"))}, 1285 }, 1286 &[]*struct { 1287 Col1 int64 1288 Col2 float64 1289 Col3 string 1290 }{}, 1291 errDecodeColumn(0, errSrcVal(bytesProto([]byte("value")), "List")), 1292 }, 1293 { 1294 // Field specifies ARRAY<STRUCT> type, value is for BYTES type. 1295 &Row{ 1296 []*sppb.StructType_Field{ 1297 { 1298 Name: "Col0", 1299 Type: listType( 1300 structType( 1301 mkField("Col1", intType()), 1302 mkField("Col2", floatType()), 1303 mkField("Col3", stringType()), 1304 ), 1305 ), 1306 }, 1307 }, 1308 []*proto3.Value{listProto(bytesProto([]byte("value")))}, 1309 }, 1310 &[]NullRow{}, 1311 errDecodeColumn(0, errNotStructElement(0, bytesProto([]byte("value")))), 1312 }, 1313 { 1314 // Field specifies ARRAY<STRUCT> type, value is for ARRAY<BYTES> type. 1315 &Row{ 1316 []*sppb.StructType_Field{ 1317 { 1318 Name: "Col0", 1319 Type: listType( 1320 structType( 1321 mkField("Col1", intType()), 1322 mkField("Col2", floatType()), 1323 mkField("Col3", stringType()), 1324 ), 1325 ), 1326 }, 1327 }, 1328 []*proto3.Value{listProto(bytesProto([]byte("value")))}, 1329 }, 1330 &[]*struct { 1331 Col1 int64 1332 Col2 float64 1333 Col3 string 1334 }{}, 1335 errDecodeColumn(0, errDecodeArrayElement(0, bytesProto([]byte("value")), 1336 "STRUCT", errSrcVal(bytesProto([]byte("value")), "List"))), 1337 }, 1338 { 1339 // Field specifies ARRAY<STRUCT>, but is having nil StructType. 1340 &Row{ 1341 []*sppb.StructType_Field{ 1342 { 1343 Name: "Col0", Type: listType(&sppb.Type{Code: sppb.TypeCode_STRUCT}), 1344 }, 1345 }, 1346 []*proto3.Value{listProto(listProto(intProto(1), floatProto(2.0), stringProto("3")))}, 1347 }, 1348 &[]*struct { 1349 Col1 int64 1350 Col2 float64 1351 Col3 string 1352 }{}, 1353 errDecodeColumn(0, errDecodeArrayElement(0, listProto(intProto(1), floatProto(2.0), stringProto("3")), 1354 "STRUCT", errNilSpannerStructType())), 1355 }, 1356 { 1357 // Field specifies ARRAY<STRUCT>, but the second struct value is for BOOL type instead of FLOAT64. 1358 &Row{ 1359 []*sppb.StructType_Field{ 1360 { 1361 Name: "Col0", 1362 Type: listType( 1363 structType( 1364 mkField("Col1", intType()), 1365 mkField("Col2", floatType()), 1366 mkField("Col3", stringType()), 1367 ), 1368 ), 1369 }, 1370 }, 1371 []*proto3.Value{listProto(listProto(intProto(1), boolProto(true), stringProto("3")))}, 1372 }, 1373 &[]*struct { 1374 Col1 int64 1375 Col2 float64 1376 Col3 string 1377 }{}, 1378 errDecodeColumn( 1379 0, 1380 errDecodeArrayElement( 1381 0, listProto(intProto(1), boolProto(true), stringProto("3")), "STRUCT", 1382 errDecodeStructField( 1383 &sppb.StructType{ 1384 Fields: []*sppb.StructType_Field{ 1385 mkField("Col1", intType()), 1386 mkField("Col2", floatType()), 1387 mkField("Col3", stringType()), 1388 }, 1389 }, 1390 "Col2", 1391 errSrcVal(boolProto(true), "Number"), 1392 ), 1393 ), 1394 ), 1395 }, 1396 } { 1397 if gotErr := test.row.Column(0, test.dst); !testEqual(gotErr, test.wantErr) { 1398 t.Errorf("%v: test.row.Column(0) got error %v, want %v", i, gotErr, test.wantErr) 1399 } 1400 if gotErr := test.row.ColumnByName("Col0", test.dst); !testEqual(gotErr, test.wantErr) { 1401 t.Errorf("%v: test.row.ColumnByName(%q) got error %v, want %v", i, "Col0", gotErr, test.wantErr) 1402 } 1403 if gotErr := test.row.Columns(test.dst); !testEqual(gotErr, test.wantErr) { 1404 t.Errorf("%v: test.row.Columns(%T) got error %v, want %v", i, test.dst, gotErr, test.wantErr) 1405 } 1406 } 1407} 1408 1409// Test Row.ToStruct(). 1410func TestToStruct(t *testing.T) { 1411 s := []struct { 1412 // STRING / STRING ARRAY 1413 PrimaryKey string `spanner:"STRING"` 1414 NullString NullString `spanner:"NULL_STRING"` 1415 StringArray []NullString `spanner:"STRING_ARRAY"` 1416 NullStringArray []NullString `spanner:"NULL_STRING_ARRAY"` 1417 // BYTES / BYTES ARRAY 1418 Bytes []byte `spanner:"BYTES"` 1419 NullBytes []byte `spanner:"NULL_BYTES"` 1420 BytesArray [][]byte `spanner:"BYTES_ARRAY"` 1421 NullBytesArray [][]byte `spanner:"NULL_BYTES_ARRAY"` 1422 // INT64 / INT64 ARRAY 1423 Int64 int64 `spanner:"INT64"` 1424 NullInt64 NullInt64 `spanner:"NULL_INT64"` 1425 Int64Array []NullInt64 `spanner:"INT64_ARRAY"` 1426 NullInt64Array []NullInt64 `spanner:"NULL_INT64_ARRAY"` 1427 // BOOL / BOOL ARRAY 1428 Bool bool `spanner:"BOOL"` 1429 NullBool NullBool `spanner:"NULL_BOOL"` 1430 BoolArray []NullBool `spanner:"BOOL_ARRAY"` 1431 NullBoolArray []NullBool `spanner:"NULL_BOOL_ARRAY"` 1432 // FLOAT64 / FLOAT64 ARRAY 1433 Float64 float64 `spanner:"FLOAT64"` 1434 NullFloat64 NullFloat64 `spanner:"NULL_FLOAT64"` 1435 Float64Array []NullFloat64 `spanner:"FLOAT64_ARRAY"` 1436 NullFloat64Array []NullFloat64 `spanner:"NULL_FLOAT64_ARRAY"` 1437 // TIMESTAMP / TIMESTAMP ARRAY 1438 Timestamp time.Time `spanner:"TIMESTAMP"` 1439 NullTimestamp NullTime `spanner:"NULL_TIMESTAMP"` 1440 TimestampArray []NullTime `spanner:"TIMESTAMP_ARRAY"` 1441 NullTimestampArray []NullTime `spanner:"NULL_TIMESTAMP_ARRAY"` 1442 // DATE / DATE ARRAY 1443 Date civil.Date `spanner:"DATE"` 1444 NullDate NullDate `spanner:"NULL_DATE"` 1445 DateArray []NullDate `spanner:"DATE_ARRAY"` 1446 NullDateArray []NullDate `spanner:"NULL_DATE_ARRAY"` 1447 1448 // STRUCT ARRAY 1449 StructArray []*struct { 1450 Col1 int64 1451 Col2 float64 1452 Col3 string 1453 } `spanner:"STRUCT_ARRAY"` 1454 NullStructArray []*struct { 1455 Col1 int64 1456 Col2 float64 1457 Col3 string 1458 } `spanner:"NULL_STRUCT_ARRAY"` 1459 }{ 1460 {}, // got 1461 { 1462 // STRING / STRING ARRAY 1463 "value", 1464 NullString{}, 1465 []NullString{{"value1", true}, {}, {"value3", true}}, 1466 []NullString(nil), 1467 // BYTES / BYTES ARRAY 1468 []byte("value"), 1469 []byte(nil), 1470 [][]byte{[]byte("value1"), nil, []byte("value3")}, 1471 [][]byte(nil), 1472 // INT64 / INT64 ARRAY 1473 int64(17), 1474 NullInt64{}, 1475 []NullInt64{{int64(1), true}, {int64(2), true}, {}}, 1476 []NullInt64(nil), 1477 // BOOL / BOOL ARRAY 1478 true, 1479 NullBool{}, 1480 []NullBool{{}, {true, true}, {false, true}}, 1481 []NullBool(nil), 1482 // FLOAT64 / FLOAT64 ARRAY 1483 1.7, 1484 NullFloat64{}, 1485 []NullFloat64{{}, {}, {1.7, true}}, 1486 []NullFloat64(nil), 1487 // TIMESTAMP / TIMESTAMP ARRAY 1488 tm, 1489 NullTime{}, 1490 []NullTime{{}, {tm, true}}, 1491 []NullTime(nil), 1492 // DATE / DATE ARRAY 1493 dt, 1494 NullDate{}, 1495 []NullDate{{}, {dt, true}}, 1496 []NullDate(nil), 1497 // STRUCT ARRAY 1498 []*struct { 1499 Col1 int64 1500 Col2 float64 1501 Col3 string 1502 }{ 1503 nil, 1504 1505 {3, 33.3, "three"}, 1506 nil, 1507 }, 1508 []*struct { 1509 Col1 int64 1510 Col2 float64 1511 Col3 string 1512 }(nil), 1513 }, // want 1514 } 1515 err := row.ToStruct(&s[0]) 1516 if err != nil { 1517 t.Errorf("row.ToStruct() returns error: %v, want nil", err) 1518 } else if !testEqual(s[0], s[1]) { 1519 t.Errorf("row.ToStruct() fetches struct %v, want %v", s[0], s[1]) 1520 } 1521} 1522 1523// Test Row.ToStruct() with custom types. 1524func TestToStructWithCustomTypes(t *testing.T) { 1525 type CustomString string 1526 type CustomNullString NullString 1527 type CustomBytes []byte 1528 type CustomInt64 int64 1529 type CustomNullInt64 NullInt64 1530 type CustomBool bool 1531 type CustomNullBool NullBool 1532 type CustomFloat64 float64 1533 type CustomNullFloat64 NullFloat64 1534 type CustomTime time.Time 1535 type CustomNullTime NullTime 1536 type CustomDate civil.Date 1537 type CustomNullDate NullDate 1538 1539 s := []struct { 1540 // STRING / STRING ARRAY 1541 PrimaryKey CustomString `spanner:"STRING"` 1542 NullString CustomNullString `spanner:"NULL_STRING"` 1543 StringArray []CustomNullString `spanner:"STRING_ARRAY"` 1544 NullStringArray []CustomNullString `spanner:"NULL_STRING_ARRAY"` 1545 // BYTES / BYTES ARRAY 1546 Bytes CustomBytes `spanner:"BYTES"` 1547 NullBytes CustomBytes `spanner:"NULL_BYTES"` 1548 BytesArray []CustomBytes `spanner:"BYTES_ARRAY"` 1549 NullBytesArray []CustomBytes `spanner:"NULL_BYTES_ARRAY"` 1550 // INT64 / INT64 ARRAY 1551 Int64 CustomInt64 `spanner:"INT64"` 1552 NullInt64 CustomNullInt64 `spanner:"NULL_INT64"` 1553 Int64Array []CustomNullInt64 `spanner:"INT64_ARRAY"` 1554 NullInt64Array []CustomNullInt64 `spanner:"NULL_INT64_ARRAY"` 1555 // BOOL / BOOL ARRAY 1556 Bool CustomBool `spanner:"BOOL"` 1557 NullBool CustomNullBool `spanner:"NULL_BOOL"` 1558 BoolArray []CustomNullBool `spanner:"BOOL_ARRAY"` 1559 NullBoolArray []CustomNullBool `spanner:"NULL_BOOL_ARRAY"` 1560 // FLOAT64 / FLOAT64 ARRAY 1561 Float64 CustomFloat64 `spanner:"FLOAT64"` 1562 NullFloat64 CustomNullFloat64 `spanner:"NULL_FLOAT64"` 1563 Float64Array []CustomNullFloat64 `spanner:"FLOAT64_ARRAY"` 1564 NullFloat64Array []CustomNullFloat64 `spanner:"NULL_FLOAT64_ARRAY"` 1565 // TIMESTAMP / TIMESTAMP ARRAY 1566 Timestamp CustomTime `spanner:"TIMESTAMP"` 1567 NullTimestamp CustomNullTime `spanner:"NULL_TIMESTAMP"` 1568 TimestampArray []CustomNullTime `spanner:"TIMESTAMP_ARRAY"` 1569 NullTimestampArray []CustomNullTime `spanner:"NULL_TIMESTAMP_ARRAY"` 1570 // DATE / DATE ARRAY 1571 Date CustomDate `spanner:"DATE"` 1572 NullDate CustomNullDate `spanner:"NULL_DATE"` 1573 DateArray []CustomNullDate `spanner:"DATE_ARRAY"` 1574 NullDateArray []CustomNullDate `spanner:"NULL_DATE_ARRAY"` 1575 1576 // STRUCT ARRAY 1577 StructArray []*struct { 1578 Col1 CustomInt64 1579 Col2 CustomFloat64 1580 Col3 CustomString 1581 } `spanner:"STRUCT_ARRAY"` 1582 NullStructArray []*struct { 1583 Col1 CustomInt64 1584 Col2 CustomFloat64 1585 Col3 CustomString 1586 } `spanner:"NULL_STRUCT_ARRAY"` 1587 }{ 1588 {}, // got 1589 { 1590 // STRING / STRING ARRAY 1591 "value", 1592 CustomNullString{}, 1593 []CustomNullString{{"value1", true}, {}, {"value3", true}}, 1594 []CustomNullString(nil), 1595 // BYTES / BYTES ARRAY 1596 CustomBytes("value"), 1597 CustomBytes(nil), 1598 []CustomBytes{[]byte("value1"), nil, []byte("value3")}, 1599 []CustomBytes(nil), 1600 // INT64 / INT64 ARRAY 1601 CustomInt64(17), 1602 CustomNullInt64{}, 1603 []CustomNullInt64{{int64(1), true}, {int64(2), true}, {}}, 1604 []CustomNullInt64(nil), 1605 // BOOL / BOOL ARRAY 1606 true, 1607 CustomNullBool{}, 1608 []CustomNullBool{{}, {true, true}, {false, true}}, 1609 []CustomNullBool(nil), 1610 // FLOAT64 / FLOAT64 ARRAY 1611 1.7, 1612 CustomNullFloat64{}, 1613 []CustomNullFloat64{{}, {}, {1.7, true}}, 1614 []CustomNullFloat64(nil), 1615 // TIMESTAMP / TIMESTAMP ARRAY 1616 CustomTime(tm), 1617 CustomNullTime{}, 1618 []CustomNullTime{{}, {tm, true}}, 1619 []CustomNullTime(nil), 1620 // DATE / DATE ARRAY 1621 CustomDate(dt), 1622 CustomNullDate{}, 1623 []CustomNullDate{{}, {dt, true}}, 1624 []CustomNullDate(nil), 1625 // STRUCT ARRAY 1626 []*struct { 1627 Col1 CustomInt64 1628 Col2 CustomFloat64 1629 Col3 CustomString 1630 }{ 1631 nil, 1632 1633 {3, 33.3, "three"}, 1634 nil, 1635 }, 1636 []*struct { 1637 Col1 CustomInt64 1638 Col2 CustomFloat64 1639 Col3 CustomString 1640 }(nil), 1641 }, // want 1642 } 1643 err := row.ToStruct(&s[0]) 1644 if err != nil { 1645 t.Errorf("row.ToStruct() returns error: %v, want nil", err) 1646 } else if !testutil.Equal(s[0], s[1], cmp.AllowUnexported(CustomTime{})) { 1647 t.Errorf("row.ToStruct() fetches struct %v, want %v", s[0], s[1]) 1648 } 1649} 1650 1651func TestToStructEmbedded(t *testing.T) { 1652 type ( 1653 S1 struct{ F1 string } 1654 S2 struct { 1655 S1 1656 F2 string 1657 } 1658 ) 1659 r := Row{ 1660 []*sppb.StructType_Field{ 1661 {Name: "F1", Type: stringType()}, 1662 {Name: "F2", Type: stringType()}, 1663 }, 1664 []*proto3.Value{ 1665 stringProto("v1"), 1666 stringProto("v2"), 1667 }, 1668 } 1669 var got S2 1670 if err := r.ToStruct(&got); err != nil { 1671 t.Fatal(err) 1672 } 1673 want := S2{S1: S1{F1: "v1"}, F2: "v2"} 1674 if !testEqual(got, want) { 1675 t.Errorf("got %+v, want %+v", got, want) 1676 } 1677} 1678 1679func TestRowToString(t *testing.T) { 1680 r := Row{ 1681 []*sppb.StructType_Field{ 1682 {Name: "F1", Type: stringType()}, 1683 {Name: "F2", Type: stringType()}, 1684 }, 1685 []*proto3.Value{ 1686 stringProto("v1"), 1687 stringProto("v2"), 1688 }, 1689 } 1690 got := r.String() 1691 want := `{fields: [name:"F1" type:{code:STRING} name:"F2" type:{code:STRING}], values: [string_value:"v1" string_value:"v2"]}` 1692 // In protobuf-go, the encoder will add an additional space based on a 1693 // deterministically random boolean value. 1694 wantWithTwoSpaces := `{fields: [name:"F1" type:{code:STRING} name:"F2" type:{code:STRING}], values: [string_value:"v1" string_value:"v2"]}` 1695 1696 if !testEqual(r.String(), want) && !testEqual(r.String(), wantWithTwoSpaces) { 1697 t.Errorf("got %+v, want %+v", got, want) 1698 } 1699} 1700 1701// Test helpers for getting column names. 1702func TestColumnNameAndIndex(t *testing.T) { 1703 // Test Row.Size(). 1704 if rs := row.Size(); rs != len(row.fields) { 1705 t.Errorf("row.Size() returns %v, want %v", rs, len(row.fields)) 1706 } 1707 // Test Row.Size() on empty Row. 1708 if rs := (&Row{}).Size(); rs != 0 { 1709 t.Errorf("empty_row.Size() returns %v, want %v", rs, 0) 1710 } 1711 // Test Row.ColumnName() 1712 for i, col := range row.fields { 1713 if cn := row.ColumnName(i); cn != col.Name { 1714 t.Errorf("row.ColumnName(%v) returns %q, want %q", i, cn, col.Name) 1715 } 1716 goti, err := row.ColumnIndex(col.Name) 1717 if err != nil { 1718 t.Errorf("ColumnIndex(%q) error %v", col.Name, err) 1719 continue 1720 } 1721 if goti != i { 1722 t.Errorf("ColumnIndex(%q) = %d, want %d", col.Name, goti, i) 1723 } 1724 } 1725 // Test Row.ColumnName on empty Row. 1726 if cn := (&Row{}).ColumnName(0); cn != "" { 1727 t.Errorf("empty_row.ColumnName(%v) returns %q, want %q", 0, cn, "") 1728 } 1729 // Test Row.ColumnIndex on empty Row. 1730 if _, err := (&Row{}).ColumnIndex(""); err == nil { 1731 t.Error("empty_row.ColumnIndex returns nil, want error") 1732 } 1733} 1734 1735func TestNewRow(t *testing.T) { 1736 for _, test := range []struct { 1737 names []string 1738 values []interface{} 1739 want *Row 1740 wantErr error 1741 }{ 1742 { 1743 want: &Row{fields: []*sppb.StructType_Field{}, vals: []*proto3.Value{}}, 1744 }, 1745 { 1746 names: []string{}, 1747 values: []interface{}{}, 1748 want: &Row{fields: []*sppb.StructType_Field{}, vals: []*proto3.Value{}}, 1749 }, 1750 { 1751 names: []string{"a", "b"}, 1752 values: []interface{}{}, 1753 want: nil, 1754 wantErr: errNamesValuesMismatch([]string{"a", "b"}, []interface{}{}), 1755 }, 1756 { 1757 names: []string{"a", "b", "c"}, 1758 values: []interface{}{5, "abc", GenericColumnValue{listType(intType()), listProto(intProto(91), nullProto(), intProto(87))}}, 1759 want: &Row{ 1760 []*sppb.StructType_Field{ 1761 {Name: "a", Type: intType()}, 1762 {Name: "b", Type: stringType()}, 1763 {Name: "c", Type: listType(intType())}, 1764 }, 1765 []*proto3.Value{ 1766 intProto(5), 1767 stringProto("abc"), 1768 listProto(intProto(91), nullProto(), intProto(87)), 1769 }, 1770 }, 1771 }, 1772 } { 1773 got, err := NewRow(test.names, test.values) 1774 if !testEqual(err, test.wantErr) { 1775 t.Errorf("NewRow(%v,%v).err = %s, want %s", test.names, test.values, err, test.wantErr) 1776 continue 1777 } 1778 if !testEqual(got, test.want) { 1779 t.Errorf("NewRow(%v,%v) = %s, want %s", test.names, test.values, got, test.want) 1780 continue 1781 } 1782 } 1783} 1784 1785func BenchmarkColumn(b *testing.B) { 1786 var s string 1787 for i := 0; i < b.N; i++ { 1788 if err := row.Column(0, &s); err != nil { 1789 b.Fatal(err) 1790 } 1791 } 1792} 1793