Skip to content

Commit

Permalink
Translate postgres error codes
Browse files Browse the repository at this point in the history
  • Loading branch information
cdevienne committed Dec 21, 2016
1 parent b560a44 commit eb7d461
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 4 deletions.
62 changes: 60 additions & 2 deletions dialects/postgres/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"strings"

"github.com/lib/pq"
"github.com/slicebit/qb"
)

Expand Down Expand Up @@ -83,8 +84,65 @@ func (d *PostgresDialect) GetCompiler() qb.Compiler {
}

// WrapError wraps a native error in a qb Error
func (d *PostgresDialect) WrapError(err error) qb.Error {
return qb.Error{Orig: err}
func (d *PostgresDialect) WrapError(err error) (qbErr qb.Error) {
qbErr.Orig = err
pgErr, ok := err.(pq.Error)
if !ok {
return
}
switch pgErr.Code.Class() {
case "0A": // Class 0A - Feature Not Supported
qbErr.Code = qb.ErrNotSupported
case "20", // Class 20 - Case Not Found
"21": // Class 21 - Cardinality Violation
qbErr.Code = qb.ErrProgramming
case "22": // Class 22 - Data Exception
qbErr.Code = qb.ErrData
case "23": // Class 23 - Integrity Constraint Violation
qbErr.Code = qb.ErrIntegrity
case "24", // Class 24 - Invalid Cursor State
"25": // Class 25 - Invalid Transaction State
qbErr.Code = qb.ErrInternal
case "26", // Class 26 - Invalid SQL Statement Name
"27", // Class 27 - Triggered Data Change Violation
"28": // Class 28 - Invalid Authorization Specification
qbErr.Code = qb.ErrOperational
case "2B", // Class 2B - Dependent Privilege Descriptors Still Exist
"2D", // Class 2D - Invalid Transaction Termination
"2F": // Class 2F - SQL Routine Exception
qbErr.Code = qb.ErrInternal
case "34": // Class 34 - Invalid Cursor Name
qbErr.Code = qb.ErrOperational
case "38", // Class 38 - External Routine Exception
"39", // Class 39 - External Routine Invocation Exception
"3B": // Class 3B - Savepoint Exception
qbErr.Code = qb.ErrInternal
case "3D", // Class 3D - Invalid Catalog Name
"3F": // Class 3F - Invalid Schema Name
qbErr.Code = qb.ErrProgramming
case "40": // Class 40 - Transaction Rollback
qbErr.Code = qb.ErrOperational
case "42", // Class 42 - Syntax Error or Access Rule Violation
"44": // Class 44 - WITH CHECK OPTION Violation
qbErr.Code = qb.ErrProgramming
case "53", // Class 53 - Insufficient Resources
"54", // Class 54 - Program Limit Exceeded
"55", // Class 55 - Object Not In Prerequisite State
"57", // Class 57 - Operator Intervention
"58": // Class 58 - System Error (errors external to PostgreSQL itself)
qbErr.Code = qb.ErrOperational

case "F0": // Class F0 - Configuration File Error
qbErr.Code = qb.ErrInternal
case "HV": // Class HV - Foreign Data Wrapper Error (SQL/MED)
qbErr.Code = qb.ErrOperational
case "P0", // Class P0 - PL/pgSQL Error
"XX": // Class XX - Internal Error
qbErr.Code = qb.ErrInternal
default:
qbErr.Code = qb.ErrDatabase
}
return
}

// PostgresCompiler is a SQLCompiler specialised for PostgreSQL
Expand Down
30 changes: 29 additions & 1 deletion dialects/postgres/postgres_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package qb
import (
"database/sql"
"errors"
_ "github.com/lib/pq"
"github.com/lib/pq"
"github.com/slicebit/qb"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
Expand Down Expand Up @@ -71,6 +71,34 @@ func (suite *PostgresTestSuite) TestWrapError() {
err := errors.New("xxx")
qbErr := dialect.WrapError(err)
assert.Equal(suite.T(), err, qbErr.Orig)

for _, tt := range []struct {
pgCode string
qbCode qb.ErrorCode
}{
{"0A000", qb.ErrNotSupported},
{"20000", qb.ErrProgramming},
{"21000", qb.ErrProgramming},
{"22000", qb.ErrData},
{"23000", qb.ErrIntegrity},
{"24000", qb.ErrInternal},
{"27000", qb.ErrOperational},
{"2D000", qb.ErrInternal},
{"34000", qb.ErrOperational},
{"39000", qb.ErrInternal},
{"3D000", qb.ErrProgramming},
{"40000", qb.ErrOperational},
{"42000", qb.ErrProgramming},
{"54000", qb.ErrOperational},
{"F0000", qb.ErrInternal},
{"HV000", qb.ErrOperational},
{"P0000", qb.ErrInternal},
{"ZZ000", qb.ErrDatabase},
} {
pgErr := pq.Error{Code: pq.ErrorCode(tt.pgCode)}
qbErr := dialect.WrapError(pgErr)
assert.Equal(suite.T(), tt.qbCode, qbErr.Code)
}
}

func (suite *PostgresTestSuite) TestPostgres() {
Expand Down
3 changes: 2 additions & 1 deletion errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ const (
// already exists, syntax error in the SQL statement, wrong number of
// parameters specified, etc.
ErrProgramming
// ErrNotSupportError is in case a method or database API was used which
// ErrNotSupported is in case a method or database API was used which
// is not supported by the database, e.g. requesting a .rollback() on a
// connection that does not support transaction or has transactions turned
// off.
ErrNotSupported
)

// IsInterfaceError returns true if the error is a Interface error
Expand Down

0 comments on commit eb7d461

Please sign in to comment.