Add support for SQLSTATE error codes
authorAndras Mantia <andras@kdab.com>
Sun, 1 Jul 2012 14:11:00 +0000 (17:11 +0300)
committerQt by Nokia <qt-info@nokia.com>
Tue, 3 Jul 2012 11:21:23 +0000 (13:21 +0200)
Postgres can report detailed information about an error using error codes.
See http://www.postgresql.org/docs/8.1/static/errcodes-appendix.html .
The current driver doesn't report the error, nor is it supported by the
QSqlError object.
The patch appends the error to the error message, helping applications to:
- handle different errors in a specific way
- show correct, translated error messages, independently on the language of the postgres installation

Change-Id: Ica3530ac33d3aaa9985e06f6c1f302ece9891033
Reviewed-by: Mark Brand <mabrand@mabrand.nl>
dist/changes-5.0.0
src/sql/drivers/psql/qsql_psql.cpp

index b9fc030..1dfbeaa 100644 (file)
@@ -567,6 +567,11 @@ sqlite
 'true' and 'false'. Sqlite does not have a boolean column type and it is
 customary to use integer. QTBUG-23895
 
+postgres
+--------
+* the error message returned in QSqlError::text() has the SQLSTATE error code
+appended in parantheses.
+
 ****************************************************************************
 *                      Platform Specific Changes                           *
 ****************************************************************************
index bb0c1b3..7267d43 100644 (file)
@@ -195,10 +195,14 @@ public:
 };
 
 static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
-                            const QPSQLDriverPrivate *p)
+                            const QPSQLDriverPrivate *p, PGresult* result = 0)
 {
     const char *s = PQerrorMessage(p->connection);
     QString msg = p->isUtf8 ? QString::fromUtf8(s) : QString::fromLocal8Bit(s);
+    if (result) {
+      const char *sCode = PQresultErrorField(result, PG_DIAG_SQLSTATE);
+      msg += QString::fromLatin1("(%1)").arg(QString::fromLatin1(sCode));
+    }
     return QSqlError(QLatin1String("QPSQL: ") + err, msg, type);
 }
 
@@ -220,7 +224,7 @@ bool QPSQLResultPrivate::processResults()
         return true;
     }
     q->setLastError(qMakeError(QCoreApplication::translate("QPSQLResult",
-                    "Unable to create query"), QSqlError::StatementError, driver));
+                    "Unable to create query"), QSqlError::StatementError, driver, result));
     return false;
 }
 
@@ -586,7 +590,7 @@ bool QPSQLResult::prepare(const QString &query)
 
     if (PQresultStatus(result) != PGRES_COMMAND_OK) {
         setLastError(qMakeError(QCoreApplication::translate("QPSQLResult",
-                                "Unable to prepare statement"), QSqlError::StatementError, d->driver));
+                                "Unable to prepare statement"), QSqlError::StatementError, d->driver, result));
         PQclear(result);
         d->preparedStmtId.clear();
         return false;
@@ -881,9 +885,9 @@ bool QPSQLDriver::beginTransaction()
     }
     PGresult* res = d->exec("BEGIN");
     if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
-        PQclear(res);
         setLastError(qMakeError(tr("Could not begin transaction"),
-                                QSqlError::TransactionError, d));
+                                QSqlError::TransactionError, d, res));
+        PQclear(res);
         return false;
     }
     PQclear(res);
@@ -914,9 +918,9 @@ bool QPSQLDriver::commitTransaction()
     }
 
     if (!res || PQresultStatus(res) != PGRES_COMMAND_OK || transaction_failed) {
-        PQclear(res);
         setLastError(qMakeError(tr("Could not commit transaction"),
-                                QSqlError::TransactionError, d));
+                                QSqlError::TransactionError, d, res));
+        PQclear(res);
         return false;
     }
     PQclear(res);
@@ -932,7 +936,7 @@ bool QPSQLDriver::rollbackTransaction()
     PGresult* res = d->exec("ROLLBACK");
     if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
         setLastError(qMakeError(tr("Could not rollback transaction"),
-                                QSqlError::TransactionError, d));
+                                QSqlError::TransactionError, d, res));
         PQclear(res);
         return false;
     }
@@ -1316,8 +1320,9 @@ bool QPSQLDriver::subscribeToNotification(const QString &name)
         // to check for notifications immediately after executing the LISTEN
         d->seid << name;
         QString query = QLatin1String("LISTEN ") + escapeIdentifier(name, QSqlDriver::TableName);
-        if (PQresultStatus(d->exec(query)) != PGRES_COMMAND_OK) {
-            setLastError(qMakeError(tr("Unable to subscribe"), QSqlError::StatementError, d));
+        PGresult *result = d->exec(query);
+        if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+            setLastError(qMakeError(tr("Unable to subscribe"), QSqlError::StatementError, d, result));
             return false;
         }
 
@@ -1347,8 +1352,9 @@ bool QPSQLDriver::unsubscribeFromNotification(const QString &name)
     }
 
     QString query = QLatin1String("UNLISTEN ") + escapeIdentifier(name, QSqlDriver::TableName);
-    if (PQresultStatus(d->exec(query)) != PGRES_COMMAND_OK) {
-        setLastError(qMakeError(tr("Unable to unsubscribe"), QSqlError::StatementError, d));
+    PGresult *result = d->exec(query);
+    if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+        setLastError(qMakeError(tr("Unable to unsubscribe"), QSqlError::StatementError, d, result));
         return false;
     }