14

I'm trying to delete a database using the postgres driver (lib/pq) by doing a:

db.Exec("DROP DATABASE dbName;")

But I'd like to do a different conditional based on whether the error received is something strange, or is a "database does not exist" error.

Is there a constant variable or something I can use to check if the error returned is a "database does not exist" error message, or would I have to manually parse the error string myself?

I tried to look in the documentation, but could not find anything for "database does not exist". I did however find this list.

Perhaps it fits under some other error code? Also I'm not quite sure the semantically correct way of fetching and comparing the error codes through the Postgres driver. I presume I should do something like this:

if err.ErrorCode != "xxx"
Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
b0xxed1n
  • 2,063
  • 5
  • 20
  • 30

3 Answers3

34

The lib/pq package may return errors of type *pq.Error, which is a struct. If it does, you may use all its fields to inspect for details of the error.

This is how it can be done:

if err, ok := err.(*pq.Error); ok {
    // Here err is of type *pq.Error, you may inspect all its fields, e.g.:
    fmt.Println("pq error:", err.Code.Name())
}

pq.Error has the following fields:

type Error struct {
    Severity         string
    Code             ErrorCode
    Message          string
    Detail           string
    Hint             string
    Position         string
    InternalPosition string
    InternalQuery    string
    Where            string
    Schema           string
    Table            string
    Column           string
    DataTypeName     string
    Constraint       string
    File             string
    Line             string
    Routine          string
}

The meaning and possible values of these fields are Postres specific and the full list can be found here: Error and Notice Message Fields

icza
  • 389,944
  • 63
  • 907
  • 827
  • 1
    Thank you, this was helpful, however I'm just going to use what Nicarus mentioned above (DROP DATABASE IF EXISTS dbName;). If anyone is curious what the error message returned is though, it was this: pq.Error{Severity:"ERROR", Code:"3D000", Message:"database \"dbname\" does not exist", Detail:"", Hint:"", Position:"", InternalPosition:"", InternalQuery:"", Where:"", Schema:"", Table:"", Column:"", DataTypeName:"", Constraint:"", File:"dbcommands.c", Line:"799", Routine:"dropdb"} Unable to execute setup: pq: database "dbname" does not exist – b0xxed1n Jun 01 '16 at 06:26
  • Here is a list of all the error codes/names https://www.postgresql.org/docs/9.3/errcodes-appendix.html – M-Wajeeh Jun 08 '21 at 17:42
  • using errors.As https://play.golang.org/p/_SDyuC3ERAX –  Sep 05 '21 at 14:03
1

You could use this: https://github.com/omeid/pgerror

It has lots of mappings for various postgres errors.

With the package, you can do the following (taken from the README):

// example use:
_, err = stmt.Exec(SomeInsertStateMent, params...)
if err != nil {
  if e := pgerror.UniqueViolation(err); e != nil {
  // you can use e here to check the fields et al
    return SomeThingAlreadyExists
  }

  return err // other cases.
}
kelvin
  • 1,421
  • 13
  • 28
ekundayo
  • 21
  • 1
  • 4
0

This package has all the PG error constants: https://github.com/jackc/pgerrcode

Just import and you're good to go:

import "github.com/jackc/pgerrcode"

// ...

if err, ok := err.(*pq.Error); ok {
  if err.Code == pgerrcode.UniqueViolation {
    return fmt.Errorf("unique field violation on column %s", err.Column)
  }
}

The package is also in the family of one of the 2 or 3 most popular Go PostgreSQL drivers, called "pgx", so it should be reliable enough.

GoForth
  • 573
  • 7
  • 10