Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ linters:
- govet
- ineffassign
- unconvert
- gocritic

# See: https://golangci-lint.run/usage/formatters/
formatters:
Expand Down
9 changes: 5 additions & 4 deletions conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,8 @@ optionLoop:

var err error
sd, explicitPreparedStatement := c.preparedStatements[sql]
if sd != nil || mode == QueryExecModeCacheStatement || mode == QueryExecModeCacheDescribe || mode == QueryExecModeDescribeExec {
switch {
case sd != nil || mode == QueryExecModeCacheStatement || mode == QueryExecModeCacheDescribe || mode == QueryExecModeDescribeExec:
if sd == nil {
sd, err = c.getStatementDescription(ctx, mode, sql)
if err != nil {
Expand Down Expand Up @@ -846,15 +847,15 @@ optionLoop:
} else {
rows.resultReader = c.pgConn.ExecStatement(ctx, sd, c.eqb.ParamValues, c.eqb.ParamFormats, resultFormats)
}
} else if mode == QueryExecModeExec {
case mode == QueryExecModeExec:
err := c.eqb.Build(c.typeMap, nil, args)
if err != nil {
rows.fatal(err)
return rows, rows.err
}

rows.resultReader = c.pgConn.ExecParams(ctx, sql, c.eqb.ParamValues, nil, c.eqb.ParamFormats, c.eqb.ResultFormats)
} else if mode == QueryExecModeSimpleProtocol {
case mode == QueryExecModeSimpleProtocol:
sql, err = c.sanitizeForSimpleQuery(sql, args...)
if err != nil {
rows.fatal(err)
Expand All @@ -872,7 +873,7 @@ optionLoop:
}

return rows, nil
} else {
default:
err = fmt.Errorf("unknown QueryExecMode: %v", mode)
rows.fatal(err)
return rows, rows.err
Expand Down
18 changes: 10 additions & 8 deletions examples/chat/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ func main() {
os.Exit(1)
}

go listen()
go func() {
if err := listen(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}()

fmt.Println(`Type a message and press enter.

Expand Down Expand Up @@ -47,25 +52,22 @@ Type "exit" to quit.`)
}
}

func listen() {
func listen() error {
conn, err := pool.Acquire(context.Background())
if err != nil {
fmt.Fprintln(os.Stderr, "Error acquiring connection:", err)
os.Exit(1)
return fmt.Errorf("acquiring connection: %w", err)
}
defer conn.Release()

_, err = conn.Exec(context.Background(), "listen chat")
if err != nil {
fmt.Fprintln(os.Stderr, "Error listening to chat channel:", err)
os.Exit(1)
return fmt.Errorf("listening to chat channel: %w", err)
}

for {
notification, err := conn.Conn().WaitForNotification(context.Background())
if err != nil {
fmt.Fprintln(os.Stderr, "Error waiting for notification:", err)
os.Exit(1)
return fmt.Errorf("waiting for notification: %w", err)
}

fmt.Println("PID:", notification.PID, "Channel:", notification.Channel, "Payload:", notification.Payload)
Expand Down
7 changes: 4 additions & 3 deletions pgconn/auth_scram.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,11 +229,12 @@ func (sc *scramClient) clientFirstMessage() []byte {

sc.clientFirstMessageBare = fmt.Appendf(nil, "n=,r=%s", sc.clientNonce)

if sc.authMechanism == scramSHA256PlusName {
switch {
case sc.authMechanism == scramSHA256PlusName:
sc.clientGS2Header = []byte("p=tls-server-end-point,,")
} else if sc.hasTLS {
case sc.hasTLS:
sc.clientGS2Header = []byte("y,,")
} else {
default:
sc.clientGS2Header = []byte("n,,")
}

Expand Down
16 changes: 7 additions & 9 deletions pgconn/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"encoding/pem"
"errors"
"fmt"
"io"
"maps"
"math"
"net"
Expand Down Expand Up @@ -308,9 +307,7 @@ func ParseConfigWithOptions(connString string, options ParseConfigOptions) (*Con
User: settings["user"],
Password: settings["password"],
RuntimeParams: make(map[string]string),
BuildFrontend: func(r io.Reader, w io.Writer) *pgproto3.Frontend {
return pgproto3.NewFrontend(r, w)
},
BuildFrontend: pgproto3.NewFrontend,
BuildContextWatcherHandler: func(pgConn *PgConn) ctxwatch.Handler {
return &DeadlineContextWatcherHandler{Conn: pgConn.conn}
},
Expand Down Expand Up @@ -643,8 +640,9 @@ func parseKeywordValueSettings(s string) (map[string]string, error) {

key = strings.Trim(s[:eqIdx], " \t\n\r\v\f")
s = strings.TrimLeft(s[eqIdx+1:], " \t\n\r\v\f")
if len(s) == 0 {
} else if s[0] != '\'' {
switch {
case len(s) == 0:
case s[0] != '\'':
end := 0
for ; end < len(s); end++ {
if asciiSpace[s[end]] == 1 {
Expand All @@ -657,11 +655,11 @@ func parseKeywordValueSettings(s string) (map[string]string, error) {
}
}
}
val = strings.Replace(strings.Replace(s[:end], "\\\\", "\\", -1), "\\'", "'", -1)
val = strings.ReplaceAll(strings.ReplaceAll(s[:end], "\\\\", "\\"), "\\'", "'")
// Consume the value and trim any subsequent whitespace so that
// multiple trailing spaces don't cause a spurious parse failure.
s = strings.TrimLeft(s[end:], " \t\n\r\v\f")
} else { // quoted string
default: // quoted string
s = s[1:]
end := 0
for ; end < len(s); end++ {
Expand All @@ -675,7 +673,7 @@ func parseKeywordValueSettings(s string) (map[string]string, error) {
if end == len(s) {
return nil, errors.New("unterminated quoted string in connection info string")
}
val = strings.Replace(strings.Replace(s[:end], "\\\\", "\\", -1), "\\'", "'", -1)
val = strings.ReplaceAll(strings.ReplaceAll(s[:end], "\\\\", "\\"), "\\'", "'")
// Consume the closing quote and any subsequent whitespace.
s = strings.TrimLeft(s[end+1:], " \t\n\r\v\f")
}
Expand Down
7 changes: 4 additions & 3 deletions pgconn/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,13 @@ func (e *ParseConfigError) Unwrap() error {
func normalizeTimeoutError(ctx context.Context, err error) error {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
if ctx.Err() == context.Canceled {
switch ctx.Err() {
case context.Canceled:
// Since the timeout was caused by a context cancellation, the actual error is context.Canceled not the timeout error.
return context.Canceled
} else if ctx.Err() == context.DeadlineExceeded {
case context.DeadlineExceeded:
return &errTimeout{err: ctx.Err()}
} else {
default:
return &errTimeout{err: err}
}
}
Expand Down
8 changes: 3 additions & 5 deletions pgconn/pgconn.go
Original file line number Diff line number Diff line change
Expand Up @@ -1125,8 +1125,7 @@ func (pgConn *PgConn) WaitForNotification(ctx context.Context) error {
return normalizeTimeoutError(ctx, err)
}

switch msg.(type) {
case *pgproto3.NotificationResponse:
if _, ok := msg.(*pgproto3.NotificationResponse); ok {
return nil
}
}
Expand Down Expand Up @@ -1711,8 +1710,7 @@ func (rr *ResultReader) NextRow() bool {
return false
}

switch msg := msg.(type) {
case *pgproto3.DataRow:
if msg, ok := msg.(*pgproto3.DataRow); ok {
rr.rowValues = msg.Values
return true
}
Expand Down Expand Up @@ -2009,7 +2007,7 @@ func (pgConn *PgConn) EscapeString(s string) (string, error) {
return "", errors.New("EscapeString must be run with client_encoding=UTF8")
}

return strings.Replace(s, "'", "''", -1), nil
return strings.ReplaceAll(s, "'", "''"), nil
}

// CheckConn checks the underlying connection without writing any bytes. This is currently implemented by doing a read
Expand Down
7 changes: 4 additions & 3 deletions pgconn/pgconn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"errors"
"fmt"
"io"
"log"
"math"
"net"
"os"
Expand Down Expand Up @@ -4141,13 +4140,15 @@ func Example() {

pgConn, err := pgconn.Connect(ctx, os.Getenv("PGX_TEST_DATABASE"))
if err != nil {
log.Fatalln(err)
fmt.Fprintln(os.Stderr, err)
return
}
defer pgConn.Close(ctx)

result := pgConn.ExecParams(ctx, "select generate_series(1,3)", nil, nil, nil, nil).Read()
if result.Err != nil {
log.Fatalln(result.Err)
fmt.Fprintln(os.Stderr, result.Err)
return
}

for _, row := range result.Rows {
Expand Down
7 changes: 4 additions & 3 deletions pgproto3/function_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,12 @@ func (dst *FunctionCall) Decode(src []byte) error {
// As a special case, -1 indicates a NULL argument value. No value bytes follow in the NULL case.
argumentLength := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
if argumentLength == -1 {
switch {
case argumentLength == -1:
arguments[i] = nil
} else if argumentLength < 0 {
case argumentLength < 0:
return &invalidMessageFormatErr{messageType: "FunctionCall"}
} else {
default:
if len(src[rp:]) < argumentLength {
return &invalidMessageFormatErr{messageType: "FunctionCall"}
}
Expand Down
7 changes: 4 additions & 3 deletions pgtype/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,11 @@ func parseUntypedTextArray(src string) (*untypedTextArray, error) {
return nil, fmt.Errorf("unexpected trailing data: %v", buf.String())
}

if len(dst.Elements) == 0 {
} else if len(explicitDimensions) > 0 {
switch {
case len(dst.Elements) == 0:
case len(explicitDimensions) > 0:
dst.Dimensions = explicitDimensions
} else {
default:
dst.Dimensions = implicitDimensions
}

Expand Down
6 changes: 2 additions & 4 deletions pgtype/array_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,10 +391,8 @@ func isRagged(slice reflect.Value) bool {
for i := range sliceLen {
if i == 0 {
innerLen = slice.Index(i).Len()
} else {
if slice.Index(i).Len() != innerLen {
return true
}
} else if slice.Index(i).Len() != innerLen {
return true
}
if isRagged(slice.Index(i)) {
return true
Expand Down
11 changes: 4 additions & 7 deletions pgtype/bits.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ func (dst *Bits) Scan(src any) error {
return nil
}

switch src := src.(type) {
case string:
if src, ok := src.(string); ok {
return scanPlanTextAnyToBitsScanner{}.Scan([]byte(src), dst)
}

Expand Down Expand Up @@ -131,13 +130,11 @@ func (encodePlanBitsCodecText) Encode(value any, buf []byte) (newBuf []byte, err
func (BitsCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
switch format {
case BinaryFormatCode:
switch target.(type) {
case BitsScanner:
if _, ok := target.(BitsScanner); ok {
return scanPlanBinaryBitsToBitsScanner{}
}
case TextFormatCode:
switch target.(type) {
case BitsScanner:
if _, ok := target.(BitsScanner); ok {
return scanPlanTextAnyToBitsScanner{}
}
}
Expand Down Expand Up @@ -203,7 +200,7 @@ func (scanPlanTextAnyToBitsScanner) Scan(src []byte, dst any) error {
if b == '1' {
byteIdx := i / 8
bitIdx := uint(i % 8)
buf[byteIdx] = buf[byteIdx] | (128 >> bitIdx)
buf[byteIdx] |= 128 >> bitIdx
}
}

Expand Down
4 changes: 2 additions & 2 deletions pgtype/bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,9 +336,9 @@ func planTextToBool(src []byte) (bool, error) {
s := string(bytes.ToLower(bytes.TrimSpace(src)))

switch {
case strings.HasPrefix("true", s), strings.HasPrefix("yes", s), s == "on", s == "1":
case strings.HasPrefix("true", s), strings.HasPrefix("yes", s), s == "on", s == "1": //nolint:gocritic // s is intentionally the prefix argument so partial inputs (t, tr, tru) also match.
return true, nil
case strings.HasPrefix("false", s), strings.HasPrefix("no", s), strings.HasPrefix("off", s), s == "0":
case strings.HasPrefix("false", s), strings.HasPrefix("no", s), strings.HasPrefix("off", s), s == "0": //nolint:gocritic // s is intentionally the prefix argument so partial inputs (f, fa, fal) also match.
return false, nil
default:
return false, fmt.Errorf("unknown boolean string representation %q", src)
Expand Down
9 changes: 3 additions & 6 deletions pgtype/box.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ func (dst *Box) Scan(src any) error {
return nil
}

switch src := src.(type) {
case string:
if src, ok := src.(string); ok {
return scanPlanTextAnyToBoxScanner{}.Scan([]byte(src), dst)
}

Expand Down Expand Up @@ -131,13 +130,11 @@ func (encodePlanBoxCodecText) Encode(value any, buf []byte) (newBuf []byte, err
func (BoxCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
switch format {
case BinaryFormatCode:
switch target.(type) {
case BoxScanner:
if _, ok := target.(BoxScanner); ok {
return scanPlanBinaryBoxToBoxScanner{}
}
case TextFormatCode:
switch target.(type) {
case BoxScanner:
if _, ok := target.(BoxScanner); ok {
return scanPlanTextAnyToBoxScanner{}
}
}
Expand Down
2 changes: 1 addition & 1 deletion pgtype/builtin_wrappers.go
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ func (a *anyMultiDimSliceArray) Index(i int) any {
for j := len(a.dims) - 1; j >= 0; j-- {
dimLen := int(a.dims[j].Length)
indexes[j] = i % dimLen
i = i / dimLen
i /= dimLen
}

v := a.slice
Expand Down
9 changes: 3 additions & 6 deletions pgtype/circle.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ func (dst *Circle) Scan(src any) error {
return nil
}

switch src := src.(type) {
case string:
if src, ok := src.(string); ok {
return scanPlanTextAnyToCircleScanner{}.Scan([]byte(src), dst)
}

Expand Down Expand Up @@ -130,13 +129,11 @@ func (encodePlanCircleCodecText) Encode(value any, buf []byte) (newBuf []byte, e
func (CircleCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
switch format {
case BinaryFormatCode:
switch target.(type) {
case CircleScanner:
if _, ok := target.(CircleScanner); ok {
return scanPlanBinaryCircleToCircleScanner{}
}
case TextFormatCode:
switch target.(type) {
case CircleScanner:
if _, ok := target.(CircleScanner); ok {
return scanPlanTextAnyToCircleScanner{}
}
}
Expand Down
Loading
Loading