Hello, I have been very slow to react on this one but finally went ahead and added a base36decoding of the SQLSTATE of Postgres, so as to report an integer for the error code (which used to be always 0).
It is bijective, so you can base36 encode the error code in your application to recognize the Postgres error codes from the table: http://www.postgresql.org/docs/8.4/interactive/errcodes-appendix.html Or in the attached postgres error codes spreadsheet, I've provided the conversion to integer for all errors. You will find attached the patch for version 0.8.2-1 and 0.8.3-1 I don't know how we should handle this, should I get CVS access and push the change, or do you want to apply the patch? Please have a look and see if you like it. Regards, Emmanuel Courreges. On lun., 2008-11-17 at 10:53 +0100, Markus Hoenicka wrote: > Hi, > > Quoting Emmanuel Courrèges <ecourre...@echo.fr>: > > > Hello, > > Currently with the PostgreSQL driver, there seems to be no way to get > > the "error code string" in the form: > > http://www.postgresql.org/docs/8.1/static/errcodes-appendix.html > > > > dbi_conn_error() always returns 0, and the error message returned is > > just the Postgresql error message which is localized (french for me). > > I would greatly appreciate if we could change this to "error code - > > error message" for example, so at least the error would be parsable even > > if the message is localized in any language, also you wouldn't have to > > parse full text. > > > > I checked how other drivers handle this. The sqlite and sqlite3 > drivers set the error code and provide a non-localized text. The mysql > driver also sets an error code and returns a text, which may be > localized by means of a client library compile-time option (i.e. > usually it is not localized, but you can't bet on it). The pgsql > driver indeed does not set the error code as PostgreSQL uses a > non-numeric five-letter code. I don't know how the remaining drivers > are implemented. > > I agree that parsing error messages in languages not known at compile > time is error prone, to say the least. Would it be acceptable to > convert the PostgreSQL error code to a numeric code? If my math is > right, a five digit base 25 number can be converted to a long int with > no round-trip losses. The driver could also provide a custom function > to convert this number back to the PostgreSQL alphanumeric error code. > This solution would be more in line with the error code - error > message semantics of dbi_conn_error(). I'd like to hear other opinions > before changing the driver though. > > > How does the acceptance process for the change work? > > Should I do the change? > > Basically I don't want to run on a lib-dbi-drivers that would be patched > > by me, I'd rather have it in the official branch. > > > > If we find a consensus about the suggested change on this list, I'd > greatly appreciate if you could provide a patch against the current > cvs revision and send it to this list. We'll have a look at it and > apply it if it does the trick. > > regards, > Markus > >
--- libdbi-drivers-0.8.2-1/drivers/pgsql/dbd_pgsql.c 2006-09-21 21:44:13.000000000 +0200 +++ newlibdbi-drivers-0.8.2-1/drivers/pgsql/dbd_pgsql.c 2010-07-09 17:00:25.085266121 +0200 @@ -103,8 +103,26 @@ /* this function is available through the PostgreSQL client library, but it is not declared in any of their headers. I hope this won't break anything */ -char *pg_encoding_to_char(int encoding_id); +const char *pg_encoding_to_char(int encoding_id); +/* base36 decoding to convert the 5 alphanumeric chars of SQLSTATE to a 32bit int */ +int base36decode(char *base36) { + int len = strlen(base36); + int output = 0; + int pos = 0; + + for (; pos < len; pos++) { + char c = base36[pos]; + if ( ((c - '0') >= 0) && ((c - '0') <= 9) ) { + c = c - '0'; + } else { + c = c - 'A' + 10; + } + output = 36 * output + c; + } + + return output; +} /* real code starts here */ void dbd_register_driver(const dbi_info_t **_driver_info, const char ***_custom_functions, const char ***_reserved_words) { @@ -247,7 +265,7 @@ } const char *dbd_get_encoding(dbi_conn_t *conn){ - char* my_enc; + const char* my_enc; int n_encoding; const char* encodingopt; char* sql_cmd; @@ -453,10 +471,14 @@ res = PQexec((PGconn *)conn->connection, statement); if (res) resstatus = PQresultStatus(res); if (!res || ((resstatus != PGRES_COMMAND_OK) && (resstatus != PGRES_TUPLES_OK))) { + char * base36 = PQresultErrorField(res, PG_DIAG_SQLSTATE); + conn->error_number = (! base36) ? 0 : base36decode(base36); PQclear(res); return NULL; } + conn->error_number = 0; + result = _dbd_result_create(conn, (void *)res, (unsigned long long)PQntuples(res), (unsigned long long)atoll(PQcmdTuples(res))); _dbd_result_set_numfields(result, (unsigned int)PQnfields((PGresult *)result->result_handle)); _get_field_info(result); @@ -490,10 +512,10 @@ /* put error number into errno, error string into errstr * return 0 if error, 1 if errno filled, 2 if errstr filled, 3 if both errno and errstr filled */ - *errno = 0; + *errno = conn->error_number; *errstr = strdup(PQerrorMessage((PGconn *)conn->connection)); - return 2; + return 3; } unsigned long long dbd_get_seq_last(dbi_conn_t *conn, const char *sequence) {
--- libdbi-drivers-0.8.3-1/drivers/pgsql/dbd_pgsql.c 2008-01-26 18:39:50.000000000 +0100 +++ newlibdbi-drivers-0.8.3-1/drivers/pgsql/dbd_pgsql.c 2010-07-09 16:56:33.784015113 +0200 @@ -127,6 +127,26 @@ asprintf( &conninfo, fmt, key, value ); \ } while(0) + +/* base36 decoding to convert the 5 alphanumeric chars of SQLSTATE to a 32bit int */ +int base36decode(char *base36) { + int len = strlen(base36); + int output = 0; + int pos = 0; + + for (; pos < len; pos++) { + char c = base36[pos]; + if ( ((c - '0') >= 0) && ((c - '0') <= 9) ) { + c = c - '0'; + } else { + c = c - 'A' + 10; + } + output = 36 * output + c; + } + + return output; +} + /* real code starts here */ void dbd_register_driver(const dbi_info_t **_driver_info, const char ***_custom_functions, const char ***_reserved_words) { /* this is the first function called after the driver module is loaded into memory */ @@ -487,10 +507,14 @@ res = PQexec((PGconn *)conn->connection, statement); if (res) resstatus = PQresultStatus(res); if (!res || ((resstatus != PGRES_COMMAND_OK) && (resstatus != PGRES_TUPLES_OK))) { + char * base36 = PQresultErrorField(res, PG_DIAG_SQLSTATE); + conn->error_number = (! base36) ? 0 : base36decode(base36); PQclear(res); return NULL; } + conn->error_number = 0; + result = _dbd_result_create(conn, (void *)res, (unsigned long long)PQntuples(res), (unsigned long long)atoll(PQcmdTuples(res))); _dbd_result_set_numfields(result, (unsigned int)PQnfields((PGresult *)result->result_handle)); _get_field_info(result); @@ -524,10 +548,10 @@ /* put error number into errno, error string into errstr * return 0 if error, 1 if errno filled, 2 if errstr filled, 3 if both errno and errstr filled */ - *errno = 0; + *errno = conn->error_number; *errstr = strdup(PQerrorMessage((PGconn *)conn->connection)); - return 2; + return 3; } unsigned long long dbd_get_seq_last(dbi_conn_t *conn, const char *sequence) {
postgrescodes.ods
Description: application/vnd.oasis.opendocument.spreadsheet
------------------------------------------------------------------------------ This SF.net email is sponsored by Sprint What will you do first with EVO, the first 4G phone? Visit sprint.com/first -- http://p.sf.net/sfu/sprint-com-first
_______________________________________________ Libdbi-drivers-devel mailing list Libdbi-drivers-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libdbi-drivers-devel