1 #pragma once 2 3 4 #include <QSqlQuery> 5 #include <QSqlRecord> 6 #include <QSqlError> 7 8 #include "util/db/dbid.h" 9 #include "util/db/dbfieldindex.h" 10 11 #include "util/assert.h" 12 13 // forward declarations 14 class SqlQueryFinisher; 15 class FwdSqlQuerySelectResult; 16 17 18 // A forward-only QSqlQuery that is prepared immediately 19 // during initialization. It offers a limited set of functions 20 // from QSqlQuery. 21 // 22 // Setting QSqlQuery to forward-only causes memory savings since 23 // QSqlCachedResult (what QtSQLite uses) won't allocate a giant 24 // in-memory table that we won't use at all when invoking only 25 // QSqlQuery::next() to iterate over the results. 26 // 27 // Prefer to use this derived class instead of QSqlQuery to avoid 28 // performance bottlenecks and for implicit logging failed query 29 // executions. 30 // 31 // Please note that forward-only queries don't provide information 32 // about the size of the result set! 33 class FwdSqlQuery: protected QSqlQuery { 34 friend class SqlQueryFinisher; 35 friend class FwdSqlQuerySelectResult; 36 37 public: 38 FwdSqlQuery( 39 const QSqlDatabase& database, 40 const QString& statement); 41 isPrepared()42 bool isPrepared() const { 43 return m_prepared; 44 } 45 hasError()46 bool hasError() const { 47 return lastError().isValid() && 48 (lastError().type() != QSqlError::NoError); 49 } lastError()50 QSqlError lastError() const { 51 return QSqlQuery::lastError(); 52 } 53 bindValue(const QString & placeholder,const QVariant & value)54 void bindValue(const QString& placeholder, const QVariant& value) { 55 QSqlQuery::bindValue(placeholder, value); 56 } 57 58 // Overloaded function for type DbId bindValue(const QString & placeholder,const DbId & value)59 void bindValue(const QString& placeholder, const DbId& value) { 60 bindValue(placeholder, value.toVariant()); 61 } 62 63 // Execute the prepared query and log errors on failure. 64 // 65 // Please note, that the member function exec() inherited 66 // from the base class QSqlQuery is not polymorphic (virtual) 67 // and can't be overridden safely! 68 bool execPrepared(); 69 record()70 QSqlRecord record() const { 71 return QSqlQuery::record(); 72 } 73 numRowsAffected()74 int numRowsAffected() const { 75 DEBUG_ASSERT(!hasError()); 76 return QSqlQuery::numRowsAffected(); 77 } 78 lastInsertId()79 QVariant lastInsertId() const { 80 DEBUG_ASSERT(!lastError().isValid()); 81 DEBUG_ASSERT(!isSelect()); 82 QVariant result(QSqlQuery::lastInsertId()); 83 DEBUG_ASSERT(result.isValid()); 84 DEBUG_ASSERT(!result.isNull()); 85 return result; 86 } 87 next()88 bool next() { 89 DEBUG_ASSERT(!hasError()); 90 DEBUG_ASSERT(isSelect()); 91 return QSqlQuery::next(); 92 } 93 94 DbFieldIndex fieldIndex(const QString& fieldName) const; 95 fieldValue(DbFieldIndex fieldIndex)96 QVariant fieldValue(DbFieldIndex fieldIndex) const { 97 DEBUG_ASSERT(!hasError()); 98 DEBUG_ASSERT(isSelect()); 99 return value(fieldIndex); 100 } 101 102 bool fieldValueBoolean(DbFieldIndex fieldIndex) const; 103 104 private: 105 FwdSqlQuery() = default; // hidden 106 107 bool m_prepared; 108 }; 109