diff --git a/query_test.go b/query_test.go index 8439a47f..21d366fe 100644 --- a/query_test.go +++ b/query_test.go @@ -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() diff --git a/rows.go b/rows.go index 7da3605e..5ae1427e 100644 --- a/rows.go +++ b/rows.go @@ -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)