2
0

Remove ValueReader

This commit is contained in:
Jack Christensen
2017-04-12 07:46:25 -05:00
parent ccfff83d1a
commit 932ab58cf7
3 changed files with 36 additions and 208 deletions
+31 -41
View File
@@ -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()
}
+5 -1
View File
@@ -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
View File
@@ -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
}