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