mirror of https://github.com/jackc/pgx.git
Conform closer to database/sql style and add no rows test
parent
566d713285
commit
01f261c71c
23
conn.go
23
conn.go
|
@ -85,15 +85,9 @@ func (ct CommandTag) RowsAffected() int64 {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotSingleRowError is returned when exactly 1 row is expected, but 0 or more than
|
var ErrNoRows = errors.New("no rows in result set")
|
||||||
// 1 row is returned
|
var ErrNotificationTimeout = errors.New("notification timeout")
|
||||||
type NotSingleRowError struct {
|
var ErrDeadConn = errors.New("conn is dead")
|
||||||
RowCount int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e NotSingleRowError) Error() string {
|
|
||||||
return fmt.Sprintf("Expected to find 1 row exactly, instead found %d", e.RowCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProtocolError string
|
type ProtocolError string
|
||||||
|
|
||||||
|
@ -101,9 +95,6 @@ func (e ProtocolError) Error() string {
|
||||||
return string(e)
|
return string(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
var NotificationTimeoutError = errors.New("Notification Timeout")
|
|
||||||
var DeadConnError = errors.New("Connection is dead")
|
|
||||||
|
|
||||||
// Connect establishes a connection with a PostgreSQL server using config.
|
// Connect establishes a connection with a PostgreSQL server using config.
|
||||||
// config.Host must be specified. config.User will default to the OS user name.
|
// config.Host must be specified. config.User will default to the OS user name.
|
||||||
// Other config fields are optional.
|
// Other config fields are optional.
|
||||||
|
@ -340,7 +331,7 @@ func (c *Conn) Listen(channel string) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitForNotification waits for a PostgreSQL notification for up to timeout.
|
// WaitForNotification waits for a PostgreSQL notification for up to timeout.
|
||||||
// If the timeout occurs it returns pgx.NotificationTimeoutError
|
// If the timeout occurs it returns pgx.ErrNotificationTimeout
|
||||||
func (c *Conn) WaitForNotification(timeout time.Duration) (*Notification, error) {
|
func (c *Conn) WaitForNotification(timeout time.Duration) (*Notification, error) {
|
||||||
if len(c.notifications) > 0 {
|
if len(c.notifications) > 0 {
|
||||||
notification := c.notifications[0]
|
notification := c.notifications[0]
|
||||||
|
@ -370,7 +361,7 @@ func (c *Conn) WaitForNotification(timeout time.Duration) (*Notification, error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.conn.SetReadDeadline(zeroTime) // we can only return one error and we already have one -- so ignore possiple error from SetReadDeadline
|
c.conn.SetReadDeadline(zeroTime) // we can only return one error and we already have one -- so ignore possiple error from SetReadDeadline
|
||||||
if err, ok := err.(*net.OpError); ok && err.Timeout() {
|
if err, ok := err.(*net.OpError); ok && err.Timeout() {
|
||||||
return nil, NotificationTimeoutError
|
return nil, ErrNotificationTimeout
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -417,7 +408,7 @@ func (r *Row) Scan(dest ...interface{}) (err error) {
|
||||||
|
|
||||||
if !qr.NextRow() {
|
if !qr.NextRow() {
|
||||||
if qr.Err() == nil {
|
if qr.Err() == nil {
|
||||||
return errors.New("No rows")
|
return ErrNoRows
|
||||||
} else {
|
} else {
|
||||||
return qr.Err()
|
return qr.Err()
|
||||||
}
|
}
|
||||||
|
@ -940,7 +931,7 @@ func (c *Conn) processContextFreeMsg(t byte, r *MsgReader) (err error) {
|
||||||
|
|
||||||
func (c *Conn) rxMsg() (t byte, r *MsgReader, err error) {
|
func (c *Conn) rxMsg() (t byte, r *MsgReader, err error) {
|
||||||
if !c.alive {
|
if !c.alive {
|
||||||
return 0, nil, DeadConnError
|
return 0, nil, ErrDeadConn
|
||||||
}
|
}
|
||||||
|
|
||||||
t, err = c.mr.rxMsg()
|
t, err = c.mr.rxMsg()
|
||||||
|
|
37
conn_test.go
37
conn_test.go
|
@ -182,6 +182,20 @@ func TestConnectWithMD5Password(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConnectWithConnectionRefused(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Presumably nothing is listening on 127.0.0.1:1
|
||||||
|
bad := *defaultConnConfig
|
||||||
|
bad.Host = "127.0.0.1"
|
||||||
|
bad.Port = 1
|
||||||
|
|
||||||
|
_, err := pgx.Connect(bad)
|
||||||
|
if !strings.Contains(err.Error(), "connection refused") {
|
||||||
|
t.Fatal("Unable to establish connection: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseURI(t *testing.T) {
|
func TestParseURI(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
@ -788,7 +802,7 @@ func TestListenNotify(t *testing.T) {
|
||||||
|
|
||||||
// when timeout occurs
|
// when timeout occurs
|
||||||
notification, err = listener.WaitForNotification(time.Millisecond)
|
notification, err = listener.WaitForNotification(time.Millisecond)
|
||||||
if err != pgx.NotificationTimeoutError {
|
if err != pgx.ErrNotificationTimeout {
|
||||||
t.Errorf("WaitForNotification returned the wrong kind of error: %v", err)
|
t.Errorf("WaitForNotification returned the wrong kind of error: %v", err)
|
||||||
}
|
}
|
||||||
if notification != nil {
|
if notification != nil {
|
||||||
|
@ -1066,6 +1080,27 @@ func TestQueryRowPreparedErrors(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestQueryRowNoResults(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
conn := mustConnect(t, *defaultConnConfig)
|
||||||
|
defer closeConn(t, conn)
|
||||||
|
|
||||||
|
sql := "select 1 where 1=0"
|
||||||
|
psName := "selectNothing"
|
||||||
|
mustPrepare(t, conn, psName, sql)
|
||||||
|
|
||||||
|
for _, sql := range []string{sql, psName} {
|
||||||
|
var n int32
|
||||||
|
err := conn.QueryRow(sql).Scan(&n)
|
||||||
|
if err != pgx.ErrNoRows {
|
||||||
|
t.Errorf("Expected pgx.ErrNoRows, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureConnValid(t, conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestQueryPreparedEncodeError(t *testing.T) {
|
func TestQueryPreparedEncodeError(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|
|
@ -45,11 +45,13 @@ func afterConnect(conn *pgx.Conn) (err error) {
|
||||||
|
|
||||||
func getUrlHandler(w http.ResponseWriter, req *http.Request) {
|
func getUrlHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
var url string
|
var url string
|
||||||
if err := pool.QueryRow("getUrl", req.URL.Path).Scan(&url); err == nil {
|
err := pool.QueryRow("getUrl", req.URL.Path).Scan(&url)
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
http.Redirect(w, req, url, http.StatusSeeOther)
|
http.Redirect(w, req, url, http.StatusSeeOther)
|
||||||
} else if _, ok := err.(pgx.NotSingleRowError); ok {
|
case pgx.ErrNoRows:
|
||||||
http.NotFound(w, req)
|
http.NotFound(w, req)
|
||||||
} else {
|
default:
|
||||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue