Skip to content

spanner: SelectAll with annotations is broken #13299

@bramoudith-sc

Description

@bramoudith-sc

Client

Spanner

Environment

go 1.25.1
commit 6e77e86

Code and Dependencies

diff --git a/spanner/row_test.go b/spanner/row_test.go
index 0b84e82f51..313da1074a 100644
--- a/spanner/row_test.go
+++ b/spanner/row_test.go
@@ -2288,6 +2288,13 @@ func TestSelectAll(t *testing.T) {
 		Col3 string    `spanner:"taG3"`
 		Col4 time.Time `spanner:"TAG4"`
 	}
+
+	type testStructWithSimpleTag struct {
+		Col1 int64 `spanner:"tag1"`
+		Col2 int64 `spanner:"tag2"`
+		Col3 int64 `spanner:"tag3"`
+		Col4 int64 `spanner:"tag4"`
+	}
 	tests := []struct {
 		name    string
 		args    args
@@ -2523,6 +2530,78 @@ func TestSelectAll(t *testing.T) {
 				{Col1: 2, Col2: 2.2, Col3: "value2", Col4: tm.Add(24 * time.Hour)},
 			},
 		},
+		{
+			name: "success: using slice of structs with simple spanner tag annotations in different order",
+			args: args{
+				destination: &[]testStructWithSimpleTag{},
+				mock: newMockIterator(
+					&Row{
+						[]*sppb.StructType_Field{
+							{Name: "Tag2", Type: intType()},
+							{Name: "Tag1", Type: intType()},
+							{Name: "Tag4", Type: intType()},
+							{Name: "Tag3", Type: intType()},
+						},
+						[]*proto3.Value{intProto(2), intProto(1), intProto(4), intProto(3)},
+					},
+					&Row{
+						[]*sppb.StructType_Field{
+							{Name: "Tag1", Type: intType()},
+							{Name: "Tag2", Type: intType()},
+							{Name: "Tag3", Type: intType()},
+							{Name: "Tag4", Type: intType()},
+						},
+						[]*proto3.Value{intProto(1), intProto(2), intProto(3), intProto(4)},
+					},
+					&Row{
+						[]*sppb.StructType_Field{
+							{Name: "Tag2", Type: intType()},
+							{Name: "Tag1", Type: intType()},
+							{Name: "Tag4", Type: intType()},
+							{Name: "Tag3", Type: intType()},
+						},
+						[]*proto3.Value{intProto(2), intProto(1), intProto(4), intProto(3)},
+					},
+					iterator.Done,
+				),
+			},
+			want: &[]testStructWithSimpleTag{
+				{Col1: 1, Col2: 2, Col3: 3, Col4: 4},
+				{Col1: 1, Col2: 2, Col3: 3, Col4: 4},
+				{Col1: 1, Col2: 2, Col3: 3, Col4: 4},
+			},
+		},
+		{
+			name: "success: using slice of structs with spanner tag annotations in different order",
+			args: args{
+				destination: &[]testStructWithTag{},
+				mock: newMockIterator(
+					&Row{
+						[]*sppb.StructType_Field{
+							{Name: "Tag2", Type: floatType()},
+							{Name: "Tag1", Type: intType()},
+							{Name: "Tag4", Type: timeType()},
+							{Name: "Tag3", Type: stringType()},
+						},
+						[]*proto3.Value{floatProto(1.1), intProto(1), timeProto(tm), stringProto("value")},
+					},
+					&Row{
+						[]*sppb.StructType_Field{
+							{Name: "Tag2", Type: floatType()},
+							{Name: "Tag1", Type: intType()},
+							{Name: "Tag4", Type: timeType()},
+							{Name: "Tag3", Type: stringType()},
+						},
+						[]*proto3.Value{floatProto(2.2), intProto(2), timeProto(tm.Add(24 * time.Hour)), stringProto("value2")},
+					},
+					iterator.Done,
+				),
+			},
+			want: &[]testStructWithTag{
+				{Col1: 1, Col2: 1.1, Col3: "value", Col4: tm},
+				{Col1: 2, Col2: 2.2, Col3: "value2", Col4: tm.Add(24 * time.Hour)},
+			},
+		},
 		{
 			name: "failure: in case of error destination will have the partial result",
 			args: args{

Expected behavior

The unit tests added should pass - I believe the order of the tags should have no impact on the decoding? I may be misunderstanding how this function is supposed to work though.

basically if I have

type rowStruct struct {
      b int64 `spanner:"b"`
      a int64 `spanner:"a"`
}

and I do

Select b, a from foo

The resulting row should properly decode into rowStruct. The current behaviour is unexpected.

Actual behavior

Output of testcases added

--- FAIL: TestSelectAll (0.00s)
    --- FAIL: TestSelectAll/success:_using_slice_of_structs_with_simple_spanner_tag_annotations_in_different_order (0.00s)
       google-cloud-go/spanner/row_test.go:2702: SelectAll() = &[{2 2 4 4} {1 2 3 4} {2 1 4 3}], want &[{1 2 3 4} {1 2 3 4} {1 2 3 4}]
    --- FAIL: TestSelectAll/success:_using_slice_of_structs_with_spanner_tag_annotations_in_different_order (0.00s)
panic: reflect.Set: value of type float64 is not assignable to type int64 [recovered, repanicked]

Note that in the test case we do (Tag2, Tag1, Tag4, Tag3) then (Tag1, Tag2, Tag3, Tag4) then (Tag2, Tag1, Tag4, Tag3) again, but we end up with [{2 2 4 4} {1 2 3 4} {2 1 4 3}]somehow.
(output edited to hide local user details in the path)

Metadata

Metadata

Assignees

Labels

api: spannerIssues related to the Spanner API.triage meI really want to be triaged.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions