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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
|
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef MYSQL_CONNECTION_H
#define MYSQL_CONNECTION_H
#include <dhcpsrv/database_connection.h>
#include <boost/scoped_ptr.hpp>
#include <mysql.h>
#include <vector>
#include <stdint.h>
namespace isc {
namespace dhcp {
/// @brief MySQL True/False constants
///
/// Declare typed values so as to avoid problems of data conversion. These
/// are local to the file but are given the prefix MLM (MySql Lease Manager) to
/// avoid any likely conflicts with variables in header files named TRUE or
/// FALSE.
extern const my_bool MLM_FALSE;
extern const my_bool MLM_TRUE;
// Define the current database schema values
const uint32_t CURRENT_VERSION_VERSION = 3;
const uint32_t CURRENT_VERSION_MINOR = 0;
/// @brief Fetch and Release MySQL Results
///
/// When a MySQL statement is expected, to fetch the results the function
/// mysql_stmt_fetch() must be called. As well as getting data, this
/// allocates internal state. Subsequent calls to mysql_stmt_fetch can be
/// made, but when all the data is retrieved, mysql_stmt_free_result must be
/// called to free up the resources allocated.
///
/// Created prior to the first fetch, this class's destructor calls
/// mysql_stmt_free_result, so eliminating the need for an explicit release
/// in the method calling mysql_stmt_free_result. In this way, it guarantees
/// that the resources are released even if the MySqlLeaseMgr method concerned
/// exits via an exception.
class MySqlFreeResult {
public:
/// @brief Constructor
///
/// Store the pointer to the statement for which data is being fetched.
///
/// Note that according to the MySQL documentation, mysql_stmt_free_result
/// only releases resources if a cursor has been allocated for the
/// statement. This implies that it is a no-op if none have been. Either
/// way, any error from mysql_stmt_free_result is ignored. (Generating
/// an exception is not much help, as it will only confuse things if the
/// method calling mysql_stmt_fetch is exiting via an exception.)
MySqlFreeResult(MYSQL_STMT* statement) : statement_(statement)
{}
/// @brief Destructor
///
/// Frees up fetch context if a fetch has been successfully executed.
~MySqlFreeResult() {
(void) mysql_stmt_free_result(statement_);
}
private:
MYSQL_STMT* statement_; ///< Statement for which results are freed
};
/// @brief MySQL Selection Statements
///
/// Each statement is associated with an index, which is used to reference the
/// associated prepared statement.
struct TaggedStatement {
uint32_t index;
const char* text;
};
/// @brief MySQL Handle Holder
///
/// Small RAII object for safer initialization, will close the database
/// connection upon destruction. This means that if an exception is thrown
/// during database initialization, resources allocated to the database are
/// guaranteed to be freed.
///
/// It makes no sense to copy an object of this class. After the copy, both
/// objects would contain pointers to the same MySql context object. The
/// destruction of one would invalid the context in the remaining object.
/// For this reason, the class is declared noncopyable.
class MySqlHolder : public boost::noncopyable {
public:
/// @brief Constructor
///
/// Initialize MySql and store the associated context object.
///
/// @throw DbOpenError Unable to initialize MySql handle.
MySqlHolder() : mysql_(mysql_init(NULL)) {
if (mysql_ == NULL) {
isc_throw(DbOpenError, "unable to initialize MySQL");
}
}
/// @brief Destructor
///
/// Frees up resources allocated by the initialization of MySql.
~MySqlHolder() {
if (mysql_ != NULL) {
mysql_close(mysql_);
}
// The library itself shouldn't be needed anymore
mysql_library_end();
}
/// @brief Conversion Operator
///
/// Allows the MySqlHolder object to be passed as the context argument to
/// mysql_xxx functions.
operator MYSQL*() const {
return (mysql_);
}
private:
MYSQL* mysql_; ///< Initialization context
};
/// @brief Common MySQL Connector Pool
///
/// This class provides common operations for MySQL database connection
/// used by both MySqlLeaseMgr and MySqlHostDataSource. It manages connecting
/// to the database and preparing compiled statements. Its fields are
/// public, because they are used (both set and retrieved) in classes
/// that use instances of MySqlConnection.
class MySqlConnection : public DatabaseConnection {
public:
/// @brief Constructor
///
/// Initialize MySqlConnection object with parameters needed for connection.
MySqlConnection(const ParameterMap& parameters)
: DatabaseConnection(parameters) {
}
/// @brief Destructor
virtual ~MySqlConnection();
/// @brief Prepare Single Statement
///
/// Creates a prepared statement from the text given and adds it to the
/// statements_ vector at the given index.
///
/// @param index Index into the statements_ vector into which the text
/// should be placed. The vector must be big enough for the index
/// to be valid, else an exception will be thrown.
/// @param text Text of the SQL statement to be prepared.
///
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
/// @throw isc::InvalidParameter 'index' is not valid for the vector.
void prepareStatement(uint32_t index, const char* text);
/// @brief Prepare statements
///
/// Creates the prepared statements for all of the SQL statements used
/// by the MySQL backend.
/// @param tagged_statements an array of statements to be compiled
/// @param num_statements number of statements in tagged_statements
///
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
/// @throw isc::InvalidParameter 'index' is not valid for the vector. This
/// represents an internal error within the code.
void prepareStatements(const TaggedStatement tagged_statements[],
size_t num_statements);
/// @brief Open Database
///
/// Opens the database using the information supplied in the parameters
/// passed to the constructor.
///
/// @throw NoDatabaseName Mandatory database name not given
/// @throw DbOpenError Error opening the database
void openDatabase();
///@{
/// The following methods are used to convert between times and time
/// intervals stored in the Lease object, and the times stored in the
/// database. The reason for the difference is because in the DHCP server,
/// the cltt (Client Time Since Last Transmission) is the natural data; in
/// the lease file - which may be read by the user - it is the expiry time
/// of the lease.
/// @brief Convert time_t value to database time.
///
/// @param input_time A time_t value representing time.
/// @param output_time Reference to MYSQL_TIME object where converted time
/// will be put.
static
void convertToDatabaseTime(const time_t input_time, MYSQL_TIME& output_time);
/// @brief Convert Lease Time to Database Times
///
/// Within the DHCP servers, times are stored as client last transmit time
/// and valid lifetime. In the database, the information is stored as
/// valid lifetime and "expire" (time of expiry of the lease). They are
/// related by the equation:
///
/// - expire = client last transmit time + valid lifetime
///
/// This method converts from the times in the lease object into times
/// able to be added to the database.
///
/// @param cltt Client last transmit time
/// @param valid_lifetime Valid lifetime
/// @param expire Reference to MYSQL_TIME object where the expiry time of
/// the lease will be put.
///
/// @throw isc::BadValue if the sum of the calculated expiration time is
/// greater than the value of @c LeaseMgr::MAX_DB_TIME.
static
void convertToDatabaseTime(const time_t cltt, const uint32_t valid_lifetime,
MYSQL_TIME& expire);
/// @brief Convert Database Time to Lease Times
///
/// Within the database, time is stored as "expire" (time of expiry of the
/// lease) and valid lifetime. In the DHCP server, the information is
/// stored client last transmit time and valid lifetime. These are related
/// by the equation:
///
/// - client last transmit time = expire - valid_lifetime
///
/// This method converts from the times in the database into times
/// able to be inserted into the lease object.
///
/// @param expire Reference to MYSQL_TIME object from where the expiry
/// time of the lease is taken.
/// @param valid_lifetime lifetime of the lease.
/// @param cltt Reference to location where client last transmit time
/// is put.
static
void convertFromDatabaseTime(const MYSQL_TIME& expire,
uint32_t valid_lifetime, time_t& cltt);
///@}
/// @brief Commit Transactions
///
/// Commits all pending database operations. On databases that don't
/// support transactions, this is a no-op.
///
/// @throw DbOperationError If the commit failed.
void commit();
/// @brief Rollback Transactions
///
/// Rolls back all pending database operations. On databases that don't
/// support transactions, this is a no-op.
///
/// @throw DbOperationError If the rollback failed.
void rollback();
/// @brief Prepared statements
///
/// This field is public, because it is used heavily from MySqlConnection
/// and will be from MySqlHostDataSource.
std::vector<MYSQL_STMT*> statements_;
/// @brief Raw text of statements
///
/// This field is public, because it is used heavily from MySqlConnection
/// and will be from MySqlHostDataSource.
std::vector<std::string> text_statements_;
/// @brief MySQL connection handle
///
/// This field is public, because it is used heavily from MySqlConnection
/// and will be from MySqlHostDataSource.
MySqlHolder mysql_;
};
}; // end of isc::dhcp namespace
}; // end of isc namespace
#endif // MYSQL_CONNECTION_H
|