1 /*
2 * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #ifndef OWNSQL_H
20 #define OWNSQL_H
21
22 #include <QLoggingCategory>
23 #include <QObject>
24 #include <QVariant>
25
26 #include "ocsynclib.h"
27
28 struct sqlite3;
29 struct sqlite3_stmt;
30
31 namespace OCC {
Q_DECLARE_LOGGING_CATEGORY(lcSql)32 OCSYNC_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcSql)
33
34 class SqlQuery;
35
36 /**
37 * @brief The SqlDatabase class
38 * @ingroup libsync
39 */
40 class OCSYNC_EXPORT SqlDatabase
41 {
42 Q_DISABLE_COPY(SqlDatabase)
43 public:
44 explicit SqlDatabase();
45 ~SqlDatabase();
46
47 bool isOpen();
48 bool openOrCreateReadWrite(const QString &filename);
49 bool openReadOnly(const QString &filename);
50 bool transaction();
51 bool commit();
52 void close();
53 QString error() const;
54 sqlite3 *sqliteDb();
55
56 private:
57 enum class CheckDbResult {
58 Ok,
59 CantPrepare,
60 CantExec,
61 NotOk,
62 };
63
64 bool openHelper(const QString &filename, int sqliteFlags);
65 CheckDbResult checkDb();
66
67 sqlite3 *_db = nullptr;
68 QString _error; // last error string
69 int _errId = 0;
70
71 friend class SqlQuery;
72 QSet<SqlQuery *> _queries;
73 };
74
75 /**
76 * @brief The SqlQuery class
77 * @ingroup libsync
78 *
79 * There is basically 3 ways to initialize and use a query:
80 *
81 SqlQuery q1;
82 [...]
83 q1.initOrReset(...);
84 q1.bindValue(...);
85 q1.exec(...)
86 *
87 SqlQuery q2(db);
88 q2.prepare(...);
89 [...]
90 q2.reset_and_clear_bindings();
91 q2.bindValue(...);
92 q2.exec(...)
93 *
94 SqlQuery q3("...", db);
95 q3.bindValue(...);
96 q3.exec(...)
97 *
98 */
99 class OCSYNC_EXPORT SqlQuery
100 {
101 Q_DISABLE_COPY(SqlQuery)
102 public:
103 explicit SqlQuery() = default;
104 explicit SqlQuery(SqlDatabase &db);
105 explicit SqlQuery(const QByteArray &sql, SqlDatabase &db);
106 /**
107 * Prepare the SqlQuery.
108 * If the query was already prepared, this will first call finish(), and re-prepare it.
109 * This function must only be used if the constructor was setting a SqlDatabase
110 */
111 int prepare(const QByteArray &sql, bool allow_failure = false);
112
113 ~SqlQuery();
114 QString error() const;
115 int errorId() const;
116
117 /// Checks whether the value at the given column index is NULL
118 bool nullValue(int index);
119
120 QString stringValue(int index);
121 int intValue(int index);
122 quint64 int64Value(int index);
123 QByteArray baValue(int index);
124 bool isSelect();
125 bool isPragma();
126 bool exec();
127
128 struct NextResult
129 {
130 bool ok = false;
131 bool hasData = false;
132 };
133 NextResult next();
134
135 template<class T, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
bindValue(int pos,const T & value)136 void bindValue(int pos, const T &value)
137 {
138 qCDebug(lcSql) << "SQL bind" << pos << value;
139 bindValueInternal(pos, static_cast<int>(value));
140 }
141
142 template<class T, typename std::enable_if<!std::is_enum<T>::value, int>::type = 0>
bindValue(int pos,const T & value)143 void bindValue(int pos, const T &value)
144 {
145 qCDebug(lcSql) << "SQL bind" << pos << value;
146 bindValueInternal(pos, value);
147 }
148
bindValue(int pos,const QByteArray & value)149 void bindValue(int pos, const QByteArray &value)
150 {
151 qCDebug(lcSql) << "SQL bind" << pos << QString::fromUtf8(value);
152 bindValueInternal(pos, value);
153 }
154
155 const QByteArray &lastQuery() const;
156 int numRowsAffected();
157 void reset_and_clear_bindings();
158
159 private:
160 void bindValueInternal(int pos, const QVariant &value);
161 void finish();
162
163 SqlDatabase *_sqldb = nullptr;
164 sqlite3 *_db = nullptr;
165 sqlite3_stmt *_stmt = nullptr;
166 QString _error;
167 int _errId;
168 QByteArray _sql;
169
170 friend class SqlDatabase;
171 friend class PreparedSqlQueryManager;
172 };
173
174 } // namespace OCC
175
176 #endif // OWNSQL_H
177