Remove ValueReader
This commit is contained in:
@@ -43,7 +43,6 @@ type Rows struct {
|
||||
conn *Conn
|
||||
mr *msgReader
|
||||
fields []FieldDescription
|
||||
vr ValueReader
|
||||
rowCount int
|
||||
columnIdx int
|
||||
err error
|
||||
@@ -114,7 +113,6 @@ func (rows *Rows) Next() bool {
|
||||
|
||||
rows.rowCount++
|
||||
rows.columnIdx = 0
|
||||
rows.vr = ValueReader{}
|
||||
|
||||
for {
|
||||
t, r, err := rows.conn.rxMsg()
|
||||
@@ -163,24 +161,23 @@ func (rows *Rows) Conn() *Conn {
|
||||
return rows.conn
|
||||
}
|
||||
|
||||
func (rows *Rows) nextColumn() (*ValueReader, bool) {
|
||||
func (rows *Rows) nextColumn() ([]byte, *FieldDescription, bool) {
|
||||
if rows.closed {
|
||||
return nil, false
|
||||
return nil, nil, false
|
||||
}
|
||||
if len(rows.fields) <= rows.columnIdx {
|
||||
rows.Fatal(ProtocolError("No next column available"))
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if rows.vr.Len() > 0 {
|
||||
rows.mr.readBytes(rows.vr.Len())
|
||||
return nil, nil, false
|
||||
}
|
||||
|
||||
fd := &rows.fields[rows.columnIdx]
|
||||
rows.columnIdx++
|
||||
size := rows.mr.readInt32()
|
||||
rows.vr = ValueReader{mr: rows.mr, fd: fd, valueBytesRemaining: size}
|
||||
return &rows.vr, true
|
||||
var buf []byte
|
||||
if size >= 0 {
|
||||
buf = rows.mr.readBytes(size)
|
||||
}
|
||||
return buf, fd, true
|
||||
}
|
||||
|
||||
type scanArgError struct {
|
||||
@@ -204,49 +201,49 @@ func (rows *Rows) Scan(dest ...interface{}) (err error) {
|
||||
}
|
||||
|
||||
for i, d := range dest {
|
||||
vr, _ := rows.nextColumn()
|
||||
buf, fd, _ := rows.nextColumn()
|
||||
|
||||
if d == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if s, ok := d.(pgtype.BinaryDecoder); ok && vr.Type().FormatCode == BinaryFormatCode {
|
||||
err = s.DecodeBinary(rows.conn.ConnInfo, vr.bytes())
|
||||
if s, ok := d.(pgtype.BinaryDecoder); ok && fd.FormatCode == BinaryFormatCode {
|
||||
err = s.DecodeBinary(rows.conn.ConnInfo, buf)
|
||||
if err != nil {
|
||||
rows.Fatal(scanArgError{col: i, err: err})
|
||||
}
|
||||
} else if s, ok := d.(pgtype.TextDecoder); ok && vr.Type().FormatCode == TextFormatCode {
|
||||
err = s.DecodeText(rows.conn.ConnInfo, vr.bytes())
|
||||
} else if s, ok := d.(pgtype.TextDecoder); ok && fd.FormatCode == TextFormatCode {
|
||||
err = s.DecodeText(rows.conn.ConnInfo, buf)
|
||||
if err != nil {
|
||||
rows.Fatal(scanArgError{col: i, err: err})
|
||||
}
|
||||
} else {
|
||||
if dt, ok := rows.conn.ConnInfo.DataTypeForOid(vr.Type().DataType); ok {
|
||||
if dt, ok := rows.conn.ConnInfo.DataTypeForOid(fd.DataType); ok {
|
||||
value := dt.Value
|
||||
switch vr.Type().FormatCode {
|
||||
switch fd.FormatCode {
|
||||
case TextFormatCode:
|
||||
if textDecoder, ok := value.(pgtype.TextDecoder); ok {
|
||||
err = textDecoder.DecodeText(rows.conn.ConnInfo, vr.bytes())
|
||||
err = textDecoder.DecodeText(rows.conn.ConnInfo, buf)
|
||||
if err != nil {
|
||||
vr.Fatal(err)
|
||||
rows.Fatal(scanArgError{col: i, err: err})
|
||||
}
|
||||
} else {
|
||||
vr.Fatal(fmt.Errorf("%T is not a pgtype.TextDecoder", value))
|
||||
rows.Fatal(scanArgError{col: i, err: fmt.Errorf("%T is not a pgtype.TextDecoder", value)})
|
||||
}
|
||||
case BinaryFormatCode:
|
||||
if binaryDecoder, ok := value.(pgtype.BinaryDecoder); ok {
|
||||
err = binaryDecoder.DecodeBinary(rows.conn.ConnInfo, vr.bytes())
|
||||
err = binaryDecoder.DecodeBinary(rows.conn.ConnInfo, buf)
|
||||
if err != nil {
|
||||
vr.Fatal(err)
|
||||
rows.Fatal(scanArgError{col: i, err: err})
|
||||
}
|
||||
} else {
|
||||
vr.Fatal(fmt.Errorf("%T is not a pgtype.BinaryDecoder", value))
|
||||
rows.Fatal(scanArgError{col: i, err: fmt.Errorf("%T is not a pgtype.BinaryDecoder", value)})
|
||||
}
|
||||
default:
|
||||
vr.Fatal(fmt.Errorf("unknown format code: %v", vr.Type().FormatCode))
|
||||
rows.Fatal(scanArgError{col: i, err: fmt.Errorf("unknown format code: %v", fd.FormatCode)})
|
||||
}
|
||||
|
||||
if vr.Err() == nil {
|
||||
if rows.Err() == nil {
|
||||
if scanner, ok := d.(sql.Scanner); ok {
|
||||
sqlSrc, err := pgtype.DatabaseSQLValue(rows.conn.ConnInfo, value)
|
||||
if err != nil {
|
||||
@@ -257,16 +254,13 @@ func (rows *Rows) Scan(dest ...interface{}) (err error) {
|
||||
rows.Fatal(scanArgError{col: i, err: err})
|
||||
}
|
||||
} else if err := value.AssignTo(d); err != nil {
|
||||
vr.Fatal(err)
|
||||
rows.Fatal(scanArgError{col: i, err: err})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rows.Fatal(scanArgError{col: i, err: fmt.Errorf("unknown oid: %v", vr.Type().DataType)})
|
||||
rows.Fatal(scanArgError{col: i, err: fmt.Errorf("unknown oid: %v", fd.DataType)})
|
||||
}
|
||||
}
|
||||
if vr.Err() != nil {
|
||||
rows.Fatal(scanArgError{col: i, err: vr.Err()})
|
||||
}
|
||||
|
||||
if rows.Err() != nil {
|
||||
return rows.Err()
|
||||
@@ -285,23 +279,23 @@ func (rows *Rows) Values() ([]interface{}, error) {
|
||||
values := make([]interface{}, 0, len(rows.fields))
|
||||
|
||||
for range rows.fields {
|
||||
vr, _ := rows.nextColumn()
|
||||
buf, fd, _ := rows.nextColumn()
|
||||
|
||||
if vr.Len() == -1 {
|
||||
if buf == nil {
|
||||
values = append(values, nil)
|
||||
continue
|
||||
}
|
||||
|
||||
if dt, ok := rows.conn.ConnInfo.DataTypeForOid(vr.Type().DataType); ok {
|
||||
if dt, ok := rows.conn.ConnInfo.DataTypeForOid(fd.DataType); ok {
|
||||
value := dt.Value
|
||||
|
||||
switch vr.Type().FormatCode {
|
||||
switch fd.FormatCode {
|
||||
case TextFormatCode:
|
||||
decoder := value.(pgtype.TextDecoder)
|
||||
if decoder == nil {
|
||||
decoder = &pgtype.GenericText{}
|
||||
}
|
||||
err := decoder.DecodeText(rows.conn.ConnInfo, vr.bytes())
|
||||
err := decoder.DecodeText(rows.conn.ConnInfo, buf)
|
||||
if err != nil {
|
||||
rows.Fatal(err)
|
||||
}
|
||||
@@ -311,7 +305,7 @@ func (rows *Rows) Values() ([]interface{}, error) {
|
||||
if decoder == nil {
|
||||
decoder = &pgtype.GenericBinary{}
|
||||
}
|
||||
err := decoder.DecodeBinary(rows.conn.ConnInfo, vr.bytes())
|
||||
err := decoder.DecodeBinary(rows.conn.ConnInfo, buf)
|
||||
if err != nil {
|
||||
rows.Fatal(err)
|
||||
}
|
||||
@@ -323,10 +317,6 @@ func (rows *Rows) Values() ([]interface{}, error) {
|
||||
rows.Fatal(errors.New("Unknown type"))
|
||||
}
|
||||
|
||||
if vr.Err() != nil {
|
||||
rows.Fatal(vr.Err())
|
||||
}
|
||||
|
||||
if rows.Err() != nil {
|
||||
return nil, rows.Err()
|
||||
}
|
||||
|
||||
@@ -32,6 +32,10 @@ No longer can read raw bytes of any value into a []byte. Use pgtype.GenericBinar
|
||||
|
||||
OID constants moved from pgx to pgtype package
|
||||
|
||||
Removed ValueReader
|
||||
|
||||
Replaced Scanner, Encoder, and PgxScanner interfaces with pgtype system
|
||||
|
||||
## TODO / Possible / Investigate
|
||||
|
||||
Organize errors better
|
||||
@@ -46,7 +50,7 @@ Remove names from prepared statements - use database/sql style objects
|
||||
|
||||
Better way of handling text/binary protocol choice than pgx.DefaultTypeFormats or manually editing a PreparedStatement. Possibly an optional part of preparing a statement is specifying the format and/or a decoder. Or maybe it is part of a QueryEx call... Could be very interesting to make encoding and decoding possible without being a method of the type. This could drastically clean up those huge type switches.
|
||||
|
||||
dValueReader / msgReader cleanup
|
||||
msgReader cleanup
|
||||
|
||||
Make easier / possible to mock Conn or ConnPool (https://github.com/jackc/pgx/pull/162)
|
||||
|
||||
|
||||
-166
@@ -1,166 +0,0 @@
|
||||
package pgx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/jackc/pgx/pgtype"
|
||||
)
|
||||
|
||||
// ValueReader is used by the Scanner interface to decode values.
|
||||
type ValueReader struct {
|
||||
mr *msgReader
|
||||
fd *FieldDescription
|
||||
valueBytesRemaining int32
|
||||
err error
|
||||
}
|
||||
|
||||
// Err returns any error that the ValueReader has experienced
|
||||
func (r *ValueReader) Err() error {
|
||||
return r.err
|
||||
}
|
||||
|
||||
// Fatal tells r that a Fatal error has occurred
|
||||
func (r *ValueReader) Fatal(err error) {
|
||||
r.err = err
|
||||
}
|
||||
|
||||
// Len returns the number of unread bytes
|
||||
func (r *ValueReader) Len() int32 {
|
||||
return r.valueBytesRemaining
|
||||
}
|
||||
|
||||
// Type returns the *FieldDescription of the value
|
||||
func (r *ValueReader) Type() *FieldDescription {
|
||||
return r.fd
|
||||
}
|
||||
|
||||
func (r *ValueReader) ReadByte() byte {
|
||||
if r.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
r.valueBytesRemaining--
|
||||
if r.valueBytesRemaining < 0 {
|
||||
r.Fatal(errors.New("read past end of value"))
|
||||
return 0
|
||||
}
|
||||
|
||||
return r.mr.readByte()
|
||||
}
|
||||
|
||||
func (r *ValueReader) ReadInt16() int16 {
|
||||
if r.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
r.valueBytesRemaining -= 2
|
||||
if r.valueBytesRemaining < 0 {
|
||||
r.Fatal(errors.New("read past end of value"))
|
||||
return 0
|
||||
}
|
||||
|
||||
return r.mr.readInt16()
|
||||
}
|
||||
|
||||
func (r *ValueReader) ReadUint16() uint16 {
|
||||
if r.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
r.valueBytesRemaining -= 2
|
||||
if r.valueBytesRemaining < 0 {
|
||||
r.Fatal(errors.New("read past end of value"))
|
||||
return 0
|
||||
}
|
||||
|
||||
return r.mr.readUint16()
|
||||
}
|
||||
|
||||
func (r *ValueReader) ReadInt32() int32 {
|
||||
if r.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
r.valueBytesRemaining -= 4
|
||||
if r.valueBytesRemaining < 0 {
|
||||
r.Fatal(errors.New("read past end of value"))
|
||||
return 0
|
||||
}
|
||||
|
||||
return r.mr.readInt32()
|
||||
}
|
||||
|
||||
func (r *ValueReader) ReadUint32() uint32 {
|
||||
if r.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
r.valueBytesRemaining -= 4
|
||||
if r.valueBytesRemaining < 0 {
|
||||
r.Fatal(errors.New("read past end of value"))
|
||||
return 0
|
||||
}
|
||||
|
||||
return r.mr.readUint32()
|
||||
}
|
||||
|
||||
func (r *ValueReader) ReadInt64() int64 {
|
||||
if r.err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
r.valueBytesRemaining -= 8
|
||||
if r.valueBytesRemaining < 0 {
|
||||
r.Fatal(errors.New("read past end of value"))
|
||||
return 0
|
||||
}
|
||||
|
||||
return r.mr.readInt64()
|
||||
}
|
||||
|
||||
func (r *ValueReader) ReadOid() pgtype.Oid {
|
||||
return pgtype.Oid(r.ReadUint32())
|
||||
}
|
||||
|
||||
// ReadString reads count bytes and returns as string
|
||||
func (r *ValueReader) ReadString(count int32) string {
|
||||
if r.err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
r.valueBytesRemaining -= count
|
||||
if r.valueBytesRemaining < 0 {
|
||||
r.Fatal(errors.New("read past end of value"))
|
||||
return ""
|
||||
}
|
||||
|
||||
return r.mr.readString(count)
|
||||
}
|
||||
|
||||
// ReadBytes reads count bytes and returns as []byte
|
||||
func (r *ValueReader) ReadBytes(count int32) []byte {
|
||||
if r.err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if count < 0 {
|
||||
r.Fatal(errors.New("count must not be negative"))
|
||||
return nil
|
||||
}
|
||||
|
||||
r.valueBytesRemaining -= count
|
||||
if r.valueBytesRemaining < 0 {
|
||||
r.Fatal(errors.New("read past end of value"))
|
||||
return nil
|
||||
}
|
||||
|
||||
return r.mr.readBytes(count)
|
||||
}
|
||||
|
||||
// bytes is a compatibility function for pgtype.TextDecoder and pgtype.BinaryDecoder
|
||||
func (r *ValueReader) bytes() []byte {
|
||||
if r.Len() >= 0 {
|
||||
return r.ReadBytes(r.Len())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user