]>
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"
30 #include "pdns/logger.hh"
36 ** Set all the parameters in the compiled SQL statement to NULL.
38 * copied from sqlite 3.3.6 // cmouse
40 int pdns_sqlite3_clear_bindings(sqlite3_stmt
*pStmt
){
43 for(i
=1; rc
==SQLITE_OK
&& i
<=sqlite3_bind_parameter_count(pStmt
); i
++){
44 rc
= sqlite3_bind_null(pStmt
, i
);
49 class SSQLite3Statement
: public SSqlStatement
52 SSQLite3Statement(SSQLite3
*db
, bool dolog
, const string
& query
) : d_prepared(false)
54 this->d_query
= query
;
55 this->d_dolog
= dolog
;
61 int name2idx(const string
& name
) {
62 string zName
= string(":")+name
;
64 return sqlite3_bind_parameter_index(d_stmt
, zName
.c_str());
65 // XXX: support @ and $?
68 SSqlStatement
* bind(const string
& name
, bool value
) { int idx
= name2idx(name
); if (idx
>0) { sqlite3_bind_int(d_stmt
, idx
, value
? 1 : 0); }; return this; }
69 SSqlStatement
* bind(const string
& name
, int value
) { int idx
= name2idx(name
); if (idx
>0) { sqlite3_bind_int(d_stmt
, idx
, value
); }; return this; }
70 SSqlStatement
* bind(const string
& name
, uint32_t value
) { int idx
= name2idx(name
); if (idx
>0) { sqlite3_bind_int64(d_stmt
, idx
, value
); }; return this; }
71 SSqlStatement
* bind(const string
& name
, long value
) { int idx
= name2idx(name
); if (idx
>0) { sqlite3_bind_int64(d_stmt
, idx
, value
); }; return this; }
72 SSqlStatement
* bind(const string
& name
, unsigned long value
) { int idx
= name2idx(name
); if (idx
>0) { sqlite3_bind_int64(d_stmt
, idx
, value
); }; return this; }
73 SSqlStatement
* bind(const string
& name
, long long value
) { int idx
= name2idx(name
); if (idx
>0) { sqlite3_bind_int64(d_stmt
, idx
, value
); }; return this; };
74 SSqlStatement
* bind(const string
& name
, unsigned long long value
) { int idx
= name2idx(name
); if (idx
>0) { sqlite3_bind_int64(d_stmt
, idx
, value
); }; return this; }
75 SSqlStatement
* bind(const string
& name
, const std::string
& value
) { int idx
= name2idx(name
); if (idx
>0) { sqlite3_bind_text(d_stmt
, idx
, value
.c_str(), value
.size(), SQLITE_TRANSIENT
); }; return this; }
76 SSqlStatement
* bindNull(const string
& name
) { int idx
= name2idx(name
); if (idx
>0) { sqlite3_bind_null(d_stmt
, idx
); }; return this; }
78 SSqlStatement
* execute() {
81 L
<<Logger::Warning
<< "Query: " << d_query
<< endl
;
82 int attempts
= d_db
->inTransaction(); // try only once
83 while(attempts
< 2 && (d_rc
= sqlite3_step(d_stmt
)) == SQLITE_BUSY
) attempts
++;
85 if (d_rc
!= SQLITE_ROW
&& d_rc
!= SQLITE_DONE
) {
88 if (d_rc
== SQLITE_CANTOPEN
)
89 throw SSqlException(string("CANTOPEN error in sqlite3, often caused by unwritable sqlite3 db *directory*: ")+string(sqlite3_errmsg(d_db
->db())));
90 throw SSqlException(string("Error while retrieving SQLite query results: ")+string(sqlite3_errmsg(d_db
->db())));
94 bool hasNextRow() { return d_rc
== SQLITE_ROW
; }
96 SSqlStatement
* nextRow(row_t
& row
) {
98 int numCols
= sqlite3_column_count(d_stmt
);
99 row
.reserve(numCols
); // preallocate memory
100 // Another row received, process it.
101 for ( int i
=0; i
<numCols
; i
++)
103 if (sqlite3_column_type(d_stmt
,i
) == SQLITE_NULL
) {
106 const char *pData
= (const char*) sqlite3_column_text(d_stmt
, i
);
107 row
.push_back(string(pData
, sqlite3_column_bytes(d_stmt
, i
)));
110 d_rc
= sqlite3_step(d_stmt
);
114 SSqlStatement
* getResult(result_t
& result
) {
116 while(hasNextRow()) {
119 result
.push_back(row
);
124 SSqlStatement
* reset() {
125 sqlite3_reset(d_stmt
);
126 #if SQLITE_VERSION_NUMBER >= 3003009
127 sqlite3_clear_bindings(d_stmt
);
129 pdns_sqlite3_clear_bindings(d_stmt
);
134 ~SSQLite3Statement() {
135 // deallocate if necessary
139 const string
& getQuery() { return d_query
; };
142 sqlite3_stmt
* d_stmt
;
148 void prepareStatement() {
151 if (d_prepared
) return;
152 #if SQLITE_VERSION_NUMBER >= 3003009
153 if (sqlite3_prepare_v2(d_db
->db(), d_query
.c_str(), -1, &d_stmt
, &pTail
) != SQLITE_OK
)
155 if (sqlite3_prepare(d_db
->db(), d_query
.c_str(), -1, &d_stmt
, &pTail
) != SQLITE_OK
)
159 throw SSqlException(string("Unable to compile SQLite statement : '")+d_query
+"': "+sqlite3_errmsg(d_db
->db()));
161 if (pTail
&& strlen(pTail
)>0)
162 L
<<Logger::Warning
<<"Sqlite3 command partially processed. Unprocessed part: "<<pTail
<<endl
;
166 void releaseStatement() {
168 sqlite3_finalize(d_stmt
);
175 SSQLite3::SSQLite3( const std::string
& database
, bool creat
)
177 if (access( database
.c_str(), F_OK
) == -1){
179 throw sPerrorException( "SQLite database '"+database
+"' does not exist yet" );
182 throw sPerrorException( "SQLite database '"+database
+"' already exists" );
185 if ( sqlite3_open( database
.c_str(), &m_pDB
)!=SQLITE_OK
)
186 throw sPerrorException( "Could not connect to the SQLite database '" + database
+ "'" );
188 m_in_transaction
= false;
189 sqlite3_busy_handler(m_pDB
, busyHandler
, 0);
192 void SSQLite3::setLog(bool state
)
198 SSQLite3::~SSQLite3()
201 for(int n
= 0; n
< 2 ; ++n
) {
202 if((ret
=sqlite3_close( m_pDB
)) != SQLITE_OK
) {
203 if(n
|| ret
!= SQLITE_BUSY
) { // if we have SQLITE_BUSY, and a working m_Pstmt, try finalize
204 cerr
<<"Unable to close down sqlite connection: "<<ret
<<endl
;
213 std::unique_ptr
<SSqlStatement
> SSQLite3::prepare(const string
& query
, int nparams
__attribute__((unused
))) {
214 return std::unique_ptr
<SSqlStatement
>(new SSQLite3Statement(this, m_dolog
, query
));
217 void SSQLite3::execute(const string
& query
) {
220 if (sqlite3_exec(m_pDB
, query
.c_str(), NULL
, NULL
, &errmsg
) == SQLITE_BUSY
) {
221 if (m_in_transaction
) {
222 throw("Failed to execute query: " + string(errmsg
));
224 if ((rc
= sqlite3_exec(m_pDB
, query
.c_str(), NULL
, NULL
, &errmsg
) != SQLITE_OK
) && rc
!= SQLITE_DONE
&& rc
!= SQLITE_ROW
)
225 throw("Failed to execute query: " + string(errmsg
));
230 int SSQLite3::busyHandler(void*, int)
232 Utility::usleep(1000);
236 void SSQLite3::startTransaction() {
238 m_in_transaction
= true;
241 void SSQLite3::rollback() {
243 m_in_transaction
= false;
246 void SSQLite3::commit() {
248 m_in_transaction
= false;
251 // Constructs a SSqlException object.
252 SSqlException
SSQLite3::sPerrorException( const std::string
& reason
)
254 return SSqlException( reason
);