summaryrefslogtreecommitdiffstats
path: root/src/util/db/fwdsqlquery.h
blob: 5a08a04ba33c8b495fa001948747738e3aa1df8a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#pragma once

#include <QSqlError>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QString>
#include <QVariant>

#include "util/assert.h"
#include "util/db/dbfieldindex.h"
#include "util/db/dbid.h"

// forward declarations
class SqlQueryFinisher;
class FwdSqlQuerySelectResult;

// A forward-only QSqlQuery that is prepared immediately
// during initialization. It offers a limited set of functions
// from QSqlQuery.
//
// Setting QSqlQuery to forward-only causes memory savings since
// QSqlCachedResult (what QtSQLite uses) won't allocate a giant
// in-memory table that we won't use at all when invoking only
// QSqlQuery::next() to iterate over the results.
//
// Prefer to use this derived class instead of QSqlQuery to avoid
// performance bottlenecks and for implicit logging failed query
// executions.
//
// Please note that forward-only queries don't provide information
// about the size of the result set!
class FwdSqlQuery : protected QSqlQuery {
    friend class SqlQueryFinisher;
    friend class FwdSqlQuerySelectResult;

  public:
    FwdSqlQuery()
            : m_prepared(false) {
    }
    FwdSqlQuery(
            const QSqlDatabase& database,
            const QString& statement);

    bool isPrepared() const {
        return m_prepared;
    }

    bool hasError() const {
        return lastError().isValid() &&
                (lastError().type() != QSqlError::NoError);
    }
    bool hasDuplicateColumnNameError() const;
    QSqlError lastError() const {
        return QSqlQuery::lastError();
    }

    void bindValue(const QString& placeholder, const QVariant& value) {
        QSqlQuery::bindValue(placeholder, value);
    }

    // Overloaded function for type DbId
    void bindValue(const QString& placeholder, const DbId& value) {
        bindValue(placeholder, value.toVariant());
    }

    QString executedQuery() const {
        return QSqlQuery::executedQuery();
    }

    // Execute the prepared query and log errors on failure.
    //
    // Please note, that the member function exec() inherited
    // from the base class QSqlQuery is not polymorphic (virtual)
    // and can't be overridden safely!
    bool execPrepared();

    QSqlRecord record() const {
        return QSqlQuery::record();
    }

    int numRowsAffected() const {
        DEBUG_ASSERT(!hasError());
        return QSqlQuery::numRowsAffected();
    }

    QVariant lastInsertId() const {
        DEBUG_ASSERT(!lastError().isValid());
        DEBUG_ASSERT(!isSelect());
        QVariant result(QSqlQuery::lastInsertId());
        DEBUG_ASSERT(result.isValid());
        DEBUG_ASSERT(!result.isNull());
        return result;
    }

    bool next() {
        DEBUG_ASSERT(!hasError());
        DEBUG_ASSERT(isSelect());
        return QSqlQuery::next();
    }

    DbFieldIndex fieldIndex(const QString& fieldName) const;

    QVariant fieldValue(DbFieldIndex fieldIndex) const {
        DEBUG_ASSERT(!hasError());
        DEBUG_ASSERT(isSelect());
        return value(fieldIndex);
    }

    bool fieldValueBoolean(DbFieldIndex fieldIndex) const;

  private:
    bool m_prepared;
};