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