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
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@ unreleased
- Support `sslrootcert=system` and use `~/.postgresql/root.crt` as the default
value of sslrootcert ([#1280], [#1281]).

- Add a new `pqerror` package with PostgreSQL error codes ([#1275]).

For example, to test if an error is a UNIQUE constraint violation:

if pqErr, ok := errors.AsType[*pq.Error](err); ok && pqErr.Code == pqerror.UniqueViolation {
log.Fatalf("email %q already exsts", email)
}

To make this a bit more convenient, it also adds a `pq.As()` function:

pqErr := pq.As(err, pqerror.UniqueViolation)
if pqErr != nil {
log.Fatalf("email %q already exsts", email)
}

### Fixes

- Fix SSL key permission check to allow modes stricter than 0600/0640#1265 ([#1265]).
Expand All @@ -48,6 +63,7 @@ unreleased
[#1270]: https://github.com/lib/pq/pull/1270
[#1271]: https://github.com/lib/pq/pull/1271
[#1272]: https://github.com/lib/pq/pull/1272
[#1275]: https://github.com/lib/pq/pull/1275
[#1277]: https://github.com/lib/pq/pull/1277
[#1278]: https://github.com/lib/pq/pull/1278
[#1279]: https://github.com/lib/pq/pull/1279
Expand Down Expand Up @@ -167,6 +183,8 @@ newer. Previously PostgreSQL 8.4 and newer were supported.

- Handle ErrorResponse in readReadyForQuery and return proper error ([#1136]).

- Detect COPY even if the query starts with whitespace or comments ([#1198]).

- CopyIn() and CopyInSchema() now work if the list of columns is empty, in which
case it will copy all columns ([#1239]).

Expand All @@ -192,6 +210,7 @@ newer. Previously PostgreSQL 8.4 and newer were supported.
[#1180]: https://github.com/lib/pq/pull/1180
[#1184]: https://github.com/lib/pq/pull/1184
[#1188]: https://github.com/lib/pq/pull/1188
[#1198]: https://github.com/lib/pq/pull/1198
[#1211]: https://github.com/lib/pq/pull/1211
[#1212]: https://github.com/lib/pq/pull/1212
[#1214]: https://github.com/lib/pq/pull/1214
Expand Down
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,17 @@ The libpq way (which also works in pq) is to use `options='-c k=v'` like so:

Errors
------
Errors from PostgreSQL are returned as [pq.Error]; the Error() string contains
the error message and code:
Errors from PostgreSQL are returned as [pq.Error]; [pq.As] can be used to
convert an error to `pq.Error`:

```go
pqErr := pq.As(err, pqerror.UniqueViolation)
if pqErr != nil {
return fmt.Errorf("email %q already exsts", email)
}
```

the Error() string contains the error message and code:

pq: duplicate key value violates unique constraint "users_lower_idx" (23505)

Expand All @@ -118,6 +127,7 @@ It contains the context where this error occurred:
^

[pq.Error]: https://pkg.go.dev/github.com/lib/pq#Error
[pq.As]: https://pkg.go.dev/github.com/lib/pq#As

PostgreSQL features
-------------------
Expand Down
26 changes: 26 additions & 0 deletions as.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//go:build !go1.26

package pq

import (
"errors"
"slices"
)

// As asserts that the given error is [pq.Error] and returns it, returning nil
// if it's not a pq.Error.
//
// It will return nil if the pq.Error is not one of the given error codes. If no
// codes are given it will always return the Error.
//
// This is safe to call with a nil error.
func As(err error, codes ...ErrorCode) *Error {
if err == nil { // Not strictly needed, but prevents alloc for nil errors.
return nil
}
pqErr := new(Error)
if errors.As(err, &pqErr) && (len(codes) == 0 || slices.Contains(codes, pqErr.Code)) {
return pqErr
}
return nil
}
23 changes: 23 additions & 0 deletions as_go126.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//go:build go1.26

package pq

import (
"errors"
"github.com/lib/pq/pqerror"
"slices"
)

// As asserts that the given error is [pq.Error] and returns it, returning nil
// if it's not a pq.Error.
//
// It will return nil if the pq.Error is not one of the given error codes. If no
// codes are given it will always return the Error.
//
// This is safe to call with a nil error.
func As(err error, codes ...pqerror.Code) *Error {
if pqErr, ok := errors.AsType[*Error](err); ok && (len(codes) == 0 || slices.Contains(codes, pqErr.Code)) {
return pqErr
}
return nil
}
Loading