gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

errors.go (5721B)


      1 package pgconn
      2 
      3 import (
      4 	"context"
      5 	"errors"
      6 	"fmt"
      7 	"net"
      8 	"net/url"
      9 	"regexp"
     10 	"strings"
     11 )
     12 
     13 // SafeToRetry checks if the err is guaranteed to have occurred before sending any data to the server.
     14 func SafeToRetry(err error) bool {
     15 	if e, ok := err.(interface{ SafeToRetry() bool }); ok {
     16 		return e.SafeToRetry()
     17 	}
     18 	return false
     19 }
     20 
     21 // Timeout checks if err was was caused by a timeout. To be specific, it is true if err was caused within pgconn by a
     22 // context.Canceled, context.DeadlineExceeded or an implementer of net.Error where Timeout() is true.
     23 func Timeout(err error) bool {
     24 	var timeoutErr *errTimeout
     25 	return errors.As(err, &timeoutErr)
     26 }
     27 
     28 // PgError represents an error reported by the PostgreSQL server. See
     29 // http://www.postgresql.org/docs/11/static/protocol-error-fields.html for
     30 // detailed field description.
     31 type PgError struct {
     32 	Severity         string
     33 	Code             string
     34 	Message          string
     35 	Detail           string
     36 	Hint             string
     37 	Position         int32
     38 	InternalPosition int32
     39 	InternalQuery    string
     40 	Where            string
     41 	SchemaName       string
     42 	TableName        string
     43 	ColumnName       string
     44 	DataTypeName     string
     45 	ConstraintName   string
     46 	File             string
     47 	Line             int32
     48 	Routine          string
     49 }
     50 
     51 func (pe *PgError) Error() string {
     52 	return pe.Severity + ": " + pe.Message + " (SQLSTATE " + pe.Code + ")"
     53 }
     54 
     55 // SQLState returns the SQLState of the error.
     56 func (pe *PgError) SQLState() string {
     57 	return pe.Code
     58 }
     59 
     60 type connectError struct {
     61 	config *Config
     62 	msg    string
     63 	err    error
     64 }
     65 
     66 func (e *connectError) Error() string {
     67 	sb := &strings.Builder{}
     68 	fmt.Fprintf(sb, "failed to connect to `host=%s user=%s database=%s`: %s", e.config.Host, e.config.User, e.config.Database, e.msg)
     69 	if e.err != nil {
     70 		fmt.Fprintf(sb, " (%s)", e.err.Error())
     71 	}
     72 	return sb.String()
     73 }
     74 
     75 func (e *connectError) Unwrap() error {
     76 	return e.err
     77 }
     78 
     79 type connLockError struct {
     80 	status string
     81 }
     82 
     83 func (e *connLockError) SafeToRetry() bool {
     84 	return true // a lock failure by definition happens before the connection is used.
     85 }
     86 
     87 func (e *connLockError) Error() string {
     88 	return e.status
     89 }
     90 
     91 type parseConfigError struct {
     92 	connString string
     93 	msg        string
     94 	err        error
     95 }
     96 
     97 func (e *parseConfigError) Error() string {
     98 	connString := redactPW(e.connString)
     99 	if e.err == nil {
    100 		return fmt.Sprintf("cannot parse `%s`: %s", connString, e.msg)
    101 	}
    102 	return fmt.Sprintf("cannot parse `%s`: %s (%s)", connString, e.msg, e.err.Error())
    103 }
    104 
    105 func (e *parseConfigError) Unwrap() error {
    106 	return e.err
    107 }
    108 
    109 // preferContextOverNetTimeoutError returns ctx.Err() if ctx.Err() is present and err is a net.Error with Timeout() ==
    110 // true. Otherwise returns err.
    111 func preferContextOverNetTimeoutError(ctx context.Context, err error) error {
    112 	if err, ok := err.(net.Error); ok && err.Timeout() && ctx.Err() != nil {
    113 		return &errTimeout{err: ctx.Err()}
    114 	}
    115 	return err
    116 }
    117 
    118 type pgconnError struct {
    119 	msg         string
    120 	err         error
    121 	safeToRetry bool
    122 }
    123 
    124 func (e *pgconnError) Error() string {
    125 	if e.msg == "" {
    126 		return e.err.Error()
    127 	}
    128 	if e.err == nil {
    129 		return e.msg
    130 	}
    131 	return fmt.Sprintf("%s: %s", e.msg, e.err.Error())
    132 }
    133 
    134 func (e *pgconnError) SafeToRetry() bool {
    135 	return e.safeToRetry
    136 }
    137 
    138 func (e *pgconnError) Unwrap() error {
    139 	return e.err
    140 }
    141 
    142 // errTimeout occurs when an error was caused by a timeout. Specifically, it wraps an error which is
    143 // context.Canceled, context.DeadlineExceeded, or an implementer of net.Error where Timeout() is true.
    144 type errTimeout struct {
    145 	err error
    146 }
    147 
    148 func (e *errTimeout) Error() string {
    149 	return fmt.Sprintf("timeout: %s", e.err.Error())
    150 }
    151 
    152 func (e *errTimeout) SafeToRetry() bool {
    153 	return SafeToRetry(e.err)
    154 }
    155 
    156 func (e *errTimeout) Unwrap() error {
    157 	return e.err
    158 }
    159 
    160 type contextAlreadyDoneError struct {
    161 	err error
    162 }
    163 
    164 func (e *contextAlreadyDoneError) Error() string {
    165 	return fmt.Sprintf("context already done: %s", e.err.Error())
    166 }
    167 
    168 func (e *contextAlreadyDoneError) SafeToRetry() bool {
    169 	return true
    170 }
    171 
    172 func (e *contextAlreadyDoneError) Unwrap() error {
    173 	return e.err
    174 }
    175 
    176 // newContextAlreadyDoneError double-wraps a context error in `contextAlreadyDoneError` and `errTimeout`.
    177 func newContextAlreadyDoneError(ctx context.Context) (err error) {
    178 	return &errTimeout{&contextAlreadyDoneError{err: ctx.Err()}}
    179 }
    180 
    181 type writeError struct {
    182 	err         error
    183 	safeToRetry bool
    184 }
    185 
    186 func (e *writeError) Error() string {
    187 	return fmt.Sprintf("write failed: %s", e.err.Error())
    188 }
    189 
    190 func (e *writeError) SafeToRetry() bool {
    191 	return e.safeToRetry
    192 }
    193 
    194 func (e *writeError) Unwrap() error {
    195 	return e.err
    196 }
    197 
    198 func redactPW(connString string) string {
    199 	if strings.HasPrefix(connString, "postgres://") || strings.HasPrefix(connString, "postgresql://") {
    200 		if u, err := url.Parse(connString); err == nil {
    201 			return redactURL(u)
    202 		}
    203 	}
    204 	quotedDSN := regexp.MustCompile(`password='[^']*'`)
    205 	connString = quotedDSN.ReplaceAllLiteralString(connString, "password=xxxxx")
    206 	plainDSN := regexp.MustCompile(`password=[^ ]*`)
    207 	connString = plainDSN.ReplaceAllLiteralString(connString, "password=xxxxx")
    208 	brokenURL := regexp.MustCompile(`:[^:@]+?@`)
    209 	connString = brokenURL.ReplaceAllLiteralString(connString, ":xxxxxx@")
    210 	return connString
    211 }
    212 
    213 func redactURL(u *url.URL) string {
    214 	if u == nil {
    215 		return ""
    216 	}
    217 	if _, pwSet := u.User.Password(); pwSet {
    218 		u.User = url.UserPassword(u.User.Username(), "xxxxx")
    219 	}
    220 	return u.String()
    221 }
    222 
    223 type NotPreferredError struct {
    224 	err         error
    225 	safeToRetry bool
    226 }
    227 
    228 func (e *NotPreferredError) Error() string {
    229 	return fmt.Sprintf("standby server not found: %s", e.err.Error())
    230 }
    231 
    232 func (e *NotPreferredError) SafeToRetry() bool {
    233 	return e.safeToRetry
    234 }
    235 
    236 func (e *NotPreferredError) Unwrap() error {
    237 	return e.err
    238 }