This repository has been archived by the owner on Aug 31, 2018. It is now read-only.
/
error.go
110 lines (93 loc) · 2.74 KB
/
error.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package db
import (
"context"
"database/sql"
"database/sql/driver"
"github.com/BenLubar/hook"
"github.com/BenLubar/webscale/internal"
"github.com/pkg/errors"
)
// FilterAppendErrorDetails registers a function to be called when an error is
// being described. Filter functions should either return the byte slice
// unchanged or append text starting with a newline '\n'.
var FilterAppendErrorDetails = hook.NewFilter(&applyFilterAppendErrorDetails).(func(func([]byte, context.Context) ([]byte, error), int))
var applyFilterAppendErrorDetails func([]byte, context.Context) ([]byte, error)
// Error is the type of most errors returned by package db.
type Error struct {
cause error
stmt *Stmt
tx *Tx
stacks []internal.StackTrace
}
func wrapError(err error, stmt *Stmt, tx *Tx, stacks ...internal.StackTrace) error {
if err == nil || err == sql.ErrTxDone || err == sql.ErrNoRows || err == driver.ErrBadConn {
return err
}
return &Error{
cause: err,
stmt: stmt,
tx: tx,
stacks: append(stacks, internal.Callers(3)),
}
}
// Cause implements the cause interface from github.com/pkg/errors.
func (err *Error) Cause() error {
return err.cause
}
// Error implements the error interface.
func (err *Error) Error() string {
buf := []byte(err.cause.Error())
for _, stack := range err.stacks {
buf = append(buf, "\n\nStack trace:"...)
buf = stack.AppendTo(buf)
}
if err.tx != nil {
buf = err.tx.appendErrorDetails(buf)
}
if err.stmt != nil {
buf = err.stmt.appendErrorDetails(buf)
}
if err.tx != nil {
ctxBuf, ctxErr := applyFilterAppendErrorDetails(nil, err.tx.ctx)
if ctxErr != nil {
buf = append(buf, "\n\n!!! ERROR WHILE GETTING ERROR DETAILS !!!\n"...)
buf = append(buf, ctxErr.Error()...)
} else {
buf = append(buf, ctxBuf...)
}
}
buf = appendDriverErrorDetails(buf, err.cause, err.stmt, err.tx)
return string(buf)
}
// Timeout returns true if the cause of this error was a timeout.
func (err *Error) Timeout() bool {
if te, ok := err.cause.(interface {
Timeout() bool
}); ok {
return te.Timeout()
}
return false
}
// Temporary returns true if the cause of this error was temporary.
func (err *Error) Temporary() bool {
if te, ok := err.cause.(interface {
Temporary() bool
}); ok {
return te.Temporary()
}
return false
}
// StackTrace implements the stackTrace interface from github.com/pkg/errors.
func (err *Error) StackTrace() errors.StackTrace {
return err.stacks[len(err.stacks)-1].StackTrace()
}
// IsConstraint returns true if the given error is a violation of a constraint
// with the given name.
func IsConstraint(err error, name string) bool {
if e, ok := err.(*Error); ok {
if constraint, ok := constraintFromDriverError(e.cause); ok {
return constraint == name
}
}
return false
}