QSQL: cleanup/modernize PostgreSQL plugin

Cleanup/modernize the PostgreSQL plugin
 - use nullptr
 - use range-based for loop
 - use QStringLiteral or QByteArray::fromRawData instead
   QLatin1String/QString::fromLatin1 where possible
 - use QRegularExpression instead QRegExp
 - use QQueue instead QList
 - uppercase SQL keywords

Change-Id: Ie22be1538328ff1e2b663066ede96741d271e050
Reviewed-by: Andy Shaw <andy.shaw@qt.io>
bb10
Christian Ehrlicher 2018-12-20 09:51:30 +01:00
parent 0cc9c30479
commit 8551b7d93c
3 changed files with 94 additions and 85 deletions

View File

@ -61,11 +61,9 @@ QPSQLDriverPlugin::QPSQLDriverPlugin()
QSqlDriver* QPSQLDriverPlugin::create(const QString &name)
{
if (name == QLatin1String("QPSQL") || name == QLatin1String("QPSQL7")) {
QPSQLDriver* driver = new QPSQLDriver();
return driver;
}
return 0;
if (name == QLatin1String("QPSQL") || name == QLatin1String("QPSQL7"))
return new QPSQLDriver;
return nullptr;
}
QT_END_NAMESPACE

View File

@ -42,7 +42,7 @@
#include <qcoreapplication.h>
#include <qvariant.h>
#include <qdatetime.h>
#include <qregexp.h>
#include <qregularexpression.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
#include <qsqlindex.h>
@ -54,6 +54,8 @@
#include <QtSql/private/qsqlresult_p.h>
#include <QtSql/private/qsqldriver_p.h>
#include <queue>
#include <libpq-fe.h>
#include <pg_config.h>
@ -147,10 +149,10 @@ class QPSQLDriverPrivate final : public QSqlDriverPrivate
Q_DECLARE_PUBLIC(QPSQLDriver)
public:
QPSQLDriverPrivate() : QSqlDriverPrivate(),
connection(0),
connection(nullptr),
isUtf8(false),
pro(QPSQLDriver::Version6),
sn(0),
sn(nullptr),
pendingNotifyCheck(false),
hasBackslashEscape(false),
stmtCount(0),
@ -187,11 +189,13 @@ public:
void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type)
{
QString query = QString::fromLatin1("select pg_class.relname, pg_namespace.nspname from pg_class "
"left join pg_namespace on (pg_class.relnamespace = pg_namespace.oid) "
"where (pg_class.relkind = '%1') and (pg_class.relname !~ '^Inv') "
"and (pg_class.relname !~ '^pg_') "
"and (pg_namespace.nspname != 'information_schema')").arg(type);
const QString query =
QStringLiteral("SELECT pg_class.relname, pg_namespace.nspname FROM pg_class "
"LEFT JOIN pg_namespace ON (pg_class.relnamespace = pg_namespace.oid) "
"WHERE (pg_class.relkind = '") + type +
QStringLiteral("') AND (pg_class.relname !~ '^Inv') "
"AND (pg_class.relname !~ '^pg_') "
"AND (pg_namespace.nspname != 'information_schema')");
t.exec(query);
while (t.next()) {
QString schema = t.value(1).toString();
@ -294,10 +298,10 @@ public:
Q_DECLARE_SQLDRIVER_PRIVATE(QPSQLDriver)
QPSQLResultPrivate(QPSQLResult *q, const QPSQLDriver *drv)
: QSqlResultPrivate(q, drv),
result(0),
result(nullptr),
stmtId(InvalidStatementId),
currentSize(-1),
canFetchMoreRows(false),
stmtId(InvalidStatementId),
preparedQueriesEnabled(false)
{ }
@ -305,12 +309,12 @@ public:
void deallocatePreparedStmt();
PGresult *result;
QList<PGresult*> nextResultSets;
std::queue<PGresult*> nextResultSets;
QString preparedStmtId;
StatementId stmtId;
int currentSize;
bool canFetchMoreRows;
StatementId stmtId;
bool preparedQueriesEnabled;
QString preparedStmtId;
bool processResults();
};
@ -423,7 +427,7 @@ static QVariant::Type qDecodePSQLType(int t)
void QPSQLResultPrivate::deallocatePreparedStmt()
{
const QString stmt = QLatin1String("DEALLOCATE ") + preparedStmtId;
const QString stmt = QStringLiteral("DEALLOCATE ") + preparedStmtId;
PGresult *result = drv_d_func()->exec(stmt);
if (PQresultStatus(result) != PGRES_COMMAND_OK)
@ -460,8 +464,10 @@ void QPSQLResult::cleanup()
if (d->result)
PQclear(d->result);
d->result = nullptr;
while (!d->nextResultSets.isEmpty())
PQclear(d->nextResultSets.takeFirst());
while (!d->nextResultSets.empty()) {
PQclear(d->nextResultSets.front());
d->nextResultSets.pop();
}
if (d->stmtId != InvalidStatementId) {
if (d->drv_d_func())
d->drv_d_func()->finishQuery(d->stmtId);
@ -622,7 +628,11 @@ bool QPSQLResult::nextResult()
if (d->result)
PQclear(d->result);
d->result = d->nextResultSets.isEmpty() ? nullptr : d->nextResultSets.takeFirst();
d->result = nullptr;
if (!d->nextResultSets.empty()) {
d->result = d->nextResultSets.front();
d->nextResultSets.pop();
}
return d->processResults();
}
@ -646,9 +656,9 @@ QVariant QPSQLResult::data(int i)
return d->drv_d_func()->isUtf8 ? QString::fromUtf8(val) : QString::fromLatin1(val);
case QVariant::LongLong:
if (val[0] == '-')
return QString::fromLatin1(val).toLongLong();
return QByteArray::fromRawData(val, qstrlen(val)).toLongLong();
else
return QString::fromLatin1(val).toULongLong();
return QByteArray::fromRawData(val, qstrlen(val)).toULongLong();
case QVariant::Int:
return atoi(val);
case QVariant::Double: {
@ -754,7 +764,7 @@ bool QPSQLResult::reset (const QString& query)
if (!isForwardOnly()) {
// Fetch all result sets right away
while (PGresult *nextResultSet = d->drv_d_func()->getResult(d->stmtId))
d->nextResultSets.append(nextResultSet);
d->nextResultSets.push(nextResultSet);
}
return d->processResults();
}
@ -768,7 +778,8 @@ int QPSQLResult::size()
int QPSQLResult::numRowsAffected()
{
Q_D(const QPSQLResult);
return QString::fromLatin1(PQcmdTuples(d->result)).toInt();
const char *tuples = PQcmdTuples(d->result);
return QByteArray::fromRawData(tuples, qstrlen(tuples)).toInt();
}
QVariant QPSQLResult::lastInsertId() const
@ -777,7 +788,7 @@ QVariant QPSQLResult::lastInsertId() const
if (d->drv_d_func()->pro >= QPSQLDriver::Version8_1) {
QSqlQuery qry(driver()->createResult());
// Most recent sequence value obtained from nextval
if (qry.exec(QLatin1String("SELECT lastval();")) && qry.next())
if (qry.exec(QStringLiteral("SELECT lastval();")) && qry.next())
return qry.value(0);
} else if (isActive()) {
Oid id = PQoidValue(d->result);
@ -868,15 +879,13 @@ static QString qCreateParamString(const QVector<QVariant> &boundValues, const QS
QString params;
QSqlField f;
for (int i = 0; i < boundValues.count(); ++i) {
const QVariant &val = boundValues.at(i);
for (const QVariant &val : boundValues) {
f.setType(val.type());
if (val.isNull())
f.clear();
else
f.setValue(val);
if(!params.isNull())
if (!params.isNull())
params.append(QLatin1String(", "));
params.append(driver->formatValue(f));
}
@ -886,7 +895,7 @@ static QString qCreateParamString(const QVector<QVariant> &boundValues, const QS
QString qMakePreparedStmtId()
{
static QBasicAtomicInt qPreparedStmtCount = Q_BASIC_ATOMIC_INITIALIZER(0);
QString id = QLatin1String("qpsqlpstmt_") + QString::number(qPreparedStmtCount.fetchAndAddRelaxed(1) + 1, 16);
QString id = QStringLiteral("qpsqlpstmt_") + QString::number(qPreparedStmtCount.fetchAndAddRelaxed(1) + 1, 16);
return id;
}
@ -902,7 +911,7 @@ bool QPSQLResult::prepare(const QString &query)
d->deallocatePreparedStmt();
const QString stmtId = qMakePreparedStmtId();
const QString stmt = QString::fromLatin1("PREPARE %1 AS ").arg(stmtId).append(d->positionalToNamedBinding(query));
const QString stmt = QStringLiteral("PREPARE %1 AS ").arg(stmtId).append(d->positionalToNamedBinding(query));
PGresult *result = d->drv_d_func()->exec(stmt);
@ -930,9 +939,9 @@ bool QPSQLResult::exec()
QString stmt;
const QString params = qCreateParamString(boundValues(), driver());
if (params.isEmpty())
stmt = QString::fromLatin1("EXECUTE %1").arg(d->preparedStmtId);
stmt = QStringLiteral("EXECUTE %1").arg(d->preparedStmtId);
else
stmt = QString::fromLatin1("EXECUTE %1 (%2)").arg(d->preparedStmtId, params);
stmt = QStringLiteral("EXECUTE %1 (%2)").arg(d->preparedStmtId, params);
d->stmtId = d->drv_d_func()->sendQuery(stmt);
if (d->stmtId == InvalidStatementId) {
@ -948,7 +957,7 @@ bool QPSQLResult::exec()
if (!isForwardOnly()) {
// Fetch all result sets right away
while (PGresult *nextResultSet = d->drv_d_func()->getResult(d->stmtId))
d->nextResultSets.append(nextResultSet);
d->nextResultSets.push(nextResultSet);
}
return d->processResults();
}
@ -994,7 +1003,7 @@ void QPSQLDriverPrivate::detectBackslashEscape()
hasBackslashEscape = true;
} else {
hasBackslashEscape = false;
PGresult* result = exec(QLatin1String("SELECT '\\\\' x"));
PGresult* result = exec(QStringLiteral("SELECT '\\\\' x"));
int status = PQresultStatus(result);
if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK)
if (QString::fromLatin1(PQgetvalue(result, 0, 0)) == QLatin1String("\\"))
@ -1072,20 +1081,21 @@ static QPSQLDriver::Protocol qMakePSQLVersion(int vMaj, int vMin)
static QPSQLDriver::Protocol qFindPSQLVersion(const QString &versionString)
{
const QRegExp rx(QStringLiteral("(\\d+)(?:\\.(\\d+))?"));
if (rx.indexIn(versionString) != -1) {
const QRegularExpression rx(QStringLiteral("(\\d+)(?:\\.(\\d+))?"));
const QRegularExpressionMatch match = rx.match(versionString);
if (match.hasMatch()) {
// Beginning with PostgreSQL version 10, a major release is indicated by
// increasing the first part of the version, e.g. 10 to 11.
// Before version 10, a major release was indicated by increasing either
// the first or second part of the version number, e.g. 9.5 to 9.6.
int vMaj = rx.cap(1).toInt();
int vMaj = match.capturedRef(1).toInt();
int vMin;
if (vMaj >= 10) {
vMin = 0;
} else {
if (rx.cap(2).isEmpty())
if (match.capturedRef(2).isEmpty())
return QPSQLDriver::VersionUnknown;
vMin = rx.cap(2).toInt();
vMin = match.capturedRef(2).toInt();
}
return qMakePSQLVersion(vMaj, vMin);
}
@ -1096,7 +1106,7 @@ static QPSQLDriver::Protocol qFindPSQLVersion(const QString &versionString)
QPSQLDriver::Protocol QPSQLDriverPrivate::getPSQLVersion()
{
QPSQLDriver::Protocol serverVersion = QPSQLDriver::Version6;
PGresult* result = exec("select version()");
PGresult* result = exec("SELECT version()");
int status = PQresultStatus(result);
if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) {
serverVersion = qFindPSQLVersion(
@ -1355,8 +1365,8 @@ QStringList QPSQLDriver::tables(QSql::TableType type) const
if (type & QSql::Views)
const_cast<QPSQLDriverPrivate*>(d)->appendTables(tl, t, QLatin1Char('v'));
if (type & QSql::SystemTables) {
t.exec(QLatin1String("select relname from pg_class where (relkind = 'r') "
"and (relname like 'pg_%') "));
t.exec(QStringLiteral("SELECT relname FROM pg_class WHERE (relkind = 'r') "
"AND (relname LIKE 'pg_%') "));
while (t.next())
tl.append(t.value(0).toString());
}
@ -1394,20 +1404,20 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
else
schema = std::move(schema).toLower();
QString stmt = QLatin1String("SELECT pg_attribute.attname, pg_attribute.atttypid::int, "
"pg_class.relname "
"FROM pg_attribute, pg_class "
"WHERE %1 pg_class.oid IN "
"(SELECT indexrelid FROM pg_index WHERE indisprimary = true AND indrelid IN "
"(SELECT oid FROM pg_class WHERE relname = '%2')) "
"AND pg_attribute.attrelid = pg_class.oid "
"AND pg_attribute.attisdropped = false "
"ORDER BY pg_attribute.attnum");
QString stmt = QStringLiteral("SELECT pg_attribute.attname, pg_attribute.atttypid::int, "
"pg_class.relname "
"FROM pg_attribute, pg_class "
"WHERE %1 pg_class.oid IN "
"(SELECT indexrelid FROM pg_index WHERE indisprimary = true AND indrelid IN "
"(SELECT oid FROM pg_class WHERE relname = '%2')) "
"AND pg_attribute.attrelid = pg_class.oid "
"AND pg_attribute.attisdropped = false "
"ORDER BY pg_attribute.attnum");
if (schema.isEmpty())
stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid) AND"));
stmt = stmt.arg(QStringLiteral("pg_table_is_visible(pg_class.oid) AND"));
else
stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from "
"pg_namespace where pg_namespace.nspname = '%1') AND").arg(schema));
stmt = stmt.arg(QStringLiteral("pg_class.relnamespace = (SELECT oid FROM "
"pg_namespace WHERE pg_namespace.nspname = '%1') AND").arg(schema));
i.exec(stmt.arg(tbl));
while (i.isActive() && i.next()) {
@ -1438,23 +1448,23 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
else
schema = std::move(schema).toLower();
QString stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, "
"pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
"pg_attrdef.adsrc "
"from pg_class, pg_attribute "
"left join pg_attrdef on (pg_attrdef.adrelid = "
"pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) "
"where %1 "
"and pg_class.relname = '%2' "
"and pg_attribute.attnum > 0 "
"and pg_attribute.attrelid = pg_class.oid "
"and pg_attribute.attisdropped = false "
"order by pg_attribute.attnum");
QString stmt = QStringLiteral("SELECT pg_attribute.attname, pg_attribute.atttypid::int, "
"pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
"pg_attrdef.adsrc "
"FROM pg_class, pg_attribute "
"LEFT JOIN pg_attrdef ON (pg_attrdef.adrelid = "
"pg_attribute.attrelid AND pg_attrdef.adnum = pg_attribute.attnum) "
"WHERE %1 "
"AND pg_class.relname = '%2' "
"AND pg_attribute.attnum > 0 "
"AND pg_attribute.attrelid = pg_class.oid "
"AND pg_attribute.attisdropped = false "
"ORDER BY pg_attribute.attnum");
if (schema.isEmpty())
stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid)"));
stmt = stmt.arg(QStringLiteral("pg_table_is_visible(pg_class.oid)"));
else
stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from "
"pg_namespace where pg_namespace.nspname = '%1')").arg(schema));
stmt = stmt.arg(QStringLiteral("pg_class.relnamespace = (SELECT oid FROM "
"pg_namespace WHERE pg_namespace.nspname = '%1')").arg(schema));
QSqlQuery query(createResult());
query.exec(stmt.arg(tbl));
@ -1496,9 +1506,10 @@ inline void assignSpecialPsqlFloatValue(FloatType val, QString *target)
QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
{
Q_D(const QPSQLDriver);
const auto nullStr = [](){ return QStringLiteral("NULL"); };
QString r;
if (field.isNull()) {
r = QLatin1String("NULL");
r = nullStr();
} else {
switch (int(field.type())) {
case QVariant::DateTime:
@ -1507,14 +1518,14 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
// we force the value to be considered with a timezone information, and we force it to be UTC
// this is safe since postgresql stores only the UTC value and not the timezone offset (only used
// while parsing), so we have correct behavior in both case of with timezone and without tz
r = QLatin1String("TIMESTAMP WITH TIME ZONE ") + QLatin1Char('\'') +
QLocale::c().toString(field.value().toDateTime().toUTC(), QLatin1String("yyyy-MM-ddThh:mm:ss.zzz")) +
r = QStringLiteral("TIMESTAMP WITH TIME ZONE ") + QLatin1Char('\'') +
QLocale::c().toString(field.value().toDateTime().toUTC(), QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz")) +
QLatin1Char('Z') + QLatin1Char('\'');
} else {
r = QLatin1String("NULL");
r = nullStr();
}
#else
r = QLatin1String("NULL");
r = nullStr();
#endif // datestring
break;
case QVariant::Time:
@ -1524,19 +1535,19 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
} else
#endif
{
r = QLatin1String("NULL");
r = nullStr();
}
break;
case QVariant::String:
r = QSqlDriver::formatValue(field, trimStrings);
if (d->hasBackslashEscape)
r.replace(QLatin1String("\\"), QLatin1String("\\\\"));
r.replace(QLatin1Char('\\'), QLatin1String("\\\\"));
break;
case QVariant::Bool:
if (field.value().toBool())
r = QLatin1String("TRUE");
r = QStringLiteral("TRUE");
else
r = QLatin1String("FALSE");
r = QStringLiteral("FALSE");
break;
case QVariant::ByteArray: {
QByteArray ba(field.value().toByteArray());
@ -1615,7 +1626,7 @@ bool QPSQLDriver::subscribeToNotification(const QString &name)
// Add the name to the list of subscriptions here so that QSQLDriverPrivate::exec knows
// to check for notifications immediately after executing the LISTEN
d->seid << name;
QString query = QLatin1String("LISTEN ") + escapeIdentifier(name, QSqlDriver::TableName);
QString query = QStringLiteral("LISTEN ") + escapeIdentifier(name, QSqlDriver::TableName);
PGresult *result = d->exec(query);
if (PQresultStatus(result) != PGRES_COMMAND_OK) {
d->seid.removeLast();
@ -1651,7 +1662,7 @@ bool QPSQLDriver::unsubscribeFromNotification(const QString &name)
return false;
}
QString query = QLatin1String("UNLISTEN ") + escapeIdentifier(name, QSqlDriver::TableName);
QString query = QStringLiteral("UNLISTEN ") + escapeIdentifier(name, QSqlDriver::TableName);
PGresult *result = d->exec(query);
if (PQresultStatus(result) != PGRES_COMMAND_OK) {
setLastError(qMakeError(tr("Unable to unsubscribe"), QSqlError::StatementError, d, result));

View File

@ -96,8 +96,8 @@ public:
UnknownLaterVersion = 100000
};
explicit QPSQLDriver(QObject *parent=0);
explicit QPSQLDriver(PGconn *conn, QObject *parent=0);
explicit QPSQLDriver(QObject *parent = nullptr);
explicit QPSQLDriver(PGconn *conn, QObject *parent = nullptr);
~QPSQLDriver();
bool hasFeature(DriverFeature f) const override;
bool open(const QString & db,