Allow reading a result row multiple times

refs #478
pull/594/head
Jack Christensen 2019-08-31 10:50:14 -05:00
parent f20f026b7d
commit 53921a0a22
2 changed files with 50 additions and 20 deletions

View File

@ -161,6 +161,51 @@ func TestConnQueryValues(t *testing.T) {
}
}
// https://github.com/jackc/pgx/issues/478
func TestConnQueryReadRowMultipleTimes(t *testing.T) {
t.Parallel()
conn := mustConnectString(t, os.Getenv("PGX_TEST_DATABASE"))
defer closeConn(t, conn)
var rowCount int32
rows, err := conn.Query(context.Background(), "select 'foo'::text, 'bar'::varchar, n, null, n from generate_series(1,$1) n", 10)
require.NoError(t, err)
defer rows.Close()
for rows.Next() {
rowCount++
for i := 0; i < 2; i++ {
values, err := rows.Values()
require.NoError(t, err)
require.Len(t, values, 5)
require.Equal(t, "foo", values[0])
require.Equal(t, "bar", values[1])
require.Equal(t, rowCount, values[2])
require.Nil(t, values[3])
require.Equal(t, rowCount, values[4])
var a, b string
var c int32
var d pgtype.Unknown
var e int32
err = rows.Scan(&a, &b, &c, &d, &e)
require.NoError(t, err)
require.Equal(t, "foo", a)
require.Equal(t, "bar", b)
require.Equal(t, rowCount, c)
require.Equal(t, pgtype.Null, d.Status)
require.Equal(t, rowCount, e)
}
}
require.NoError(t, rows.Err())
require.Equal(t, int32(10), rowCount)
}
// https://github.com/jackc/pgx/issues/386
func TestConnQueryValuesWithMultipleComplexColumnsOfSameType(t *testing.T) {
t.Parallel()

25
rows.go
View File

@ -81,7 +81,6 @@ type connRows struct {
connInfo *pgtype.ConnInfo
values [][]byte
rowCount int
columnIdx int
err error
startTime time.Time
sql string
@ -151,7 +150,6 @@ func (rows *connRows) Next() bool {
if rows.resultReader.NextRow() {
rows.rowCount++
rows.columnIdx = 0
rows.values = rows.resultReader.Values()
return true
} else {
@ -160,21 +158,6 @@ func (rows *connRows) Next() bool {
}
}
func (rows *connRows) nextColumn() ([]byte, *pgproto3.FieldDescription, bool) {
if rows.closed {
return nil, nil, false
}
if len(rows.FieldDescriptions()) <= rows.columnIdx {
rows.fatal(errors.New("No next column available"))
return nil, nil, false
}
buf := rows.values[rows.columnIdx]
fd := &rows.FieldDescriptions()[rows.columnIdx]
rows.columnIdx++
return buf, fd, true
}
func (rows *connRows) Scan(dest ...interface{}) error {
if len(rows.FieldDescriptions()) != len(dest) {
err := errors.Errorf("Scan received wrong number of arguments, got %d but expected %d", len(dest), len(rows.FieldDescriptions()))
@ -183,7 +166,8 @@ func (rows *connRows) Scan(dest ...interface{}) error {
}
for i, d := range dest {
buf, fd, _ := rows.nextColumn()
buf := rows.values[i]
fd := &rows.FieldDescriptions()[i]
if d == nil {
continue
@ -206,8 +190,9 @@ func (rows *connRows) Values() ([]interface{}, error) {
values := make([]interface{}, 0, len(rows.FieldDescriptions()))
for range rows.FieldDescriptions() {
buf, fd, _ := rows.nextColumn()
for i := range rows.FieldDescriptions() {
buf := rows.values[i]
fd := &rows.FieldDescriptions()[i]
if buf == nil {
values = append(values, nil)