Changeset 824


Ignore:
Timestamp:
Feb 6, 2016, 7:17:34 AM (4 years ago)
Author:
cito
Message:

Decode error message properly when using Python 3

The error message can contain non-ASCII characters and must be properly decoded,
using either the client encoding or the current locale if the error happened during
connection and the client encoding is not yet set.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/pgdb.py

    r823 r824  
    13751375### Module Interface
    13761376
    1377 _connect_ = connect
     1377_connect = connect
    13781378
    13791379def connect(dsn=None,
     
    14201420
    14211421    # open the connection
    1422     cnx = _connect_(dbbase, dbhost, dbport, dbopt, dbuser, dbpasswd)
     1422    cnx = _connect(dbbase, dbhost, dbport, dbopt, dbuser, dbpasswd)
    14231423    return Connection(cnx)
    14241424
  • trunk/pgmodule.c

    r823 r824  
    215215
    216216static PyObject *
    217 get_decoded_string(char *str, Py_ssize_t size, int encoding)
     217get_decoded_string(const char *str, Py_ssize_t size, int encoding)
    218218{
    219219        if (encoding == pg_encoding_utf8)
     
    13671367}
    13681368
    1369 /* sets database error with sqlstate attribute */
    1370 /* This should be used when raising a subclass of DatabaseError */
     1369/* sets database error message and sqlstate attribute */
    13711370static void
    1372 set_dberror(PyObject *type, const char *msg, PGresult *result)
     1371set_error_msg_and_state(PyObject *type,
     1372        const char *msg, int encoding, const char *sqlstate)
    13731373{
    13741374        PyObject   *err_obj, *msg_obj, *sql_obj = NULL;
    13751375
    1376         if (result)
    1377         {
    1378                 char *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
    1379                 if (sqlstate)
    1380                 {
    1381                         sql_obj = PyStr_FromStringAndSize(sqlstate, 5);
    1382                         type = get_error_type(sqlstate);
    1383                 }
    1384         }
    1385         if (!sql_obj)
    1386         {
    1387                 Py_INCREF(Py_None);
    1388                 sql_obj = Py_None;
    1389         }
    1390         msg_obj = PyStr_FromString(msg);
     1376#if IS_PY3
     1377        if (encoding == -1) /* unknown */
     1378        {
     1379                msg_obj = PyUnicode_DecodeLocale(msg, NULL);
     1380        }
     1381        else
     1382                msg_obj = get_decoded_string(msg, strlen(msg), encoding);
     1383        if (!msg_obj) /* cannot decode */
     1384#endif
     1385        msg_obj = PyBytes_FromString(msg);
     1386
     1387        if (sqlstate)
     1388                sql_obj = PyStr_FromStringAndSize(sqlstate, 5);
     1389        else
     1390        {
     1391                Py_INCREF(Py_None); sql_obj = Py_None;
     1392        }
     1393
    13911394        err_obj = PyObject_CallFunctionObjArgs(type, msg_obj, NULL);
    13921395        if (err_obj)
     
    14041407}
    14051408
     1409/* sets given database error message */
     1410static void
     1411set_error_msg(PyObject *type, const char *msg)
     1412{
     1413        set_error_msg_and_state(type, msg, pg_encoding_ascii, NULL);
     1414}
     1415
     1416/* sets database error from connection and/or result */
     1417static void
     1418set_error(PyObject *type, const char * msg, PGconn *cnx, PGresult *result)
     1419{
     1420        char *sqlstate = NULL; int encoding = pg_encoding_ascii;
     1421
     1422        if (cnx)
     1423        {
     1424                char *err_msg = PQerrorMessage(cnx);
     1425                if (err_msg)
     1426                {
     1427                        msg = err_msg;
     1428                        encoding = PQclientEncoding(cnx);
     1429                }
     1430        }
     1431        if (result)
     1432        {
     1433                sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
     1434                if (sqlstate) type = get_error_type(sqlstate);
     1435        }
     1436
     1437        set_error_msg_and_state(type, msg, encoding, sqlstate);
     1438}
     1439
    14061440/* checks connection validity */
    14071441static int
     
    14101444        if (!self->valid)
    14111445        {
    1412                 set_dberror(OperationalError, "Connection has been closed", NULL);
     1446                set_error_msg(OperationalError, "Connection has been closed");
    14131447                return 0;
    14141448        }
     
    15841618        if (!self->lo_oid)
    15851619        {
    1586                 set_dberror(IntegrityError, "Object is not valid (null oid)", NULL);
     1620                set_error_msg(IntegrityError, "Object is not valid (null oid)");
    15871621                return 0;
    15881622        }
     
    22882322                        case PGRES_FATAL_ERROR:
    22892323                        case PGRES_NONFATAL_ERROR:
    2290                                 set_dberror(ProgrammingError,
    2291                                         PQerrorMessage(self->cnx), result);
     2324                                set_error(ProgrammingError, "Cannot execute query",
     2325                                        self->cnx, result);
    22922326                                break;
    22932327                        case PGRES_COMMAND_OK:
     
    23162350                                return Py_None;
    23172351                        default:
    2318                                 set_dberror(InternalError, "Unknown result status", result);
     2352                                set_error_msg(InternalError, "Unknown result status");
    23192353                }
    23202354
     
    30423076        if (lo_oid == 0)
    30433077        {
    3044                 set_dberror(OperationalError, "Can't create large object", NULL);
     3078                set_error_msg(OperationalError, "Can't create large object");
    30453079                return NULL;
    30463080        }
     
    31063140        if (lo_oid == 0)
    31073141        {
    3108                 set_dberror(OperationalError, "Can't create large object", NULL);
     3142                set_error_msg(OperationalError, "Can't create large object");
    31093143                return NULL;
    31103144        }
     
    32753309        if (!self->cnx)
    32763310        {
    3277                 set_dberror(InternalError, "Connection already closed", NULL);
     3311                set_error_msg(InternalError, "Connection already closed");
    32783312                return NULL;
    32793313        }
     
    35223556        if (!self->valid)
    35233557        {
    3524                 set_dberror(OperationalError, "Object has been closed", NULL);
     3558                set_error_msg(OperationalError, "Object has been closed");
    35253559                return 0;
    35263560        }
     
    35283562        if ((level & CHECK_RESULT) && !self->result)
    35293563        {
    3530                 set_dberror(DatabaseError, "No result", NULL);
     3564                set_error_msg(DatabaseError, "No result");
    35313565                return 0;
    35323566        }
     
    35343568        if ((level & CHECK_DQL) && self->result_type != RESULT_DQL)
    35353569        {
    3536                 set_dberror(DatabaseError,
    3537                         "Last query did not return tuples", self->result);
     3570                set_error_msg(DatabaseError, "Last query did not return tuples");
    35383571                return 0;
    35393572        }
     
    36833716                case PGRES_FATAL_ERROR:
    36843717                case PGRES_NONFATAL_ERROR:
    3685                         set_dberror(ProgrammingError,
    3686                                 PQerrorMessage(self->pgcnx->cnx), self->result);
     3718                        set_error(ProgrammingError, "Cannot execute command",
     3719                                self->pgcnx->cnx, self->result);
    36873720                        break;
    36883721                default:
    3689                         set_dberror(InternalError, "Internal error: "
    3690                                 "unknown result status", self->result);
     3722                        set_error_msg(InternalError, "Internal error: "
     3723                                "unknown result status");
    36913724        }
    36923725
     
    44264459        if (!(npgobj = PyObject_NEW(connObject, &connType)))
    44274460        {
    4428                 set_dberror(InternalError, "Can't create new connection object", NULL);
     4461                set_error_msg(InternalError, "Can't create new connection object");
    44294462                return NULL;
    44304463        }
     
    44494482        if (PQstatus(npgobj->cnx) == CONNECTION_BAD)
    44504483        {
    4451                 set_dberror(InternalError, PQerrorMessage(npgobj->cnx), NULL);
     4484                set_error(InternalError, "Cannot connect", npgobj->cnx, NULL);
    44524485                Py_XDECREF(npgobj);
    44534486                return NULL;
Note: See TracChangeset for help on using the changeset viewer.