]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/ssqlite3.cc
1 /* SQLite backend for PowerDNS
2 * Copyright (C) 2003, Michel Stol <michel@powerdns.com>
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.
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.
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.
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
27 #include "ssqlite3.hh"
31 #include "pdns/logger.hh"
37 ** Set all the parameters in the compiled SQL statement to NULL.
39 * copied from sqlite 3.3.6 // cmouse
41 #if SQLITE_VERSION_NUMBER < 3003009
42 static int pdns_sqlite3_clear_bindings(sqlite3_stmt
* pStmt
)
46 for (i
= 1; rc
== SQLITE_OK
&& i
<= sqlite3_bind_parameter_count(pStmt
); i
++) {
47 rc
= sqlite3_bind_null(pStmt
, i
);
53 static string
SSQLite3ErrorString(sqlite3
* database
)
55 return string(sqlite3_errmsg(database
) + string(" (") + std::to_string(sqlite3_extended_errcode(database
)) + string(")"));
58 class SSQLite3Statement
: public SSqlStatement
61 SSQLite3Statement(SSQLite3
* database
, bool dolog
, string query
) :
62 d_query(std::move(query
)),
68 SSQLite3Statement(const SSQLite3Statement
&) = delete;
69 SSQLite3Statement(SSQLite3Statement
&&) = delete;
70 SSQLite3Statement
& operator=(const SSQLite3Statement
&) = delete;
71 SSQLite3Statement
& operator=(SSQLite3Statement
&&) = delete;
73 int name2idx(const string
& name
)
75 string zName
= string(":") + name
;
77 return sqlite3_bind_parameter_index(d_stmt
, zName
.c_str());
78 // XXX: support @ and $?
81 SSqlStatement
* bind(const string
& name
, bool value
) override
83 int idx
= name2idx(name
);
85 sqlite3_bind_int(d_stmt
, idx
, value
? 1 : 0);
90 SSqlStatement
* bind(const string
& name
, int value
) override
92 int idx
= name2idx(name
);
94 sqlite3_bind_int(d_stmt
, idx
, value
);
99 SSqlStatement
* bind(const string
& name
, uint32_t value
) override
101 int idx
= name2idx(name
);
103 sqlite3_bind_int64(d_stmt
, idx
, value
);
108 SSqlStatement
* bind(const string
& name
, long value
) override
110 int idx
= name2idx(name
);
112 sqlite3_bind_int64(d_stmt
, idx
, value
);
117 SSqlStatement
* bind(const string
& name
, unsigned long value
) override
119 int idx
= name2idx(name
);
121 sqlite3_bind_int64(d_stmt
, idx
, static_cast<sqlite3_int64
>(value
));
126 SSqlStatement
* bind(const string
& name
, long long value
) override
128 int idx
= name2idx(name
);
130 sqlite3_bind_int64(d_stmt
, idx
, value
);
135 SSqlStatement
* bind(const string
& name
, unsigned long long value
) override
137 int idx
= name2idx(name
);
139 sqlite3_bind_int64(d_stmt
, idx
, static_cast<sqlite3_int64
>(value
));
144 SSqlStatement
* bind(const string
& name
, const std::string
& value
) override
146 int idx
= name2idx(name
);
148 sqlite3_bind_text(d_stmt
, idx
, value
.c_str(), static_cast<int>(value
.size()), SQLITE_TRANSIENT
);
153 SSqlStatement
* bindNull(const string
& name
) override
155 int idx
= name2idx(name
);
157 sqlite3_bind_null(d_stmt
, idx
);
162 SSqlStatement
* execute() override
166 g_log
<< Logger::Warning
<< "Query " << this << ": " << d_query
<< endl
;
170 int attempts
= d_db
->inTransaction() ? 1 : 0; // try only once
171 while (attempts
< 2 && (d_rc
= sqlite3_step(d_stmt
)) == SQLITE_BUSY
) {
175 if (d_rc
!= SQLITE_ROW
&& d_rc
!= SQLITE_DONE
) {
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()));
181 throw SSqlException(string("Error while retrieving SQLite query results: ") + SSQLite3ErrorString(d_db
->db()));
184 g_log
<< Logger::Warning
<< "Query " << this << ": " << d_dtime
.udiffNoReset() << " us to execute" << endl
;
189 bool hasNextRow() override
191 if (d_dolog
&& d_rc
!= SQLITE_ROW
) {
192 g_log
<< Logger::Warning
<< "Query " << this << ": " << d_dtime
.udiffNoReset() << " us total to last row" << endl
;
194 return d_rc
== SQLITE_ROW
;
197 SSqlStatement
* nextRow(row_t
& row
) override
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("");
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
));
213 d_rc
= sqlite3_step(d_stmt
);
217 SSqlStatement
* getResult(result_t
& result
) override
220 while (hasNextRow()) {
223 result
.push_back(std::move(row
));
228 SSqlStatement
* reset() override
230 sqlite3_reset(d_stmt
);
231 #if SQLITE_VERSION_NUMBER >= 3003009
232 sqlite3_clear_bindings(d_stmt
);
234 pdns_sqlite3_clear_bindings(d_stmt
);
239 ~SSQLite3Statement() override
241 // deallocate if necessary
245 const string
& getQuery() override
{ return d_query
; };
250 sqlite3_stmt
* d_stmt
{nullptr};
251 SSQLite3
* d_db
{nullptr};
254 bool d_prepared
{false};
256 void prepareStatement()
258 const char* pTail
= nullptr;
263 #if SQLITE_VERSION_NUMBER >= 3003009
264 if (sqlite3_prepare_v2(d_db
->db(), d_query
.c_str(), -1, &d_stmt
, &pTail
) != SQLITE_OK
)
266 if (sqlite3_prepare(d_db
->db(), d_query
.c_str(), -1, &d_stmt
, &pTail
) != SQLITE_OK
)
270 throw SSqlException(string("Unable to compile SQLite statement : '") + d_query
+ "': " + SSQLite3ErrorString(d_db
->db()));
272 if ((pTail
!= nullptr) && strlen(pTail
) > 0) {
273 g_log
<< Logger::Warning
<< "Sqlite3 command partially processed. Unprocessed part: " << pTail
<< endl
;
278 void releaseStatement()
280 if (d_stmt
!= nullptr) {
281 sqlite3_finalize(d_stmt
);
289 SSQLite3::SSQLite3(const std::string
& database
, const std::string
& journalmode
, bool creat
)
291 if (access(database
.c_str(), F_OK
) == -1) {
293 throw SSqlException("SQLite database '" + database
+ "' does not exist yet");
298 throw SSqlException("SQLite database '" + database
+ "' already exists");
302 if (sqlite3_open(database
.c_str(), &m_pDB
) != SQLITE_OK
) {
303 throw SSqlException("Could not connect to the SQLite database '" + database
+ "'");
306 m_in_transaction
= false;
307 sqlite3_busy_handler(m_pDB
, busyHandler
, nullptr);
309 if (journalmode
.length() != 0) {
310 executeImpl("PRAGMA journal_mode=" + journalmode
);
314 void SSQLite3::setLog(bool state
)
320 SSQLite3::~SSQLite3()
322 for (int tried
= 0;; ++tried
) {
323 int ret
= sqlite3_close(m_pDB
);
324 if (ret
== SQLITE_OK
) {
327 cerr
<< "SQLite3 error state while tearing down database: " << SSQLite3ErrorString(m_pDB
) << endl
;
328 if (tried
== 0 && ret
== SQLITE_BUSY
) {
331 cerr
<< "Unable to close down sqlite connection: " << ret
<< endl
;
336 std::unique_ptr
<SSqlStatement
> SSQLite3::prepare(const string
& query
, int nparams
__attribute__((unused
)))
338 return std::make_unique
<SSQLite3Statement
>(this, m_dolog
, query
);
341 void SSQLite3::executeImpl(const string
& query
)
343 char* errmsg
= nullptr;
345 int execRet
= sqlite3_exec(m_pDB
, query
.c_str(), nullptr, nullptr, &errmsg
);
346 if (execRet
!= SQLITE_OK
) {
348 sqlite3_free(errmsg
);
350 if (execRet
== SQLITE_BUSY
) {
351 if (m_in_transaction
) {
352 throw SSqlException("Failed to execute query: " + errstr1
);
354 execRet
= sqlite3_exec(m_pDB
, query
.c_str(), nullptr, nullptr, &errmsg
);
356 if (execRet
!= SQLITE_OK
) {
358 sqlite3_free(errmsg
);
359 throw SSqlException("Failed to execute query: " + errstr2
);
362 else if (execRet
!= SQLITE_OK
) {
363 throw SSqlException("Failed to execute query: " + errstr1
);
367 void SSQLite3::execute(const string
& query
)
372 int SSQLite3::busyHandler([[maybe_unused
]] void* userData
, [[maybe_unused
]] int invocationsSoFar
)
374 Utility::usleep(1000);
378 void SSQLite3::startTransaction()
381 m_in_transaction
= true;
384 void SSQLite3::rollback()
387 m_in_transaction
= false;
390 void SSQLite3::commit()
393 m_in_transaction
= false;
396 // Constructs a SSqlException object.
397 SSqlException
SSQLite3::sPerrorException(const std::string
& reason
)