]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/ssqlite3.cc
Merge pull request #14300 from omoerbeek/rec-doc-max-map-count
[thirdparty/pdns.git] / pdns / ssqlite3.cc
1 /* SQLite backend for PowerDNS
2 * Copyright (C) 2003, Michel Stol <michel@powerdns.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation.
7 *
8 * Additionally, the license of this program contains a special
9 * exception which allows to distribute the program in binary form when
10 * it is linked against OpenSSL.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <string>
26 #include <sstream>
27 #include "ssqlite3.hh"
28 #include <iostream>
29 #include <fstream>
30 #include <utility>
31 #include "pdns/logger.hh"
32 #include "misc.hh"
33 #include "utility.hh"
34 #include <unistd.h>
35
36 /*
37 ** Set all the parameters in the compiled SQL statement to NULL.
38 *
39 * copied from sqlite 3.3.6 // cmouse
40 */
41 #if SQLITE_VERSION_NUMBER < 3003009
42 static int pdns_sqlite3_clear_bindings(sqlite3_stmt* pStmt)
43 {
44 int i;
45 int rc = SQLITE_OK;
46 for (i = 1; rc == SQLITE_OK && i <= sqlite3_bind_parameter_count(pStmt); i++) {
47 rc = sqlite3_bind_null(pStmt, i);
48 }
49 return rc;
50 }
51 #endif
52
53 static string SSQLite3ErrorString(sqlite3* database)
54 {
55 return string(sqlite3_errmsg(database) + string(" (") + std::to_string(sqlite3_extended_errcode(database)) + string(")"));
56 }
57
58 class SSQLite3Statement : public SSqlStatement
59 {
60 public:
61 SSQLite3Statement(SSQLite3* database, bool dolog, string query) :
62 d_query(std::move(query)),
63 d_db(database),
64 d_dolog(dolog)
65 {
66 }
67
68 SSQLite3Statement(const SSQLite3Statement&) = delete;
69 SSQLite3Statement(SSQLite3Statement&&) = delete;
70 SSQLite3Statement& operator=(const SSQLite3Statement&) = delete;
71 SSQLite3Statement& operator=(SSQLite3Statement&&) = delete;
72
73 int name2idx(const string& name)
74 {
75 string zName = string(":") + name;
76 prepareStatement();
77 return sqlite3_bind_parameter_index(d_stmt, zName.c_str());
78 // XXX: support @ and $?
79 }
80
81 SSqlStatement* bind(const string& name, bool value) override
82 {
83 int idx = name2idx(name);
84 if (idx > 0) {
85 sqlite3_bind_int(d_stmt, idx, value ? 1 : 0);
86 };
87 return this;
88 }
89
90 SSqlStatement* bind(const string& name, int value) override
91 {
92 int idx = name2idx(name);
93 if (idx > 0) {
94 sqlite3_bind_int(d_stmt, idx, value);
95 };
96 return this;
97 }
98
99 SSqlStatement* bind(const string& name, uint32_t value) override
100 {
101 int idx = name2idx(name);
102 if (idx > 0) {
103 sqlite3_bind_int64(d_stmt, idx, value);
104 };
105 return this;
106 }
107
108 SSqlStatement* bind(const string& name, long value) override
109 {
110 int idx = name2idx(name);
111 if (idx > 0) {
112 sqlite3_bind_int64(d_stmt, idx, value);
113 };
114 return this;
115 }
116
117 SSqlStatement* bind(const string& name, unsigned long value) override
118 {
119 int idx = name2idx(name);
120 if (idx > 0) {
121 sqlite3_bind_int64(d_stmt, idx, static_cast<sqlite3_int64>(value));
122 };
123 return this;
124 }
125
126 SSqlStatement* bind(const string& name, long long value) override
127 {
128 int idx = name2idx(name);
129 if (idx > 0) {
130 sqlite3_bind_int64(d_stmt, idx, value);
131 };
132 return this;
133 };
134
135 SSqlStatement* bind(const string& name, unsigned long long value) override
136 {
137 int idx = name2idx(name);
138 if (idx > 0) {
139 sqlite3_bind_int64(d_stmt, idx, static_cast<sqlite3_int64>(value));
140 };
141 return this;
142 }
143
144 SSqlStatement* bind(const string& name, const std::string& value) override
145 {
146 int idx = name2idx(name);
147 if (idx > 0) {
148 sqlite3_bind_text(d_stmt, idx, value.c_str(), static_cast<int>(value.size()), SQLITE_TRANSIENT);
149 };
150 return this;
151 }
152
153 SSqlStatement* bindNull(const string& name) override
154 {
155 int idx = name2idx(name);
156 if (idx > 0) {
157 sqlite3_bind_null(d_stmt, idx);
158 };
159 return this;
160 }
161
162 SSqlStatement* execute() override
163 {
164 prepareStatement();
165 if (d_dolog) {
166 g_log << Logger::Warning << "Query " << this << ": " << d_query << endl;
167 d_dtime.set();
168 }
169
170 int attempts = d_db->inTransaction() ? 1 : 0; // try only once
171 while (attempts < 2 && (d_rc = sqlite3_step(d_stmt)) == SQLITE_BUSY) {
172 attempts++;
173 }
174
175 if (d_rc != SQLITE_ROW && d_rc != SQLITE_DONE) {
176 // failed.
177 releaseStatement();
178 if (d_rc == SQLITE_CANTOPEN) {
179 throw SSqlException(string("CANTOPEN error in sqlite3, often caused by unwritable sqlite3 db *directory*: ") + SSQLite3ErrorString(d_db->db()));
180 }
181 throw SSqlException(string("Error while retrieving SQLite query results: ") + SSQLite3ErrorString(d_db->db()));
182 }
183 if (d_dolog) {
184 g_log << Logger::Warning << "Query " << this << ": " << d_dtime.udiffNoReset() << " us to execute" << endl;
185 }
186 return this;
187 }
188
189 bool hasNextRow() override
190 {
191 if (d_dolog && d_rc != SQLITE_ROW) {
192 g_log << Logger::Warning << "Query " << this << ": " << d_dtime.udiffNoReset() << " us total to last row" << endl;
193 }
194 return d_rc == SQLITE_ROW;
195 }
196
197 SSqlStatement* nextRow(row_t& row) override
198 {
199 row.clear();
200 int numCols = sqlite3_column_count(d_stmt);
201 row.reserve(numCols); // preallocate memory
202 // Another row received, process it.
203 for (int i = 0; i < numCols; i++) {
204 if (sqlite3_column_type(d_stmt, i) == SQLITE_NULL) {
205 row.emplace_back("");
206 }
207 else {
208 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast): SQLite API returns unsigned char strings and std::strings are signed char.
209 const char* pData = (const char*)sqlite3_column_text(d_stmt, i);
210 row.emplace_back(pData, sqlite3_column_bytes(d_stmt, i));
211 }
212 }
213 d_rc = sqlite3_step(d_stmt);
214 return this;
215 }
216
217 SSqlStatement* getResult(result_t& result) override
218 {
219 result.clear();
220 while (hasNextRow()) {
221 row_t row;
222 nextRow(row);
223 result.push_back(std::move(row));
224 }
225 return this;
226 }
227
228 SSqlStatement* reset() override
229 {
230 sqlite3_reset(d_stmt);
231 #if SQLITE_VERSION_NUMBER >= 3003009
232 sqlite3_clear_bindings(d_stmt);
233 #else
234 pdns_sqlite3_clear_bindings(d_stmt);
235 #endif
236 return this;
237 }
238
239 ~SSQLite3Statement() override
240 {
241 // deallocate if necessary
242 releaseStatement();
243 }
244
245 const string& getQuery() override { return d_query; };
246
247 private:
248 string d_query;
249 DTime d_dtime;
250 sqlite3_stmt* d_stmt{nullptr};
251 SSQLite3* d_db{nullptr};
252 int d_rc{0};
253 bool d_dolog;
254 bool d_prepared{false};
255
256 void prepareStatement()
257 {
258 const char* pTail = nullptr;
259
260 if (d_prepared) {
261 return;
262 }
263 #if SQLITE_VERSION_NUMBER >= 3003009
264 if (sqlite3_prepare_v2(d_db->db(), d_query.c_str(), -1, &d_stmt, &pTail) != SQLITE_OK)
265 #else
266 if (sqlite3_prepare(d_db->db(), d_query.c_str(), -1, &d_stmt, &pTail) != SQLITE_OK)
267 #endif
268 {
269 releaseStatement();
270 throw SSqlException(string("Unable to compile SQLite statement : '") + d_query + "': " + SSQLite3ErrorString(d_db->db()));
271 }
272 if ((pTail != nullptr) && strlen(pTail) > 0) {
273 g_log << Logger::Warning << "Sqlite3 command partially processed. Unprocessed part: " << pTail << endl;
274 }
275 d_prepared = true;
276 }
277
278 void releaseStatement()
279 {
280 if (d_stmt != nullptr) {
281 sqlite3_finalize(d_stmt);
282 }
283 d_stmt = nullptr;
284 d_prepared = false;
285 }
286 };
287
288 // Constructor.
289 SSQLite3::SSQLite3(const std::string& database, const std::string& journalmode, bool creat)
290 {
291 if (access(database.c_str(), F_OK) == -1) {
292 if (!creat) {
293 throw SSqlException("SQLite database '" + database + "' does not exist yet");
294 }
295 }
296 else {
297 if (creat) {
298 throw SSqlException("SQLite database '" + database + "' already exists");
299 }
300 }
301
302 if (sqlite3_open(database.c_str(), &m_pDB) != SQLITE_OK) {
303 throw SSqlException("Could not connect to the SQLite database '" + database + "'");
304 }
305 m_dolog = false;
306 m_in_transaction = false;
307 sqlite3_busy_handler(m_pDB, busyHandler, nullptr);
308
309 if (journalmode.length() != 0) {
310 executeImpl("PRAGMA journal_mode=" + journalmode);
311 }
312 }
313
314 void SSQLite3::setLog(bool state)
315 {
316 m_dolog = state;
317 }
318
319 // Destructor.
320 SSQLite3::~SSQLite3()
321 {
322 for (int tried = 0;; ++tried) {
323 int ret = sqlite3_close(m_pDB);
324 if (ret == SQLITE_OK) {
325 break;
326 }
327 cerr << "SQLite3 error state while tearing down database: " << SSQLite3ErrorString(m_pDB) << endl;
328 if (tried == 0 && ret == SQLITE_BUSY) {
329 continue;
330 }
331 cerr << "Unable to close down sqlite connection: " << ret << endl;
332 abort();
333 }
334 }
335
336 std::unique_ptr<SSqlStatement> SSQLite3::prepare(const string& query, int nparams __attribute__((unused)))
337 {
338 return std::make_unique<SSQLite3Statement>(this, m_dolog, query);
339 }
340
341 void SSQLite3::executeImpl(const string& query)
342 {
343 char* errmsg = nullptr;
344 std::string errstr1;
345 int execRet = sqlite3_exec(m_pDB, query.c_str(), nullptr, nullptr, &errmsg);
346 if (execRet != SQLITE_OK) {
347 errstr1 = errmsg;
348 sqlite3_free(errmsg);
349 }
350 if (execRet == SQLITE_BUSY) {
351 if (m_in_transaction) {
352 throw SSqlException("Failed to execute query: " + errstr1);
353 }
354 execRet = sqlite3_exec(m_pDB, query.c_str(), nullptr, nullptr, &errmsg);
355 std::string errstr2;
356 if (execRet != SQLITE_OK) {
357 errstr2 = errmsg;
358 sqlite3_free(errmsg);
359 throw SSqlException("Failed to execute query: " + errstr2);
360 }
361 }
362 else if (execRet != SQLITE_OK) {
363 throw SSqlException("Failed to execute query: " + errstr1);
364 }
365 }
366
367 void SSQLite3::execute(const string& query)
368 {
369 executeImpl(query);
370 }
371
372 int SSQLite3::busyHandler([[maybe_unused]] void* userData, [[maybe_unused]] int invocationsSoFar)
373 {
374 Utility::usleep(1000);
375 return 1;
376 }
377
378 void SSQLite3::startTransaction()
379 {
380 execute("begin");
381 m_in_transaction = true;
382 }
383
384 void SSQLite3::rollback()
385 {
386 execute("rollback");
387 m_in_transaction = false;
388 }
389
390 void SSQLite3::commit()
391 {
392 execute("commit");
393 m_in_transaction = false;
394 }
395
396 // Constructs a SSqlException object.
397 SSqlException SSQLite3::sPerrorException(const std::string& reason)
398 {
399 return {reason};
400 }