PDA

View Full Version : [patch] QPSQL: set an error code so QSqlError::number() gives a useful value



Alexei.Sheplyakov
10th December 2008, 13:16
Problem: in my application (which makes use of PostgreSQL and Qt4) I
need to distinguish between different kinds of (SQL) errors, that is,
I need to check if the error is a foreign key violation, or uniqness
voilation, etc. This information is available via `native' PostgreSQL
API, the relevant function is

char *PQresultErrorField(const PGresult *res, int fieldcode)

However, QPSQL driver does not provide this information, i.e. QSqlError
returned by QPSQL always has number() == -1. Also, there's no (easy)
way to retrive PGresult* from the driver. Hence the patch below. With
this patch number() returns an error code (as described in the Appendix A
of the PostgreSQL manual). There's one quirk, though. PostgreSQLs error
codes are 5 character ASCII strings, but QSqlError expects an integer
instead. The patch treats error codes as integres in base 29. To get
back the original error code, one should convert that integer back.



Index: qt4-x11-4.4.3/src/sql/drivers/psql/qsql_psql.cpp
================================================== =================
--- qt4-x11-4.4.3.orig/src/sql/drivers/psql/qsql_psql.cpp 2008-12-08 11:42:21.000000000 +0200
+++ qt4-x11-4.4.3/src/sql/drivers/psql/qsql_psql.cpp 2008-12-08 11:48:11.000000000 +0200
@@ -146,11 +146,28 @@
};

static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
- const QPSQLDriverPrivate *p)
+ const QPSQLDriverPrivate *p,
+ const PGresult *res = 0)
{
const char *s = PQerrorMessage(p->connection);
+ int errnum = -1;
+ if (res) {
+ const char *sql_state_ = PQresultErrorField(res, PG_DIAG_SQLSTATE);
+ if (sql_state_) {
+ bool ok;
+ // PQresultErrorField returns 5-character error code,
+ // see the appendix A (titled `PostgreSQL Error Codes')
+ // of the PostgreSQL manual. On the other hand, Qt
+ // expects an integer.
+ static const int latin_base = 29;
+ // Error code contains arbitrary alphanumeric characters
+ errnum = QString::fromAscii(sql_state_).toInt(&ok, latin_base);
+ if (!ok)
+ errnum = -1;
+ }
+ }
QString msg = p->isUtf8 ? QString::fromUtf8(s) : QString::fromLocal8Bit(s);
- return QSqlError(QLatin1String("QPSQL: ") + err, msg, type);
+ return QSqlError(QLatin1String("QPSQL: ") + err, msg, type, errnum);
}

bool QPSQLResultPrivate::processResults()
@@ -171,7 +188,7 @@
return true;
}
q->setLastError(qMakeError(QCoreApplication::translat e("QPSQLResult",
- "Unable to create query"), QSqlError::StatementError, driver));
+ "Unable to create query"), QSqlError::StatementError, driver, result));
return false;
}

@@ -543,6 +560,7 @@
: stmt.toLocal8Bit().constData());

if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+ // XXX: do we need to setNumber() here?
setLastError(qMakeError(QCoreApplication::translat e("QPSQLResult",
"Unable to prepare statement"), QSqlError::StatementError, d->driver));
PQclear(result);
@@ -1173,6 +1191,7 @@
d->isUtf8 ? query.toUtf8().constData()
: query.toLocal8Bit().constData())
) != PGRES_COMMAND_OK) {
+ // XXX: do we need to setNumber() here?
setLastError(qMakeError(tr("Unable to subscribe"), QSqlError::StatementError, d));
return false;
}
@@ -1205,6 +1224,7 @@
d->isUtf8 ? query.toUtf8().constData()
: query.toLocal8Bit().constData())
) != PGRES_COMMAND_OK) {
+ // XXX: do we need to setNumber() here?
setLastError(qMakeError(tr("Unable to unsubscribe"), QSqlError::StatementError, d));
return false;
}

jpn
23rd December 2008, 21:33
Try sending the patch to Trolls via Task-Tracker.

haldrik
22nd April 2012, 07:12
The problem persist on Qt4.7.4, could you please guide me for apply this patch?