diff options
Diffstat (limited to 'src/plugins/sqldrivers')
21 files changed, 795 insertions, 521 deletions
diff --git a/src/plugins/sqldrivers/db2/qsql_db2.cpp b/src/plugins/sqldrivers/db2/qsql_db2.cpp index 2bfd99cfa9..1d7e985731 100644 --- a/src/plugins/sqldrivers/db2/qsql_db2.cpp +++ b/src/plugins/sqldrivers/db2/qsql_db2.cpp @@ -92,24 +92,24 @@ class QDB2Result: public QSqlResult public: QDB2Result(const QDB2Driver *drv); ~QDB2Result(); - bool prepare(const QString &query) Q_DECL_OVERRIDE; - bool exec() Q_DECL_OVERRIDE; - QVariant handle() const Q_DECL_OVERRIDE; + bool prepare(const QString &query) override; + bool exec() override; + QVariant handle() const override; protected: - QVariant data(int field) Q_DECL_OVERRIDE; - bool reset(const QString &query) Q_DECL_OVERRIDE; - bool fetch(int i) Q_DECL_OVERRIDE; - bool fetchNext() Q_DECL_OVERRIDE; - bool fetchFirst() Q_DECL_OVERRIDE; - bool fetchLast() Q_DECL_OVERRIDE; - bool isNull(int i) Q_DECL_OVERRIDE; - int size() Q_DECL_OVERRIDE; - int numRowsAffected() Q_DECL_OVERRIDE; - QSqlRecord record() const Q_DECL_OVERRIDE; - void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; - void detachFromResultSet() Q_DECL_OVERRIDE; - bool nextResult() Q_DECL_OVERRIDE; + QVariant data(int field) override; + bool reset(const QString &query) override; + bool fetch(int i) override; + bool fetchNext() override; + bool fetchFirst() override; + bool fetchLast() override; + bool isNull(int i) override; + int size() override; + int numRowsAffected() override; + QSqlRecord record() const override; + void virtual_hook(int id, void *data) override; + void detachFromResultSet() override; + bool nextResult() override; }; class QDB2ResultPrivate: public QSqlResultPrivate @@ -156,7 +156,7 @@ static SQLTCHAR* qToTChar(const QString& str) return (SQLTCHAR*)str.utf16(); } -static QString qWarnDB2Handle(int handleType, SQLHANDLE handle) +static QString qWarnDB2Handle(int handleType, SQLHANDLE handle, int *errorCode) { SQLINTEGER nativeCode; SQLSMALLINT msgLen; @@ -171,22 +171,51 @@ static QString qWarnDB2Handle(int handleType, SQLHANDLE handle) (SQLTCHAR*) description, SQL_MAX_MESSAGE_LENGTH - 1, /* in bytes, not in characters */ &msgLen); - if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) + if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) { + if (errorCode) + *errorCode = nativeCode; return QString(qFromTChar(description)); + } return QString(); } -static QString qDB2Warn(const QDB2DriverPrivate* d) +static QString qDB2Warn(const QDB2DriverPrivate* d, QStringList *errorCodes = nullptr) { - return (qWarnDB2Handle(SQL_HANDLE_ENV, d->hEnv) + QLatin1Char(' ') - + qWarnDB2Handle(SQL_HANDLE_DBC, d->hDbc)); + int errorCode = 0; + QString error = qWarnDB2Handle(SQL_HANDLE_ENV, d->hEnv, &errorCode); + if (errorCodes && errorCode != 0) { + *errorCodes << QString::number(errorCode); + errorCode = 0; + } + if (!error.isEmpty()) + error += QLatin1Char(' '); + error += qWarnDB2Handle(SQL_HANDLE_DBC, d->hDbc, &errorCode); + if (errorCodes && errorCode != 0) + *errorCodes << QString::number(errorCode); + return error; } -static QString qDB2Warn(const QDB2ResultPrivate* d) +static QString qDB2Warn(const QDB2ResultPrivate* d, QStringList *errorCodes = nullptr) { - return (qWarnDB2Handle(SQL_HANDLE_ENV, d->drv_d_func()->hEnv) + QLatin1Char(' ') - + qWarnDB2Handle(SQL_HANDLE_DBC, d->drv_d_func()->hDbc) - + qWarnDB2Handle(SQL_HANDLE_STMT, d->hStmt)); + int errorCode = 0; + QString error = qWarnDB2Handle(SQL_HANDLE_ENV, d->drv_d_func()->hEnv, &errorCode); + if (errorCodes && errorCode != 0) { + *errorCodes << QString::number(errorCode); + errorCode = 0; + } + if (!error.isEmpty()) + error += QLatin1Char(' '); + error += qWarnDB2Handle(SQL_HANDLE_DBC, d->drv_d_func()->hDbc, &errorCode); + if (errorCodes && errorCode != 0) { + *errorCodes << QString::number(errorCode); + errorCode = 0; + } + if (!error.isEmpty()) + error += QLatin1Char(' '); + error += qWarnDB2Handle(SQL_HANDLE_STMT, d->hStmt, &errorCode); + if (errorCodes && errorCode != 0) + *errorCodes << QString::number(errorCode); + return error; } static void qSqlWarning(const QString& message, const QDB2DriverPrivate* d) @@ -204,13 +233,19 @@ static void qSqlWarning(const QString& message, const QDB2ResultPrivate* d) static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, const QDB2DriverPrivate* p) { - return QSqlError(QLatin1String("QDB2: ") + err, qDB2Warn(p), type); + QStringList errorCodes; + const QString error = qDB2Warn(p, &errorCodes); + return QSqlError(QStringLiteral("QDB2: ") + err, error, type, + errorCodes.join(QLatin1Char(';'))); } static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, const QDB2ResultPrivate* p) { - return QSqlError(QLatin1String("QDB2: ") + err, qDB2Warn(p), type); + QStringList errorCodes; + const QString error = qDB2Warn(p, &errorCodes); + return QSqlError(QStringLiteral("QDB2: ") + err, error, type, + errorCodes.join(QLatin1Char(';'))); } static QVariant::Type qDecodeDB2Type(SQLSMALLINT sqltype) diff --git a/src/plugins/sqldrivers/db2/qsql_db2_p.h b/src/plugins/sqldrivers/db2/qsql_db2_p.h index fa6d739479..79ae54ab2d 100644 --- a/src/plugins/sqldrivers/db2/qsql_db2_p.h +++ b/src/plugins/sqldrivers/db2/qsql_db2_p.h @@ -75,24 +75,24 @@ public: explicit QDB2Driver(QObject* parent = 0); QDB2Driver(Qt::HANDLE env, Qt::HANDLE con, QObject* parent = 0); ~QDB2Driver(); - bool hasFeature(DriverFeature) const Q_DECL_OVERRIDE; - void close() Q_DECL_OVERRIDE; - QSqlRecord record(const QString &tableName) const Q_DECL_OVERRIDE; - QStringList tables(QSql::TableType type) const Q_DECL_OVERRIDE; - QSqlResult *createResult() const Q_DECL_OVERRIDE; - QSqlIndex primaryIndex(const QString &tablename) const Q_DECL_OVERRIDE; - bool beginTransaction() Q_DECL_OVERRIDE; - bool commitTransaction() Q_DECL_OVERRIDE; - bool rollbackTransaction() Q_DECL_OVERRIDE; - QString formatValue(const QSqlField &field, bool trimStrings) const Q_DECL_OVERRIDE; - QVariant handle() const Q_DECL_OVERRIDE; + bool hasFeature(DriverFeature) const override; + void close() override; + QSqlRecord record(const QString &tableName) const override; + QStringList tables(QSql::TableType type) const override; + QSqlResult *createResult() const override; + QSqlIndex primaryIndex(const QString &tablename) const override; + bool beginTransaction() override; + bool commitTransaction() override; + bool rollbackTransaction() override; + QString formatValue(const QSqlField &field, bool trimStrings) const override; + QVariant handle() const override; bool open(const QString &db, const QString &user, const QString &password, const QString &host, int port, - const QString& connOpts) Q_DECL_OVERRIDE; - QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE; + const QString& connOpts) override; + QString escapeIdentifier(const QString &identifier, IdentifierType type) const override; private: bool setAutoCommit(bool autoCommit); diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp index c50fc7916a..d89051191c 100644 --- a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp +++ b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp @@ -356,16 +356,16 @@ class QIBaseResult : public QSqlCachedResult public: explicit QIBaseResult(const QIBaseDriver* db); - bool prepare(const QString &query) Q_DECL_OVERRIDE; - bool exec() Q_DECL_OVERRIDE; - QVariant handle() const Q_DECL_OVERRIDE; + bool prepare(const QString &query) override; + bool exec() override; + QVariant handle() const override; protected: - bool gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx) Q_DECL_OVERRIDE; - bool reset (const QString &query) Q_DECL_OVERRIDE; - int size() Q_DECL_OVERRIDE; - int numRowsAffected() Q_DECL_OVERRIDE; - QSqlRecord record() const Q_DECL_OVERRIDE; + bool gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx) override; + bool reset (const QString &query) override; + int size() override; + int numRowsAffected() override; + QSqlRecord record() const override; }; class QIBaseResultPrivate: public QSqlCachedResultPrivate @@ -388,7 +388,8 @@ public: return false; q->setLastError(QSqlError(QCoreApplication::translate("QIBaseResult", msg), - imsg, typ, int(sqlcode))); + imsg, typ, + sqlcode != -1 ? QString::number(sqlcode) : QString())); return true; } diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase_p.h b/src/plugins/sqldrivers/ibase/qsql_ibase_p.h index c7cee41462..295f6c0cec 100644 --- a/src/plugins/sqldrivers/ibase/qsql_ibase_p.h +++ b/src/plugins/sqldrivers/ibase/qsql_ibase_p.h @@ -74,36 +74,36 @@ public: explicit QIBaseDriver(QObject *parent = 0); explicit QIBaseDriver(isc_db_handle connection, QObject *parent = 0); virtual ~QIBaseDriver(); - bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE; + bool hasFeature(DriverFeature f) const override; bool open(const QString &db, const QString &user, const QString &password, const QString &host, int port, - const QString &connOpts) Q_DECL_OVERRIDE; + const QString &connOpts) override; bool open(const QString &db, const QString &user, const QString &password, const QString &host, int port) { return open(db, user, password, host, port, QString()); } - void close() Q_DECL_OVERRIDE; - QSqlResult *createResult() const Q_DECL_OVERRIDE; - bool beginTransaction() Q_DECL_OVERRIDE; - bool commitTransaction() Q_DECL_OVERRIDE; - bool rollbackTransaction() Q_DECL_OVERRIDE; - QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE; + void close() override; + QSqlResult *createResult() const override; + bool beginTransaction() override; + bool commitTransaction() override; + bool rollbackTransaction() override; + QStringList tables(QSql::TableType) const override; - QSqlRecord record(const QString& tablename) const Q_DECL_OVERRIDE; - QSqlIndex primaryIndex(const QString &table) const Q_DECL_OVERRIDE; + QSqlRecord record(const QString& tablename) const override; + QSqlIndex primaryIndex(const QString &table) const override; - QString formatValue(const QSqlField &field, bool trimStrings) const Q_DECL_OVERRIDE; - QVariant handle() const Q_DECL_OVERRIDE; + QString formatValue(const QSqlField &field, bool trimStrings) const override; + QVariant handle() const override; - QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE; + QString escapeIdentifier(const QString &identifier, IdentifierType type) const override; - bool subscribeToNotification(const QString &name) Q_DECL_OVERRIDE; - bool unsubscribeFromNotification(const QString &name) Q_DECL_OVERRIDE; - QStringList subscribedToNotifications() const Q_DECL_OVERRIDE; + bool subscribeToNotification(const QString &name) override; + bool unsubscribeFromNotification(const QString &name) override; + QStringList subscribedToNotifications() const override; private Q_SLOTS: void qHandleEventNotification(void* updatedResultBuffer); diff --git a/src/plugins/sqldrivers/mysql/main.cpp b/src/plugins/sqldrivers/mysql/main.cpp index 00d9c5bb34..d8d70483ef 100644 --- a/src/plugins/sqldrivers/mysql/main.cpp +++ b/src/plugins/sqldrivers/mysql/main.cpp @@ -51,7 +51,7 @@ class QMYSQLDriverPlugin : public QSqlDriverPlugin public: QMYSQLDriverPlugin(); - QSqlDriver* create(const QString &) Q_DECL_OVERRIDE; + QSqlDriver* create(const QString &) override; }; QMYSQLDriverPlugin::QMYSQLDriverPlugin() diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp index 365f89957a..53a72779a9 100644 --- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp +++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp @@ -175,26 +175,26 @@ public: explicit QMYSQLResult(const QMYSQLDriver *db); ~QMYSQLResult(); - QVariant handle() const Q_DECL_OVERRIDE; + QVariant handle() const override; protected: void cleanup(); - bool fetch(int i) Q_DECL_OVERRIDE; - bool fetchNext() Q_DECL_OVERRIDE; - bool fetchLast() Q_DECL_OVERRIDE; - bool fetchFirst() Q_DECL_OVERRIDE; - QVariant data(int field) Q_DECL_OVERRIDE; - bool isNull(int field) Q_DECL_OVERRIDE; - bool reset (const QString& query) Q_DECL_OVERRIDE; - int size() Q_DECL_OVERRIDE; - int numRowsAffected() Q_DECL_OVERRIDE; - QVariant lastInsertId() const Q_DECL_OVERRIDE; - QSqlRecord record() const Q_DECL_OVERRIDE; - void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; - bool nextResult() Q_DECL_OVERRIDE; + bool fetch(int i) override; + bool fetchNext() override; + bool fetchLast() override; + bool fetchFirst() override; + QVariant data(int field) override; + bool isNull(int field) override; + bool reset (const QString& query) override; + int size() override; + int numRowsAffected() override; + QVariant lastInsertId() const override; + QSqlRecord record() const override; + void virtual_hook(int id, void *data) override; + bool nextResult() override; #if MYSQL_VERSION_ID >= 40108 - bool prepare(const QString &stmt) Q_DECL_OVERRIDE; - bool exec() Q_DECL_OVERRIDE; + bool prepare(const QString &stmt) override; + bool exec() override; #endif }; @@ -269,7 +269,7 @@ static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, const char *cerr = p->mysql ? mysql_error(p->mysql) : 0; return QSqlError(QLatin1String("QMYSQL: ") + err, p->tc ? toUnicode(p->tc, cerr) : QString::fromLatin1(cerr), - type, mysql_errno(p->mysql)); + type, QString::number(mysql_errno(p->mysql))); } @@ -349,7 +349,7 @@ static QSqlError qMakeStmtError(const QString& err, QSqlError::ErrorType type, const char *cerr = mysql_stmt_error(stmt); return QSqlError(QLatin1String("QMYSQL3: ") + err, QString::fromLatin1(cerr), - type, mysql_stmt_errno(stmt)); + type, QString::number(mysql_stmt_errno(stmt))); } static bool qIsBlob(int t) diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql_p.h b/src/plugins/sqldrivers/mysql/qsql_mysql_p.h index 7641f9aa34..48b04fb1f5 100644 --- a/src/plugins/sqldrivers/mysql/qsql_mysql_p.h +++ b/src/plugins/sqldrivers/mysql/qsql_mysql_p.h @@ -78,29 +78,29 @@ public: explicit QMYSQLDriver(QObject *parent=0); explicit QMYSQLDriver(MYSQL *con, QObject * parent=0); ~QMYSQLDriver(); - bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE; + bool hasFeature(DriverFeature f) const override; bool open(const QString & db, const QString & user, const QString & password, const QString & host, int port, - const QString& connOpts) Q_DECL_OVERRIDE; - void close() Q_DECL_OVERRIDE; - QSqlResult *createResult() const Q_DECL_OVERRIDE; - QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE; - QSqlIndex primaryIndex(const QString& tablename) const Q_DECL_OVERRIDE; - QSqlRecord record(const QString& tablename) const Q_DECL_OVERRIDE; + const QString& connOpts) override; + void close() override; + QSqlResult *createResult() const override; + QStringList tables(QSql::TableType) const override; + QSqlIndex primaryIndex(const QString& tablename) const override; + QSqlRecord record(const QString& tablename) const override; QString formatValue(const QSqlField &field, - bool trimStrings) const Q_DECL_OVERRIDE; - QVariant handle() const Q_DECL_OVERRIDE; - QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE; + bool trimStrings) const override; + QVariant handle() const override; + QString escapeIdentifier(const QString &identifier, IdentifierType type) const override; - bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE; + bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const override; protected: - bool beginTransaction() Q_DECL_OVERRIDE; - bool commitTransaction() Q_DECL_OVERRIDE; - bool rollbackTransaction() Q_DECL_OVERRIDE; + bool beginTransaction() override; + bool commitTransaction() override; + bool rollbackTransaction() override; private: void init(); }; diff --git a/src/plugins/sqldrivers/oci/qsql_oci.cpp b/src/plugins/sqldrivers/oci/qsql_oci.cpp index 9ce2fc1b55..272e1bc083 100644 --- a/src/plugins/sqldrivers/oci/qsql_oci.cpp +++ b/src/plugins/sqldrivers/oci/qsql_oci.cpp @@ -55,6 +55,7 @@ #include <qvarlengtharray.h> #include <qvector.h> #include <qdebug.h> +#include <qtimezone.h> // This is needed for oracle oci when compiling with mingw-w64 headers #if defined(__MINGW64_VERSION_MAJOR) && defined(_WIN64) @@ -112,9 +113,6 @@ static const ub2 qOraCharset = OCI_UCS2ID; typedef QVarLengthArray<sb2, 32> IndicatorArray; typedef QVarLengthArray<ub2, 32> SizeArray; -static QByteArray qMakeOraDate(const QDateTime& dt); -static QDateTime qMakeDate(const char* oraDate); - static QByteArray qMakeOCINumber(const qlonglong &ll, OCIError *err); static QByteArray qMakeOCINumber(const qulonglong& ull, OCIError* err); @@ -156,6 +154,60 @@ QOCIRowId::~QOCIRowId() OCIDescriptorFree(id, OCI_DTYPE_ROWID); } +class QOCIDateTime +{ +public: + QOCIDateTime(OCIEnv *env, OCIError *err, const QDateTime &dt = QDateTime()); + ~QOCIDateTime(); + OCIDateTime *dateTime; + static QDateTime fromOCIDateTime(OCIEnv *env, OCIError *err, OCIDateTime *dt); +}; + +QOCIDateTime::QOCIDateTime(OCIEnv *env, OCIError *err, const QDateTime &dt) + : dateTime(nullptr) +{ + OCIDescriptorAlloc(env, reinterpret_cast<void**>(&dateTime), OCI_DTYPE_TIMESTAMP_TZ, 0, 0); + if (dt.isValid()) { + const QDate date = dt.date(); + const QTime time = dt.time(); + // Zone in +hh:mm format (stripping UTC prefix from OffsetName) + QString timeZone = dt.timeZone().displayName(dt, QTimeZone::OffsetName).mid(3); + const OraText *tz = reinterpret_cast<const OraText *>(timeZone.utf16()); + OCIDateTimeConstruct(env, err, dateTime, date.year(), date.month(), date.day(), time.hour(), + time.minute(), time.second(), time.msec() * 1000000, + const_cast<OraText *>(tz), timeZone.length() * sizeof(QChar)); + } +} + +QOCIDateTime::~QOCIDateTime() +{ + if (dateTime != nullptr) + OCIDescriptorFree(dateTime, OCI_DTYPE_TIMESTAMP_TZ); +} + +QDateTime QOCIDateTime::fromOCIDateTime(OCIEnv *env, OCIError *err, OCIDateTime *dateTime) +{ + sb2 year; + ub1 month, day, hour, minute, second; + ub4 nsec; + sb1 tzHour, tzMinute; + + OCIDateTimeGetDate(env, err, dateTime, &year, &month, &day); + OCIDateTimeGetTime(env, err, dateTime, &hour, &minute, &second, &nsec); + OCIDateTimeGetTimeZoneOffset(env, err, dateTime, &tzHour, &tzMinute); + int secondsOffset = (qAbs(tzHour) * 60 + tzMinute) * 60; + if (tzHour < 0) + secondsOffset = -secondsOffset; + // OCIDateTimeGetTime gives "fractions of second" as nanoseconds + return QDateTime(QDate(year, month, day), QTime(hour, minute, second, nsec / 1000000), + Qt::OffsetFromUTC, secondsOffset); +} + +struct TempStorage { + QList<QByteArray> rawData; + QList<QOCIDateTime *> dateTimes; +}; + typedef QSharedDataPointer<QOCIRowId> QOCIRowIdPointer; QT_BEGIN_INCLUDE_NAMESPACE Q_DECLARE_METATYPE(QOCIRowIdPointer) @@ -193,19 +245,19 @@ class QOCIResult: public QSqlCachedResult public: QOCIResult(const QOCIDriver *db); ~QOCIResult(); - bool prepare(const QString &query) Q_DECL_OVERRIDE; - bool exec() Q_DECL_OVERRIDE; - QVariant handle() const Q_DECL_OVERRIDE; + bool prepare(const QString &query) override; + bool exec() override; + QVariant handle() const override; protected: - bool gotoNext(ValueCache &values, int index) Q_DECL_OVERRIDE; - bool reset(const QString &query) Q_DECL_OVERRIDE; - int size() Q_DECL_OVERRIDE; - int numRowsAffected() Q_DECL_OVERRIDE; - QSqlRecord record() const Q_DECL_OVERRIDE; - QVariant lastInsertId() const Q_DECL_OVERRIDE; - bool execBatch(bool arrayBind = false) Q_DECL_OVERRIDE; - void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; + bool gotoNext(ValueCache &values, int index) override; + bool reset(const QString &query) override; + int size() override; + int numRowsAffected() override; + QSqlRecord record() const override; + QVariant lastInsertId() const override; + bool execBatch(bool arrayBind = false) override; + void virtual_hook(int id, void *data) override; bool fetchNext() override; }; @@ -228,11 +280,11 @@ public: void setStatementAttributes(); int bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos, - const QVariant &val, dvoid *indPtr, ub2 *tmpSize, QList<QByteArray> &tmpStorage); + const QVariant &val, dvoid *indPtr, ub2 *tmpSize, TempStorage &tmpStorage); int bindValues(QVector<QVariant> &values, IndicatorArray &indicators, SizeArray &tmpSizes, - QList<QByteArray> &tmpStorage); + TempStorage &tmpStorage); void outValues(QVector<QVariant> &values, IndicatorArray &indicators, - QList<QByteArray> &tmpStorage); + TempStorage &tmpStorage); inline bool isOutValue(int i) const { Q_Q(const QOCIResult); return q->bindValueType(i) & QSql::Out; } inline bool isBinaryValue(int i) const @@ -305,7 +357,7 @@ void QOCIResultPrivate::setStatementAttributes() } int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos, - const QVariant &val, dvoid *indPtr, ub2 *tmpSize, QList<QByteArray> &tmpStorage) + const QVariant &val, dvoid *indPtr, ub2 *tmpSize, TempStorage &tmpStorage) { int r = OCI_SUCCESS; void *data = const_cast<void *>(val.constData()); @@ -323,14 +375,15 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in case QVariant::Time: case QVariant::Date: case QVariant::DateTime: { - QByteArray ba = qMakeOraDate(val.toDateTime()); + QOCIDateTime *ptr = new QOCIDateTime(env, err, val.toDateTime()); r = OCIBindByPos(sql, hbnd, err, pos + 1, - ba.data(), - ba.size(), - SQLT_DAT, indPtr, 0, 0, 0, 0, OCI_DEFAULT); - tmpStorage.append(ba); - break; } + &ptr->dateTime, + sizeof(OCIDateTime *), + SQLT_TIMESTAMP_TZ, indPtr, 0, 0, 0, 0, OCI_DEFAULT); + tmpStorage.dateTimes.append(ptr); + break; + } case QVariant::Int: r = OCIBindByPos(sql, hbnd, err, pos + 1, @@ -357,7 +410,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in ba.data(), ba.size(), SQLT_VNU, indPtr, 0, 0, 0, 0, OCI_DEFAULT); - tmpStorage.append(ba); + tmpStorage.rawData.append(ba); break; } case QVariant::ULongLong: @@ -368,7 +421,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in ba.data(), ba.size(), SQLT_VNU, indPtr, 0, 0, 0, 0, OCI_DEFAULT); - tmpStorage.append(ba); + tmpStorage.rawData.append(ba); break; } case QVariant::Double: @@ -438,7 +491,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in } if (r == OCI_SUCCESS) setCharset(*hbnd, OCI_HTYPE_BIND); - tmpStorage.append(ba); + tmpStorage.rawData.append(ba); break; } // default case } // switch @@ -448,7 +501,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in } int QOCIResultPrivate::bindValues(QVector<QVariant> &values, IndicatorArray &indicators, - SizeArray &tmpSizes, QList<QByteArray> &tmpStorage) + SizeArray &tmpSizes, TempStorage &tmpStorage) { int r = OCI_SUCCESS; for (int i = 0; i < values.count(); ++i) { @@ -466,27 +519,30 @@ int QOCIResultPrivate::bindValues(QVector<QVariant> &values, IndicatorArray &ind } // will assign out value and remove its temp storage. -static void qOraOutValue(QVariant &value, QList<QByteArray> &storage, OCIError* err) +static void qOraOutValue(QVariant &value, TempStorage &tmpStorage, OCIEnv *env, OCIError* err) { switch (value.type()) { case QVariant::Time: - value = qMakeDate(storage.takeFirst()).time(); + value = QOCIDateTime::fromOCIDateTime(env, err, + tmpStorage.dateTimes.takeFirst()->dateTime).time(); break; case QVariant::Date: - value = qMakeDate(storage.takeFirst()).date(); + value = QOCIDateTime::fromOCIDateTime(env, err, + tmpStorage.dateTimes.takeFirst()->dateTime).date(); break; case QVariant::DateTime: - value = qMakeDate(storage.takeFirst()); + value = QOCIDateTime::fromOCIDateTime(env, err, + tmpStorage.dateTimes.takeFirst()->dateTime); break; case QVariant::LongLong: - value = qMakeLongLong(storage.takeFirst(), err); + value = qMakeLongLong(tmpStorage.rawData.takeFirst(), err); break; case QVariant::ULongLong: - value = qMakeULongLong(storage.takeFirst(), err); + value = qMakeULongLong(tmpStorage.rawData.takeFirst(), err); break; case QVariant::String: value = QString( - reinterpret_cast<const QChar *>(storage.takeFirst().constData())); + reinterpret_cast<const QChar *>(tmpStorage.rawData.takeFirst().constData())); break; default: break; //nothing @@ -494,14 +550,14 @@ static void qOraOutValue(QVariant &value, QList<QByteArray> &storage, OCIError* } void QOCIResultPrivate::outValues(QVector<QVariant> &values, IndicatorArray &indicators, - QList<QByteArray> &tmpStorage) + TempStorage &tmpStorage) { for (int i = 0; i < values.count(); ++i) { if (!isOutValue(i)) continue; - qOraOutValue(values[i], tmpStorage, err); + qOraOutValue(values[i], tmpStorage, env, err); QVariant::Type typ = values.at(i).type(); if (indicators[i] == -1) // NULL @@ -588,7 +644,8 @@ QSqlError qMakeError(const QString& errString, QSqlError::ErrorType type, OCIErr { int errorCode = 0; const QString oraErrorString = qOraWarn(err, &errorCode); - return QSqlError(errString, oraErrorString, type, errorCode); + return QSqlError(errString, oraErrorString, type, + errorCode != -1 ? QString::number(errorCode) : QString()); } QVariant::Type qDecodeOCIType(const QString& ocitype, QSql::NumericalPrecisionPolicy precisionPolicy) @@ -693,11 +750,9 @@ QVariant::Type qDecodeOCIType(int ocitype, QSql::NumericalPrecisionPolicy precis break; case SQLT_DAT: case SQLT_ODT: -#ifdef SQLT_TIMESTAMP case SQLT_TIMESTAMP: case SQLT_TIMESTAMP_TZ: case SQLT_TIMESTAMP_LTZ: -#endif type = QVariant::DateTime; break; default: @@ -724,27 +779,6 @@ static QSqlField qFromOraInf(const OraFieldInfo &ofi) } /*! - \internal - - Convert QDateTime to the internal Oracle DATE format NB! - It does not handle BCE dates. -*/ -QByteArray qMakeOraDate(const QDateTime& dt) -{ - QByteArray ba; - ba.resize(7); - int year = dt.date().year(); - ba[0]= (year / 100) + 100; // century - ba[1]= (year % 100) + 100; // year - ba[2]= dt.date().month(); - ba[3]= dt.date().day(); - ba[4]= dt.time().hour() + 1; - ba[5]= dt.time().minute() + 1; - ba[6]= dt.time().second() + 1; - return ba; -} - -/*! \internal Convert qlonglong to the internal Oracle OCINumber format. @@ -794,22 +828,6 @@ qulonglong qMakeULongLong(const char* ociNumber, OCIError* err) return qull; } -QDateTime qMakeDate(const char* oraDate) -{ - int century = uchar(oraDate[0]); - if(century >= 100){ - int year = uchar(oraDate[1]); - year = ((century-100)*100) + (year-100); - int month = oraDate[2]; - int day = oraDate[3]; - int hour = oraDate[4] - 1; - int min = oraDate[5] - 1; - int sec = oraDate[6] - 1; - return QDateTime(QDate(year,month,day), QTime(hour,min,sec)); - } - return QDateTime(); -} - class QOCICols { public: @@ -832,7 +850,7 @@ private: class OraFieldInf { public: - OraFieldInf(): data(0), len(0), ind(0), typ(QVariant::Invalid), oraType(0), def(0), lob(0) + OraFieldInf() : data(0), len(0), ind(0), typ(QVariant::Invalid), oraType(0), def(0), lob(0), dataPtr(nullptr) {} ~OraFieldInf(); char *data; @@ -842,6 +860,7 @@ private: ub4 oraType; OCIDefine *def; OCILobLocator *lob; + void *dataPtr; }; QVector<OraFieldInf> fieldInf; @@ -856,6 +875,20 @@ QOCICols::OraFieldInf::~OraFieldInf() if (r != 0) qWarning("QOCICols: Cannot free LOB descriptor"); } + if (dataPtr) { + switch (typ) { + case QVariant::Date: + case QVariant::Time: + case QVariant::DateTime: { + int r = OCIDescriptorFree(dataPtr, OCI_DTYPE_TIMESTAMP_TZ); + if (r != OCI_SUCCESS) + qWarning("QOCICols: Cannot free OCIDateTime descriptor"); + break; + } + default: + break; + } + } } QOCICols::QOCICols(int size, QOCIResultPrivate* dp) @@ -902,13 +935,18 @@ QOCICols::QOCICols(int size, QOCIResultPrivate* dp) switch (ofi.type) { case QVariant::DateTime: + r = OCIDescriptorAlloc(d->env, (void **)&fieldInf[idx].dataPtr, OCI_DTYPE_TIMESTAMP_TZ, 0, 0); + if (r != OCI_SUCCESS) { + qWarning("QOCICols: Unable to allocate the OCIDateTime descriptor"); + break; + } r = OCIDefineByPos(d->sql, &dfn, d->err, count, - create(idx, dataSize+1), - dataSize+1, - SQLT_DAT, + &fieldInf[idx].dataPtr, + sizeof(OCIDateTime *), + SQLT_TIMESTAMP_TZ, &(fieldInf[idx].ind), 0, 0, OCI_DEFAULT); break; @@ -1323,11 +1361,10 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b fieldTypes.append(tp == QVariant::List ? boundValues.at(i).toList().value(0).type() : tp); } - - QList<QByteArray> tmpStorage; SizeArray tmpSizes(columnCount); QVector<QOCIBatchColumn> columns(columnCount); QOCIBatchCleanupHandler cleaner(columns); + TempStorage tmpStorage; // figuring out buffer sizes for (i = 0; i < columnCount; ++i) { @@ -1364,8 +1401,8 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b case QVariant::Time: case QVariant::Date: case QVariant::DateTime: - col.bindAs = SQLT_DAT; - col.maxLen = 7; + col.bindAs = SQLT_TIMESTAMP_TZ; + col.maxLen = sizeof(OCIDateTime *); break; case QVariant::Int: @@ -1433,7 +1470,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b for (uint row = 0; row < col.recordCount; ++row) { const QVariant &val = boundValues.at(i).toList().at(row); - if (val.isNull()){ + if (val.isNull() && !d->isOutValue(i)) { columns[i].indicators[row] = -1; columns[i].lengths[row] = 0; } else { @@ -1444,9 +1481,8 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b case QVariant::Date: case QVariant::DateTime:{ columns[i].lengths[row] = columns[i].maxLen; - const QByteArray ba = qMakeOraDate(val.toDateTime()); - Q_ASSERT(ba.size() == int(columns[i].maxLen)); - memcpy(dataPtr, ba.constData(), columns[i].maxLen); + QOCIDateTime *date = new QOCIDateTime(d->env, d->err, val.toDateTime()); + *reinterpret_cast<OCIDateTime**>(dataPtr) = date->dateTime; break; } case QVariant::Int: @@ -1582,7 +1618,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b QVariant::Type tp = boundValues.at(i).type(); if (tp != QVariant::List) { - qOraOutValue(boundValues[i], tmpStorage, d->err); + qOraOutValue(boundValues[i], tmpStorage, d->env, d->err); if (*columns[i].indicators == -1) boundValues[i] = QVariant(tp); continue; @@ -1594,16 +1630,16 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b for (uint r = 0; r < columns[i].recordCount; ++r){ if (columns[i].indicators[r] == -1) { - (*list)[r] = QVariant(); + (*list)[r] = QVariant(fieldTypes[i]); continue; } switch(columns[i].bindAs) { - case SQLT_DAT: - (*list)[r] = qMakeDate(data + r * columns[i].maxLen); + case SQLT_TIMESTAMP_TZ: + (*list)[r] = QOCIDateTime::fromOCIDateTime(d->env, d->err, + *reinterpret_cast<OCIDateTime **>(data + r * columns[i].maxLen)); break; - case SQLT_INT: (*list)[r] = *reinterpret_cast<int*>(data + r * columns[i].maxLen); break; @@ -1647,6 +1683,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector<QVariant> &boundValues, b d->q_func()->setAt(QSql::BeforeFirstRow); d->q_func()->setActive(true); + qDeleteAll(tmpStorage.dateTimes); return true; } @@ -1755,7 +1792,8 @@ void QOCICols::getValues(QVector<QVariant> &v, int index) switch (fld.typ) { case QVariant::DateTime: - v[index + i] = QVariant(qMakeDate(fld.data)); + v[index + i] = QVariant(QOCIDateTime::fromOCIDateTime(d->env, d->err, + reinterpret_cast<OCIDateTime *>(fld.dataPtr))); break; case QVariant::Double: case QVariant::Int: @@ -1985,7 +2023,7 @@ bool QOCIResult::exec() ub2 stmtType=0; ub4 iters; ub4 mode; - QList<QByteArray> tmpStorage; + TempStorage tmpStorage; IndicatorArray indicators(boundValueCount()); SizeArray tmpSizes(boundValueCount()); @@ -2056,7 +2094,7 @@ bool QOCIResult::exec() if (hasOutValues()) d->outValues(boundValues(), indicators, tmpStorage); - + qDeleteAll(tmpStorage.dateTimes); return true; } diff --git a/src/plugins/sqldrivers/oci/qsql_oci_p.h b/src/plugins/sqldrivers/oci/qsql_oci_p.h index 69911f4bee..295c131f1a 100644 --- a/src/plugins/sqldrivers/oci/qsql_oci_p.h +++ b/src/plugins/sqldrivers/oci/qsql_oci_p.h @@ -84,21 +84,21 @@ public: const QString &password, const QString &host, int port, - const QString &connOpts) Q_DECL_OVERRIDE; - void close() Q_DECL_OVERRIDE; - QSqlResult *createResult() const Q_DECL_OVERRIDE; - QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE; - QSqlRecord record(const QString &tablename) const Q_DECL_OVERRIDE; - QSqlIndex primaryIndex(const QString& tablename) const Q_DECL_OVERRIDE; + const QString &connOpts) override; + void close() override; + QSqlResult *createResult() const override; + QStringList tables(QSql::TableType) const override; + QSqlRecord record(const QString &tablename) const override; + QSqlIndex primaryIndex(const QString& tablename) const override; QString formatValue(const QSqlField &field, - bool trimStrings) const Q_DECL_OVERRIDE; - QVariant handle() const Q_DECL_OVERRIDE; - QString escapeIdentifier(const QString &identifier, IdentifierType) const Q_DECL_OVERRIDE; + bool trimStrings) const override; + QVariant handle() const override; + QString escapeIdentifier(const QString &identifier, IdentifierType) const override; protected: - bool beginTransaction() Q_DECL_OVERRIDE; - bool commitTransaction() Q_DECL_OVERRIDE; - bool rollbackTransaction() Q_DECL_OVERRIDE; + bool beginTransaction() override; + bool commitTransaction() override; + bool rollbackTransaction() override; }; QT_END_NAMESPACE diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp index c32a29c5e7..547eb2043d 100644 --- a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp +++ b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp @@ -163,27 +163,27 @@ public: QODBCResult(const QODBCDriver *db); virtual ~QODBCResult(); - bool prepare(const QString &query) Q_DECL_OVERRIDE; - bool exec() Q_DECL_OVERRIDE; + bool prepare(const QString &query) override; + bool exec() override; - QVariant lastInsertId() const Q_DECL_OVERRIDE; - QVariant handle() const Q_DECL_OVERRIDE; + QVariant lastInsertId() const override; + QVariant handle() const override; protected: - bool fetchNext() Q_DECL_OVERRIDE; - bool fetchFirst() Q_DECL_OVERRIDE; - bool fetchLast() Q_DECL_OVERRIDE; - bool fetchPrevious() Q_DECL_OVERRIDE; - bool fetch(int i) Q_DECL_OVERRIDE; - bool reset(const QString &query) Q_DECL_OVERRIDE; - QVariant data(int field) Q_DECL_OVERRIDE; - bool isNull(int field) Q_DECL_OVERRIDE; - int size() Q_DECL_OVERRIDE; - int numRowsAffected() Q_DECL_OVERRIDE; - QSqlRecord record() const Q_DECL_OVERRIDE; - void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; - void detachFromResultSet() Q_DECL_OVERRIDE; - bool nextResult() Q_DECL_OVERRIDE; + bool fetchNext() override; + bool fetchFirst() override; + bool fetchLast() override; + bool fetchPrevious() override; + bool fetch(int i) override; + bool reset(const QString &query) override; + QVariant data(int field) override; + bool isNull(int field) override; + int size() override; + int numRowsAffected() override; + QSqlRecord record() const override; + void virtual_hook(int id, void *data) override; + void detachFromResultSet() override; + bool nextResult() override; }; class QODBCResultPrivate: public QSqlResultPrivate @@ -335,7 +335,8 @@ static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, const { int nativeCode = -1; QString message = qODBCWarn(p, &nativeCode); - return QSqlError(QLatin1String("QODBC3: ") + err, message, type, nativeCode); + return QSqlError(QLatin1String("QODBC3: ") + err, message, type, + nativeCode != -1 ? QString::number(nativeCode) : QString()); } static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, @@ -343,7 +344,8 @@ static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, { int nativeCode = -1; QString message = qODBCWarn(p, &nativeCode); - return QSqlError(QLatin1String("QODBC3: ") + err, qODBCWarn(p), type, nativeCode); + return QSqlError(QLatin1String("QODBC3: ") + err, qODBCWarn(p), type, + nativeCode != -1 ? QString::number(nativeCode) : QString()); } static QVariant::Type qDecodeODBCType(SQLSMALLINT sqltype, bool isSigned = true) diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc_p.h b/src/plugins/sqldrivers/odbc/qsql_odbc_p.h index f4ce8bc243..ea0aa6fc8b 100644 --- a/src/plugins/sqldrivers/odbc/qsql_odbc_p.h +++ b/src/plugins/sqldrivers/odbc/qsql_odbc_p.h @@ -92,30 +92,30 @@ public: explicit QODBCDriver(QObject *parent=0); QODBCDriver(SQLHANDLE env, SQLHANDLE con, QObject * parent=0); virtual ~QODBCDriver(); - bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE; - void close() Q_DECL_OVERRIDE; - QSqlResult *createResult() const Q_DECL_OVERRIDE; - QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE; - QSqlRecord record(const QString &tablename) const Q_DECL_OVERRIDE; - QSqlIndex primaryIndex(const QString &tablename) const Q_DECL_OVERRIDE; - QVariant handle() const Q_DECL_OVERRIDE; + bool hasFeature(DriverFeature f) const override; + void close() override; + QSqlResult *createResult() const override; + QStringList tables(QSql::TableType) const override; + QSqlRecord record(const QString &tablename) const override; + QSqlIndex primaryIndex(const QString &tablename) const override; + QVariant handle() const override; QString formatValue(const QSqlField &field, - bool trimStrings) const Q_DECL_OVERRIDE; + bool trimStrings) const override; bool open(const QString &db, const QString &user, const QString &password, const QString &host, int port, - const QString &connOpts) Q_DECL_OVERRIDE; + const QString &connOpts) override; - QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE; + QString escapeIdentifier(const QString &identifier, IdentifierType type) const override; - bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE; + bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const override; protected: - bool beginTransaction() Q_DECL_OVERRIDE; - bool commitTransaction() Q_DECL_OVERRIDE; - bool rollbackTransaction() Q_DECL_OVERRIDE; + bool beginTransaction() override; + bool commitTransaction() override; + bool rollbackTransaction() override; private: bool endTrans(); diff --git a/src/plugins/sqldrivers/psql/main.cpp b/src/plugins/sqldrivers/psql/main.cpp index 7657fcbfdf..c5d546f6ff 100644 --- a/src/plugins/sqldrivers/psql/main.cpp +++ b/src/plugins/sqldrivers/psql/main.cpp @@ -51,7 +51,7 @@ class QPSQLDriverPlugin : public QSqlDriverPlugin public: QPSQLDriverPlugin(); - QSqlDriver* create(const QString &) Q_DECL_OVERRIDE; + QSqlDriver* create(const QString &) override; }; QPSQLDriverPlugin::QPSQLDriverPlugin() diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index 35b0f9a3e3..6f105f79ca 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -125,6 +125,14 @@ inline void qPQfreemem(void *buffer) PQfreemem(buffer); } +/* Missing declaration of PGRES_SINGLE_TUPLE for PSQL below 9.2 */ +#if !defined PG_VERSION_NUM || PG_VERSION_NUM-0 < 90200 +static const int PGRES_SINGLE_TUPLE = 9; +#endif + +typedef int StatementId; +static const StatementId InvalidStatementId = 0; + class QPSQLResultPrivate; class QPSQLResult: public QSqlResult @@ -135,23 +143,25 @@ public: QPSQLResult(const QPSQLDriver *db); ~QPSQLResult(); - QVariant handle() const Q_DECL_OVERRIDE; - void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; + QVariant handle() const override; + void virtual_hook(int id, void *data) override; protected: void cleanup(); - bool fetch(int i) Q_DECL_OVERRIDE; - bool fetchFirst() Q_DECL_OVERRIDE; - bool fetchLast() Q_DECL_OVERRIDE; - QVariant data(int i) Q_DECL_OVERRIDE; - bool isNull(int field) Q_DECL_OVERRIDE; - bool reset (const QString &query) Q_DECL_OVERRIDE; - int size() Q_DECL_OVERRIDE; - int numRowsAffected() Q_DECL_OVERRIDE; - QSqlRecord record() const Q_DECL_OVERRIDE; - QVariant lastInsertId() const Q_DECL_OVERRIDE; - bool prepare(const QString &query) Q_DECL_OVERRIDE; - bool exec() Q_DECL_OVERRIDE; + bool fetch(int i) override; + bool fetchFirst() override; + bool fetchLast() override; + bool fetchNext() override; + bool nextResult() override; + QVariant data(int i) override; + bool isNull(int field) override; + bool reset (const QString &query) override; + int size() override; + int numRowsAffected() override; + QSqlRecord record() const override; + QVariant lastInsertId() const override; + bool prepare(const QString &query) override; + bool exec() override; }; class QPSQLDriverPrivate : public QSqlDriverPrivate @@ -164,7 +174,9 @@ public: pro(QPSQLDriver::Version6), sn(0), pendingNotifyCheck(false), - hasBackslashEscape(false) + hasBackslashEscape(false), + stmtCount(0), + currentStmtId(InvalidStatementId) { dbmsType = QSqlDriver::PostgreSQL; } PGconn *connection; @@ -174,10 +186,19 @@ public: QStringList seid; mutable bool pendingNotifyCheck; bool hasBackslashEscape; + int stmtCount; + StatementId currentStmtId; void appendTables(QStringList &tl, QSqlQuery &t, QChar type); - PGresult * exec(const char * stmt) const; - PGresult * exec(const QString & stmt) const; + PGresult *exec(const char *stmt); + PGresult *exec(const QString &stmt); + StatementId sendQuery(const QString &stmt); + bool setSingleRowMode() const; + PGresult *getResult(StatementId stmtId) const; + void finishQuery(StatementId stmtId); + void discardResults() const; + StatementId generateStatementId(); + void checkPendingNotifications() const; QPSQLDriver::Protocol getPSQLVersion(); bool setEncodingUtf8(); void setDatestyle(); @@ -187,18 +208,11 @@ public: void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type) { - QString query; - if (pro >= QPSQLDriver::Version7_3) { - 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); - } else { - query = QString::fromLatin1("select relname, null from pg_class where (relkind = '%1') " - "and (relname !~ '^Inv') " - "and (relname !~ '^pg_') ").arg(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); t.exec(query); while (t.next()) { QString schema = t.value(1).toString(); @@ -209,20 +223,89 @@ void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type) } } -PGresult * QPSQLDriverPrivate::exec(const char * stmt) const +PGresult *QPSQLDriverPrivate::exec(const char *stmt) { - Q_Q(const QPSQLDriver); + // PQexec() silently discards any prior query results that the application didn't eat. PGresult *result = PQexec(connection, stmt); - if (seid.size() && !pendingNotifyCheck) { - pendingNotifyCheck = true; - QMetaObject::invokeMethod(const_cast<QPSQLDriver*>(q), "_q_handleNotification", Qt::QueuedConnection, Q_ARG(int,0)); + currentStmtId = result ? generateStatementId() : InvalidStatementId; + checkPendingNotifications(); + return result; +} + +PGresult *QPSQLDriverPrivate::exec(const QString &stmt) +{ + return exec((isUtf8 ? stmt.toUtf8() : stmt.toLocal8Bit()).constData()); +} + +StatementId QPSQLDriverPrivate::sendQuery(const QString &stmt) +{ + // Discard any prior query results that the application didn't eat. + // This is required for PQsendQuery() + discardResults(); + const int result = PQsendQuery(connection, + (isUtf8 ? stmt.toUtf8() : stmt.toLocal8Bit()).constData()); + currentStmtId = result ? generateStatementId() : InvalidStatementId; + return currentStmtId; +} + +bool QPSQLDriverPrivate::setSingleRowMode() const +{ + // Activates single-row mode for last sent query, see: + // https://www.postgresql.org/docs/9.2/static/libpq-single-row-mode.html + // This method should be called immediately after the sendQuery() call. +#if defined PG_VERSION_NUM && PG_VERSION_NUM-0 >= 90200 + return PQsetSingleRowMode(connection) > 0; +#else + return false; +#endif +} + +PGresult *QPSQLDriverPrivate::getResult(StatementId stmtId) const +{ + // Make sure the results of stmtId weren't discaded. This might + // happen for forward-only queries if somebody executed another + // SQL query on the same db connection. + if (stmtId != currentStmtId) { + // If you change the following warning, remember to update it + // on sql-driver.html page too. + qWarning("QPSQLDriver::getResult: Query results lost - " + "probably discarded on executing another SQL query."); + return nullptr; } + PGresult *result = PQgetResult(connection); + checkPendingNotifications(); return result; } -PGresult * QPSQLDriverPrivate::exec(const QString & stmt) const +void QPSQLDriverPrivate::finishQuery(StatementId stmtId) +{ + if (stmtId != InvalidStatementId && stmtId == currentStmtId) { + discardResults(); + currentStmtId = InvalidStatementId; + } +} + +void QPSQLDriverPrivate::discardResults() const +{ + while (PGresult *result = PQgetResult(connection)) + PQclear(result); +} + +StatementId QPSQLDriverPrivate::generateStatementId() { - return exec(isUtf8 ? stmt.toUtf8().constData() : stmt.toLocal8Bit().constData()); + int stmtId = ++stmtCount; + if (stmtId <= 0) + stmtId = stmtCount = 1; + return stmtId; +} + +void QPSQLDriverPrivate::checkPendingNotifications() const +{ + Q_Q(const QPSQLDriver); + if (seid.size() && !pendingNotifyCheck) { + pendingNotifyCheck = true; + QMetaObject::invokeMethod(const_cast<QPSQLDriver*>(q), "_q_handleNotification", Qt::QueuedConnection, Q_ARG(int,0)); + } } class QPSQLResultPrivate : public QSqlResultPrivate @@ -234,14 +317,19 @@ public: : QSqlResultPrivate(q, drv), result(0), currentSize(-1), + canFetchMoreRows(false), + stmtId(InvalidStatementId), preparedQueriesEnabled(false) { } - QString fieldSerial(int i) const Q_DECL_OVERRIDE { return QLatin1Char('$') + QString::number(i + 1); } + QString fieldSerial(int i) const override { return QLatin1Char('$') + QString::number(i + 1); } void deallocatePreparedStmt(); PGresult *result; + QList<PGresult*> nextResultSets; int currentSize; + bool canFetchMoreRows; + StatementId stmtId; bool preparedQueriesEnabled; QString preparedStmtId; @@ -264,21 +352,45 @@ static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, bool QPSQLResultPrivate::processResults() { Q_Q(QPSQLResult); - if (!result) + if (!result) { + q->setSelect(false); + q->setActive(false); + currentSize = -1; + canFetchMoreRows = false; + if (stmtId != drv_d_func()->currentStmtId) { + q->setLastError(qMakeError(QCoreApplication::translate("QPSQLResult", + "Query results lost - probably discarded on executing " + "another SQL query."), QSqlError::StatementError, drv_d_func(), result)); + } return false; - + } int status = PQresultStatus(result); - if (status == PGRES_TUPLES_OK) { + switch (status) { + case PGRES_TUPLES_OK: q->setSelect(true); q->setActive(true); - currentSize = PQntuples(result); + currentSize = q->isForwardOnly() ? -1 : PQntuples(result); + canFetchMoreRows = false; + return true; + case PGRES_SINGLE_TUPLE: + q->setSelect(true); + q->setActive(true); + currentSize = -1; + canFetchMoreRows = true; return true; - } else if (status == PGRES_COMMAND_OK) { + case PGRES_COMMAND_OK: q->setSelect(false); q->setActive(true); currentSize = -1; + canFetchMoreRows = false; return true; + default: + break; } + q->setSelect(false); + q->setActive(false); + currentSize = -1; + canFetchMoreRows = false; q->setLastError(qMakeError(QCoreApplication::translate("QPSQLResult", "Unable to create query"), QSqlError::StatementError, drv_d_func(), result)); return false; @@ -368,9 +480,15 @@ void QPSQLResult::cleanup() Q_D(QPSQLResult); if (d->result) PQclear(d->result); - d->result = 0; + d->result = nullptr; + while (!d->nextResultSets.isEmpty()) + PQclear(d->nextResultSets.takeFirst()); + if (d->stmtId != InvalidStatementId) + d->drv_d_func()->finishQuery(d->stmtId); + d->stmtId = InvalidStatementId; setAt(QSql::BeforeFirstRow); d->currentSize = -1; + d->canFetchMoreRows = false; setActive(false); } @@ -381,23 +499,150 @@ bool QPSQLResult::fetch(int i) return false; if (i < 0) return false; - if (i >= d->currentSize) - return false; if (at() == i) return true; + + if (isForwardOnly()) { + if (i < at()) + return false; + bool ok = true; + while (ok && i > at()) + ok = fetchNext(); + return ok; + } + + if (i >= d->currentSize) + return false; setAt(i); return true; } bool QPSQLResult::fetchFirst() { + Q_D(const QPSQLResult); + if (!isActive()) + return false; + if (at() == 0) + return true; + + if (isForwardOnly()) { + if (at() == QSql::BeforeFirstRow) { + // First result has been already fetched by exec() or + // nextResult(), just check it has at least one row. + if (d->result && PQntuples(d->result) > 0) { + setAt(0); + return true; + } + } + return false; + } + return fetch(0); } bool QPSQLResult::fetchLast() { Q_D(const QPSQLResult); - return fetch(PQntuples(d->result) - 1); + if (!isActive()) + return false; + + if (isForwardOnly()) { + // Cannot seek to last row in forwardOnly mode, so we have to use brute force + int i = at(); + if (i == QSql::AfterLastRow) + return false; + if (i == QSql::BeforeFirstRow) + i = 0; + while (fetchNext()) + ++i; + setAt(i); + return true; + } + + return fetch(d->currentSize - 1); +} + +bool QPSQLResult::fetchNext() +{ + Q_D(QPSQLResult); + if (!isActive()) + return false; + + const int currentRow = at(); // Small optimalization + if (currentRow == QSql::BeforeFirstRow) + return fetchFirst(); + if (currentRow == QSql::AfterLastRow) + return false; + + if (isForwardOnly()) { + if (!d->canFetchMoreRows) + return false; + PQclear(d->result); + d->result = d->drv_d_func()->getResult(d->stmtId); + if (!d->result) { + setLastError(qMakeError(QCoreApplication::translate("QPSQLResult", + "Unable to get result"), QSqlError::StatementError, d->drv_d_func(), d->result)); + d->canFetchMoreRows = false; + return false; + } + int status = PQresultStatus(d->result); + switch (status) { + case PGRES_SINGLE_TUPLE: + // Fetched next row of current result set + Q_ASSERT(PQntuples(d->result) == 1); + Q_ASSERT(d->canFetchMoreRows); + setAt(currentRow + 1); + return true; + case PGRES_TUPLES_OK: + // In single-row mode PGRES_TUPLES_OK means end of current result set + Q_ASSERT(PQntuples(d->result) == 0); + d->canFetchMoreRows = false; + return false; + default: + setLastError(qMakeError(QCoreApplication::translate("QPSQLResult", + "Unable to get result"), QSqlError::StatementError, d->drv_d_func(), d->result)); + d->canFetchMoreRows = false; + return false; + } + } + + if (currentRow + 1 >= d->currentSize) + return false; + setAt(currentRow + 1); + return true; +} + +bool QPSQLResult::nextResult() +{ + Q_D(QPSQLResult); + if (!isActive()) + return false; + + setAt(QSql::BeforeFirstRow); + + if (isForwardOnly()) { + if (d->canFetchMoreRows) { + // Skip all rows from current result set + while (d->result && PQresultStatus(d->result) == PGRES_SINGLE_TUPLE) { + PQclear(d->result); + d->result = d->drv_d_func()->getResult(d->stmtId); + } + d->canFetchMoreRows = false; + // Check for unexpected errors + if (d->result && PQresultStatus(d->result) == PGRES_FATAL_ERROR) + return d->processResults(); + } + // Fetch first result from next result set + if (d->result) + PQclear(d->result); + d->result = d->drv_d_func()->getResult(d->stmtId); + return d->processResults(); + } + + if (d->result) + PQclear(d->result); + d->result = d->nextResultSets.isEmpty() ? nullptr : d->nextResultSets.takeFirst(); + return d->processResults(); } QVariant QPSQLResult::data(int i) @@ -407,11 +652,12 @@ QVariant QPSQLResult::data(int i) qWarning("QPSQLResult::data: column %d out of range", i); return QVariant(); } + const int currentRow = isForwardOnly() ? 0 : at(); int ptype = PQftype(d->result, i); QVariant::Type type = qDecodePSQLType(ptype); - const char *val = PQgetvalue(d->result, at(), i); - if (PQgetisnull(d->result, at(), i)) + if (PQgetisnull(d->result, currentRow, i)) return QVariant(type); + const char *val = PQgetvalue(d->result, currentRow, i); switch (type) { case QVariant::Bool: return QVariant((bool)(val[0] == 't')); @@ -495,8 +741,8 @@ QVariant QPSQLResult::data(int i) bool QPSQLResult::isNull(int field) { Q_D(const QPSQLResult); - PQgetvalue(d->result, at(), field); - return PQgetisnull(d->result, at(), field); + const int currentRow = isForwardOnly() ? 0 : at(); + return PQgetisnull(d->result, currentRow, field); } bool QPSQLResult::reset (const QString& query) @@ -507,7 +753,23 @@ bool QPSQLResult::reset (const QString& query) return false; if (!driver()->isOpen() || driver()->isOpenError()) return false; - d->result = d->drv_d_func()->exec(query); + + d->stmtId = d->drv_d_func()->sendQuery(query); + if (d->stmtId == InvalidStatementId) { + setLastError(qMakeError(QCoreApplication::translate("QPSQLResult", + "Unable to send query"), QSqlError::StatementError, d->drv_d_func())); + return false; + } + + if (isForwardOnly()) + setForwardOnly(d->drv_d_func()->setSingleRowMode()); + + d->result = d->drv_d_func()->getResult(d->stmtId); + if (!isForwardOnly()) { + // Fetch all result sets right away + while (PGresult *nextResultSet = d->drv_d_func()->getResult(d->stmtId)) + d->nextResultSets.append(nextResultSet); + } return d->processResults(); } @@ -553,10 +815,17 @@ QSqlRecord QPSQLResult::record() const f.setName(QString::fromUtf8(PQfname(d->result, i))); else f.setName(QString::fromLocal8Bit(PQfname(d->result, i))); - QSqlQuery qry(driver()->createResult()); - if (qry.exec(QStringLiteral("SELECT relname FROM pg_class WHERE pg_class.oid = %1") - .arg(PQftable(d->result, i))) && qry.next()) { - f.setTableName(qry.value(0).toString()); + + // WARNING: We cannot execute any other SQL queries on + // the same db connection while forward-only mode is active + // (this would discard all results of forward-only query). + // So we just skip this... + if (!isForwardOnly()) { + QSqlQuery qry(driver()->createResult()); + if (qry.exec(QStringLiteral("SELECT relname FROM pg_class WHERE pg_class.oid = %1") + .arg(PQftable(d->result, i))) && qry.next()) { + f.setTableName(qry.value(0).toString()); + } } int ptype = PQftype(d->result, i); f.setType(qDecodePSQLType(ptype)); @@ -675,8 +944,22 @@ bool QPSQLResult::exec() else stmt = QString::fromLatin1("EXECUTE %1 (%2)").arg(d->preparedStmtId, params); - d->result = d->drv_d_func()->exec(stmt); + d->stmtId = d->drv_d_func()->sendQuery(stmt); + if (d->stmtId == InvalidStatementId) { + setLastError(qMakeError(QCoreApplication::translate("QPSQLResult", + "Unable to send query"), QSqlError::StatementError, d->drv_d_func())); + return false; + } + + if (isForwardOnly()) + setForwardOnly(d->drv_d_func()->setSingleRowMode()); + d->result = d->drv_d_func()->getResult(d->stmtId); + if (!isForwardOnly()) { + // Fetch all result sets right away + while (PGresult *nextResultSet = d->drv_d_func()->getResult(d->stmtId)) + d->nextResultSets.append(nextResultSet); + } return d->processResults(); } @@ -895,6 +1178,8 @@ bool QPSQLDriver::hasFeature(DriverFeature f) const case LastInsertId: case LowPrecisionNumbers: case EventNotifications: + case MultipleResultSets: + case BLOB: return true; case PreparedQueries: case PositionalPlaceholders: @@ -903,11 +1188,8 @@ bool QPSQLDriver::hasFeature(DriverFeature f) const case NamedPlaceholders: case SimpleLocking: case FinishQuery: - case MultipleResultSets: case CancelQuery: return false; - case BLOB: - return d->pro >= QPSQLDriver::Version7_1; case Unicode: return d->isUtf8; } @@ -1004,7 +1286,7 @@ QSqlResult *QPSQLDriver::createResult() const bool QPSQLDriver::beginTransaction() { - Q_D(const QPSQLDriver); + Q_D(QPSQLDriver); if (!isOpen()) { qWarning("QPSQLDriver::beginTransaction: Database not open"); return false; @@ -1101,12 +1383,10 @@ static void qSplitTableName(QString &tablename, QString &schema) QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const { - Q_D(const QPSQLDriver); QSqlIndex idx(tablename); if (!isOpen()) return idx; QSqlQuery i(createResult()); - QString stmt; QString tbl = tablename; QString schema; @@ -1122,42 +1402,20 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const else schema = std::move(schema).toLower(); - if (d->pro == QPSQLDriver::Version6) { - stmt = QLatin1String("select pg_att1.attname, int(pg_att1.atttypid), pg_cl.relname " - "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind " - "where pg_cl.relname = '%1_pkey' " - "and pg_cl.oid = pg_ind.indexrelid " - "and pg_att2.attrelid = pg_ind.indexrelid " - "and pg_att1.attrelid = pg_ind.indrelid " - "and pg_att1.attnum = pg_ind.indkey[pg_att2.attnum-1] " - "order by pg_att2.attnum"); - } else if (d->pro == QPSQLDriver::Version7 || d->pro == QPSQLDriver::Version7_1) { - stmt = QLatin1String("select pg_att1.attname, pg_att1.atttypid::int, pg_cl.relname " - "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind " - "where pg_cl.relname = '%1_pkey' " - "and pg_cl.oid = pg_ind.indexrelid " - "and pg_att2.attrelid = pg_ind.indexrelid " - "and pg_att1.attrelid = pg_ind.indrelid " - "and pg_att1.attnum = pg_ind.indkey[pg_att2.attnum-1] " - "order by pg_att2.attnum"); - } else if (d->pro >= QPSQLDriver::Version7_3) { - 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"); - if (schema.isEmpty()) - stmt = stmt.arg(QLatin1String("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)); - } else { - qFatal("QPSQLDriver::primaryIndex(tablename): unknown PSQL version, query statement not set"); - } + 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"); + if (schema.isEmpty()) + stmt = stmt.arg(QLatin1String("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)); i.exec(stmt.arg(tbl)); while (i.isActive() && i.next()) { @@ -1170,7 +1428,6 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const QSqlRecord QPSQLDriver::record(const QString& tablename) const { - Q_D(const QPSQLDriver); QSqlRecord info; if (!isOpen()) return info; @@ -1189,105 +1446,44 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const else schema = std::move(schema).toLower(); - QString stmt; - if (d->pro == QPSQLDriver::Version6) { - stmt = QLatin1String("select pg_attribute.attname, int(pg_attribute.atttypid), " - "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, " - "int(pg_attribute.attrelid), pg_attribute.attnum " - "from pg_class, pg_attribute " - "where pg_class.relname = '%1' " - "and pg_attribute.attnum > 0 " - "and pg_attribute.attrelid = pg_class.oid "); - } else if (d->pro == QPSQLDriver::Version7) { - stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, " - "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, " - "pg_attribute.attrelid::int, pg_attribute.attnum " - "from pg_class, pg_attribute " - "where pg_class.relname = '%1' " - "and pg_attribute.attnum > 0 " - "and pg_attribute.attrelid = pg_class.oid "); - } else if (d->pro == QPSQLDriver::Version7_1) { - 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 pg_class.relname = '%1' " - "and pg_attribute.attnum > 0 " - "and pg_attribute.attrelid = pg_class.oid " - "order by pg_attribute.attnum "); - } else if (d->pro >= QPSQLDriver::Version7_3) { - 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 "); - if (schema.isEmpty()) - stmt = stmt.arg(QLatin1String("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)); - } else { - qFatal("QPSQLDriver::record(tablename): unknown PSQL version, query statement not set"); - } + 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"); + if (schema.isEmpty()) + stmt = stmt.arg(QLatin1String("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)); QSqlQuery query(createResult()); query.exec(stmt.arg(tbl)); - if (d->pro >= QPSQLDriver::Version7_1) { - while (query.next()) { - int len = query.value(3).toInt(); - int precision = query.value(4).toInt(); - // swap length and precision if length == -1 - if (len == -1 && precision > -1) { - len = precision - 4; - precision = -1; - } - QString defVal = query.value(5).toString(); - if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\'')) - defVal = defVal.mid(1, defVal.length() - 2); - QSqlField f(query.value(0).toString(), qDecodePSQLType(query.value(1).toInt()), tablename); - f.setRequired(query.value(2).toBool()); - f.setLength(len); - f.setPrecision(precision); - f.setDefaultValue(defVal); - f.setSqlType(query.value(1).toInt()); - info.append(f); - } - } else { - // Postgres < 7.1 cannot handle outer joins - while (query.next()) { - QString defVal; - QString stmt2 = QLatin1String("select pg_attrdef.adsrc from pg_attrdef where " - "pg_attrdef.adrelid = %1 and pg_attrdef.adnum = %2 "); - QSqlQuery query2(createResult()); - query2.exec(stmt2.arg(query.value(5).toInt()).arg(query.value(6).toInt())); - if (query2.isActive() && query2.next()) - defVal = query2.value(0).toString(); - if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\'')) - defVal = defVal.mid(1, defVal.length() - 2); - int len = query.value(3).toInt(); - int precision = query.value(4).toInt(); - // swap length and precision if length == -1 - if (len == -1 && precision > -1) { - len = precision - 4; - precision = -1; - } - QSqlField f(query.value(0).toString(), qDecodePSQLType(query.value(1).toInt()), tablename); - f.setRequired(query.value(2).toBool()); - f.setLength(len); - f.setPrecision(precision); - f.setDefaultValue(defVal); - f.setSqlType(query.value(1).toInt()); - info.append(f); + while (query.next()) { + int len = query.value(3).toInt(); + int precision = query.value(4).toInt(); + // swap length and precision if length == -1 + if (len == -1 && precision > -1) { + len = precision - 4; + precision = -1; } + QString defVal = query.value(5).toString(); + if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\'')) + defVal = defVal.mid(1, defVal.length() - 2); + QSqlField f(query.value(0).toString(), qDecodePSQLType(query.value(1).toInt()), tablename); + f.setRequired(query.value(2).toBool()); + f.setLength(len); + f.setPrecision(precision); + f.setDefaultValue(defVal); + f.setSqlType(query.value(1).toInt()); + info.append(f); } return info; diff --git a/src/plugins/sqldrivers/psql/qsql_psql_p.h b/src/plugins/sqldrivers/psql/qsql_psql_p.h index f5cb2e9bd0..2873a9f851 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql_p.h +++ b/src/plugins/sqldrivers/psql/qsql_psql_p.h @@ -98,34 +98,34 @@ public: explicit QPSQLDriver(QObject *parent=0); explicit QPSQLDriver(PGconn *conn, QObject *parent=0); ~QPSQLDriver(); - bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE; + bool hasFeature(DriverFeature f) const override; bool open(const QString & db, const QString & user, const QString & password, const QString & host, int port, - const QString& connOpts) Q_DECL_OVERRIDE; - bool isOpen() const Q_DECL_OVERRIDE; - void close() Q_DECL_OVERRIDE; - QSqlResult *createResult() const Q_DECL_OVERRIDE; - QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE; - QSqlIndex primaryIndex(const QString& tablename) const Q_DECL_OVERRIDE; - QSqlRecord record(const QString& tablename) const Q_DECL_OVERRIDE; + const QString& connOpts) override; + bool isOpen() const override; + void close() override; + QSqlResult *createResult() const override; + QStringList tables(QSql::TableType) const override; + QSqlIndex primaryIndex(const QString& tablename) const override; + QSqlRecord record(const QString& tablename) const override; Protocol protocol() const; - QVariant handle() const Q_DECL_OVERRIDE; + QVariant handle() const override; - QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE; - QString formatValue(const QSqlField &field, bool trimStrings) const Q_DECL_OVERRIDE; + QString escapeIdentifier(const QString &identifier, IdentifierType type) const override; + QString formatValue(const QSqlField &field, bool trimStrings) const override; - bool subscribeToNotification(const QString &name) Q_DECL_OVERRIDE; - bool unsubscribeFromNotification(const QString &name) Q_DECL_OVERRIDE; - QStringList subscribedToNotifications() const Q_DECL_OVERRIDE; + bool subscribeToNotification(const QString &name) override; + bool unsubscribeFromNotification(const QString &name) override; + QStringList subscribedToNotifications() const override; protected: - bool beginTransaction() Q_DECL_OVERRIDE; - bool commitTransaction() Q_DECL_OVERRIDE; - bool rollbackTransaction() Q_DECL_OVERRIDE; + bool beginTransaction() override; + bool commitTransaction() override; + bool rollbackTransaction() override; private Q_SLOTS: void _q_handleNotification(int); diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp index 444b18686a..d1a6582c5a 100644 --- a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp +++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp @@ -123,19 +123,19 @@ class QSQLiteResult : public QSqlCachedResult public: explicit QSQLiteResult(const QSQLiteDriver* db); ~QSQLiteResult(); - QVariant handle() const Q_DECL_OVERRIDE; + QVariant handle() const override; protected: - bool gotoNext(QSqlCachedResult::ValueCache& row, int idx) Q_DECL_OVERRIDE; - bool reset(const QString &query) Q_DECL_OVERRIDE; - bool prepare(const QString &query) Q_DECL_OVERRIDE; - bool exec() Q_DECL_OVERRIDE; - int size() Q_DECL_OVERRIDE; - int numRowsAffected() Q_DECL_OVERRIDE; - QVariant lastInsertId() const Q_DECL_OVERRIDE; - QSqlRecord record() const Q_DECL_OVERRIDE; - void detachFromResultSet() Q_DECL_OVERRIDE; - void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; + bool gotoNext(QSqlCachedResult::ValueCache& row, int idx) override; + bool reset(const QString &query) override; + bool prepare(const QString &query) override; + bool exec() override; + int size() override; + int numRowsAffected() override; + QVariant lastInsertId() const override; + QSqlRecord record() const override; + void detachFromResultSet() override; + void virtual_hook(int id, void *data) override; }; class QSQLiteDriverPrivate : public QSqlDriverPrivate diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h b/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h index ca969a4b53..61be4c937f 100644 --- a/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h +++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h @@ -75,28 +75,28 @@ public: explicit QSQLiteDriver(QObject *parent = 0); explicit QSQLiteDriver(sqlite3 *connection, QObject *parent = 0); ~QSQLiteDriver(); - bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE; + bool hasFeature(DriverFeature f) const override; bool open(const QString & db, const QString & user, const QString & password, const QString & host, int port, - const QString & connOpts) Q_DECL_OVERRIDE; - void close() Q_DECL_OVERRIDE; - QSqlResult *createResult() const Q_DECL_OVERRIDE; - bool beginTransaction() Q_DECL_OVERRIDE; - bool commitTransaction() Q_DECL_OVERRIDE; - bool rollbackTransaction() Q_DECL_OVERRIDE; - QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE; + const QString & connOpts) override; + void close() override; + QSqlResult *createResult() const override; + bool beginTransaction() override; + bool commitTransaction() override; + bool rollbackTransaction() override; + QStringList tables(QSql::TableType) const override; - QSqlRecord record(const QString& tablename) const Q_DECL_OVERRIDE; - QSqlIndex primaryIndex(const QString &table) const Q_DECL_OVERRIDE; - QVariant handle() const Q_DECL_OVERRIDE; - QString escapeIdentifier(const QString &identifier, IdentifierType) const Q_DECL_OVERRIDE; + QSqlRecord record(const QString& tablename) const override; + QSqlIndex primaryIndex(const QString &table) const override; + QVariant handle() const override; + QString escapeIdentifier(const QString &identifier, IdentifierType) const override; - bool subscribeToNotification(const QString &name) Q_DECL_OVERRIDE; - bool unsubscribeFromNotification(const QString &name) Q_DECL_OVERRIDE; - QStringList subscribedToNotifications() const Q_DECL_OVERRIDE; + bool subscribeToNotification(const QString &name) override; + bool unsubscribeFromNotification(const QString &name) override; + QStringList subscribedToNotifications() const override; private Q_SLOTS: void handleNotification(const QString &tableName, qint64 rowid); }; diff --git a/src/plugins/sqldrivers/sqlite/smain.cpp b/src/plugins/sqldrivers/sqlite/smain.cpp index 2ad466a61e..092813990c 100644 --- a/src/plugins/sqldrivers/sqlite/smain.cpp +++ b/src/plugins/sqldrivers/sqlite/smain.cpp @@ -51,7 +51,7 @@ class QSQLiteDriverPlugin : public QSqlDriverPlugin public: QSQLiteDriverPlugin(); - QSqlDriver* create(const QString &) Q_DECL_OVERRIDE; + QSqlDriver* create(const QString &) override; }; QSQLiteDriverPlugin::QSQLiteDriverPlugin() diff --git a/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp b/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp index 93f47e3f13..390f05c7aa 100644 --- a/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp +++ b/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp @@ -107,16 +107,16 @@ class QSQLite2Result : public QSqlCachedResult public: explicit QSQLite2Result(const QSQLite2Driver* db); ~QSQLite2Result(); - QVariant handle() const Q_DECL_OVERRIDE; + QVariant handle() const override; protected: - bool gotoNext(QSqlCachedResult::ValueCache &row, int idx) Q_DECL_OVERRIDE; - bool reset(const QString &query) Q_DECL_OVERRIDE; - int size() Q_DECL_OVERRIDE; - int numRowsAffected() Q_DECL_OVERRIDE; - QSqlRecord record() const Q_DECL_OVERRIDE; - void detachFromResultSet() Q_DECL_OVERRIDE; - void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; + bool gotoNext(QSqlCachedResult::ValueCache &row, int idx) override; + bool reset(const QString &query) override; + int size() override; + int numRowsAffected() override; + QSqlRecord record() const override; + void detachFromResultSet() override; + void virtual_hook(int id, void *data) override; }; class QSQLite2ResultPrivate: public QSqlCachedResultPrivate @@ -178,7 +178,8 @@ void QSQLite2ResultPrivate::finalize() if (err) { q->setLastError(QSqlError(QCoreApplication::translate("QSQLite2Result", "Unable to fetch results"), QString::fromLatin1(err), - QSqlError::StatementError, res)); + QSqlError::StatementError, + res != -1 ? QString::number(res) : QString())); sqlite_freemem(err); } currentMachine = 0; diff --git a/src/plugins/sqldrivers/sqlite2/qsql_sqlite2_p.h b/src/plugins/sqldrivers/sqlite2/qsql_sqlite2_p.h index 83b248ec6a..48c64536f1 100644 --- a/src/plugins/sqldrivers/sqlite2/qsql_sqlite2_p.h +++ b/src/plugins/sqldrivers/sqlite2/qsql_sqlite2_p.h @@ -79,29 +79,29 @@ public: explicit QSQLite2Driver(QObject *parent = 0); explicit QSQLite2Driver(sqlite *connection, QObject *parent = 0); ~QSQLite2Driver(); - bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE; + bool hasFeature(DriverFeature f) const override; bool open(const QString &db, const QString &user, const QString &password, const QString &host, int port, - const QString &connOpts) Q_DECL_OVERRIDE; + const QString &connOpts) override; bool open(const QString &db, const QString &user, const QString &password, const QString &host, int port) { return open(db, user, password, host, port, QString()); } - void close() Q_DECL_OVERRIDE; - QSqlResult *createResult() const Q_DECL_OVERRIDE; - bool beginTransaction() Q_DECL_OVERRIDE; - bool commitTransaction() Q_DECL_OVERRIDE; - bool rollbackTransaction() Q_DECL_OVERRIDE; - QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE; + void close() override; + QSqlResult *createResult() const override; + bool beginTransaction() override; + bool commitTransaction() override; + bool rollbackTransaction() override; + QStringList tables(QSql::TableType) const override; - QSqlRecord record(const QString &tablename) const Q_DECL_OVERRIDE; - QSqlIndex primaryIndex(const QString &table) const Q_DECL_OVERRIDE; - QVariant handle() const Q_DECL_OVERRIDE; - QString escapeIdentifier(const QString &identifier, IdentifierType) const Q_DECL_OVERRIDE; + QSqlRecord record(const QString &tablename) const override; + QSqlIndex primaryIndex(const QString &table) const override; + QVariant handle() const override; + QString escapeIdentifier(const QString &identifier, IdentifierType) const override; }; QT_END_NAMESPACE diff --git a/src/plugins/sqldrivers/tds/qsql_tds.cpp b/src/plugins/sqldrivers/tds/qsql_tds.cpp index 670198af81..ad95b097ef 100644 --- a/src/plugins/sqldrivers/tds/qsql_tds.cpp +++ b/src/plugins/sqldrivers/tds/qsql_tds.cpp @@ -132,7 +132,8 @@ QT_BEGIN_NAMESPACE QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, int errNo = -1) { - return QSqlError(QLatin1String("QTDS: ") + err, QString(), type, errNo); + return QSqlError(QLatin1String("QTDS: ") + err, QString(), type, + errNo != -1 ? QString::number(errNo) : QString()); } class QTDSDriverPrivate : public QSqlDriverPrivate @@ -163,15 +164,15 @@ class QTDSResult : public QSqlCachedResult public: explicit QTDSResult(const QTDSDriver* db); ~QTDSResult(); - QVariant handle() const Q_DECL_OVERRIDE; + QVariant handle() const override; protected: void cleanup(); - bool reset(const QString &query) Q_DECL_OVERRIDE; - int size() Q_DECL_OVERRIDE; - int numRowsAffected() Q_DECL_OVERRIDE; - bool gotoNext(QSqlCachedResult::ValueCache &values, int index) Q_DECL_OVERRIDE; - QSqlRecord record() const Q_DECL_OVERRIDE; + bool reset(const QString &query) override; + int size() override; + int numRowsAffected() override; + bool gotoNext(QSqlCachedResult::ValueCache &values, int index) override; + QSqlRecord record() const override; }; class QTDSResultPrivate: public QSqlCachedResultPrivate diff --git a/src/plugins/sqldrivers/tds/qsql_tds_p.h b/src/plugins/sqldrivers/tds/qsql_tds_p.h index d0914455a2..948e3c7024 100644 --- a/src/plugins/sqldrivers/tds/qsql_tds_p.h +++ b/src/plugins/sqldrivers/tds/qsql_tds_p.h @@ -88,29 +88,29 @@ public: explicit QTDSDriver(QObject* parent = 0); QTDSDriver(LOGINREC* rec, const QString& host, const QString &db, QObject* parent = 0); ~QTDSDriver(); - bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE; + bool hasFeature(DriverFeature f) const override; bool open(const QString &db, const QString &user, const QString &password, const QString &host, int port, - const QString &connOpts) Q_DECL_OVERRIDE; - void close() Q_DECL_OVERRIDE; - QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE; - QSqlResult *createResult() const Q_DECL_OVERRIDE; - QSqlRecord record(const QString &tablename) const Q_DECL_OVERRIDE; - QSqlIndex primaryIndex(const QString &tablename) const Q_DECL_OVERRIDE; + const QString &connOpts) override; + void close() override; + QStringList tables(QSql::TableType) const override; + QSqlResult *createResult() const override; + QSqlRecord record(const QString &tablename) const override; + QSqlIndex primaryIndex(const QString &tablename) const override; QString formatValue(const QSqlField &field, - bool trimStrings) const Q_DECL_OVERRIDE; - QVariant handle() const Q_DECL_OVERRIDE; + bool trimStrings) const override; + QVariant handle() const override; - QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE; + QString escapeIdentifier(const QString &identifier, IdentifierType type) const override; protected: - bool beginTransaction() Q_DECL_OVERRIDE; - bool commitTransaction() Q_DECL_OVERRIDE; - bool rollbackTransaction() Q_DECL_OVERRIDE; + bool beginTransaction() override; + bool commitTransaction() override; + bool rollbackTransaction() override; private: void init(); }; |