From 932ab58cf7eb6c665d40ebbaeae91973b95fc870 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Wed, 12 Apr 2017 07:46:25 -0500 Subject: [PATCH] Remove ValueReader --- query.go | 72 +++++++++------------ v3.md | 6 +- value_reader.go | 166 ------------------------------------------------ 3 files changed, 36 insertions(+), 208 deletions(-) delete mode 100644 value_reader.go diff --git a/query.go b/query.go index 72f987b4..f7d8ed19 100644 --- a/query.go +++ b/query.go @@ -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() } diff --git a/v3.md b/v3.md index 20038938..d9017890 100644 --- a/v3.md +++ b/v3.md @@ -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) diff --git a/value_reader.go b/value_reader.go deleted file mode 100644 index fea21d49..00000000 --- a/value_reader.go +++ /dev/null @@ -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 -}