Skip to content

Commit a401e4a

Browse files
authored
* Fixed bug from scan unexpected column name (#418)
1 parent 618e731 commit a401e4a

File tree

4 files changed

+76
-14
lines changed

4 files changed

+76
-14
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
* Fixed bug from scan unexpected column name
2+
13
## v3.38.4
24
* Changed type of `table/options.{Create,Alter,Drop}TableOption` from func to interface
35
* Added implementations of `table/options.{Create,Alter,Drop}Option`

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ require (
99
github.com/stretchr/testify v1.7.1
1010
github.com/ydb-platform/ydb-go-genproto v0.0.0-20220922065549-66df47a830ba
1111
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
12+
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
1213
google.golang.org/grpc v1.47.0
1314
google.golang.org/protobuf v1.28.0
1415
)

internal/table/scanner/scanner.go

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package scanner
22

33
import (
4-
"bytes"
54
"database/sql"
65
"encoding/json"
76
"errors"
@@ -15,6 +14,7 @@ import (
1514

1615
"github.com/ydb-platform/ydb-go-sdk/v3/internal/timeutil"
1716
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
17+
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value/allocator"
1818
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
1919
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
2020
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
@@ -173,9 +173,9 @@ func (s *scanner) Scan(values ...indexed.RequiredOrOptional) (err error) {
173173
return s.Err()
174174
}
175175

176-
func (s *scanner) ScanNamed(namedValues ...named.Value) (err error) {
177-
if err = s.Err(); err != nil {
178-
return
176+
func (s *scanner) ScanNamed(namedValues ...named.Value) error {
177+
if err := s.Err(); err != nil {
178+
return err
179179
}
180180
if s.ColumnCount() < len(namedValues) {
181181
panic(fmt.Sprintf("scan row failed: count of columns less then values (%d < %d)", s.ColumnCount(), len(namedValues)))
@@ -184,8 +184,8 @@ func (s *scanner) ScanNamed(namedValues ...named.Value) (err error) {
184184
panic("scan row failed: double scan per row")
185185
}
186186
for _, v := range namedValues {
187-
if err = s.seekItemByName(v.Name); err != nil {
188-
return
187+
if err := s.seekItemByName(v.Name); err != nil {
188+
return err
189189
}
190190
switch t := v.Type; t {
191191
case named.TypeRequired:
@@ -250,8 +250,9 @@ func (s *scanner) reset(set *Ydb.ResultSet, columnNames ...string) {
250250
}
251251

252252
func (s *scanner) path() string {
253-
var buf bytes.Buffer
254-
_, _ = s.writePathTo(&buf)
253+
buf := allocator.Buffers.Get()
254+
defer allocator.Buffers.Put(buf)
255+
_, _ = s.writePathTo(buf)
255256
return buf.String()
256257
}
257258

@@ -280,7 +281,7 @@ func (s *scanner) hasItems() bool {
280281

281282
func (s *scanner) seekItemByID(id int) error {
282283
if !s.hasItems() || id >= len(s.set.Columns) {
283-
return s.noValueError()
284+
return s.notFoundColumnByIndex(id)
284285
}
285286
col := s.set.Columns[id]
286287
s.stack.scanItem.name = col.Name
@@ -291,7 +292,7 @@ func (s *scanner) seekItemByID(id int) error {
291292

292293
func (s *scanner) seekItemByName(name string) error {
293294
if !s.hasItems() {
294-
return s.noValueError()
295+
return s.notFoundColumnName(name)
295296
}
296297
for i, c := range s.set.Columns {
297298
if name == c.Name {
@@ -301,7 +302,7 @@ func (s *scanner) seekItemByName(name string) error {
301302
return s.Err()
302303
}
303304
}
304-
return s.noValueError()
305+
return s.notFoundColumnName(name)
305306
}
306307

307308
func (s *scanner) setColumnIndexes(columns []string) {
@@ -1123,11 +1124,19 @@ func (s *scanner) valueTypeError(act, exp interface{}) {
11231124
)
11241125
}
11251126

1126-
func (s *scanner) noValueError() error {
1127+
func (s *scanner) notFoundColumnByIndex(idx int) error {
11271128
return s.errorf(
11281129
2,
1129-
"no value at %q",
1130-
s.path(),
1130+
"not found %d column",
1131+
idx,
1132+
)
1133+
}
1134+
1135+
func (s *scanner) notFoundColumnName(name string) error {
1136+
return s.errorf(
1137+
2,
1138+
"not found column '%s'",
1139+
name,
11311140
)
11321141
}
11331142

table/table_regress_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ package table_test
55

66
import (
77
"context"
8+
"fmt"
89
"os"
910
"testing"
1011
"time"
1112

1213
"github.com/stretchr/testify/require"
14+
"golang.org/x/xerrors"
1315

1416
"github.com/ydb-platform/ydb-go-sdk/v3"
1517
"github.com/ydb-platform/ydb-go-sdk/v3/table"
18+
"github.com/ydb-platform/ydb-go-sdk/v3/table/result/named"
1619
"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
1720
)
1821

@@ -115,3 +118,50 @@ func TestIssue259IntervalFromDuration(t *testing.T) {
115118
})
116119
require.NoError(t, err)
117120
}
121+
122+
func TestIssue415ScanError(t *testing.T) {
123+
// https://github.com/ydb-platform/ydb-go-sdk/issues/415
124+
ctx, cancel := context.WithCancel(context.Background())
125+
defer cancel()
126+
127+
db := connect(t)
128+
defer db.Close(ctx)
129+
err := db.Table().DoTx(ctx, func(ctx context.Context, tx table.TransactionActor) error {
130+
res, err := tx.Execute(ctx, `SELECT 1 as abc, 2 as def;`, nil)
131+
if err != nil {
132+
return err
133+
}
134+
err = res.NextResultSetErr(ctx)
135+
if err != nil {
136+
return err
137+
}
138+
if !res.NextRow() {
139+
if err = res.Err(); err != nil {
140+
return err
141+
}
142+
return fmt.Errorf("unexpected empty result set")
143+
}
144+
var abc, def int32
145+
err = res.ScanNamed(
146+
named.Required("abc", &abc),
147+
named.Required("ghi", &def),
148+
)
149+
if err != nil {
150+
return err
151+
}
152+
fmt.Println(abc, def)
153+
return res.Err()
154+
}, table.WithTxSettings(table.TxSettings(table.WithSnapshotReadOnly())))
155+
require.Error(t, err)
156+
err = func(err error) error {
157+
for {
158+
//nolint:errorlint
159+
if unwrappedErr, has := err.(xerrors.Wrapper); has {
160+
err = unwrappedErr.Unwrap()
161+
} else {
162+
return err
163+
}
164+
}
165+
}(err)
166+
require.Equal(t, "not found column 'ghi'", err.Error())
167+
}

0 commit comments

Comments
 (0)