mirror of https://github.com/jackc/pgx.git
parent
01f261c71c
commit
d7529600e0
218
conn.go
218
conn.go
|
@ -59,7 +59,7 @@ type Conn struct {
|
|||
alive bool
|
||||
causeOfDeath error
|
||||
logger log.Logger
|
||||
qr QueryResult
|
||||
rows Rows
|
||||
mr MsgReader
|
||||
}
|
||||
|
||||
|
@ -397,29 +397,29 @@ func (c *Conn) CauseOfDeath() error {
|
|||
return c.causeOfDeath
|
||||
}
|
||||
|
||||
type Row QueryResult
|
||||
type Row Rows
|
||||
|
||||
func (r *Row) Scan(dest ...interface{}) (err error) {
|
||||
qr := (*QueryResult)(r)
|
||||
rows := (*Rows)(r)
|
||||
|
||||
if qr.Err() != nil {
|
||||
return qr.Err()
|
||||
if rows.Err() != nil {
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
if !qr.NextRow() {
|
||||
if qr.Err() == nil {
|
||||
if !rows.NextRow() {
|
||||
if rows.Err() == nil {
|
||||
return ErrNoRows
|
||||
} else {
|
||||
return qr.Err()
|
||||
return rows.Err()
|
||||
}
|
||||
}
|
||||
|
||||
qr.Scan(dest...)
|
||||
qr.Close()
|
||||
return qr.Err()
|
||||
rows.Scan(dest...)
|
||||
rows.Close()
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
type QueryResult struct {
|
||||
type Rows struct {
|
||||
pool *ConnPool
|
||||
conn *Conn
|
||||
mr *MsgReader
|
||||
|
@ -430,174 +430,174 @@ type QueryResult struct {
|
|||
closed bool
|
||||
}
|
||||
|
||||
func (qr *QueryResult) FieldDescriptions() []FieldDescription {
|
||||
return qr.fields
|
||||
func (rows *Rows) FieldDescriptions() []FieldDescription {
|
||||
return rows.fields
|
||||
}
|
||||
|
||||
func (qr *QueryResult) MsgReader() *MsgReader {
|
||||
return qr.mr
|
||||
func (rows *Rows) MsgReader() *MsgReader {
|
||||
return rows.mr
|
||||
}
|
||||
|
||||
func (qr *QueryResult) close() {
|
||||
if qr.pool != nil {
|
||||
qr.pool.Release(qr.conn)
|
||||
qr.pool = nil
|
||||
func (rows *Rows) close() {
|
||||
if rows.pool != nil {
|
||||
rows.pool.Release(rows.conn)
|
||||
rows.pool = nil
|
||||
}
|
||||
|
||||
qr.closed = true
|
||||
rows.closed = true
|
||||
}
|
||||
|
||||
func (qr *QueryResult) readUntilReadyForQuery() {
|
||||
func (rows *Rows) readUntilReadyForQuery() {
|
||||
for {
|
||||
t, r, err := qr.conn.rxMsg()
|
||||
t, r, err := rows.conn.rxMsg()
|
||||
if err != nil {
|
||||
qr.close()
|
||||
rows.close()
|
||||
return
|
||||
}
|
||||
|
||||
switch t {
|
||||
case readyForQuery:
|
||||
qr.conn.rxReadyForQuery(r)
|
||||
qr.close()
|
||||
rows.conn.rxReadyForQuery(r)
|
||||
rows.close()
|
||||
return
|
||||
case rowDescription:
|
||||
case dataRow:
|
||||
case commandComplete:
|
||||
case bindComplete:
|
||||
default:
|
||||
err = qr.conn.processContextFreeMsg(t, r)
|
||||
err = rows.conn.processContextFreeMsg(t, r)
|
||||
if err != nil {
|
||||
qr.close()
|
||||
rows.close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (qr *QueryResult) Close() {
|
||||
if qr.closed {
|
||||
func (rows *Rows) Close() {
|
||||
if rows.closed {
|
||||
return
|
||||
}
|
||||
qr.readUntilReadyForQuery()
|
||||
qr.close()
|
||||
rows.readUntilReadyForQuery()
|
||||
rows.close()
|
||||
}
|
||||
|
||||
func (qr *QueryResult) Err() error {
|
||||
return qr.err
|
||||
func (rows *Rows) Err() error {
|
||||
return rows.err
|
||||
}
|
||||
|
||||
// abort signals that the query was not successfully sent to the server.
|
||||
// This differs from Fatal in that it is not necessary to readUntilReadyForQuery
|
||||
func (qr *QueryResult) abort(err error) {
|
||||
if qr.err != nil {
|
||||
func (rows *Rows) abort(err error) {
|
||||
if rows.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
qr.err = err
|
||||
qr.close()
|
||||
rows.err = err
|
||||
rows.close()
|
||||
}
|
||||
|
||||
// Fatal signals an error occurred after the query was sent to the server
|
||||
func (qr *QueryResult) Fatal(err error) {
|
||||
if qr.err != nil {
|
||||
func (rows *Rows) Fatal(err error) {
|
||||
if rows.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
qr.err = err
|
||||
qr.Close()
|
||||
rows.err = err
|
||||
rows.Close()
|
||||
}
|
||||
|
||||
func (qr *QueryResult) NextRow() bool {
|
||||
if qr.closed {
|
||||
func (rows *Rows) NextRow() bool {
|
||||
if rows.closed {
|
||||
return false
|
||||
}
|
||||
|
||||
qr.rowCount++
|
||||
qr.columnIdx = 0
|
||||
rows.rowCount++
|
||||
rows.columnIdx = 0
|
||||
|
||||
for {
|
||||
t, r, err := qr.conn.rxMsg()
|
||||
t, r, err := rows.conn.rxMsg()
|
||||
if err != nil {
|
||||
qr.Fatal(err)
|
||||
rows.Fatal(err)
|
||||
return false
|
||||
}
|
||||
|
||||
switch t {
|
||||
case readyForQuery:
|
||||
qr.conn.rxReadyForQuery(r)
|
||||
qr.close()
|
||||
rows.conn.rxReadyForQuery(r)
|
||||
rows.close()
|
||||
return false
|
||||
case dataRow:
|
||||
fieldCount := r.ReadInt16()
|
||||
if int(fieldCount) != len(qr.fields) {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Row description field count (%v) and data row field count (%v) do not match", len(qr.fields), fieldCount)))
|
||||
if int(fieldCount) != len(rows.fields) {
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Row description field count (%v) and data row field count (%v) do not match", len(rows.fields), fieldCount)))
|
||||
return false
|
||||
}
|
||||
|
||||
qr.mr = r
|
||||
rows.mr = r
|
||||
return true
|
||||
case commandComplete:
|
||||
case bindComplete:
|
||||
default:
|
||||
err = qr.conn.processContextFreeMsg(t, r)
|
||||
err = rows.conn.processContextFreeMsg(t, r)
|
||||
if err != nil {
|
||||
qr.Fatal(err)
|
||||
rows.Fatal(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (qr *QueryResult) nextColumn() (*FieldDescription, int32, bool) {
|
||||
if qr.closed {
|
||||
func (rows *Rows) nextColumn() (*FieldDescription, int32, bool) {
|
||||
if rows.closed {
|
||||
return nil, 0, false
|
||||
}
|
||||
if len(qr.fields) <= qr.columnIdx {
|
||||
qr.Fatal(ProtocolError("No next column available"))
|
||||
if len(rows.fields) <= rows.columnIdx {
|
||||
rows.Fatal(ProtocolError("No next column available"))
|
||||
return nil, 0, false
|
||||
}
|
||||
|
||||
fd := &qr.fields[qr.columnIdx]
|
||||
qr.columnIdx++
|
||||
size := qr.mr.ReadInt32()
|
||||
fd := &rows.fields[rows.columnIdx]
|
||||
rows.columnIdx++
|
||||
size := rows.mr.ReadInt32()
|
||||
return fd, size, true
|
||||
}
|
||||
|
||||
func (qr *QueryResult) Scan(dest ...interface{}) (err error) {
|
||||
if len(qr.fields) != len(dest) {
|
||||
func (rows *Rows) Scan(dest ...interface{}) (err error) {
|
||||
if len(rows.fields) != len(dest) {
|
||||
err = errors.New("Scan received wrong number of arguments")
|
||||
qr.Fatal(err)
|
||||
rows.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, d := range dest {
|
||||
fd, size, _ := qr.nextColumn()
|
||||
fd, size, _ := rows.nextColumn()
|
||||
switch d := d.(type) {
|
||||
case *bool:
|
||||
*d = decodeBool(qr, fd, size)
|
||||
*d = decodeBool(rows, fd, size)
|
||||
case *[]byte:
|
||||
*d = decodeBytea(qr, fd, size)
|
||||
*d = decodeBytea(rows, fd, size)
|
||||
case *int64:
|
||||
*d = decodeInt8(qr, fd, size)
|
||||
*d = decodeInt8(rows, fd, size)
|
||||
case *int16:
|
||||
*d = decodeInt2(qr, fd, size)
|
||||
*d = decodeInt2(rows, fd, size)
|
||||
case *int32:
|
||||
*d = decodeInt4(qr, fd, size)
|
||||
*d = decodeInt4(rows, fd, size)
|
||||
case *string:
|
||||
*d = decodeText(qr, fd, size)
|
||||
*d = decodeText(rows, fd, size)
|
||||
case *float32:
|
||||
*d = decodeFloat4(qr, fd, size)
|
||||
*d = decodeFloat4(rows, fd, size)
|
||||
case *float64:
|
||||
*d = decodeFloat8(qr, fd, size)
|
||||
*d = decodeFloat8(rows, fd, size)
|
||||
case *time.Time:
|
||||
if fd.DataType == DateOid {
|
||||
*d = decodeDate(qr, fd, size)
|
||||
*d = decodeDate(rows, fd, size)
|
||||
} else {
|
||||
*d = decodeTimestampTz(qr, fd, size)
|
||||
*d = decodeTimestampTz(rows, fd, size)
|
||||
}
|
||||
|
||||
case Scanner:
|
||||
err = d.Scan(qr, fd, size)
|
||||
err = d.Scan(rows, fd, size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -609,39 +609,39 @@ func (qr *QueryResult) Scan(dest ...interface{}) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (qr *QueryResult) ReadValue() (v interface{}, err error) {
|
||||
fd, size, _ := qr.nextColumn()
|
||||
if qr.Err() != nil {
|
||||
return nil, qr.Err()
|
||||
func (rows *Rows) ReadValue() (v interface{}, err error) {
|
||||
fd, size, _ := rows.nextColumn()
|
||||
if rows.Err() != nil {
|
||||
return nil, rows.Err()
|
||||
}
|
||||
|
||||
switch fd.DataType {
|
||||
case BoolOid:
|
||||
return decodeBool(qr, fd, size), qr.Err()
|
||||
return decodeBool(rows, fd, size), rows.Err()
|
||||
case ByteaOid:
|
||||
return decodeBytea(qr, fd, size), qr.Err()
|
||||
return decodeBytea(rows, fd, size), rows.Err()
|
||||
case Int8Oid:
|
||||
return decodeInt8(qr, fd, size), qr.Err()
|
||||
return decodeInt8(rows, fd, size), rows.Err()
|
||||
case Int2Oid:
|
||||
return decodeInt2(qr, fd, size), qr.Err()
|
||||
return decodeInt2(rows, fd, size), rows.Err()
|
||||
case Int4Oid:
|
||||
return decodeInt4(qr, fd, size), qr.Err()
|
||||
return decodeInt4(rows, fd, size), rows.Err()
|
||||
case VarcharOid, TextOid:
|
||||
return decodeText(qr, fd, size), qr.Err()
|
||||
return decodeText(rows, fd, size), rows.Err()
|
||||
case Float4Oid:
|
||||
return decodeFloat4(qr, fd, size), qr.Err()
|
||||
return decodeFloat4(rows, fd, size), rows.Err()
|
||||
case Float8Oid:
|
||||
return decodeFloat8(qr, fd, size), qr.Err()
|
||||
return decodeFloat8(rows, fd, size), rows.Err()
|
||||
case DateOid:
|
||||
return decodeDate(qr, fd, size), qr.Err()
|
||||
return decodeDate(rows, fd, size), rows.Err()
|
||||
case TimestampTzOid:
|
||||
return decodeTimestampTz(qr, fd, size), qr.Err()
|
||||
return decodeTimestampTz(rows, fd, size), rows.Err()
|
||||
}
|
||||
|
||||
// if it is not an intrinsic type then return the text
|
||||
switch fd.FormatCode {
|
||||
case TextFormatCode:
|
||||
return qr.MsgReader().ReadString(size), qr.Err()
|
||||
return rows.MsgReader().ReadString(size), rows.Err()
|
||||
// TODO
|
||||
//case BinaryFormatCode:
|
||||
default:
|
||||
|
@ -650,23 +650,23 @@ func (qr *QueryResult) ReadValue() (v interface{}, err error) {
|
|||
}
|
||||
|
||||
// TODO - document
|
||||
func (c *Conn) Query(sql string, args ...interface{}) (*QueryResult, error) {
|
||||
c.qr = QueryResult{conn: c}
|
||||
qr := &c.qr
|
||||
func (c *Conn) Query(sql string, args ...interface{}) (*Rows, error) {
|
||||
c.rows = Rows{conn: c}
|
||||
rows := &c.rows
|
||||
|
||||
if ps, present := c.preparedStatements[sql]; present {
|
||||
qr.fields = ps.FieldDescriptions
|
||||
rows.fields = ps.FieldDescriptions
|
||||
err := c.sendPreparedQuery(ps, args...)
|
||||
if err != nil {
|
||||
qr.abort(err)
|
||||
rows.abort(err)
|
||||
}
|
||||
return qr, qr.err
|
||||
return rows, rows.err
|
||||
}
|
||||
|
||||
err := c.sendSimpleQuery(sql, args...)
|
||||
if err != nil {
|
||||
qr.abort(err)
|
||||
return qr, qr.err
|
||||
rows.abort(err)
|
||||
return rows, rows.err
|
||||
}
|
||||
|
||||
// Simple queries don't know the field descriptions of the result.
|
||||
|
@ -674,27 +674,27 @@ func (c *Conn) Query(sql string, args ...interface{}) (*QueryResult, error) {
|
|||
for {
|
||||
t, r, err := c.rxMsg()
|
||||
if err != nil {
|
||||
qr.Fatal(err)
|
||||
return qr, qr.err
|
||||
rows.Fatal(err)
|
||||
return rows, rows.err
|
||||
}
|
||||
|
||||
switch t {
|
||||
case rowDescription:
|
||||
qr.fields = qr.conn.rxRowDescription(r)
|
||||
return qr, nil
|
||||
rows.fields = rows.conn.rxRowDescription(r)
|
||||
return rows, nil
|
||||
default:
|
||||
err = qr.conn.processContextFreeMsg(t, r)
|
||||
err = rows.conn.processContextFreeMsg(t, r)
|
||||
if err != nil {
|
||||
qr.Fatal(err)
|
||||
return qr, qr.err
|
||||
rows.Fatal(err)
|
||||
return rows, rows.err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) QueryRow(sql string, args ...interface{}) *Row {
|
||||
qr, _ := c.Query(sql, args...)
|
||||
return (*Row)(qr)
|
||||
rows, _ := c.Query(sql, args...)
|
||||
return (*Row)(rows)
|
||||
}
|
||||
|
||||
func (c *Conn) sendQuery(sql string, arguments ...interface{}) (err error) {
|
||||
|
|
18
conn_pool.go
18
conn_pool.go
|
@ -176,26 +176,26 @@ func (p *ConnPool) Exec(sql string, arguments ...interface{}) (commandTag Comman
|
|||
return c.Exec(sql, arguments...)
|
||||
}
|
||||
|
||||
func (p *ConnPool) Query(sql string, args ...interface{}) (*QueryResult, error) {
|
||||
func (p *ConnPool) Query(sql string, args ...interface{}) (*Rows, error) {
|
||||
c, err := p.Acquire()
|
||||
if err != nil {
|
||||
// Because checking for errors can be deferred to the *QueryResult, build one with the error
|
||||
return &QueryResult{closed: true, err: err}, err
|
||||
// Because checking for errors can be deferred to the *Rows, build one with the error
|
||||
return &Rows{closed: true, err: err}, err
|
||||
}
|
||||
|
||||
qr, err := c.Query(sql, args...)
|
||||
rows, err := c.Query(sql, args...)
|
||||
if err != nil {
|
||||
p.Release(c)
|
||||
return qr, err
|
||||
return rows, err
|
||||
}
|
||||
|
||||
qr.pool = p
|
||||
return qr, nil
|
||||
rows.pool = p
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func (p *ConnPool) QueryRow(sql string, args ...interface{}) *Row {
|
||||
qr, _ := p.Query(sql, args...)
|
||||
return (*Row)(qr)
|
||||
rows, _ := p.Query(sql, args...)
|
||||
return (*Row)(rows)
|
||||
}
|
||||
|
||||
// Transaction acquires a connection, delegates the call to that connection,
|
||||
|
|
|
@ -209,8 +209,8 @@ func TestPoolAcquireAndReleaseCycleAutoConnect(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Unable to Acquire: %v", err)
|
||||
}
|
||||
qr, _ := c.Query("select 1")
|
||||
qr.Close()
|
||||
rows, _ := c.Query("select 1")
|
||||
rows.Close()
|
||||
pool.Release(c)
|
||||
}
|
||||
|
||||
|
@ -273,9 +273,9 @@ func TestPoolReleaseDiscardsDeadConnections(t *testing.T) {
|
|||
}
|
||||
|
||||
// do something with the connection so it knows it's dead
|
||||
qr, _ := c1.Query("select 1")
|
||||
qr.Close()
|
||||
if qr.Err() == nil {
|
||||
rows, _ := c1.Query("select 1")
|
||||
rows.Close()
|
||||
if rows.Err() == nil {
|
||||
t.Fatal("Expected error but none occurred")
|
||||
}
|
||||
|
||||
|
@ -400,7 +400,7 @@ func TestConnPoolQuery(t *testing.T) {
|
|||
|
||||
var sum, rowCount int32
|
||||
|
||||
qr, err := pool.Query("select generate_series(1,$1)", 10)
|
||||
rows, err := pool.Query("select generate_series(1,$1)", 10)
|
||||
if err != nil {
|
||||
t.Fatalf("pool.Query failed: %v", err)
|
||||
}
|
||||
|
@ -410,14 +410,14 @@ func TestConnPoolQuery(t *testing.T) {
|
|||
t.Fatalf("Unexpected connection pool stats: %v", stats)
|
||||
}
|
||||
|
||||
for qr.NextRow() {
|
||||
for rows.NextRow() {
|
||||
var n int32
|
||||
qr.Scan(&n)
|
||||
rows.Scan(&n)
|
||||
sum += n
|
||||
rowCount++
|
||||
}
|
||||
|
||||
if qr.Err() != nil {
|
||||
if rows.Err() != nil {
|
||||
t.Fatalf("conn.Query failed: ", err)
|
||||
}
|
||||
|
||||
|
|
96
conn_test.go
96
conn_test.go
|
@ -295,10 +295,10 @@ func TestExecFailure(t *testing.T) {
|
|||
t.Fatal("Expected SQL syntax error")
|
||||
}
|
||||
|
||||
qr, _ := conn.Query("select 1")
|
||||
qr.Close()
|
||||
if qr.Err() != nil {
|
||||
t.Fatalf("Exec failure appears to have broken connection: %v", qr.Err())
|
||||
rows, _ := conn.Query("select 1")
|
||||
rows.Close()
|
||||
if rows.Err() != nil {
|
||||
t.Fatalf("Exec failure appears to have broken connection: %v", rows.Err())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,20 +339,20 @@ func TestConnQuery(t *testing.T) {
|
|||
func ensureConnValid(t *testing.T, conn *pgx.Conn) {
|
||||
var sum, rowCount int32
|
||||
|
||||
qr, err := conn.Query("select generate_series(1,$1)", 10)
|
||||
rows, err := conn.Query("select generate_series(1,$1)", 10)
|
||||
if err != nil {
|
||||
t.Fatalf("conn.Query failed: ", err)
|
||||
}
|
||||
defer qr.Close()
|
||||
defer rows.Close()
|
||||
|
||||
for qr.NextRow() {
|
||||
for rows.NextRow() {
|
||||
var n int32
|
||||
qr.Scan(&n)
|
||||
rows.Scan(&n)
|
||||
sum += n
|
||||
rowCount++
|
||||
}
|
||||
|
||||
if qr.Err() != nil {
|
||||
if rows.Err() != nil {
|
||||
t.Fatalf("conn.Query failed: ", err)
|
||||
}
|
||||
|
||||
|
@ -372,32 +372,32 @@ func TestConnQueryCloseEarly(t *testing.T) {
|
|||
defer closeConn(t, conn)
|
||||
|
||||
// Immediately close query without reading any rows
|
||||
qr, err := conn.Query("select generate_series(1,$1)", 10)
|
||||
rows, err := conn.Query("select generate_series(1,$1)", 10)
|
||||
if err != nil {
|
||||
t.Fatalf("conn.Query failed: ", err)
|
||||
}
|
||||
qr.Close()
|
||||
rows.Close()
|
||||
|
||||
ensureConnValid(t, conn)
|
||||
|
||||
// Read partial response then close
|
||||
qr, err = conn.Query("select generate_series(1,$1)", 10)
|
||||
rows, err = conn.Query("select generate_series(1,$1)", 10)
|
||||
if err != nil {
|
||||
t.Fatalf("conn.Query failed: ", err)
|
||||
}
|
||||
|
||||
ok := qr.NextRow()
|
||||
ok := rows.NextRow()
|
||||
if !ok {
|
||||
t.Fatal("qr.NextRow terminated early")
|
||||
t.Fatal("rows.NextRow terminated early")
|
||||
}
|
||||
|
||||
var n int32
|
||||
qr.Scan(&n)
|
||||
rows.Scan(&n)
|
||||
if n != 1 {
|
||||
t.Fatalf("Expected 1 from first row, but got %v", n)
|
||||
}
|
||||
|
||||
qr.Close()
|
||||
rows.Close()
|
||||
|
||||
ensureConnValid(t, conn)
|
||||
}
|
||||
|
@ -410,16 +410,16 @@ func TestConnQueryReadWrongTypeError(t *testing.T) {
|
|||
defer closeConn(t, conn)
|
||||
|
||||
// Read a single value incorrectly
|
||||
qr, err := conn.Query("select generate_series(1,$1)", 10)
|
||||
rows, err := conn.Query("select generate_series(1,$1)", 10)
|
||||
if err != nil {
|
||||
t.Fatalf("conn.Query failed: ", err)
|
||||
}
|
||||
|
||||
rowsRead := 0
|
||||
|
||||
for qr.NextRow() {
|
||||
for rows.NextRow() {
|
||||
var t time.Time
|
||||
qr.Scan(&t)
|
||||
rows.Scan(&t)
|
||||
rowsRead++
|
||||
}
|
||||
|
||||
|
@ -427,8 +427,8 @@ func TestConnQueryReadWrongTypeError(t *testing.T) {
|
|||
t.Fatalf("Expected error to cause only 1 row to be read, but %d were read", rowsRead)
|
||||
}
|
||||
|
||||
if qr.Err() == nil {
|
||||
t.Fatal("Expected QueryResult to have an error after an improper read but it didn't")
|
||||
if rows.Err() == nil {
|
||||
t.Fatal("Expected Rows to have an error after an improper read but it didn't")
|
||||
}
|
||||
|
||||
ensureConnValid(t, conn)
|
||||
|
@ -442,16 +442,16 @@ func TestConnQueryReadTooManyValues(t *testing.T) {
|
|||
defer closeConn(t, conn)
|
||||
|
||||
// Read too many values
|
||||
qr, err := conn.Query("select generate_series(1,$1)", 10)
|
||||
rows, err := conn.Query("select generate_series(1,$1)", 10)
|
||||
if err != nil {
|
||||
t.Fatalf("conn.Query failed: ", err)
|
||||
}
|
||||
|
||||
rowsRead := 0
|
||||
|
||||
for qr.NextRow() {
|
||||
for rows.NextRow() {
|
||||
var n, m int32
|
||||
qr.Scan(&n, &m)
|
||||
rows.Scan(&n, &m)
|
||||
rowsRead++
|
||||
}
|
||||
|
||||
|
@ -459,8 +459,8 @@ func TestConnQueryReadTooManyValues(t *testing.T) {
|
|||
t.Fatalf("Expected error to cause only 1 row to be read, but %d were read", rowsRead)
|
||||
}
|
||||
|
||||
if qr.Err() == nil {
|
||||
t.Fatal("Expected QueryResult to have an error after an improper read but it didn't")
|
||||
if rows.Err() == nil {
|
||||
t.Fatal("Expected Rows to have an error after an improper read but it didn't")
|
||||
}
|
||||
|
||||
ensureConnValid(t, conn)
|
||||
|
@ -472,22 +472,22 @@ func TestConnQueryUnpreparedScanner(t *testing.T) {
|
|||
conn := mustConnect(t, *defaultConnConfig)
|
||||
defer closeConn(t, conn)
|
||||
|
||||
qr, err := conn.Query("select null::int8, 1::int8")
|
||||
rows, err := conn.Query("select null::int8, 1::int8")
|
||||
if err != nil {
|
||||
t.Fatalf("conn.Query failed: ", err)
|
||||
}
|
||||
|
||||
ok := qr.NextRow()
|
||||
ok := rows.NextRow()
|
||||
if !ok {
|
||||
t.Fatal("qr.NextRow terminated early")
|
||||
t.Fatal("rows.NextRow terminated early")
|
||||
}
|
||||
|
||||
var n, m pgx.NullInt64
|
||||
err = qr.Scan(&n, &m)
|
||||
err = rows.Scan(&n, &m)
|
||||
if err != nil {
|
||||
t.Fatalf("qr.Scan failed: ", err)
|
||||
t.Fatalf("rows.Scan failed: ", err)
|
||||
}
|
||||
qr.Close()
|
||||
rows.Close()
|
||||
|
||||
if n.Valid {
|
||||
t.Error("Null should not be valid, but it was")
|
||||
|
@ -512,22 +512,22 @@ func TestConnQueryPreparedScanner(t *testing.T) {
|
|||
|
||||
mustPrepare(t, conn, "scannerTest", "select null::int8, 1::int8")
|
||||
|
||||
qr, err := conn.Query("scannerTest")
|
||||
rows, err := conn.Query("scannerTest")
|
||||
if err != nil {
|
||||
t.Fatalf("conn.Query failed: ", err)
|
||||
}
|
||||
|
||||
ok := qr.NextRow()
|
||||
ok := rows.NextRow()
|
||||
if !ok {
|
||||
t.Fatal("qr.NextRow terminated early")
|
||||
t.Fatal("rows.NextRow terminated early")
|
||||
}
|
||||
|
||||
var n, m pgx.NullInt64
|
||||
err = qr.Scan(&n, &m)
|
||||
err = rows.Scan(&n, &m)
|
||||
if err != nil {
|
||||
t.Fatalf("qr.Scan failed: ", err)
|
||||
t.Fatalf("rows.Scan failed: ", err)
|
||||
}
|
||||
qr.Close()
|
||||
rows.Close()
|
||||
|
||||
if n.Valid {
|
||||
t.Error("Null should not be valid, but it was")
|
||||
|
@ -552,22 +552,22 @@ func TestConnQueryUnpreparedEncoder(t *testing.T) {
|
|||
|
||||
n := pgx.NullInt64{Int64: 1, Valid: true}
|
||||
|
||||
qr, err := conn.Query("select $1::int8", &n)
|
||||
rows, err := conn.Query("select $1::int8", &n)
|
||||
if err != nil {
|
||||
t.Fatalf("conn.Query failed: ", err)
|
||||
}
|
||||
|
||||
ok := qr.NextRow()
|
||||
ok := rows.NextRow()
|
||||
if !ok {
|
||||
t.Fatal("qr.NextRow terminated early")
|
||||
t.Fatal("rows.NextRow terminated early")
|
||||
}
|
||||
|
||||
var m pgx.NullInt64
|
||||
err = qr.Scan(&m)
|
||||
err = rows.Scan(&m)
|
||||
if err != nil {
|
||||
t.Fatalf("qr.Scan failed: ", err)
|
||||
t.Fatalf("rows.Scan failed: ", err)
|
||||
}
|
||||
qr.Close()
|
||||
rows.Close()
|
||||
|
||||
if !m.Valid {
|
||||
t.Error("m should be valid, but it wasn't")
|
||||
|
@ -787,10 +787,10 @@ func TestListenNotify(t *testing.T) {
|
|||
|
||||
// when notification has already been read during previous query
|
||||
mustExec(t, notifier, "notify chat")
|
||||
qr, _ := listener.Query("select 1")
|
||||
qr.Close()
|
||||
if qr.Err() != nil {
|
||||
t.Fatalf("Unexpected error on Query: %v", qr.Err())
|
||||
rows, _ := listener.Query("select 1")
|
||||
rows.Close()
|
||||
if rows.Err() != nil {
|
||||
t.Fatalf("Unexpected error on Query: %v", rows.Err())
|
||||
}
|
||||
notification, err = listener.WaitForNotification(0)
|
||||
if err != nil {
|
||||
|
|
|
@ -133,12 +133,12 @@ func (c *Conn) Query(query string, argsV []driver.Value) (driver.Rows, error) {
|
|||
|
||||
args := valueToInterface(argsV)
|
||||
|
||||
qr, err := c.conn.Query(query, args...)
|
||||
rows, err := c.conn.Query(query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Rows{qr: qr}, nil
|
||||
return &Rows{rows: rows}, nil
|
||||
}
|
||||
|
||||
type Stmt struct {
|
||||
|
@ -164,11 +164,11 @@ func (s *Stmt) Query(argsV []driver.Value) (driver.Rows, error) {
|
|||
|
||||
// TODO - rename to avoid alloc
|
||||
type Rows struct {
|
||||
qr *pgx.QueryResult
|
||||
rows *pgx.Rows
|
||||
}
|
||||
|
||||
func (r *Rows) Columns() []string {
|
||||
fieldDescriptions := r.qr.FieldDescriptions()
|
||||
fieldDescriptions := r.rows.FieldDescriptions()
|
||||
names := make([]string, 0, len(fieldDescriptions))
|
||||
for _, fd := range fieldDescriptions {
|
||||
names = append(names, fd.Name)
|
||||
|
@ -177,22 +177,22 @@ func (r *Rows) Columns() []string {
|
|||
}
|
||||
|
||||
func (r *Rows) Close() error {
|
||||
r.qr.Close()
|
||||
r.rows.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Rows) Next(dest []driver.Value) error {
|
||||
more := r.qr.NextRow()
|
||||
more := r.rows.NextRow()
|
||||
if !more {
|
||||
if r.qr.Err() == nil {
|
||||
if r.rows.Err() == nil {
|
||||
return io.EOF
|
||||
} else {
|
||||
return r.qr.Err()
|
||||
return r.rows.Err()
|
||||
}
|
||||
}
|
||||
|
||||
for i, _ := range r.qr.FieldDescriptions() {
|
||||
v, err := r.qr.ReadValue()
|
||||
for i, _ := range r.rows.FieldDescriptions() {
|
||||
v, err := r.rows.ReadValue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
128
values.go
128
values.go
|
@ -40,7 +40,7 @@ func (e SerializationError) Error() string {
|
|||
type Scanner interface {
|
||||
// Scan MUST check fd's DataType and FormatCode before decoding. It should
|
||||
// not assume that it was called on the type of value.
|
||||
Scan(qr *QueryResult, fd *FieldDescription, size int32) error
|
||||
Scan(rows *Rows, fd *FieldDescription, size int32) error
|
||||
}
|
||||
|
||||
// TextEncoder is an interface used to encode values in text format for
|
||||
|
@ -145,14 +145,14 @@ func SanitizeSql(sql string, args ...interface{}) (output string, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (n *NullInt64) Scan(qr *QueryResult, fd *FieldDescription, size int32) error {
|
||||
func (n *NullInt64) Scan(rows *Rows, fd *FieldDescription, size int32) error {
|
||||
if size == -1 {
|
||||
n.Int64, n.Valid = 0, false
|
||||
return nil
|
||||
}
|
||||
n.Valid = true
|
||||
n.Int64 = decodeInt8(qr, fd, size)
|
||||
return qr.Err()
|
||||
n.Int64 = decodeInt8(rows, fd, size)
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func (n *NullInt64) EncodeText() (string, error) {
|
||||
|
@ -163,28 +163,28 @@ func (n *NullInt64) EncodeText() (string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func decodeBool(qr *QueryResult, fd *FieldDescription, size int32) bool {
|
||||
func decodeBool(rows *Rows, fd *FieldDescription, size int32) bool {
|
||||
switch fd.FormatCode {
|
||||
case TextFormatCode:
|
||||
s := qr.mr.ReadString(size)
|
||||
s := rows.mr.ReadString(size)
|
||||
switch s {
|
||||
case "t":
|
||||
return true
|
||||
case "f":
|
||||
return false
|
||||
default:
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received invalid bool: %v", s)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received invalid bool: %v", s)))
|
||||
return false
|
||||
}
|
||||
case BinaryFormatCode:
|
||||
if size != 1 {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an bool: %d", size)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an bool: %d", size)))
|
||||
return false
|
||||
}
|
||||
b := qr.mr.ReadByte()
|
||||
b := rows.mr.ReadByte()
|
||||
return b != 0
|
||||
default:
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -207,29 +207,29 @@ func encodeBool(w *WriteBuf, value interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func decodeInt8(qr *QueryResult, fd *FieldDescription, size int32) int64 {
|
||||
func decodeInt8(rows *Rows, fd *FieldDescription, size int32) int64 {
|
||||
if fd.DataType != Int8Oid {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Expected type oid %v but received type oid %v", Int8Oid, fd.DataType)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Expected type oid %v but received type oid %v", Int8Oid, fd.DataType)))
|
||||
return 0
|
||||
}
|
||||
|
||||
switch fd.FormatCode {
|
||||
case TextFormatCode:
|
||||
s := qr.mr.ReadString(size)
|
||||
s := rows.mr.ReadString(size)
|
||||
n, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received invalid int8: %v", s)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received invalid int8: %v", s)))
|
||||
return 0
|
||||
}
|
||||
return n
|
||||
case BinaryFormatCode:
|
||||
if size != 8 {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an int8: %d", size)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an int8: %d", size)))
|
||||
return 0
|
||||
}
|
||||
return qr.mr.ReadInt64()
|
||||
return rows.mr.ReadInt64()
|
||||
default:
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
@ -268,29 +268,29 @@ func encodeInt8(w *WriteBuf, value interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func decodeInt2(qr *QueryResult, fd *FieldDescription, size int32) int16 {
|
||||
func decodeInt2(rows *Rows, fd *FieldDescription, size int32) int16 {
|
||||
if fd.DataType != Int2Oid {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Expected type oid %v but received type oid %v", Int2Oid, fd.DataType)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Expected type oid %v but received type oid %v", Int2Oid, fd.DataType)))
|
||||
return 0
|
||||
}
|
||||
|
||||
switch fd.FormatCode {
|
||||
case TextFormatCode:
|
||||
s := qr.mr.ReadString(size)
|
||||
s := rows.mr.ReadString(size)
|
||||
n, err := strconv.ParseInt(s, 10, 16)
|
||||
if err != nil {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received invalid int2: %v", s)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received invalid int2: %v", s)))
|
||||
return 0
|
||||
}
|
||||
return int16(n)
|
||||
case BinaryFormatCode:
|
||||
if size != 2 {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an int2: %d", size)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an int2: %d", size)))
|
||||
return 0
|
||||
}
|
||||
return qr.mr.ReadInt16()
|
||||
return rows.mr.ReadInt16()
|
||||
default:
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
@ -344,28 +344,28 @@ func encodeInt2(w *WriteBuf, value interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func decodeInt4(qr *QueryResult, fd *FieldDescription, size int32) int32 {
|
||||
func decodeInt4(rows *Rows, fd *FieldDescription, size int32) int32 {
|
||||
if fd.DataType != Int4Oid {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Expected type oid %v but received type oid %v", Int4Oid, fd.DataType)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Expected type oid %v but received type oid %v", Int4Oid, fd.DataType)))
|
||||
return 0
|
||||
}
|
||||
|
||||
switch fd.FormatCode {
|
||||
case TextFormatCode:
|
||||
s := qr.mr.ReadString(size)
|
||||
s := rows.mr.ReadString(size)
|
||||
n, err := strconv.ParseInt(s, 10, 32)
|
||||
if err != nil {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received invalid int4: %v", s)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received invalid int4: %v", s)))
|
||||
}
|
||||
return int32(n)
|
||||
case BinaryFormatCode:
|
||||
if size != 4 {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an int4: %d", size)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an int4: %d", size)))
|
||||
return 0
|
||||
}
|
||||
return qr.mr.ReadInt32()
|
||||
return rows.mr.ReadInt32()
|
||||
default:
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
@ -413,27 +413,27 @@ func encodeInt4(w *WriteBuf, value interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func decodeFloat4(qr *QueryResult, fd *FieldDescription, size int32) float32 {
|
||||
func decodeFloat4(rows *Rows, fd *FieldDescription, size int32) float32 {
|
||||
switch fd.FormatCode {
|
||||
case TextFormatCode:
|
||||
s := qr.mr.ReadString(size)
|
||||
s := rows.mr.ReadString(size)
|
||||
n, err := strconv.ParseFloat(s, 32)
|
||||
if err != nil {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received invalid float4: %v", s)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received invalid float4: %v", s)))
|
||||
return 0
|
||||
}
|
||||
return float32(n)
|
||||
case BinaryFormatCode:
|
||||
if size != 4 {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an float4: %d", size)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an float4: %d", size)))
|
||||
return 0
|
||||
}
|
||||
|
||||
i := qr.mr.ReadInt32()
|
||||
i := rows.mr.ReadInt32()
|
||||
p := unsafe.Pointer(&i)
|
||||
return *(*float32)(p)
|
||||
default:
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
@ -460,27 +460,27 @@ func encodeFloat4(w *WriteBuf, value interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func decodeFloat8(qr *QueryResult, fd *FieldDescription, size int32) float64 {
|
||||
func decodeFloat8(rows *Rows, fd *FieldDescription, size int32) float64 {
|
||||
switch fd.FormatCode {
|
||||
case TextFormatCode:
|
||||
s := qr.mr.ReadString(size)
|
||||
s := rows.mr.ReadString(size)
|
||||
v, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received invalid float8: %v", s)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received invalid float8: %v", s)))
|
||||
return 0
|
||||
}
|
||||
return v
|
||||
case BinaryFormatCode:
|
||||
if size != 8 {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an float8: %d", size)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an float8: %d", size)))
|
||||
return 0
|
||||
}
|
||||
|
||||
i := qr.mr.ReadInt64()
|
||||
i := rows.mr.ReadInt64()
|
||||
p := unsafe.Pointer(&i)
|
||||
return *(*float64)(p)
|
||||
default:
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
@ -504,8 +504,8 @@ func encodeFloat8(w *WriteBuf, value interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func decodeText(qr *QueryResult, fd *FieldDescription, size int32) string {
|
||||
return qr.mr.ReadString(size)
|
||||
func decodeText(rows *Rows, fd *FieldDescription, size int32) string {
|
||||
return rows.mr.ReadString(size)
|
||||
}
|
||||
|
||||
func encodeText(w *WriteBuf, value interface{}) error {
|
||||
|
@ -520,20 +520,20 @@ func encodeText(w *WriteBuf, value interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func decodeBytea(qr *QueryResult, fd *FieldDescription, size int32) []byte {
|
||||
func decodeBytea(rows *Rows, fd *FieldDescription, size int32) []byte {
|
||||
switch fd.FormatCode {
|
||||
case TextFormatCode:
|
||||
s := qr.mr.ReadString(size)
|
||||
s := rows.mr.ReadString(size)
|
||||
b, err := hex.DecodeString(s[2:])
|
||||
if err != nil {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Can't decode byte array: %v - %v", err, s)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Can't decode byte array: %v - %v", err, s)))
|
||||
return nil
|
||||
}
|
||||
return b
|
||||
case BinaryFormatCode:
|
||||
return qr.mr.ReadBytes(size)
|
||||
return rows.mr.ReadBytes(size)
|
||||
default:
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -550,31 +550,31 @@ func encodeBytea(w *WriteBuf, value interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func decodeDate(qr *QueryResult, fd *FieldDescription, size int32) time.Time {
|
||||
func decodeDate(rows *Rows, fd *FieldDescription, size int32) time.Time {
|
||||
var zeroTime time.Time
|
||||
|
||||
if fd.DataType != DateOid {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Expected type oid %v but received type oid %v", DateOid, fd.DataType)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Expected type oid %v but received type oid %v", DateOid, fd.DataType)))
|
||||
return zeroTime
|
||||
}
|
||||
|
||||
switch fd.FormatCode {
|
||||
case TextFormatCode:
|
||||
s := qr.mr.ReadString(size)
|
||||
s := rows.mr.ReadString(size)
|
||||
t, err := time.ParseInLocation("2006-01-02", s, time.Local)
|
||||
if err != nil {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Can't decode date: %v", s)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Can't decode date: %v", s)))
|
||||
return zeroTime
|
||||
}
|
||||
return t
|
||||
case BinaryFormatCode:
|
||||
if size != 4 {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an date: %d", size)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an date: %d", size)))
|
||||
}
|
||||
dayOffset := qr.mr.ReadInt32()
|
||||
dayOffset := rows.mr.ReadInt32()
|
||||
return time.Date(2000, 1, int(1+dayOffset), 0, 0, 0, 0, time.Local)
|
||||
default:
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
return zeroTime
|
||||
}
|
||||
}
|
||||
|
@ -589,33 +589,33 @@ func encodeDate(w *WriteBuf, value interface{}) error {
|
|||
return encodeText(w, s)
|
||||
}
|
||||
|
||||
func decodeTimestampTz(qr *QueryResult, fd *FieldDescription, size int32) time.Time {
|
||||
func decodeTimestampTz(rows *Rows, fd *FieldDescription, size int32) time.Time {
|
||||
var zeroTime time.Time
|
||||
|
||||
if fd.DataType != TimestampTzOid {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Expected type oid %v but received type oid %v", TimestampTzOid, fd.DataType)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Expected type oid %v but received type oid %v", TimestampTzOid, fd.DataType)))
|
||||
return zeroTime
|
||||
}
|
||||
|
||||
switch fd.FormatCode {
|
||||
case TextFormatCode:
|
||||
s := qr.mr.ReadString(size)
|
||||
s := rows.mr.ReadString(size)
|
||||
t, err := time.Parse("2006-01-02 15:04:05.999999-07", s)
|
||||
if err != nil {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Can't decode timestamptz: %v - %v", err, s)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Can't decode timestamptz: %v - %v", err, s)))
|
||||
return zeroTime
|
||||
}
|
||||
return t
|
||||
case BinaryFormatCode:
|
||||
if size != 8 {
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an timestamptz: %d", size)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an timestamptz: %d", size)))
|
||||
}
|
||||
microsecFromUnixEpochToY2K := int64(946684800 * 1000000)
|
||||
microsecSinceY2K := qr.mr.ReadInt64()
|
||||
microsecSinceY2K := rows.mr.ReadInt64()
|
||||
microsecSinceUnixEpoch := microsecFromUnixEpochToY2K + microsecSinceY2K
|
||||
return time.Unix(microsecSinceUnixEpoch/1000000, (microsecSinceUnixEpoch%1000000)*1000)
|
||||
default:
|
||||
qr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
rows.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", fd.FormatCode)))
|
||||
return zeroTime
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue