Kea  2.5.2
mysql_lease_mgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2023 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
10 #include <dhcp/duid.h>
11 #include <dhcp/hwaddr.h>
12 #include <dhcpsrv/cfg_db_access.h>
13 #include <dhcpsrv/cfgmgr.h>
14 #include <dhcpsrv/dhcpsrv_log.h>
17 #include <dhcpsrv/timer_mgr.h>
18 #include <mysql/mysql_connection.h>
20 
21 #include <boost/array.hpp>
22 #include <boost/make_shared.hpp>
23 #include <boost/static_assert.hpp>
24 #include <mysqld_error.h>
25 
26 #include <iostream>
27 #include <iomanip>
28 #include <limits>
29 #include <sstream>
30 #include <string>
31 #include <time.h>
32 
33 using namespace isc;
34 using namespace isc::asiolink;
35 using namespace isc::db;
36 using namespace isc::dhcp;
37 using namespace isc::data;
38 using namespace isc::util;
39 using namespace std;
40 
82 
83 namespace {
84 
89 const size_t HOSTNAME_MAX_LEN = 255;
90 
95 const size_t ADDRESS6_TEXT_MAX_LEN = 39;
96 
98 const size_t USER_CONTEXT_MAX_LEN = 8192;
99 
101 const size_t LIMITS_TEXT_MAX_LEN = 512;
102 
103 boost::array<TaggedStatement, MySqlLeaseMgr::NUM_STATEMENTS>
104 tagged_statements = { {
105  {MySqlLeaseMgr::DELETE_LEASE4,
106  "DELETE FROM lease4 WHERE address = ? AND expire = ?"},
107  {MySqlLeaseMgr::DELETE_LEASE4_STATE_EXPIRED,
108  "DELETE FROM lease4 "
109  "WHERE state = ? AND expire < ?"},
110  {MySqlLeaseMgr::DELETE_LEASE6,
111  "DELETE FROM lease6 WHERE address = ? AND expire = ?"},
112  {MySqlLeaseMgr::DELETE_LEASE6_STATE_EXPIRED,
113  "DELETE FROM lease6 "
114  "WHERE state = ? AND expire < ?"},
115  {MySqlLeaseMgr::GET_LEASE4,
116  "SELECT address, hwaddr, client_id, "
117  "valid_lifetime, expire, subnet_id, "
118  "fqdn_fwd, fqdn_rev, hostname, "
119  "state, user_context, relay_id, remote_id, pool_id "
120  "FROM lease4"},
121  {MySqlLeaseMgr::GET_LEASE4_ADDR,
122  "SELECT address, hwaddr, client_id, "
123  "valid_lifetime, expire, subnet_id, "
124  "fqdn_fwd, fqdn_rev, hostname, "
125  "state, user_context, relay_id, remote_id, pool_id "
126  "FROM lease4 "
127  "WHERE address = ?"},
128  {MySqlLeaseMgr::GET_LEASE4_CLIENTID,
129  "SELECT address, hwaddr, client_id, "
130  "valid_lifetime, expire, subnet_id, "
131  "fqdn_fwd, fqdn_rev, hostname, "
132  "state, user_context, relay_id, remote_id, pool_id "
133  "FROM lease4 "
134  "WHERE client_id = ?"},
135  {MySqlLeaseMgr::GET_LEASE4_CLIENTID_SUBID,
136  "SELECT address, hwaddr, client_id, "
137  "valid_lifetime, expire, subnet_id, "
138  "fqdn_fwd, fqdn_rev, hostname, "
139  "state, user_context, relay_id, remote_id, pool_id "
140  "FROM lease4 "
141  "WHERE client_id = ? AND subnet_id = ?"},
142  {MySqlLeaseMgr::GET_LEASE4_HWADDR,
143  "SELECT address, hwaddr, client_id, "
144  "valid_lifetime, expire, subnet_id, "
145  "fqdn_fwd, fqdn_rev, hostname, "
146  "state, user_context, relay_id, remote_id, pool_id "
147  "FROM lease4 "
148  "WHERE hwaddr = ?"},
149  {MySqlLeaseMgr::GET_LEASE4_HWADDR_SUBID,
150  "SELECT address, hwaddr, client_id, "
151  "valid_lifetime, expire, subnet_id, "
152  "fqdn_fwd, fqdn_rev, hostname, "
153  "state, user_context, relay_id, remote_id, pool_id "
154  "FROM lease4 "
155  "WHERE hwaddr = ? AND subnet_id = ?"},
156  {MySqlLeaseMgr::GET_LEASE4_PAGE,
157  "SELECT address, hwaddr, client_id, "
158  "valid_lifetime, expire, subnet_id, "
159  "fqdn_fwd, fqdn_rev, hostname, "
160  "state, user_context, relay_id, remote_id, pool_id "
161  "FROM lease4 "
162  "WHERE address > ? "
163  "ORDER BY address "
164  "LIMIT ?"},
165  {MySqlLeaseMgr::GET_LEASE4_UCTX_PAGE,
166  "SELECT address, hwaddr, client_id, "
167  "valid_lifetime, expire, subnet_id, "
168  "fqdn_fwd, fqdn_rev, hostname, "
169  "state, user_context, relay_id, remote_id, pool_id "
170  "FROM lease4 "
171  "WHERE address > ? AND user_context IS NOT NULL "
172  "ORDER BY address "
173  "LIMIT ?"},
174  {MySqlLeaseMgr::GET_LEASE4_SUBID,
175  "SELECT address, hwaddr, client_id, "
176  "valid_lifetime, expire, subnet_id, "
177  "fqdn_fwd, fqdn_rev, hostname, "
178  "state, user_context, relay_id, remote_id, pool_id "
179  "FROM lease4 "
180  "WHERE subnet_id = ?"},
181  {MySqlLeaseMgr::GET_LEASE4_HOSTNAME,
182  "SELECT address, hwaddr, client_id, "
183  "valid_lifetime, expire, subnet_id, "
184  "fqdn_fwd, fqdn_rev, hostname, "
185  "state, user_context, relay_id, remote_id, pool_id "
186  "FROM lease4 "
187  "WHERE hostname = ?"},
188  {MySqlLeaseMgr::GET_LEASE4_EXPIRE,
189  "SELECT address, hwaddr, client_id, "
190  "valid_lifetime, expire, subnet_id, "
191  "fqdn_fwd, fqdn_rev, hostname, "
192  "state, user_context, relay_id, remote_id, pool_id "
193  "FROM lease4 "
194  "WHERE state != ? "
195  "AND valid_lifetime != 4294967295 "
196  "AND expire < ? "
197  "ORDER BY expire ASC "
198  "LIMIT ?"},
199  {MySqlLeaseMgr::GET_LEASE4_RELAYID,
200  "SELECT address, hwaddr, client_id, "
201  "valid_lifetime, expire, subnet_id, "
202  "fqdn_fwd, fqdn_rev, hostname, "
203  "state, user_context, relay_id, remote_id, pool_id "
204  "FROM lease4 "
205  "WHERE relay_id = ? and address > ? "
206  "ORDER BY address "
207  "LIMIT ?"},
208  {MySqlLeaseMgr::GET_LEASE4_RELAYID_QST,
209  "SELECT address, hwaddr, client_id, "
210  "valid_lifetime, expire, subnet_id, "
211  "fqdn_fwd, fqdn_rev, hostname, "
212  "state, user_context, relay_id, remote_id, pool_id "
213  "FROM lease4 "
214  "WHERE relay_id = ? and address > ? "
215  " and UNIX_TIMESTAMP(expire) - IF"
216  "(valid_lifetime = 4294967295, 0, valid_lifetime)"
217  " >= ? "
218  "ORDER BY address "
219  "LIMIT ?"},
220  {MySqlLeaseMgr::GET_LEASE4_RELAYID_QSET,
221  "SELECT address, hwaddr, client_id, "
222  "valid_lifetime, expire, subnet_id, "
223  "fqdn_fwd, fqdn_rev, hostname, "
224  "state, user_context, relay_id, remote_id, pool_id "
225  "FROM lease4 "
226  "WHERE relay_id = ? and address > ? "
227  " and UNIX_TIMESTAMP(expire) - IF"
228  "(valid_lifetime = 4294967295, 0, valid_lifetime)"
229  " >= ? "
230  " and UNIX_TIMESTAMP(expire) - IF"
231  "(valid_lifetime = 4294967295, 0, valid_lifetime)"
232  " <= ? "
233  "ORDER BY address "
234  "LIMIT ?"},
235  {MySqlLeaseMgr::GET_LEASE4_RELAYID_QET,
236  "SELECT address, hwaddr, client_id, "
237  "valid_lifetime, expire, subnet_id, "
238  "fqdn_fwd, fqdn_rev, hostname, "
239  "state, user_context, relay_id, remote_id, pool_id "
240  "FROM lease4 "
241  "WHERE relay_id = ? and address > ? "
242  " and UNIX_TIMESTAMP(expire) - IF"
243  "(valid_lifetime = 4294967295, 0, valid_lifetime)"
244  " <= ? "
245  "ORDER BY address "
246  "LIMIT ?"},
247  {MySqlLeaseMgr::GET_LEASE4_REMOTEID,
248  "SELECT address, hwaddr, client_id, "
249  "valid_lifetime, expire, subnet_id, "
250  "fqdn_fwd, fqdn_rev, hostname, "
251  "state, user_context, relay_id, remote_id, pool_id "
252  "FROM lease4 "
253  "WHERE remote_id = ? and address > ? "
254  "ORDER BY address "
255  "LIMIT ?"},
256  {MySqlLeaseMgr::GET_LEASE4_REMOTEID_QST,
257  "SELECT address, hwaddr, client_id, "
258  "valid_lifetime, expire, subnet_id, "
259  "fqdn_fwd, fqdn_rev, hostname, "
260  "state, user_context, relay_id, remote_id, pool_id "
261  "FROM lease4 "
262  "WHERE remote_id = ? and address > ? "
263  " and UNIX_TIMESTAMP(expire) - IF"
264  "(valid_lifetime = 4294967295, 0, valid_lifetime)"
265  " >= ? "
266  "ORDER BY address "
267  "LIMIT ?"},
268  {MySqlLeaseMgr::GET_LEASE4_REMOTEID_QSET,
269  "SELECT address, hwaddr, client_id, "
270  "valid_lifetime, expire, subnet_id, "
271  "fqdn_fwd, fqdn_rev, hostname, "
272  "state, user_context, relay_id, remote_id, pool_id "
273  "FROM lease4 "
274  "WHERE remote_id = ? and address > ? "
275  " and UNIX_TIMESTAMP(expire) - IF"
276  "(valid_lifetime = 4294967295, 0, valid_lifetime)"
277  " >= ? "
278  " and UNIX_TIMESTAMP(expire) - IF"
279  "(valid_lifetime = 4294967295, 0, valid_lifetime)"
280  " <= ? "
281  "ORDER BY address "
282  "LIMIT ?"},
283  {MySqlLeaseMgr::GET_LEASE4_REMOTEID_QET,
284  "SELECT address, hwaddr, client_id, "
285  "valid_lifetime, expire, subnet_id, "
286  "fqdn_fwd, fqdn_rev, hostname, "
287  "state, user_context, relay_id, remote_id, pool_id "
288  "FROM lease4 "
289  "WHERE remote_id = ? and address > ? "
290  " and UNIX_TIMESTAMP(expire) - IF"
291  "(valid_lifetime = 4294967295, 0, valid_lifetime)"
292  " <= ? "
293  "ORDER BY address "
294  "LIMIT ?"},
295  {MySqlLeaseMgr::GET_LEASE6,
296  "SELECT address, duid, valid_lifetime, "
297  "expire, subnet_id, pref_lifetime, "
298  "lease_type, iaid, prefix_len, "
299  "fqdn_fwd, fqdn_rev, hostname, "
300  "hwaddr, hwtype, hwaddr_source, "
301  "state, user_context, pool_id "
302  "FROM lease6"},
303  {MySqlLeaseMgr::GET_LEASE6_ADDR,
304  "SELECT address, duid, valid_lifetime, "
305  "expire, subnet_id, pref_lifetime, "
306  "lease_type, iaid, prefix_len, "
307  "fqdn_fwd, fqdn_rev, hostname, "
308  "hwaddr, hwtype, hwaddr_source, "
309  "state, user_context, pool_id "
310  "FROM lease6 "
311  "WHERE address = ? AND lease_type = ?"},
312  {MySqlLeaseMgr::GET_LEASE6_DUID_IAID,
313  "SELECT address, duid, valid_lifetime, "
314  "expire, subnet_id, pref_lifetime, "
315  "lease_type, iaid, prefix_len, "
316  "fqdn_fwd, fqdn_rev, hostname, "
317  "hwaddr, hwtype, hwaddr_source, "
318  "state, user_context, pool_id "
319  "FROM lease6 "
320  "WHERE duid = ? AND iaid = ? AND lease_type = ?"},
321  {MySqlLeaseMgr::GET_LEASE6_DUID_IAID_SUBID,
322  "SELECT address, duid, valid_lifetime, "
323  "expire, subnet_id, pref_lifetime, "
324  "lease_type, iaid, prefix_len, "
325  "fqdn_fwd, fqdn_rev, hostname, "
326  "hwaddr, hwtype, hwaddr_source, "
327  "state, user_context, pool_id "
328  "FROM lease6 "
329  "WHERE duid = ? AND iaid = ? AND subnet_id = ? "
330  "AND lease_type = ?"},
331  {MySqlLeaseMgr::GET_LEASE6_PAGE,
332  "SELECT address, duid, valid_lifetime, "
333  "expire, subnet_id, pref_lifetime, "
334  "lease_type, iaid, prefix_len, "
335  "fqdn_fwd, fqdn_rev, hostname, "
336  "hwaddr, hwtype, hwaddr_source, "
337  "state, user_context, pool_id "
338  "FROM lease6 "
339  "WHERE address > ? "
340  "ORDER BY address "
341  "LIMIT ?"},
342  {MySqlLeaseMgr::GET_LEASE6_UCTX_PAGE,
343  "SELECT address, duid, valid_lifetime, "
344  "expire, subnet_id, pref_lifetime, "
345  "lease_type, iaid, prefix_len, "
346  "fqdn_fwd, fqdn_rev, hostname, "
347  "hwaddr, hwtype, hwaddr_source, "
348  "state, user_context, pool_id "
349  "FROM lease6 "
350  "WHERE address > ? AND user_context IS NOT NULL "
351  "ORDER BY address "
352  "LIMIT ?"},
353  {MySqlLeaseMgr::GET_LEASE6_SUBID,
354  "SELECT address, duid, valid_lifetime, "
355  "expire, subnet_id, pref_lifetime, "
356  "lease_type, iaid, prefix_len, "
357  "fqdn_fwd, fqdn_rev, hostname, "
358  "hwaddr, hwtype, hwaddr_source, "
359  "state, user_context, pool_id "
360  "FROM lease6 "
361  "WHERE subnet_id = ?"},
362  {MySqlLeaseMgr::GET_LEASE6_DUID,
363  "SELECT address, duid, valid_lifetime, "
364  "expire, subnet_id, pref_lifetime, "
365  "lease_type, iaid, prefix_len, "
366  "fqdn_fwd, fqdn_rev, hostname, "
367  "hwaddr, hwtype, hwaddr_source, "
368  "state, user_context, pool_id "
369  "FROM lease6 "
370  "WHERE duid = ?"},
371  {MySqlLeaseMgr::GET_LEASE6_HOSTNAME,
372  "SELECT address, duid, valid_lifetime, "
373  "expire, subnet_id, pref_lifetime, "
374  "lease_type, iaid, prefix_len, "
375  "fqdn_fwd, fqdn_rev, hostname, "
376  "hwaddr, hwtype, hwaddr_source, "
377  "state, user_context, pool_id "
378  "FROM lease6 "
379  "WHERE hostname = ?"},
380  {MySqlLeaseMgr::GET_LEASE6_EXPIRE,
381  "SELECT address, duid, valid_lifetime, "
382  "expire, subnet_id, pref_lifetime, "
383  "lease_type, iaid, prefix_len, "
384  "fqdn_fwd, fqdn_rev, hostname, "
385  "hwaddr, hwtype, hwaddr_source, "
386  "state, user_context, pool_id "
387  "FROM lease6 "
388  "WHERE state != ? "
389  "AND valid_lifetime != 4294967295 "
390  "AND expire < ? "
391  "ORDER BY expire ASC "
392  "LIMIT ?"},
393  {MySqlLeaseMgr::GET_LEASE6_LINK,
394  "SELECT address, duid, valid_lifetime, "
395  "expire, subnet_id, pref_lifetime, "
396  "lease_type, iaid, prefix_len, "
397  "fqdn_fwd, fqdn_rev, hostname, "
398  "hwaddr, hwtype, hwaddr_source, "
399  "state, user_context, pool_id "
400  "FROM lease6 "
401  "WHERE address BETWEEN ? AND ? "
402  "ORDER BY address "
403  "LIMIT ?"},
404  {MySqlLeaseMgr::INSERT_LEASE4,
405  "INSERT INTO lease4(address, hwaddr, client_id, "
406  "valid_lifetime, expire, subnet_id, "
407  "fqdn_fwd, fqdn_rev, hostname, "
408  "state, user_context, relay_id, remote_id, pool_id) "
409  "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
410  {MySqlLeaseMgr::INSERT_LEASE6,
411  "INSERT INTO lease6(address, duid, valid_lifetime, "
412  "expire, subnet_id, pref_lifetime, "
413  "lease_type, iaid, prefix_len, "
414  "fqdn_fwd, fqdn_rev, hostname, "
415  "hwaddr, hwtype, hwaddr_source, "
416  "state, user_context, pool_id) "
417  "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
418  {MySqlLeaseMgr::UPDATE_LEASE4,
419  "UPDATE lease4 SET address = ?, hwaddr = ?, "
420  "client_id = ?, valid_lifetime = ?, expire = ?, "
421  "subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, "
422  "hostname = ?, "
423  "state = ?, user_context = ?, "
424  "relay_id = ?, remote_id = ?, pool_id = ? "
425  "WHERE address = ? AND expire = ?"},
426  {MySqlLeaseMgr::UPDATE_LEASE6,
427  "UPDATE lease6 SET address = ?, duid = ?, "
428  "valid_lifetime = ?, expire = ?, subnet_id = ?, "
429  "pref_lifetime = ?, lease_type = ?, iaid = ?, "
430  "prefix_len = ?, fqdn_fwd = ?, fqdn_rev = ?, "
431  "hostname = ?, hwaddr = ?, hwtype = ?, hwaddr_source = ?, "
432  "state = ?, user_context = ?, pool_id = ? "
433  "WHERE address = ? AND expire = ?"},
434  {MySqlLeaseMgr::ALL_LEASE4_STATS,
435  "SELECT subnet_id, state, leases as state_count "
436  "FROM lease4_stat ORDER BY subnet_id, state"},
437  {MySqlLeaseMgr::SUBNET_LEASE4_STATS,
438  "SELECT subnet_id, state, leases as state_count "
439  "FROM lease4_stat "
440  "WHERE subnet_id = ? "
441  "ORDER BY state"},
442  {MySqlLeaseMgr::SUBNET_RANGE_LEASE4_STATS,
443  "SELECT subnet_id, state, leases as state_count "
444  "FROM lease4_stat "
445  "WHERE subnet_id >= ? and subnet_id <= ? "
446  "ORDER BY subnet_id, state"},
447  {MySqlLeaseMgr::ALL_POOL_LEASE4_STATS,
448  "SELECT subnet_id, pool_id, state, leases as state_count "
449  "FROM lease4_pool_stat ORDER BY subnet_id, pool_id, state"},
450  {MySqlLeaseMgr::ALL_LEASE6_STATS,
451  "SELECT subnet_id, lease_type, state, leases as state_count "
452  "FROM lease6_stat ORDER BY subnet_id, lease_type, state"},
453  {MySqlLeaseMgr::SUBNET_LEASE6_STATS,
454  "SELECT subnet_id, lease_type, state, leases as state_count "
455  "FROM lease6_stat "
456  "WHERE subnet_id = ? "
457  "ORDER BY lease_type, state"},
458  {MySqlLeaseMgr::SUBNET_RANGE_LEASE6_STATS,
459  "SELECT subnet_id, lease_type, state, leases as state_count "
460  "FROM lease6_stat "
461  "WHERE subnet_id >= ? and subnet_id <= ? "
462  "ORDER BY subnet_id, lease_type, state"},
463  {MySqlLeaseMgr::ALL_POOL_LEASE6_STATS,
464  "SELECT subnet_id, pool_id, lease_type, state, leases as state_count "
465  "FROM lease6_pool_stat ORDER BY subnet_id, pool_id, lease_type, state"},
466  {MySqlLeaseMgr::CHECK_LEASE4_LIMITS,
467  "SELECT checkLease4Limits(?)"},
468  {MySqlLeaseMgr::CHECK_LEASE6_LIMITS,
469  "SELECT checkLease6Limits(?)"},
470  {MySqlLeaseMgr::IS_JSON_SUPPORTED,
471  "SELECT isJsonSupported()"},
472  {MySqlLeaseMgr::GET_LEASE4_COUNT_BY_CLASS,
473  "SELECT leases "
474  "FROM lease4_stat_by_client_class "
475  "WHERE client_class = ?"},
476  {MySqlLeaseMgr::GET_LEASE6_COUNT_BY_CLASS,
477  "SELECT leases "
478  "FROM lease6_stat_by_client_class "
479  "WHERE client_class = ? AND lease_type = ?"},
480  {MySqlLeaseMgr::WIPE_RELAY_ID6,
481  "DELETE FROM lease6_relay_id"},
482  {MySqlLeaseMgr::WIPE_REMOTE_ID6,
483  "DELETE FROM lease6_remote_id"},
484  {MySqlLeaseMgr::DELETE_RELAY_ID6,
485  "DELETE FROM lease6_relay_id WHERE lease_addr = ?"},
486  {MySqlLeaseMgr::DELETE_REMOTE_ID6,
487  "DELETE FROM lease6_remote_id WHERE lease_addr = ?"},
488  {MySqlLeaseMgr::ADD_RELAY_ID6,
489  "INSERT INTO lease6_relay_id(relay_id, lease_addr) "
490  "VALUES (?, ?)"},
491  {MySqlLeaseMgr::ADD_REMOTE_ID6,
492  "INSERT INTO lease6_remote_id(remote_id, lease_addr) "
493  "VALUES (?, ?)"},
494  {MySqlLeaseMgr::GET_RELAY_ID6,
495  "SELECT l.address, l.duid, l.valid_lifetime, "
496  "l.expire, l.subnet_id, l.pref_lifetime, "
497  "l.lease_type, l.iaid, l.prefix_len, "
498  "l.fqdn_fwd, l.fqdn_rev, l.hostname, "
499  "l.hwaddr, l.hwtype, l.hwaddr_source, "
500  "l.state, l.user_context, l.pool_id "
501  "FROM lease6 AS l "
502  "INNER JOIN lease6_relay_id AS r "
503  " ON l.address = r.lease_addr "
504  " WHERE r.relay_id = ? AND r.lease_addr > ? "
505  "GROUP BY l.address "
506  "ORDER BY l.address "
507  "LIMIT ?"},
508  {MySqlLeaseMgr::GET_REMOTE_ID6,
509  "SELECT l.address, l.duid, l.valid_lifetime, "
510  "l.expire, l.subnet_id, l.pref_lifetime, "
511  "l.lease_type, l.iaid, l.prefix_len, "
512  "l.fqdn_fwd, l.fqdn_rev, l.hostname, "
513  "l.hwaddr, l.hwtype, l.hwaddr_source, "
514  "l.state, l.user_context, l.pool_id "
515  "FROM lease6 AS l "
516  "INNER JOIN lease6_remote_id AS r "
517  " ON l.address = r.lease_addr "
518  " WHERE r.remote_id = ? AND r.lease_addr > ? "
519  "GROUP BY l.address "
520  "ORDER BY l.address "
521  "LIMIT ?"},
522  {MySqlLeaseMgr::GET_RELAY_ID6_LINK,
523  "SELECT l.address, l.duid, l.valid_lifetime, "
524  "l.expire, l.subnet_id, l.pref_lifetime, "
525  "l.lease_type, l.iaid, l.prefix_len, "
526  "l.fqdn_fwd, l.fqdn_rev, l.hostname, "
527  "l.hwaddr, l.hwtype, l.hwaddr_source, "
528  "l.state, l.user_context, l.pool_id "
529  "FROM lease6 AS l "
530  "INNER JOIN lease6_relay_id AS r "
531  " ON l.address = r.lease_addr "
532  " WHERE r.relay_id = ? AND r.lease_addr BETWEEN ? AND ? "
533  "GROUP BY l.address "
534  "ORDER BY l.address "
535  "LIMIT ?"},
536  {MySqlLeaseMgr::GET_REMOTE_ID6_LINK,
537  "SELECT l.address, l.duid, l.valid_lifetime, "
538  "l.expire, l.subnet_id, l.pref_lifetime, "
539  "l.lease_type, l.iaid, l.prefix_len, "
540  "l.fqdn_fwd, l.fqdn_rev, l.hostname, "
541  "l.hwaddr, l.hwtype, l.hwaddr_source, "
542  "l.state, l.user_context, l.pool_id "
543  "FROM lease6 AS l "
544  "INNER JOIN lease6_remote_id AS r "
545  " ON l.address = r.lease_addr "
546  " WHERE r.remote_id = ? AND r.lease_addr BETWEEN ? AND ? "
547  "GROUP BY l.address "
548  "ORDER BY l.address "
549  "LIMIT ?"},
550  {MySqlLeaseMgr::COUNT_RELAY_ID6,
551  "SELECT COUNT(*) FROM lease6_relay_id"},
552  {MySqlLeaseMgr::COUNT_REMOTE_ID6,
553  "SELECT COUNT(*) FROM lease6_remote_id"},
554 } }; // tagged_statements
555 
556 } // namespace
557 
558 namespace isc {
559 namespace dhcp {
560 
567 
569 public:
570 
582  static void setErrorIndicators(MYSQL_BIND* bind, my_bool* error,
583  size_t count) {
584  for (size_t i = 0; i < count; ++i) {
585  error[i] = MLM_FALSE;
586  bind[i].error = reinterpret_cast<my_bool*>(&error[i]);
587  }
588  }
589 
603  static std::string getColumnsInError(my_bool* error, std::string* names,
604  size_t count) {
605  std::string result = "";
606 
607  // Accumulate list of column names
608  for (size_t i = 0; i < count; ++i) {
609  if (error[i] == MLM_TRUE) {
610  if (!result.empty()) {
611  result += ", ";
612  }
613  result += names[i];
614  }
615  }
616 
617  if (result.empty()) {
618  result = "(None)";
619  }
620 
621  return (result);
622  }
623 };
624 
637 
642 
643  static const size_t ADDRESS_COL = 0;
644  static const size_t HWADDR_COL = 1;
645  static const size_t CLIENT_ID_COL = 2;
646  static const size_t VALID_LIFETIME_COL = 3;
647  static const size_t EXPIRE_COL = 4;
648  static const size_t SUBNET_ID_COL = 5;
649  static const size_t FQDN_FWD_COL = 6;
650  static const size_t FQDN_REV_COL = 7;
651  static const size_t HOSTNAME_COL = 8;
652  static const size_t STATE_COL = 9;
653  static const size_t USER_CONTEXT_COL = 10;
654  static const size_t RELAY_ID_COL = 11;
655  static const size_t REMOTE_ID_COL = 12;
656  static const size_t POOL_ID_COL = 13;
658  static const size_t LEASE_COLUMNS = 14;
660 
661 public:
662 
667  MySqlLease4Exchange() : addr4_(0), hwaddr_length_(0), hwaddr_null_(MLM_FALSE),
668  client_id_length_(0), client_id_null_(MLM_FALSE),
669  subnet_id_(0), pool_id_(0), valid_lifetime_(0),
670  fqdn_fwd_(false), fqdn_rev_(false), hostname_length_(0),
671  state_(0), user_context_length_(0),
672  user_context_null_(MLM_FALSE), relay_id_length_(0),
673  relay_id_null_(MLM_FALSE), remote_id_length_(0),
674  remote_id_null_(MLM_FALSE) {
675  memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
676  memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
677  memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
678  memset(user_context_, 0, sizeof(user_context_));
679  memset(relay_id_buffer_, 0, sizeof(relay_id_buffer_));
680  memset(remote_id_buffer_, 0, sizeof(remote_id_buffer_));
681  std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
682 
683  // Set the column names (for error messages)
684  columns_[ADDRESS_COL] = "address";
685  columns_[HWADDR_COL] = "hwaddr";
686  columns_[CLIENT_ID_COL] = "client_id";
687  columns_[VALID_LIFETIME_COL] = "valid_lifetime";
688  columns_[EXPIRE_COL] = "expire";
689  columns_[SUBNET_ID_COL] = "subnet_id";
690  columns_[FQDN_FWD_COL] = "fqdn_fwd";
691  columns_[FQDN_REV_COL] = "fqdn_rev";
692  columns_[HOSTNAME_COL] = "hostname";
693  columns_[STATE_COL] = "state";
694  columns_[USER_CONTEXT_COL] = "user_context";
695  columns_[RELAY_ID_COL] = "relay_id";
696  columns_[REMOTE_ID_COL] = "remote_id";
697  columns_[POOL_ID_COL] = "pool_id";
698  BOOST_STATIC_ASSERT(13 < LEASE_COLUMNS);
699  }
700 
710  std::vector<MYSQL_BIND> createBindForSend(const Lease4Ptr& lease) {
711 
712  // Store lease object to ensure it remains valid.
713  lease_ = lease;
714 
715  // Initialize prior to constructing the array of MYSQL_BIND structures.
716  // It sets all fields, including is_null, to zero, so we need to set
717  // is_null only if it should be true. This gives up minor performance
718  // benefit while being safe approach. For improved readability, the
719  // code that explicitly sets is_null is there, but is commented out.
720  memset(bind_, 0, sizeof(bind_));
721 
722  // Set up the structures for the various components of the lease4
723  // structure.
724 
725  try {
726  // address: uint32_t
727  // The address in the Lease structure is an IOAddress object. Convert
728  // this to an integer for storage.
729  addr4_ = lease_->addr_.toUint32();
730  bind_[0].buffer_type = MYSQL_TYPE_LONG;
731  bind_[0].buffer = reinterpret_cast<char*>(&addr4_);
732  bind_[0].is_unsigned = MLM_TRUE;
733  // bind_[0].is_null = &MLM_FALSE; // commented out for performance
734  // reasons, see memset() above
735 
736  // hwaddr: varbinary(20) - hardware/MAC address
737  HWAddrPtr hwaddr = lease_->hwaddr_;
738  if (hwaddr) {
739  hwaddr_ = hwaddr->hwaddr_;
740  hwaddr_length_ = hwaddr->hwaddr_.size();
741 
742  // Make sure that the buffer has at least length of 1, even if
743  // empty HW address is passed. This is required by some of the
744  // MySQL connectors that the buffer is set to non-null value.
745  // Otherwise, null value would be inserted into the database,
746  // rather than empty string.
747  if (hwaddr_.empty()) {
748  hwaddr_.resize(1);
749  }
750 
751  bind_[1].buffer_type = MYSQL_TYPE_BLOB;
752  bind_[1].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
753  bind_[1].buffer_length = hwaddr_length_;
754  bind_[1].length = &hwaddr_length_;
755  } else {
756  bind_[1].buffer_type = MYSQL_TYPE_NULL;
757  // According to http://dev.mysql.com/doc/refman/5.5/en/
758  // c-api-prepared-statement-data-structures.html, the other
759  // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
760  // but let's set them to some sane values in case earlier versions
761  // didn't have that assumption.
762  hwaddr_null_ = MLM_TRUE;
763  bind_[1].buffer = NULL;
764  bind_[1].is_null = &hwaddr_null_;
765  }
766 
767  // client_id: varbinary(255)
768  if (lease_->client_id_) {
769  client_id_ = lease_->client_id_->getClientId();
770  client_id_length_ = client_id_.size();
771 
772  // Make sure that the buffer has at least length of 1, even if
773  // empty client id is passed. This is required by some of the
774  // MySQL connectors that the buffer is set to non-null value.
775  // Otherwise, null value would be inserted into the database,
776  // rather than empty string.
777  if (client_id_.empty()) {
778  client_id_.resize(1);
779  }
780 
781  bind_[2].buffer_type = MYSQL_TYPE_BLOB;
782  bind_[2].buffer = reinterpret_cast<char*>(&client_id_[0]);
783  bind_[2].buffer_length = client_id_length_;
784  bind_[2].length = &client_id_length_;
785  // bind_[2].is_null = &MLM_FALSE; // commented out for performance
786  // reasons, see memset() above
787  } else {
788  bind_[2].buffer_type = MYSQL_TYPE_NULL;
789  // According to http://dev.mysql.com/doc/refman/5.5/en/
790  // c-api-prepared-statement-data-structures.html, the other
791  // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
792  // but let's set them to some sane values in case earlier versions
793  // didn't have that assumption.
794  client_id_null_ = MLM_TRUE;
795  bind_[2].buffer = NULL;
796  bind_[2].is_null = &client_id_null_;
797  }
798 
799  // valid lifetime: unsigned int
800  bind_[3].buffer_type = MYSQL_TYPE_LONG;
801  bind_[3].buffer = reinterpret_cast<char*>(&lease_->valid_lft_);
802  bind_[3].is_unsigned = MLM_TRUE;
803  // bind_[3].is_null = &MLM_FALSE; // commented out for performance
804  // reasons, see memset() above
805 
806  // expire: timestamp
807  // The lease structure holds the client last transmission time (cltt_)
808  // For convenience for external tools, this is converted to lease
809  // expiry time (expire). The relationship is given by:
810  //
811  // expire = cltt_ + valid_lft_
812  // Avoid overflow with infinite valid lifetime by using
813  // expire = cltt_ when valid_lft_ = 0xffffffff
814  uint32_t valid_lft = lease_->valid_lft_;
815  if (valid_lft == Lease::INFINITY_LFT) {
816  valid_lft = 0;
817  }
818  MySqlConnection::convertToDatabaseTime(lease_->cltt_, valid_lft,
819  expire_);
820  bind_[4].buffer_type = MYSQL_TYPE_TIMESTAMP;
821  bind_[4].buffer = reinterpret_cast<char*>(&expire_);
822  bind_[4].buffer_length = sizeof(expire_);
823  // bind_[4].is_null = &MLM_FALSE; // commented out for performance
824  // reasons, see memset() above
825 
826  // subnet_id: unsigned int
827  // Can use lease_->subnet_id_ directly as it is of type uint32_t.
828  bind_[5].buffer_type = MYSQL_TYPE_LONG;
829  bind_[5].buffer = reinterpret_cast<char*>(&lease_->subnet_id_);
830  bind_[5].is_unsigned = MLM_TRUE;
831  // bind_[5].is_null = &MLM_FALSE; // commented out for performance
832  // reasons, see memset() above
833 
834  // fqdn_fwd: boolean
835  bind_[6].buffer_type = MYSQL_TYPE_TINY;
836  bind_[6].buffer = reinterpret_cast<char*>(&lease_->fqdn_fwd_);
837  bind_[6].is_unsigned = MLM_TRUE;
838  // bind_[6].is_null = &MLM_FALSE; // commented out for performance
839  // reasons, see memset() above
840 
841  // fqdn_rev: boolean
842  bind_[7].buffer_type = MYSQL_TYPE_TINY;
843  bind_[7].buffer = reinterpret_cast<char*>(&lease_->fqdn_rev_);
844  bind_[7].is_unsigned = MLM_TRUE;
845  // bind_[7].is_null = &MLM_FALSE; // commented out for performance
846  // reasons, see memset() above
847 
848  // hostname: varchar(255)
849  // Note that previously we used MYSQL_TYPE_VARCHAR instead of
850  // MYSQL_TYPE_STRING. However, that caused 'buffer type not supported'
851  // errors on some systems running MariaDB.
852  bind_[8].buffer_type = MYSQL_TYPE_STRING;
853  bind_[8].buffer = const_cast<char*>(lease_->hostname_.c_str());
854  bind_[8].buffer_length = lease_->hostname_.length();
855  // bind_[8].is_null = &MLM_FALSE; // commented out for performance
856  // reasons, see memset() above
857 
858  // state: uint32_t
859  bind_[9].buffer_type = MYSQL_TYPE_LONG;
860  bind_[9].buffer = reinterpret_cast<char*>(&lease_->state_);
861  bind_[9].is_unsigned = MLM_TRUE;
862  // bind_[9].is_null = &MLM_FALSE; // commented out for performance
863  // reasons, see memset() above
864 
865  // user_context: text
866  ConstElementPtr ctx = lease->getContext();
867  if (ctx) {
868  bind_[10].buffer_type = MYSQL_TYPE_STRING;
869  std::string ctx_txt = ctx->str();
870  strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
871  bind_[10].buffer = user_context_;
872  bind_[10].buffer_length = ctx_txt.length();
873  // bind_[10].is_null = &MLM_FALSE; // commented out for performance
874  // reasons, see memset() above
875  } else {
876  bind_[10].buffer_type = MYSQL_TYPE_NULL;
877  }
878 
879  // relay_id: varbinary(255)
880  relay_id_ = lease_->relay_id_;
881  if (!relay_id_.empty()) {
882  bind_[11].buffer_type = MYSQL_TYPE_BLOB;
883  bind_[11].buffer = reinterpret_cast<char*>(&relay_id_[0]);
884  relay_id_length_ = relay_id_.size();
885  bind_[11].buffer_length = relay_id_length_;
886  bind_[11].length = &relay_id_length_;
887  } else {
888  bind_[11].buffer_type = MYSQL_TYPE_NULL;
889  relay_id_null_ = MLM_TRUE;
890  bind_[11].buffer = NULL;
891  bind_[11].is_null = &relay_id_null_;
892  }
893 
894  // remote_id: varbinary(255)
895  remote_id_ = lease_->remote_id_;
896  if (!remote_id_.empty()) {
897  bind_[12].buffer_type = MYSQL_TYPE_BLOB;
898  bind_[12].buffer = reinterpret_cast<char*>(&remote_id_[0]);
899  remote_id_length_ = remote_id_.size();
900  bind_[12].buffer_length = remote_id_length_;
901  bind_[12].length = &remote_id_length_;
902  } else {
903  bind_[12].buffer_type = MYSQL_TYPE_NULL;
904  remote_id_null_ = MLM_TRUE;
905  bind_[12].buffer = NULL;
906  bind_[12].is_null = &remote_id_null_;
907  }
908 
909  // pool_id: unsigned int
910  // Can use lease_->pool_id_ directly as it is of type uint32_t.
911  bind_[13].buffer_type = MYSQL_TYPE_LONG;
912  bind_[13].buffer = reinterpret_cast<char*>(&lease_->pool_id_);
913  bind_[13].is_unsigned = MLM_TRUE;
914  // bind_[13].is_null = &MLM_FALSE; // commented out for performance
915  // reasons, see memset() above
916 
917  // Add the error flags
918  setErrorIndicators(bind_, error_, LEASE_COLUMNS);
919 
920  // .. and check that we have the numbers correct at compile time.
921  BOOST_STATIC_ASSERT(13 < LEASE_COLUMNS);
922 
923  } catch (const std::exception& ex) {
925  "Could not create bind array from Lease4: "
926  << lease_->addr_.toText() << ", reason: " << ex.what());
927  }
928 
929  // Add the data to the vector. Note the end element is one after the
930  // end of the array.
931  return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
932  }
933 
939  std::vector<MYSQL_BIND> createBindForReceive() {
940 
941  // Initialize MYSQL_BIND array.
942  // It sets all fields, including is_null, to zero, so we need to set
943  // is_null only if it should be true. This gives up minor performance
944  // benefit while being safe approach. For improved readability, the
945  // code that explicitly sets is_null is there, but is commented out.
946  memset(bind_, 0, sizeof(bind_));
947 
948  // address: uint32_t
949  bind_[0].buffer_type = MYSQL_TYPE_LONG;
950  bind_[0].buffer = reinterpret_cast<char*>(&addr4_);
951  bind_[0].is_unsigned = MLM_TRUE;
952  // bind_[0].is_null = &MLM_FALSE; // commented out for performance
953  // reasons, see memset() above
954 
955  // hwaddr: varbinary(20)
956  hwaddr_null_ = MLM_FALSE;
957  hwaddr_length_ = sizeof(hwaddr_buffer_);
958  bind_[1].buffer_type = MYSQL_TYPE_BLOB;
959  bind_[1].buffer = reinterpret_cast<char*>(hwaddr_buffer_);
960  bind_[1].buffer_length = hwaddr_length_;
961  bind_[1].length = &hwaddr_length_;
962  bind_[1].is_null = &hwaddr_null_;
963 
964  // client_id: varbinary(255)
965  client_id_length_ = sizeof(client_id_buffer_);
966  bind_[2].buffer_type = MYSQL_TYPE_BLOB;
967  bind_[2].buffer = reinterpret_cast<char*>(client_id_buffer_);
968  bind_[2].buffer_length = client_id_length_;
969  bind_[2].length = &client_id_length_;
970  bind_[2].is_null = &client_id_null_;
971  // bind_[2].is_null = &MLM_FALSE; // commented out for performance
972  // reasons, see memset() above
973 
974  // valid lifetime: unsigned int
975  bind_[3].buffer_type = MYSQL_TYPE_LONG;
976  bind_[3].buffer = reinterpret_cast<char*>(&valid_lifetime_);
977  bind_[3].is_unsigned = MLM_TRUE;
978  // bind_[3].is_null = &MLM_FALSE; // commented out for performance
979  // reasons, see memset() above
980 
981  // expire: timestamp
982  bind_[4].buffer_type = MYSQL_TYPE_TIMESTAMP;
983  bind_[4].buffer = reinterpret_cast<char*>(&expire_);
984  bind_[4].buffer_length = sizeof(expire_);
985  // bind_[4].is_null = &MLM_FALSE; // commented out for performance
986  // reasons, see memset() above
987 
988  // subnet_id: unsigned int
989  bind_[5].buffer_type = MYSQL_TYPE_LONG;
990  bind_[5].buffer = reinterpret_cast<char*>(&subnet_id_);
991  bind_[5].is_unsigned = MLM_TRUE;
992  // bind_[5].is_null = &MLM_FALSE; // commented out for performance
993  // reasons, see memset() above
994 
995  // fqdn_fwd: boolean
996  bind_[6].buffer_type = MYSQL_TYPE_TINY;
997  bind_[6].buffer = reinterpret_cast<char*>(&fqdn_fwd_);
998  bind_[6].is_unsigned = MLM_TRUE;
999  // bind_[6].is_null = &MLM_FALSE; // commented out for performance
1000  // reasons, see memset() above
1001 
1002  // fqdn_rev: boolean
1003  bind_[7].buffer_type = MYSQL_TYPE_TINY;
1004  bind_[7].buffer = reinterpret_cast<char*>(&fqdn_rev_);
1005  bind_[7].is_unsigned = MLM_TRUE;
1006  // bind_[7].is_null = &MLM_FALSE; // commented out for performance
1007  // reasons, see memset() above
1008 
1009  // hostname: varchar(255)
1010  // Note that previously we used MYSQL_TYPE_VARCHAR instead of
1011  // MYSQL_TYPE_STRING. However, that caused 'buffer type not supported'
1012  // errors on some systems running MariaDB.
1013  hostname_length_ = sizeof(hostname_buffer_);
1014  bind_[8].buffer_type = MYSQL_TYPE_STRING;
1015  bind_[8].buffer = reinterpret_cast<char*>(hostname_buffer_);
1016  bind_[8].buffer_length = hostname_length_;
1017  bind_[8].length = &hostname_length_;
1018  // bind_[8].is_null = &MLM_FALSE; // commented out for performance
1019  // reasons, see memset() above
1020 
1021  // state: uint32_t
1022  bind_[9].buffer_type = MYSQL_TYPE_LONG;
1023  bind_[9].buffer = reinterpret_cast<char*>(&state_);
1024  bind_[9].is_unsigned = MLM_TRUE;
1025  // bind_[9].is_null = &MLM_FALSE; // commented out for performance
1026  // reasons, see memset() above
1027 
1028  // user_context: text
1029  user_context_null_ = MLM_FALSE;
1030  user_context_length_ = sizeof(user_context_);
1031  bind_[10].buffer_type = MYSQL_TYPE_STRING;
1032  bind_[10].buffer = reinterpret_cast<char*>(user_context_);
1033  bind_[10].buffer_length = user_context_length_;
1034  bind_[10].length = &user_context_length_;
1035  bind_[10].is_null = &user_context_null_;
1036 
1037  // relay_id: varbinary(255)
1038  relay_id_length_ = sizeof(relay_id_buffer_);
1039  bind_[11].buffer_type = MYSQL_TYPE_BLOB;
1040  bind_[11].buffer = reinterpret_cast<char*>(relay_id_buffer_);
1041  bind_[11].buffer_length = relay_id_length_;
1042  bind_[11].length = &relay_id_length_;
1043  bind_[11].is_null = &relay_id_null_;
1044 
1045  // remote_id: varbinary(255)
1046  remote_id_length_ = sizeof(remote_id_buffer_);
1047  bind_[12].buffer_type = MYSQL_TYPE_BLOB;
1048  bind_[12].buffer = reinterpret_cast<char*>(remote_id_buffer_);
1049  bind_[12].buffer_length = remote_id_length_;
1050  bind_[12].length = &remote_id_length_;
1051  bind_[12].is_null = &remote_id_null_;
1052 
1053  // pool_id: unsigned int
1054  bind_[13].buffer_type = MYSQL_TYPE_LONG;
1055  bind_[13].buffer = reinterpret_cast<char*>(&pool_id_);
1056  bind_[13].is_unsigned = MLM_TRUE;
1057  // bind_[13].is_null = &MLM_FALSE; // commented out for performance
1058  // reasons, see memset() above
1059 
1060  // Add the error flags
1061  setErrorIndicators(bind_, error_, LEASE_COLUMNS);
1062 
1063  // .. and check that we have the numbers correct at compile time.
1064  BOOST_STATIC_ASSERT(13 < LEASE_COLUMNS);
1065 
1066  // Add the data to the vector. Note the end element is one after the
1067  // end of the array.
1068  return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
1069  }
1070 
1080  // Convert times received from the database to times for the lease
1081  // structure. See the expire code of createBindForSend for
1082  // the infinite valid lifetime special case.
1083  time_t cltt = 0;
1084  // Recover from overflow
1085  uint32_t valid_lft = valid_lifetime_;
1086  if (valid_lft == Lease::INFINITY_LFT) {
1087  valid_lft = 0;
1088  }
1089  MySqlConnection::convertFromDatabaseTime(expire_, valid_lft, cltt);
1090 
1091  if (client_id_null_ == MLM_TRUE) {
1092  // There's no client-id, so we pass client-id_length_ set to 0
1093  client_id_length_ = 0;
1094  }
1095 
1096  // Hostname is passed to Lease4 as a string object. We have to create
1097  // it from the buffer holding hostname and the buffer length.
1098  std::string hostname(hostname_buffer_,
1099  hostname_buffer_ + hostname_length_);
1100 
1101  // Set hardware address if it was set
1102  HWAddrPtr hwaddr;
1103  if (hwaddr_null_ == MLM_FALSE) {
1104  hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_, HTYPE_ETHER));
1105  }
1106 
1107  // Convert user_context to string as well.
1108  std::string user_context;
1109  if (user_context_null_ == MLM_FALSE) {
1110  user_context_[user_context_length_] = '\0';
1111  user_context.assign(user_context_);
1112  }
1113 
1114  // Set the user context if there is one.
1115  ConstElementPtr ctx;
1116  if (!user_context.empty()) {
1117  ctx = Element::fromJSON(user_context);
1118  if (!ctx || (ctx->getType() != Element::map)) {
1119  isc_throw(BadValue, "user context '" << user_context
1120  << "' is not a JSON map");
1121  }
1122  }
1123 
1124  Lease4Ptr lease(boost::make_shared<Lease4>(addr4_, hwaddr,
1125  client_id_buffer_,
1126  client_id_length_,
1127  valid_lifetime_, cltt,
1128  subnet_id_, fqdn_fwd_,
1129  fqdn_rev_, hostname));
1130 
1131  // Set state.
1132  lease->state_ = state_;
1133 
1134  if (ctx) {
1135  lease->setContext(ctx);
1136  }
1137 
1138  // Set relay id if it was set.
1139  if (relay_id_null_ == MLM_FALSE) {
1140  lease->relay_id_.assign(relay_id_buffer_,
1141  relay_id_buffer_ + relay_id_length_);
1142  }
1143 
1144  // Set remote id if it was set.
1145  if (remote_id_null_ == MLM_FALSE) {
1146  lease->remote_id_.assign(remote_id_buffer_,
1147  remote_id_buffer_ + remote_id_length_);
1148  }
1149 
1150  // Set pool ID
1151  lease->pool_id_ = pool_id_;
1152 
1153  return (lease);
1154  }
1155 
1166  std::string getErrorColumns() {
1167  return (getColumnsInError(error_, columns_, LEASE_COLUMNS));
1168  }
1169 
1170 private:
1171 
1172  // Note: All array lengths are equal to the corresponding variable in the
1173  // schema.
1174  // Note: Arrays are declared fixed length for speed of creation
1175  uint32_t addr4_;
1176  MYSQL_BIND bind_[LEASE_COLUMNS];
1177  std::string columns_[LEASE_COLUMNS];
1178  my_bool error_[LEASE_COLUMNS];
1179  Lease4Ptr lease_;
1180  std::vector<uint8_t> hwaddr_;
1181  uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
1182  unsigned long hwaddr_length_;
1183  my_bool hwaddr_null_;
1184  std::vector<uint8_t> client_id_;
1185  uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
1186  unsigned long client_id_length_;
1187  my_bool client_id_null_;
1188  MYSQL_TIME expire_;
1189  uint32_t subnet_id_;
1190  uint32_t pool_id_;
1191  uint32_t valid_lifetime_;
1192  my_bool fqdn_fwd_;
1193  my_bool fqdn_rev_;
1194  char hostname_buffer_[HOSTNAME_MAX_LEN];
1195  unsigned long hostname_length_;
1196  uint32_t state_;
1197  char user_context_[USER_CONTEXT_MAX_LEN];
1198  unsigned long user_context_length_;
1199  my_bool user_context_null_;
1200  std::vector<uint8_t> relay_id_;
1201  uint8_t relay_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
1202  unsigned long relay_id_length_;
1203  my_bool relay_id_null_;
1204  std::vector<uint8_t> remote_id_;
1205  uint8_t remote_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
1206  unsigned long remote_id_length_;
1207  my_bool remote_id_null_;
1208 };
1209 
1222 
1228 
1229  static const size_t ADDRESS_COL = 0;
1230  static const size_t DUID_COL = 1;
1231  static const size_t VALID_LIFETIME_COL = 2;
1232  static const size_t EXPIRE_COL = 3;
1233  static const size_t SUBNET_ID_COL = 4;
1234  static const size_t PREF_LIFETIME_COL = 5;
1235  static const size_t LEASE_TYPE_COL = 6;
1236  static const size_t IAID_COL = 7;
1237  static const size_t PREFIX_LEN_COL = 8;
1238  static const size_t FQDN_FWD_COL = 9;
1239  static const size_t FQDN_REV_COL = 10;
1240  static const size_t HOSTNAME_COL = 11;
1241  static const size_t HWADDR_COL = 12;
1242  static const size_t HWTYPE_COL = 13;
1243  static const size_t HWADDR_SOURCE_COL = 14;
1244  static const size_t STATE_COL = 15;
1245  static const size_t USER_CONTEXT_COL = 16;
1246  static const size_t POOL_ID_COL = 17;
1248  static const size_t LEASE_COLUMNS = 18;
1250 
1251 public:
1252 
1257  MySqlLease6Exchange() : addr6_length_(16), hwaddr_length_(0),
1258  hwaddr_null_(MLM_FALSE), duid_length_(0),
1259  iaid_(0), lease_type_(0), prefix_len_(0),
1260  pref_lifetime_(0), subnet_id_(0), pool_id_(0),
1261  valid_lifetime_(0), fqdn_fwd_(false), fqdn_rev_(false),
1262  hostname_length_(0), hwtype_(0), hwaddr_source_(0),
1263  state_(0), user_context_length_(0),
1264  user_context_null_(MLM_FALSE) {
1265  memset(addr6_buffer_, 0, sizeof(addr6_buffer_));
1266  memset(duid_buffer_, 0, sizeof(duid_buffer_));
1267  memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
1268  memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
1269  memset(user_context_, 0, sizeof(user_context_));
1270  std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
1271 
1272  // Set the column names (for error messages)
1273  columns_[ADDRESS_COL] = "address";
1274  columns_[DUID_COL] = "duid";
1275  columns_[VALID_LIFETIME_COL] = "valid_lifetime";
1276  columns_[EXPIRE_COL] = "expire";
1277  columns_[SUBNET_ID_COL] = "subnet_id";
1278  columns_[PREF_LIFETIME_COL] = "pref_lifetime";
1279  columns_[LEASE_TYPE_COL] = "lease_type";
1280  columns_[IAID_COL] = "iaid";
1281  columns_[PREFIX_LEN_COL] = "prefix_len";
1282  columns_[FQDN_FWD_COL] = "fqdn_fwd";
1283  columns_[FQDN_REV_COL] = "fqdn_rev";
1284  columns_[HOSTNAME_COL] = "hostname";
1285  columns_[HWADDR_COL] = "hwaddr";
1286  columns_[HWTYPE_COL] = "hwtype";
1287  columns_[HWADDR_SOURCE_COL] = "hwaddr_source";
1288  columns_[STATE_COL] = "state";
1289  columns_[USER_CONTEXT_COL] = "user_context";
1290  columns_[POOL_ID_COL] = "pool_id";
1291  BOOST_STATIC_ASSERT(17 < LEASE_COLUMNS);
1292  }
1293 
1302  std::vector<MYSQL_BIND> createBindForSend(const Lease6Ptr& lease) {
1303  // Store lease object to ensure it remains valid.
1304  lease_ = lease;
1305 
1306  // Ensure bind_ array clear for constructing the MYSQL_BIND structures
1307  // for this lease.
1308  // It sets all fields, including is_null, to zero, so we need to set
1309  // is_null only if it should be true. This gives up minor performance
1310  // benefit while being safe approach. For improved readability, the
1311  // code that explicitly sets is_null is there, but is commented out.
1312  memset(bind_, 0, sizeof(bind_));
1313 
1314  try {
1315  // address: binary(16)
1316  addr6_ = lease->addr_.toBytes();
1317  if (addr6_.size() != 16) {
1318  isc_throw(DbOperationError, "lease6 address is not 16 bytes long");
1319  }
1320 
1321  addr6_length_ = 16;
1322  bind_[0].buffer_type = MYSQL_TYPE_BLOB;
1323  bind_[0].buffer = reinterpret_cast<char*>(&addr6_[0]);
1324  bind_[0].buffer_length = 16;
1325  bind_[0].length = &addr6_length_;
1326  // bind_[0].is_null = &MLM_FALSE; // commented out for performance
1327  // reasons, see memset() above
1328 
1329  // duid: varchar(130)
1330  if (!lease_->duid_) {
1331  isc_throw(DbOperationError, "lease6 for address " << lease->addr_.toText()
1332  << " is missing mandatory client-id.");
1333  }
1334  duid_ = lease_->duid_->getDuid();
1335  duid_length_ = duid_.size();
1336 
1337  bind_[1].buffer_type = MYSQL_TYPE_BLOB;
1338  bind_[1].buffer = reinterpret_cast<char*>(&(duid_[0]));
1339  bind_[1].buffer_length = duid_length_;
1340  bind_[1].length = &duid_length_;
1341  // bind_[1].is_null = &MLM_FALSE; // commented out for performance
1342  // reasons, see memset() above
1343 
1344  // valid lifetime: unsigned int
1345  bind_[2].buffer_type = MYSQL_TYPE_LONG;
1346  bind_[2].buffer = reinterpret_cast<char*>(&lease_->valid_lft_);
1347  bind_[2].is_unsigned = MLM_TRUE;
1348  // bind_[2].is_null = &MLM_FALSE; // commented out for performance
1349  // reasons, see memset() above
1350 
1351  // expire: timestamp
1352  // The lease structure holds the client last transmission time (cltt_)
1353  // For convenience for external tools, this is converted to lease
1354  // expiry time (expire). The relationship is given by:
1355  //
1356  // expire = cltt_ + valid_lft_
1357  // Avoid overflow with infinite valid lifetime by using
1358  // expire = cltt_ when valid_lft_ = 0xffffffff
1359  uint32_t valid_lft = lease_->valid_lft_;
1360  if (valid_lft == Lease::INFINITY_LFT) {
1361  valid_lft = 0;
1362  }
1363  MySqlConnection::convertToDatabaseTime(lease_->cltt_, valid_lft,
1364  expire_);
1365  bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
1366  bind_[3].buffer = reinterpret_cast<char*>(&expire_);
1367  bind_[3].buffer_length = sizeof(expire_);
1368  // bind_[3].is_null = &MLM_FALSE; // commented out for performance
1369  // reasons, see memset() above
1370 
1371  // subnet_id: unsigned int
1372  // Can use lease_->subnet_id_ directly as it is of type uint32_t.
1373  bind_[4].buffer_type = MYSQL_TYPE_LONG;
1374  bind_[4].buffer = reinterpret_cast<char*>(&lease_->subnet_id_);
1375  bind_[4].is_unsigned = MLM_TRUE;
1376  // bind_[4].is_null = &MLM_FALSE; // commented out for performance
1377  // reasons, see memset() above
1378 
1379  // pref_lifetime: unsigned int
1380  // Can use lease_->preferred_lft_ directly as it is of type uint32_t.
1381  bind_[5].buffer_type = MYSQL_TYPE_LONG;
1382  bind_[5].buffer = reinterpret_cast<char*>(&lease_->preferred_lft_);
1383  bind_[5].is_unsigned = MLM_TRUE;
1384  // bind_[5].is_null = &MLM_FALSE; // commented out for performance
1385  // reasons, see memset() above
1386 
1387  // lease_type: tinyint
1388  // Must convert to uint8_t as lease_->type_ is a LeaseType variable.
1389  lease_type_ = lease_->type_;
1390  bind_[6].buffer_type = MYSQL_TYPE_TINY;
1391  bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
1392  bind_[6].is_unsigned = MLM_TRUE;
1393  // bind_[6].is_null = &MLM_FALSE; // commented out for performance
1394  // reasons, see memset() above
1395 
1396  // iaid: unsigned int
1397  // Can use lease_->iaid_ directly as it is of type uint32_t.
1398  bind_[7].buffer_type = MYSQL_TYPE_LONG;
1399  bind_[7].buffer = reinterpret_cast<char*>(&lease_->iaid_);
1400  bind_[7].is_unsigned = MLM_TRUE;
1401  // bind_[7].is_null = &MLM_FALSE; // commented out for performance
1402  // reasons, see memset() above
1403 
1404  // prefix_len: unsigned tinyint
1405  // Can use lease_->prefixlen_ directly as it is uint32_t.
1406  bind_[8].buffer_type = MYSQL_TYPE_TINY;
1407  bind_[8].buffer = reinterpret_cast<char*>(&lease_->prefixlen_);
1408  bind_[8].is_unsigned = MLM_TRUE;
1409  // bind_[8].is_null = &MLM_FALSE; // commented out for performance
1410  // reasons, see memset() above
1411 
1412  // fqdn_fwd: boolean
1413  bind_[9].buffer_type = MYSQL_TYPE_TINY;
1414  bind_[9].buffer = reinterpret_cast<char*>(&lease_->fqdn_fwd_);
1415  bind_[9].is_unsigned = MLM_TRUE;
1416  // bind_[9].is_null = &MLM_FALSE; // commented out for performance
1417  // reasons, see memset() above
1418 
1419  // fqdn_rev: boolean
1420  bind_[10].buffer_type = MYSQL_TYPE_TINY;
1421  bind_[10].buffer = reinterpret_cast<char*>(&lease_->fqdn_rev_);
1422  bind_[10].is_unsigned = MLM_TRUE;
1423  // bind_[10].is_null = &MLM_FALSE; // commented out for performance
1424  // reasons, see memset() above
1425 
1426  // hostname: varchar(255)
1427  bind_[11].buffer_type = MYSQL_TYPE_STRING;
1428  bind_[11].buffer = const_cast<char*>(lease_->hostname_.c_str());
1429  bind_[11].buffer_length = lease_->hostname_.length();
1430  // bind_[11].is_null = &MLM_FALSE; // commented out for performance
1431  // reasons, see memset() above
1432 
1433  // hwaddr: varbinary(20) - hardware/MAC address
1434  HWAddrPtr hwaddr = lease_->hwaddr_;
1435  if (hwaddr) {
1436  hwaddr_ = hwaddr->hwaddr_;
1437  hwaddr_length_ = hwaddr->hwaddr_.size();
1438 
1439  // Make sure that the buffer has at least length of 1, even if
1440  // empty HW address is passed. This is required by some of the
1441  // MySQL connectors that the buffer is set to non-null value.
1442  // Otherwise, null value would be inserted into the database,
1443  // rather than empty string.
1444  if (hwaddr_.empty()) {
1445  hwaddr_.resize(1);
1446  }
1447 
1448  bind_[12].buffer_type = MYSQL_TYPE_BLOB;
1449  bind_[12].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
1450  bind_[12].buffer_length = hwaddr_length_;
1451  bind_[12].length = &hwaddr_length_;
1452  } else {
1453  bind_[12].buffer_type = MYSQL_TYPE_NULL;
1454  // According to http://dev.mysql.com/doc/refman/5.5/en/
1455  // c-api-prepared-statement-data-structures.html, the other
1456  // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
1457  // but let's set them to some sane values in case earlier versions
1458  // didn't have that assumption.
1459  hwaddr_null_ = MLM_TRUE;
1460  bind_[12].buffer = NULL;
1461  bind_[12].is_null = &hwaddr_null_;
1462  }
1463 
1464  // hardware type: unsigned short int (16 bits)
1465  if (hwaddr) {
1466  hwtype_ = lease->hwaddr_->htype_;
1467  bind_[13].buffer_type = MYSQL_TYPE_SHORT;
1468  bind_[13].buffer = reinterpret_cast<char*>(&hwtype_);
1469  bind_[13].is_unsigned = MLM_TRUE;
1470  } else {
1471  hwtype_ = 0;
1472  bind_[13].buffer_type = MYSQL_TYPE_NULL;
1473  // According to http://dev.mysql.com/doc/refman/5.5/en/
1474  // c-api-prepared-statement-data-structures.html, the other
1475  // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
1476  // but let's set them to some sane values in case earlier versions
1477  // didn't have that assumption.
1478  hwaddr_null_ = MLM_TRUE;
1479  bind_[13].buffer = NULL;
1480  bind_[13].is_null = &hwaddr_null_;
1481  }
1482 
1483  // hardware source: unsigned int (32 bits)
1484  if (hwaddr) {
1485  hwaddr_source_ = lease->hwaddr_->source_;
1486  bind_[14].buffer_type = MYSQL_TYPE_LONG;
1487  bind_[14].buffer = reinterpret_cast<char*>(&hwaddr_source_);
1488  bind_[14].is_unsigned = MLM_TRUE;
1489  } else {
1490  hwaddr_source_ = 0;
1491  bind_[14].buffer_type = MYSQL_TYPE_NULL;
1492  // According to http://dev.mysql.com/doc/refman/5.5/en/
1493  // c-api-prepared-statement-data-structures.html, the other
1494  // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
1495  // but let's set them to some sane values in case earlier versions
1496  // didn't have that assumption.
1497  hwaddr_null_ = MLM_TRUE;
1498  bind_[14].buffer = NULL;
1499  bind_[14].is_null = &hwaddr_null_;
1500  }
1501 
1502  // state: uint32_t
1503  bind_[15].buffer_type = MYSQL_TYPE_LONG;
1504  bind_[15].buffer = reinterpret_cast<char*>(&lease_->state_);
1505  bind_[15].is_unsigned = MLM_TRUE;
1506  // bind_[15].is_null = &MLM_FALSE; // commented out for performance
1507  // reasons, see memset() above
1508 
1509  // user_context: text
1510  ConstElementPtr ctx = lease->getContext();
1511  if (ctx) {
1512  bind_[16].buffer_type = MYSQL_TYPE_STRING;
1513  std::string ctx_txt = ctx->str();
1514  strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
1515  bind_[16].buffer = user_context_;
1516  bind_[16].buffer_length = ctx_txt.length();
1517  // bind_[16].is_null = &MLM_FALSE; // commented out for performance
1518  // reasons, see memset() above
1519  } else {
1520  bind_[16].buffer_type = MYSQL_TYPE_NULL;
1521  }
1522 
1523  // pool_id: unsigned int
1524  // Can use lease_->pool_id_ directly as it is of type uint32_t.
1525  bind_[17].buffer_type = MYSQL_TYPE_LONG;
1526  bind_[17].buffer = reinterpret_cast<char*>(&lease_->pool_id_);
1527  bind_[17].is_unsigned = MLM_TRUE;
1528  // bind_[17].is_null = &MLM_FALSE; // commented out for performance
1529  // reasons, see memset() above
1530 
1531  // Add the error flags
1532  setErrorIndicators(bind_, error_, LEASE_COLUMNS);
1533 
1534  // .. and check that we have the numbers correct at compile time.
1535  BOOST_STATIC_ASSERT(17 < LEASE_COLUMNS);
1536 
1537  } catch (const std::exception& ex) {
1539  "Could not create bind array from Lease6: "
1540  << lease_->addr_.toText() << ", reason: " << ex.what());
1541  }
1542 
1543  // Add the data to the vector. Note the end element is one after the
1544  // end of the array.
1545  return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
1546  }
1547 
1556  std::vector<MYSQL_BIND> createBindForReceive() {
1557 
1558  // Initialize MYSQL_BIND array.
1559  // It sets all fields, including is_null, to zero, so we need to set
1560  // is_null only if it should be true. This gives up minor performance
1561  // benefit while being safe approach. For improved readability, the
1562  // code that explicitly sets is_null is there, but is commented out.
1563  memset(bind_, 0, sizeof(bind_));
1564 
1565  // address: binary(16)
1566  addr6_length_ = 16;
1567  bind_[0].buffer_type = MYSQL_TYPE_BLOB;
1568  bind_[0].buffer = reinterpret_cast<char*>(addr6_buffer_);
1569  bind_[0].buffer_length = addr6_length_;
1570  bind_[0].length = &addr6_length_;
1571  // bind_[0].is_null = &MLM_FALSE; // commented out for performance
1572  // reasons, see memset() above
1573 
1574  // duid: varbinary(130)
1575  duid_length_ = sizeof(duid_buffer_);
1576  bind_[1].buffer_type = MYSQL_TYPE_BLOB;
1577  bind_[1].buffer = reinterpret_cast<char*>(duid_buffer_);
1578  bind_[1].buffer_length = duid_length_;
1579  bind_[1].length = &duid_length_;
1580  // bind_[1].is_null = &MLM_FALSE; // commented out for performance
1581  // reasons, see memset() above
1582 
1583  // valid lifetime: unsigned int
1584  bind_[2].buffer_type = MYSQL_TYPE_LONG;
1585  bind_[2].buffer = reinterpret_cast<char*>(&valid_lifetime_);
1586  bind_[2].is_unsigned = MLM_TRUE;
1587  // bind_[2].is_null = &MLM_FALSE; // commented out for performance
1588  // reasons, see memset() above
1589 
1590  // expire: timestamp
1591  bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
1592  bind_[3].buffer = reinterpret_cast<char*>(&expire_);
1593  bind_[3].buffer_length = sizeof(expire_);
1594  // bind_[3].is_null = &MLM_FALSE; // commented out for performance
1595  // reasons, see memset() above
1596 
1597  // subnet_id: unsigned int
1598  bind_[4].buffer_type = MYSQL_TYPE_LONG;
1599  bind_[4].buffer = reinterpret_cast<char*>(&subnet_id_);
1600  bind_[4].is_unsigned = MLM_TRUE;
1601  // bind_[4].is_null = &MLM_FALSE; // commented out for performance
1602  // reasons, see memset() above
1603 
1604  // pref_lifetime: unsigned int
1605  bind_[5].buffer_type = MYSQL_TYPE_LONG;
1606  bind_[5].buffer = reinterpret_cast<char*>(&pref_lifetime_);
1607  bind_[5].is_unsigned = MLM_TRUE;
1608  // bind_[5].is_null = &MLM_FALSE; // commented out for performance
1609  // reasons, see memset() above
1610 
1611  // lease_type: tinyint
1612  bind_[6].buffer_type = MYSQL_TYPE_TINY;
1613  bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
1614  bind_[6].is_unsigned = MLM_TRUE;
1615  // bind_[6].is_null = &MLM_FALSE; // commented out for performance
1616  // reasons, see memset() above
1617 
1618  // iaid: unsigned int
1619  bind_[7].buffer_type = MYSQL_TYPE_LONG;
1620  bind_[7].buffer = reinterpret_cast<char*>(&iaid_);
1621  bind_[7].is_unsigned = MLM_TRUE;
1622  // bind_[7].is_null = &MLM_FALSE; // commented out for performance
1623  // reasons, see memset() above
1624 
1625  // prefix_len: unsigned tinyint
1626  bind_[8].buffer_type = MYSQL_TYPE_TINY;
1627  bind_[8].buffer = reinterpret_cast<char*>(&prefix_len_);
1628  bind_[8].is_unsigned = MLM_TRUE;
1629  // bind_[8].is_null = &MLM_FALSE; // commented out for performance
1630  // reasons, see memset() above
1631 
1632  // fqdn_fwd: boolean
1633  bind_[9].buffer_type = MYSQL_TYPE_TINY;
1634  bind_[9].buffer = reinterpret_cast<char*>(&fqdn_fwd_);
1635  bind_[9].is_unsigned = MLM_TRUE;
1636  // bind_[9].is_null = &MLM_FALSE; // commented out for performance
1637  // reasons, see memset() above
1638 
1639  // fqdn_rev: boolean
1640  bind_[10].buffer_type = MYSQL_TYPE_TINY;
1641  bind_[10].buffer = reinterpret_cast<char*>(&fqdn_rev_);
1642  bind_[10].is_unsigned = MLM_TRUE;
1643  // bind_[10].is_null = &MLM_FALSE; // commented out for performance
1644  // reasons, see memset() above
1645 
1646  // hostname: varchar(255)
1647  hostname_length_ = sizeof(hostname_buffer_);
1648  bind_[11].buffer_type = MYSQL_TYPE_STRING;
1649  bind_[11].buffer = reinterpret_cast<char*>(hostname_buffer_);
1650  bind_[11].buffer_length = hostname_length_;
1651  bind_[11].length = &hostname_length_;
1652  // bind_[11].is_null = &MLM_FALSE; // commented out for performance
1653  // reasons, see memset() above
1654 
1655  // hwaddr: varbinary(20)
1656  hwaddr_null_ = MLM_FALSE;
1657  hwaddr_length_ = sizeof(hwaddr_buffer_);
1658  bind_[12].buffer_type = MYSQL_TYPE_BLOB;
1659  bind_[12].buffer = reinterpret_cast<char*>(hwaddr_buffer_);
1660  bind_[12].buffer_length = hwaddr_length_;
1661  bind_[12].length = &hwaddr_length_;
1662  bind_[12].is_null = &hwaddr_null_;
1663 
1664  // hardware type: unsigned short int (16 bits)
1665  bind_[13].buffer_type = MYSQL_TYPE_SHORT;
1666  bind_[13].buffer = reinterpret_cast<char*>(&hwtype_);
1667  bind_[13].is_unsigned = MLM_TRUE;
1668 
1669  // hardware source: unsigned int (32 bits)
1670  bind_[14].buffer_type = MYSQL_TYPE_LONG;
1671  bind_[14].buffer = reinterpret_cast<char*>(&hwaddr_source_);
1672  bind_[14].is_unsigned = MLM_TRUE;
1673 
1674  // state: uint32_t
1675  bind_[15].buffer_type = MYSQL_TYPE_LONG;
1676  bind_[15].buffer = reinterpret_cast<char*>(&state_);
1677  bind_[15].is_unsigned = MLM_TRUE;
1678  // bind_[15].is_null = &MLM_FALSE; // commented out for performance
1679  // reasons, see memset() above
1680 
1681  // user_context: text
1682  user_context_null_ = MLM_FALSE;
1683  user_context_length_ = sizeof(user_context_);
1684  bind_[16].buffer_type = MYSQL_TYPE_STRING;
1685  bind_[16].buffer = reinterpret_cast<char*>(user_context_);
1686  bind_[16].buffer_length = user_context_length_;
1687  bind_[16].length = &user_context_length_;
1688  bind_[16].is_null = &user_context_null_;
1689 
1690  // pool_id: unsigned int
1691  bind_[17].buffer_type = MYSQL_TYPE_LONG;
1692  bind_[17].buffer = reinterpret_cast<char*>(&pool_id_);
1693  bind_[17].is_unsigned = MLM_TRUE;
1694  // bind_[17].is_null = &MLM_FALSE; // commented out for performance
1695  // reasons, see memset() above
1696 
1697  // Add the error flags
1698  setErrorIndicators(bind_, error_, LEASE_COLUMNS);
1699 
1700  // .. and check that we have the numbers correct at compile time.
1701  BOOST_STATIC_ASSERT(17 < LEASE_COLUMNS);
1702 
1703  // Add the data to the vector. Note the end element is one after the
1704  // end of the array.
1705  return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
1706  }
1707 
1719  // Convert lease from network-order bytes to IOAddress.
1720  IOAddress addr = IOAddress::fromBytes(AF_INET6, addr6_buffer_);
1721  std::string address = addr.toText();
1722 
1723  // Set the lease type in a variable of the appropriate data type, which
1724  // has been initialized with an arbitrary (but valid) value.
1725  Lease::Type type = Lease::TYPE_NA;
1726  switch (lease_type_) {
1727  case Lease::TYPE_NA:
1728  type = Lease::TYPE_NA;
1729  break;
1730 
1731  case Lease::TYPE_TA:
1732  type = Lease::TYPE_TA;
1733  break;
1734 
1735  case Lease::TYPE_PD:
1736  type = Lease::TYPE_PD;
1737  break;
1738 
1739  default:
1740  isc_throw(BadValue, "invalid lease type returned (" <<
1741  static_cast<int>(lease_type_) << ") for lease with "
1742  << "address " << address << ". Only 0, 1, or 2 are "
1743  << "allowed.");
1744  }
1745 
1746  if (type != Lease::TYPE_PD) {
1747  prefix_len_ = 128;
1748  }
1749 
1750  // Set up DUID,
1751  DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_));
1752 
1753  // Hostname is passed to Lease6 as a string object, so we have to
1754  // create it from the hostname buffer and length.
1755  std::string hostname(hostname_buffer_,
1756  hostname_buffer_ + hostname_length_);
1757 
1758  // Set hardware address if it was set
1759  HWAddrPtr hwaddr;
1760  if (hwaddr_null_ == MLM_FALSE) {
1761  hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_, hwtype_));
1762  hwaddr->source_ = hwaddr_source_;
1763  }
1764 
1765  // Convert user_context to string as well.
1766  std::string user_context;
1767  if (user_context_null_ == MLM_FALSE) {
1768  user_context_[user_context_length_] = '\0';
1769  user_context.assign(user_context_);
1770  }
1771 
1772  // Set the user context if there is one.
1773  ConstElementPtr ctx;
1774  if (!user_context.empty()) {
1775  ctx = Element::fromJSON(user_context);
1776  if (!ctx || (ctx->getType() != Element::map)) {
1777  isc_throw(BadValue, "user context '" << user_context
1778  << "' is not a JSON map");
1779  }
1780  }
1781 
1782  // Create the lease and set the cltt (after converting from the
1783  // expire time retrieved from the database).
1784  Lease6Ptr result(boost::make_shared<Lease6>(type, addr, duid_ptr, iaid_,
1785  pref_lifetime_,
1786  valid_lifetime_, subnet_id_,
1787  fqdn_fwd_, fqdn_rev_,
1788  hostname, hwaddr,
1789  prefix_len_));
1790  time_t cltt = 0;
1791  // Recover from overflow (see expire code of createBindForSend).
1792  uint32_t valid_lft = valid_lifetime_;
1793  if (valid_lft == Lease::INFINITY_LFT) {
1794  valid_lft = 0;
1795  }
1796  MySqlConnection::convertFromDatabaseTime(expire_, valid_lft, cltt);
1797  // Update cltt_ and current_cltt_ explicitly.
1798  result->cltt_ = cltt;
1799  result->current_cltt_ = cltt;
1800 
1801  // Set state.
1802  result->state_ = state_;
1803 
1804  if (ctx) {
1805  result->setContext(ctx);
1806  }
1807 
1808  // Set pool ID.
1809  result->pool_id_ = pool_id_;
1810 
1811  return (result);
1812  }
1813 
1824  std::string getErrorColumns() {
1825  return (getColumnsInError(error_, columns_, LEASE_COLUMNS));
1826  }
1827 
1828 private:
1829 
1830  // Note: All array lengths are equal to the corresponding variable in the
1831  // schema.
1832  // Note: arrays are declared fixed length for speed of creation
1833  std::vector<uint8_t> addr6_;
1834  uint8_t addr6_buffer_[16];
1835  unsigned long addr6_length_;
1836  MYSQL_BIND bind_[LEASE_COLUMNS];
1837  std::string columns_[LEASE_COLUMNS];
1838  my_bool error_[LEASE_COLUMNS];
1839  Lease6Ptr lease_;
1840  std::vector<uint8_t> hwaddr_;
1841  uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
1842  unsigned long hwaddr_length_;
1843  my_bool hwaddr_null_;
1844  std::vector<uint8_t> duid_;
1845  uint8_t duid_buffer_[DUID::MAX_DUID_LEN];
1846  unsigned long duid_length_;
1847  MYSQL_TIME expire_;
1848  uint32_t iaid_;
1849  uint8_t lease_type_;
1850  uint8_t prefix_len_;
1851  uint32_t pref_lifetime_;
1852  uint32_t subnet_id_;
1853  uint32_t pool_id_;
1854  uint32_t valid_lifetime_;
1855  my_bool fqdn_fwd_;
1856  my_bool fqdn_rev_;
1857  char hostname_buffer_[HOSTNAME_MAX_LEN];
1858  unsigned long hostname_length_;
1859  uint16_t hwtype_;
1860  uint32_t hwaddr_source_;
1861  uint32_t state_;
1862  char user_context_[USER_CONTEXT_MAX_LEN];
1863  unsigned long user_context_length_;
1864  my_bool user_context_null_;
1865 };
1866 
1873 
1875 public:
1876 
1886  MySqlLeaseStatsQuery(MySqlConnection& conn, const size_t statement_index,
1887  const bool fetch_type, const bool fetch_pool = false)
1888  : conn_(conn), statement_index_(statement_index), statement_(NULL),
1889  fetch_type_(fetch_type), fetch_pool_(fetch_pool),
1890  // Set the number of columns in the bind array based on fetch_type
1891  // This is the number of columns expected in the result set
1892  bind_(fetch_type_ ? (fetch_pool_ ? 5 : 4) : (fetch_pool_ ? 4 : 3)),
1893  subnet_id_(0), pool_id_(0), lease_type_(Lease::TYPE_NA),
1894  state_(Lease::STATE_DEFAULT), state_count_(0) {
1895  validateStatement();
1896  }
1897 
1907  MySqlLeaseStatsQuery(MySqlConnection& conn, const size_t statement_index,
1908  const bool fetch_type, const SubnetID& subnet_id)
1909  : LeaseStatsQuery(subnet_id), conn_(conn), statement_index_(statement_index),
1910  statement_(NULL), fetch_type_(fetch_type), fetch_pool_(false),
1911  // Set the number of columns in the bind array based on fetch_type
1912  // This is the number of columns expected in the result set
1913  bind_(fetch_type_ ? 4 : 3), subnet_id_(0), pool_id_(0),
1914  lease_type_(Lease::TYPE_NA), state_(Lease::STATE_DEFAULT),
1915  state_count_(0) {
1916  validateStatement();
1917  }
1918 
1931  MySqlLeaseStatsQuery(MySqlConnection& conn, const size_t statement_index,
1932  const bool fetch_type, const SubnetID& first_subnet_id,
1933  const SubnetID& last_subnet_id)
1934  : LeaseStatsQuery(first_subnet_id, last_subnet_id), conn_(conn),
1935  statement_index_(statement_index), statement_(NULL),
1936  fetch_type_(fetch_type), fetch_pool_(false),
1937  // Set the number of columns in the bind array based on fetch_type
1938  // This is the number of columns expected in the result set
1939  bind_(fetch_type_ ? 4 : 3), subnet_id_(0), pool_id_(0),
1940  lease_type_(Lease::TYPE_NA), state_(Lease::STATE_DEFAULT),
1941  state_count_(0) {
1942  validateStatement();
1943  }
1944 
1947  (void) mysql_stmt_free_result(statement_);
1948  }
1949 
1957  void start() {
1958  // Set up where clause inputs if needed.
1959  if (getSelectMode() != ALL_SUBNETS && getSelectMode() != ALL_SUBNET_POOLS) {
1960  MYSQL_BIND inbind[2];
1961  memset(inbind, 0, sizeof(inbind));
1962 
1963  // Add first_subnet_id used by both single and range.
1964  inbind[0].buffer_type = MYSQL_TYPE_LONG;
1965  inbind[0].buffer = reinterpret_cast<char*>(&first_subnet_id_);
1966  inbind[0].is_unsigned = MLM_TRUE;
1967 
1968  // Add last_subnet_id for range.
1969  if (getSelectMode() == SUBNET_RANGE) {
1970  inbind[1].buffer_type = MYSQL_TYPE_LONG;
1971  inbind[1].buffer = reinterpret_cast<char*>(&last_subnet_id_);
1972  inbind[1].is_unsigned = MLM_TRUE;
1973  }
1974 
1975  // Bind the parameters to the statement
1976  int status = mysql_stmt_bind_param(statement_, &inbind[0]);
1977  conn_.checkError(status, statement_index_, "unable to bind parameters");
1978  }
1979 
1980  int col = 0;
1981  // subnet_id: unsigned int
1982  bind_[col].buffer_type = MYSQL_TYPE_LONG;
1983  bind_[col].buffer = reinterpret_cast<char*>(&subnet_id_);
1984  bind_[col].is_unsigned = MLM_TRUE;
1985  ++col;
1986 
1987  // Fetch the pool id if we were told to do so.
1988  if (fetch_pool_) {
1989  // pool id: uint32_t
1990  bind_[col].buffer_type = MYSQL_TYPE_LONG;
1991  bind_[col].buffer = reinterpret_cast<char*>(&pool_id_);
1992  bind_[col].is_unsigned = MLM_TRUE;
1993  ++col;
1994  }
1995 
1996  // Fetch the lease type if we were told to do so.
1997  if (fetch_type_) {
1998  // lease type: uint32_t
1999  bind_[col].buffer_type = MYSQL_TYPE_LONG;
2000  bind_[col].buffer = reinterpret_cast<char*>(&lease_type_);
2001  bind_[col].is_unsigned = MLM_TRUE;
2002  ++col;
2003  } else {
2004  fetch_type_ = Lease::TYPE_NA;
2005  }
2006 
2007  // state: uint32_t
2008  bind_[col].buffer_type = MYSQL_TYPE_LONG;
2009  bind_[col].buffer = reinterpret_cast<char*>(&state_);
2010  bind_[col].is_unsigned = MLM_TRUE;
2011  ++col;
2012 
2013  // state_count_: int64_t
2014  bind_[col].buffer_type = MYSQL_TYPE_LONGLONG;
2015  bind_[col].buffer = reinterpret_cast<char*>(&state_count_);
2016  //bind_[col].is_unsigned = MLM_FALSE;
2017 
2018  // Set up the MYSQL_BIND array for the data being returned
2019  // and bind it to the statement.
2020  int status = mysql_stmt_bind_result(statement_, &bind_[0]);
2021  conn_.checkError(status, statement_index_, "outbound binding failed");
2022 
2023  // Execute the statement
2024  status = MysqlExecuteStatement(statement_);
2025  conn_.checkError(status, statement_index_, "unable to execute");
2026 
2027  // Ensure that all the lease information is retrieved in one go to avoid
2028  // overhead of going back and forth between client and server.
2029  status = mysql_stmt_store_result(statement_);
2030  conn_.checkError(status, statement_index_, "results storage failed");
2031  }
2032 
2049  bool have_row = false;
2050  int status = mysql_stmt_fetch(statement_);
2051  if (status == MLM_MYSQL_FETCH_SUCCESS) {
2052  row.subnet_id_ = static_cast<SubnetID>(subnet_id_);
2053  row.pool_id_ = pool_id_;
2054  row.lease_type_ = static_cast<Lease::Type>(lease_type_);
2055  row.lease_state_ = state_;
2056  if (state_count_ >= 0) {
2057  row.state_count_ = state_count_;
2058  } else {
2059  row.state_count_ = 0;
2060  if (!negative_count_) {
2061  negative_count_ = true;
2063  }
2064  }
2065  have_row = true;
2066  } else if (status != MYSQL_NO_DATA) {
2067  conn_.checkError(status, statement_index_, "getNextRow failed");
2068  }
2069 
2070  return (have_row);
2071  }
2072 
2073 private:
2074 
2078  void validateStatement() {
2079  if (statement_index_ >= MySqlLeaseMgr::NUM_STATEMENTS) {
2080  isc_throw(BadValue, "MySqlLeaseStatsQuery"
2081  " - invalid statement index" << statement_index_);
2082  }
2083 
2084  statement_ = conn_.getStatement(statement_index_);
2085  }
2086 
2088  MySqlConnection& conn_;
2089 
2091  size_t statement_index_;
2092 
2094  MYSQL_STMT *statement_;
2095 
2097  bool fetch_type_;
2098 
2100  bool fetch_pool_;
2101 
2103  std::vector<MYSQL_BIND> bind_;
2104 
2106  uint32_t subnet_id_;
2107 
2109  uint32_t pool_id_;
2110 
2112  uint32_t lease_type_;
2113 
2115  uint32_t state_;
2116 
2118  int64_t state_count_;
2119 
2121  static bool negative_count_;
2122 };
2123 
2124 // Initialize negative state count flag to false.
2125 bool MySqlLeaseStatsQuery::negative_count_ = false;
2126 
2127 // MySqlLeaseContext Constructor
2128 
2129 MySqlLeaseContext::MySqlLeaseContext(const DatabaseConnection::ParameterMap& parameters,
2130  IOServiceAccessorPtr io_service_accessor,
2131  DbCallback db_reconnect_callback)
2132  : conn_(parameters, io_service_accessor, db_reconnect_callback) {
2133 }
2134 
2135 // MySqlLeaseContextAlloc Constructor and Destructor
2136 
2137 MySqlLeaseMgr::MySqlLeaseContextAlloc::MySqlLeaseContextAlloc(
2138  const MySqlLeaseMgr& mgr) : ctx_(), mgr_(mgr) {
2139 
2140  if (MultiThreadingMgr::instance().getMode()) {
2141  // multi-threaded
2142  {
2143  // we need to protect the whole pool_ operation, hence extra scope {}
2144  lock_guard<mutex> lock(mgr_.pool_->mutex_);
2145  if (!mgr_.pool_->pool_.empty()) {
2146  ctx_ = mgr_.pool_->pool_.back();
2147  mgr_.pool_->pool_.pop_back();
2148  }
2149  }
2150  if (!ctx_) {
2151  ctx_ = mgr_.createContext();
2152  }
2153  } else {
2154  // single-threaded
2155  if (mgr_.pool_->pool_.empty()) {
2156  isc_throw(Unexpected, "No available MySQL lease context?!");
2157  }
2158  ctx_ = mgr_.pool_->pool_.back();
2159  }
2160 }
2161 
2162 MySqlLeaseMgr::MySqlLeaseContextAlloc::~MySqlLeaseContextAlloc() {
2163  if (MultiThreadingMgr::instance().getMode()) {
2164  // multi-threaded
2165  lock_guard<mutex> lock(mgr_.pool_->mutex_);
2166  mgr_.pool_->pool_.push_back(ctx_);
2167  }
2168  // If running in single-threaded mode, there's nothing to do here.
2169 }
2170 
2171 // MySqlLeaseTrackingContextAlloc Constructor and Destructor
2172 
2173 MySqlLeaseMgr::MySqlLeaseTrackingContextAlloc::MySqlLeaseTrackingContextAlloc(
2174  MySqlLeaseMgr& mgr, const LeasePtr& lease) : ctx_(), mgr_(mgr), lease_(lease) {
2175 
2176  if (MultiThreadingMgr::instance().getMode()) {
2177  // multi-threaded
2178  {
2179  // we need to protect the whole pool_ operation, hence extra scope {}
2180  lock_guard<mutex> lock(mgr_.pool_->mutex_);
2181  if (mgr_.hasCallbacks() && !mgr_.tryLock(lease)) {
2182  isc_throw(DbOperationError, "unable to lock the lease " << lease->addr_);
2183  }
2184  if (!mgr_.pool_->pool_.empty()) {
2185  ctx_ = mgr_.pool_->pool_.back();
2186  mgr_.pool_->pool_.pop_back();
2187  }
2188  }
2189  if (!ctx_) {
2190  ctx_ = mgr_.createContext();
2191  }
2192  } else {
2193  // single-threaded
2194  if (mgr_.pool_->pool_.empty()) {
2195  isc_throw(Unexpected, "No available MySQL lease context?!");
2196  }
2197  ctx_ = mgr_.pool_->pool_.back();
2198  }
2199 }
2200 
2201 MySqlLeaseMgr::MySqlLeaseTrackingContextAlloc::~MySqlLeaseTrackingContextAlloc() {
2202  if (MultiThreadingMgr::instance().getMode()) {
2203  // multi-threaded
2204  lock_guard<mutex> lock(mgr_.pool_->mutex_);
2205  if (mgr_.hasCallbacks()) {
2206  mgr_.unlock(lease_);
2207  }
2208  mgr_.pool_->pool_.push_back(ctx_);
2209  }
2210  // If running in single-threaded mode, there's nothing to do here.
2211 }
2212 
2213 // MySqlLeaseMgr Constructor and Destructor
2214 
2216  : TrackingLeaseMgr(), parameters_(parameters), timer_name_("") {
2217 
2218  // Check if the extended info tables are enabled.
2219  setExtendedInfoTablesEnabled(parameters);
2220 
2221  // Create unique timer name per instance.
2222  timer_name_ = "MySqlLeaseMgr[";
2223  timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this));
2224  timer_name_ += "]DbReconnectTimer";
2225 
2226  // Validate schema version first.
2227  std::pair<uint32_t, uint32_t> code_version(MYSQL_SCHEMA_VERSION_MAJOR,
2229  std::pair<uint32_t, uint32_t> db_version = getVersion();
2230  if (code_version != db_version) {
2232  "MySQL schema version mismatch: need version: "
2233  << code_version.first << "." << code_version.second
2234  << " found version: " << db_version.first << "."
2235  << db_version.second);
2236  }
2237 
2238  // Create an initial context.
2239  pool_.reset(new MySqlLeaseContextPool());
2240  pool_->pool_.push_back(createContext());
2241 }
2242 
2244 }
2245 
2246 bool
2249 
2250  // Invoke application layer connection lost callback.
2251  if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) {
2252  return (false);
2253  }
2254 
2255  bool reopened = false;
2256 
2257  const std::string timer_name = db_reconnect_ctl->timerName();
2258 
2259  // At least one connection was lost.
2260  try {
2261  CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
2262  LeaseMgrFactory::recreate(cfg_db->getLeaseDbAccessString());
2263  reopened = true;
2264  } catch (const std::exception& ex) {
2266  .arg(ex.what());
2267  }
2268 
2269  if (reopened) {
2270  // Cancel the timer.
2271  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
2272  TimerMgr::instance()->unregisterTimer(timer_name);
2273  }
2274 
2275  // Invoke application layer connection recovered callback.
2276  if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) {
2277  return (false);
2278  }
2279  } else {
2280  if (!db_reconnect_ctl->checkRetries()) {
2281  // We're out of retries, log it and initiate shutdown.
2283  .arg(db_reconnect_ctl->maxRetries());
2284 
2285  // Cancel the timer.
2286  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
2287  TimerMgr::instance()->unregisterTimer(timer_name);
2288  }
2289 
2290  // Invoke application layer connection failed callback.
2292  return (false);
2293  }
2294 
2296  .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
2297  .arg(db_reconnect_ctl->maxRetries())
2298  .arg(db_reconnect_ctl->retryInterval());
2299 
2300  // Start the timer.
2301  if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
2302  TimerMgr::instance()->registerTimer(timer_name,
2303  std::bind(&MySqlLeaseMgr::dbReconnect, db_reconnect_ctl),
2304  db_reconnect_ctl->retryInterval(),
2306  }
2307  TimerMgr::instance()->setup(timer_name);
2308  }
2309 
2310  return (true);
2311 }
2312 
2313 // Create context.
2314 
2317  MySqlLeaseContextPtr ctx(new MySqlLeaseContext(parameters_,
2320 
2321  // Open the database.
2322  ctx->conn_.openDatabase();
2323 
2324  // Check if we have TLS when we required it.
2325  if (ctx->conn_.getTls()) {
2326  std::string cipher = ctx->conn_.getTlsCipher();
2327  if (cipher.empty()) {
2329  } else {
2332  .arg(cipher);
2333  }
2334  }
2335 
2336  // Prepare all statements likely to be used.
2337  ctx->conn_.prepareStatements(tagged_statements.begin(),
2338  tagged_statements.end());
2339 
2340  // Create the exchange objects for use in exchanging data between the
2341  // program and the database.
2342  ctx->exchange4_.reset(new MySqlLease4Exchange());
2343  ctx->exchange6_.reset(new MySqlLease6Exchange());
2344 
2345  // Create ReconnectCtl for this connection.
2346  ctx->conn_.makeReconnectCtl(timer_name_);
2347 
2348  return (ctx);
2349 }
2350 
2351 std::string
2353  std::stringstream tmp;
2354  tmp << "MySQL backend " << MYSQL_SCHEMA_VERSION_MAJOR;
2355  tmp << "." << MYSQL_SCHEMA_VERSION_MINOR;
2356  tmp << ", library " << mysql_get_client_info();
2357  return (tmp.str());
2358 }
2359 
2360 // Add leases to the database. The two public methods accept a lease object
2361 // (either V4 of V6), bind the contents to the appropriate prepared
2362 // statement, then call common code to execute the statement.
2363 
2364 bool
2365 MySqlLeaseMgr::addLeaseCommon(MySqlLeaseContextPtr& ctx,
2366  StatementIndex stindex,
2367  std::vector<MYSQL_BIND>& bind) {
2368  // Bind the parameters to the statement
2369  int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), &bind[0]);
2370  checkError(ctx, status, stindex, "unable to bind parameters");
2371 
2372  // Execute the statement
2373  status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
2374  if (status != 0) {
2375 
2376  // Failure: check for the special case of duplicate entry. If this is
2377  // the case, we return false to indicate that the row was not added.
2378  // Otherwise we throw an exception.
2379  if (mysql_errno(ctx->conn_.mysql_) == ER_DUP_ENTRY) {
2380  return (false);
2381  }
2382  checkError(ctx, status, stindex, "unable to execute");
2383  }
2384 
2385  // Insert succeeded
2386  return (true);
2387 }
2388 
2389 bool
2392  .arg(lease->addr_.toText());
2393 
2394  // Get a context
2395  MySqlLeaseTrackingContextAlloc get_context(*this, lease);
2396  MySqlLeaseContextPtr ctx = get_context.ctx_;
2397 
2398  // Create the MYSQL_BIND array for the lease
2399  std::vector<MYSQL_BIND> bind = ctx->exchange4_->createBindForSend(lease);
2400 
2401  // ... and drop to common code.
2402  auto result = addLeaseCommon(ctx, INSERT_LEASE4, bind);
2403 
2404  // Update lease current expiration time (allows update between the creation
2405  // of the Lease up to the point of insertion in the database).
2406  lease->updateCurrentExpirationTime();
2407 
2408  // Run installed callbacks.
2409  if (hasCallbacks()) {
2410  trackAddLease(lease, false);
2411  }
2412 
2413  return (result);
2414 }
2415 
2416 bool
2419  .arg(lease->addr_.toText())
2420  .arg(lease->type_);
2421 
2422  lease->extended_info_action_ = Lease6::ACTION_IGNORE;
2423 
2424  // Get a context
2425  MySqlLeaseTrackingContextAlloc get_context(*this, lease);
2426  MySqlLeaseContextPtr ctx = get_context.ctx_;
2427 
2428  // Create the MYSQL_BIND array for the lease
2429  std::vector<MYSQL_BIND> bind = ctx->exchange6_->createBindForSend(lease);
2430 
2431  // ... and drop to common code.
2432  auto result = addLeaseCommon(ctx, INSERT_LEASE6, bind);
2433 
2434  // Update lease current expiration time (allows update between the creation
2435  // of the Lease up to the point of insertion in the database).
2436  lease->updateCurrentExpirationTime();
2437 
2439  static_cast<void>(addExtendedInfo6(lease));
2440  }
2441 
2442  // Run installed callbacks.
2443  if (hasCallbacks()) {
2444  trackAddLease(lease, false);
2445  }
2446 
2447  return (result);
2448 }
2449 
2450 // Extraction of leases from the database.
2451 //
2452 // All getLease() methods ultimately call getLeaseCollection(). This
2453 // binds the input parameters passed to it with the appropriate prepared
2454 // statement and executes the statement. It then gets the results from the
2455 // database. getlease() methods that expect a single result back call it
2456 // with the "single" parameter set true: this causes an exception to be
2457 // generated if multiple records can be retrieved from the result set. (Such
2458 // an occurrence either indicates corruption in the database, or that an
2459 // assumption that a query can only return a single record is incorrect.)
2460 // Methods that require a collection of records have "single" set to the
2461 // default value of false. The logic is the same for both Lease4 and Lease6
2462 // objects, so the code is templated.
2463 //
2464 // Methods that require a collection of objects access this method through
2465 // two interface methods (also called getLeaseCollection()). These are
2466 // short enough as to be defined in the header file: all they do is to supply
2467 // the appropriate MySqlLeaseXExchange object depending on the type of the
2468 // LeaseCollection objects passed to them.
2469 //
2470 // Methods that require a single object to be returned access the method
2471 // through two interface methods (called getLease()). As well as supplying
2472 // the appropriate exchange object, they convert between lease collection
2473 // holding zero or one leases into an appropriate Lease object.
2474 
2475 template <typename Exchange, typename LeaseCollection>
2476 void
2477 MySqlLeaseMgr::getLeaseCollection(MySqlLeaseContextPtr& ctx,
2478  StatementIndex stindex,
2479  MYSQL_BIND* bind,
2480  Exchange& exchange,
2481  LeaseCollection& result,
2482  bool single) const {
2483  int status;
2484 
2485  if (bind) {
2486  // Bind the selection parameters to the statement
2487  status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
2488  checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
2489  }
2490 
2491  // Set up the MYSQL_BIND array for the data being returned and bind it to
2492  // the statement.
2493  std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
2494  status = mysql_stmt_bind_result(ctx->conn_.getStatement(stindex), &outbind[0]);
2495  checkError(ctx, status, stindex, "unable to bind SELECT clause parameters");
2496 
2497  // Execute the statement
2498  status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
2499  checkError(ctx, status, stindex, "unable to execute");
2500 
2501  // Ensure that all the lease information is retrieved in one go to avoid
2502  // overhead of going back and forth between client and server.
2503  status = mysql_stmt_store_result(ctx->conn_.getStatement(stindex));
2504  checkError(ctx, status, stindex, "unable to set up for storing all results");
2505 
2506  // Set up the fetch "release" object to release resources associated
2507  // with the call to mysql_stmt_fetch when this method exits, then
2508  // retrieve the data.
2509  MySqlFreeResult fetch_release(ctx->conn_.getStatement(stindex));
2510  int count = 0;
2511  while ((status = mysql_stmt_fetch(ctx->conn_.getStatement(stindex))) == 0) {
2512  try {
2513  result.push_back(exchange->getLeaseData());
2514 
2515  } catch (const isc::BadValue& ex) {
2516  // Rethrow the exception with a bit more data.
2517  isc_throw(BadValue, ex.what() << ". Statement is <" <<
2518  ctx->conn_.text_statements_[stindex] << ">");
2519  }
2520 
2521  if (single && (++count > 1)) {
2522  isc_throw(MultipleRecords, "multiple records were found in the "
2523  "database where only one was expected for query "
2524  << ctx->conn_.text_statements_[stindex]);
2525  }
2526  }
2527 
2528  // How did the fetch end?
2529  if (status == 1) {
2530  // Error - unable to fetch results
2531  checkError(ctx, status, stindex, "unable to fetch results");
2532  } else if (status == MYSQL_DATA_TRUNCATED) {
2533  // Data truncated - throw an exception indicating what was at fault
2534  isc_throw(DataTruncated, ctx->conn_.text_statements_[stindex]
2535  << " returned truncated data: columns affected are "
2536  << exchange->getErrorColumns());
2537  }
2538 }
2539 
2540 void
2541 MySqlLeaseMgr::getLease(MySqlLeaseContextPtr& ctx,
2542  StatementIndex stindex, MYSQL_BIND* bind,
2543  Lease4Ptr& result) const {
2544  // Create appropriate collection object and get all leases matching
2545  // the selection criteria. The "single" parameter is true to indicate
2546  // that the called method should throw an exception if multiple
2547  // matching records are found: this particular method is called when only
2548  // one or zero matches is expected.
2549  Lease4Collection collection;
2550  getLeaseCollection(ctx, stindex, bind, ctx->exchange4_, collection, true);
2551 
2552  // Return single record if present, else clear the lease.
2553  if (collection.empty()) {
2554  result.reset();
2555  } else {
2556  result = *collection.begin();
2557  }
2558 }
2559 
2560 void
2561 MySqlLeaseMgr::getLease(MySqlLeaseContextPtr& ctx,
2562  StatementIndex stindex, MYSQL_BIND* bind,
2563  Lease6Ptr& result) const {
2564  // Create appropriate collection object and get all leases matching
2565  // the selection criteria. The "single" parameter is true to indicate
2566  // that the called method should throw an exception if multiple
2567  // matching records are found: this particular method is called when only
2568  // one or zero matches is expected.
2569  Lease6Collection collection;
2570  getLeaseCollection(ctx, stindex, bind, ctx->exchange6_, collection, true);
2571 
2572  // Return single record if present, else clear the lease.
2573  if (collection.empty()) {
2574  result.reset();
2575  } else {
2576  result = *collection.begin();
2577  }
2578 }
2579 
2580 // Basic lease access methods. Obtain leases from the database using various
2581 // criteria.
2582 
2583 Lease4Ptr
2586  .arg(addr.toText());
2587 
2588  // Set up the WHERE clause value
2589  MYSQL_BIND inbind[1];
2590  memset(inbind, 0, sizeof(inbind));
2591 
2592  uint32_t addr4 = addr.toUint32();
2593  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2594  inbind[0].buffer = reinterpret_cast<char*>(&addr4);
2595  inbind[0].is_unsigned = MLM_TRUE;
2596 
2597  // Get the data
2598  Lease4Ptr result;
2599 
2600  // Get a context
2601  MySqlLeaseContextAlloc get_context(*this);
2602  MySqlLeaseContextPtr ctx = get_context.ctx_;
2603 
2604  getLease(ctx, GET_LEASE4_ADDR, inbind, result);
2605 
2606  return (result);
2607 }
2608 
2610 MySqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
2612  .arg(hwaddr.toText());
2613 
2614  // Set up the WHERE clause value
2615  MYSQL_BIND inbind[1];
2616  memset(inbind, 0, sizeof(inbind));
2617 
2618  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2619 
2620  unsigned long hwaddr_length = hwaddr.hwaddr_.size();
2621 
2622  // If the data happens to be empty, we have to create a 1 byte dummy
2623  // buffer and pass it to the binding.
2624  uint8_t single_byte_data = 0;
2625 
2626  // As "buffer" is "char*" - even though the data is being read - we need
2627  // to cast away the "const"ness as well as reinterpreting the data as
2628  // a "char*". (We could avoid the "const_cast" by copying the data to a
2629  // local variable, but as the data is only being read, this introduces
2630  // an unnecessary copy).
2631  uint8_t* data = !hwaddr.hwaddr_.empty() ? const_cast<uint8_t*>(&hwaddr.hwaddr_[0])
2632  : &single_byte_data;
2633 
2634  inbind[0].buffer = reinterpret_cast<char*>(data);
2635  inbind[0].buffer_length = hwaddr_length;
2636  inbind[0].length = &hwaddr_length;
2637 
2638  // Get the data
2639  Lease4Collection result;
2640 
2641  // Get a context
2642  MySqlLeaseContextAlloc get_context(*this);
2643  MySqlLeaseContextPtr ctx = get_context.ctx_;
2644 
2645  getLeaseCollection(ctx, GET_LEASE4_HWADDR, inbind, result);
2646 
2647  return (result);
2648 }
2649 
2650 Lease4Ptr
2651 MySqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
2653  .arg(subnet_id)
2654  .arg(hwaddr.toText());
2655 
2656  // Set up the WHERE clause value
2657  MYSQL_BIND inbind[2];
2658  memset(inbind, 0, sizeof(inbind));
2659 
2660  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2661 
2662  unsigned long hwaddr_length = hwaddr.hwaddr_.size();
2663 
2664  // If the data happens to be empty, we have to create a 1 byte dummy
2665  // buffer and pass it to the binding.
2666  std::vector<uint8_t> single_byte_vec(1);
2667 
2668  // As "buffer" is "char*" - even though the data is being read - we need
2669  // to cast away the "const"ness as well as reinterpreting the data as
2670  // a "char*". (We could avoid the "const_cast" by copying the data to a
2671  // local variable, but as the data is only being read, this introduces
2672  // an unnecessary copy).
2673  uint8_t* data = !hwaddr.hwaddr_.empty() ? const_cast<uint8_t*>(&hwaddr.hwaddr_[0])
2674  : &single_byte_vec[0];
2675 
2676  inbind[0].buffer = reinterpret_cast<char*>(data);
2677  inbind[0].buffer_length = hwaddr_length;
2678  inbind[0].length = &hwaddr_length;
2679 
2680  inbind[1].buffer_type = MYSQL_TYPE_LONG;
2681  inbind[1].buffer = reinterpret_cast<char*>(&subnet_id);
2682  inbind[1].is_unsigned = MLM_TRUE;
2683 
2684  // Get the data
2685  Lease4Ptr result;
2686 
2687  // Get a context
2688  MySqlLeaseContextAlloc get_context(*this);
2689  MySqlLeaseContextPtr ctx = get_context.ctx_;
2690 
2691  getLease(ctx, GET_LEASE4_HWADDR_SUBID, inbind, result);
2692 
2693  return (result);
2694 }
2695 
2697 MySqlLeaseMgr::getLease4(const ClientId& clientid) const {
2699  .arg(clientid.toText());
2700 
2701  // Set up the WHERE clause value
2702  MYSQL_BIND inbind[1];
2703  memset(inbind, 0, sizeof(inbind));
2704 
2705  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2706 
2707  std::vector<uint8_t> client_data = clientid.getClientId();
2708  unsigned long client_data_length = client_data.size();
2709 
2710  // If the data happens to be empty, we have to create a 1 byte dummy
2711  // buffer and pass it to the binding.
2712  if (client_data.empty()) {
2713  client_data.resize(1);
2714  }
2715 
2716  inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
2717  inbind[0].buffer_length = client_data_length;
2718  inbind[0].length = &client_data_length;
2719 
2720  // Get the data
2721  Lease4Collection result;
2722 
2723  // Get a context
2724  MySqlLeaseContextAlloc get_context(*this);
2725  MySqlLeaseContextPtr ctx = get_context.ctx_;
2726 
2727  getLeaseCollection(ctx, GET_LEASE4_CLIENTID, inbind, result);
2728 
2729  return (result);
2730 }
2731 
2732 Lease4Ptr
2733 MySqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
2735  .arg(subnet_id)
2736  .arg(clientid.toText());
2737 
2738  // Set up the WHERE clause value
2739  MYSQL_BIND inbind[2];
2740  memset(inbind, 0, sizeof(inbind));
2741 
2742  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2743 
2744  std::vector<uint8_t> client_data = clientid.getClientId();
2745  unsigned long client_data_length = client_data.size();
2746 
2747  // If the data happens to be empty, we have to create a 1 byte dummy
2748  // buffer and pass it to the binding.
2749  if (client_data.empty()) {
2750  client_data.resize(1);
2751  }
2752 
2753  inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
2754  inbind[0].buffer_length = client_data_length;
2755  inbind[0].length = &client_data_length;
2756 
2757  inbind[1].buffer_type = MYSQL_TYPE_LONG;
2758  inbind[1].buffer = reinterpret_cast<char*>(&subnet_id);
2759  inbind[1].is_unsigned = MLM_TRUE;
2760 
2761  // Get the data
2762  Lease4Ptr result;
2763 
2764  // Get a context
2765  MySqlLeaseContextAlloc get_context(*this);
2766  MySqlLeaseContextPtr ctx = get_context.ctx_;
2767 
2768  getLease(ctx, GET_LEASE4_CLIENTID_SUBID, inbind, result);
2769 
2770  return (result);
2771 }
2772 
2776  .arg(subnet_id);
2777 
2778  // Set up the WHERE clause value
2779  MYSQL_BIND inbind[1];
2780  memset(inbind, 0, sizeof(inbind));
2781 
2782  // Subnet ID
2783  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2784  inbind[0].buffer = reinterpret_cast<char*>(&subnet_id);
2785  inbind[0].is_unsigned = MLM_TRUE;
2786 
2787  // ... and get the data
2788  Lease4Collection result;
2789 
2790  // Get a context
2791  MySqlLeaseContextAlloc get_context(*this);
2792  MySqlLeaseContextPtr ctx = get_context.ctx_;
2793 
2794  getLeaseCollection(ctx, GET_LEASE4_SUBID, inbind, result);
2795 
2796  return (result);
2797 }
2798 
2800 MySqlLeaseMgr::getLeases4(const std::string& hostname) const {
2802  .arg(hostname);
2803 
2804  // Set up the WHERE clause value
2805  MYSQL_BIND inbind[1];
2806  memset(inbind, 0, sizeof(inbind));
2807 
2808  // Hostname
2809  inbind[0].buffer_type = MYSQL_TYPE_STRING;
2810  inbind[0].buffer = const_cast<char*>(hostname.c_str());
2811  inbind[0].buffer_length = hostname.length();
2812 
2813  // ... and get the data
2814  Lease4Collection result;
2815 
2816  // Get a context
2817  MySqlLeaseContextAlloc get_context(*this);
2818  MySqlLeaseContextPtr ctx = get_context.ctx_;
2819 
2820  getLeaseCollection(ctx, GET_LEASE4_HOSTNAME, inbind, result);
2821 
2822  return (result);
2823 }
2824 
2828 
2829  Lease4Collection result;
2830 
2831  // Get a context
2832  MySqlLeaseContextAlloc get_context(*this);
2833  MySqlLeaseContextPtr ctx = get_context.ctx_;
2834 
2835  getLeaseCollection(ctx, GET_LEASE4, 0, result);
2836 
2837  return (result);
2838 }
2839 
2841 MySqlLeaseMgr::getLeases4(const IOAddress& lower_bound_address,
2842  const LeasePageSize& page_size) const {
2843  // Expecting IPv4 address.
2844  if (!lower_bound_address.isV4()) {
2845  isc_throw(InvalidAddressFamily, "expected IPv4 address while "
2846  "retrieving leases from the lease database, got "
2847  << lower_bound_address);
2848  }
2849 
2851  .arg(page_size.page_size_)
2852  .arg(lower_bound_address.toText());
2853 
2854  // Prepare WHERE clause
2855  MYSQL_BIND inbind[2];
2856  memset(inbind, 0, sizeof(inbind));
2857 
2858  // Bind lower bound address
2859  uint32_t lb_address_data = lower_bound_address.toUint32();
2860  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2861  inbind[0].buffer = reinterpret_cast<char*>(&lb_address_data);
2862  inbind[0].is_unsigned = MLM_TRUE;
2863 
2864  // Bind page size value
2865  uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
2866  inbind[1].buffer_type = MYSQL_TYPE_LONG;
2867  inbind[1].buffer = reinterpret_cast<char*>(&ps);
2868  inbind[1].is_unsigned = MLM_TRUE;
2869 
2870  // Get the leases
2871  Lease4Collection result;
2872 
2873  // Get a context
2874  MySqlLeaseContextAlloc get_context(*this);
2875  MySqlLeaseContextPtr ctx = get_context.ctx_;
2876 
2877  getLeaseCollection(ctx, GET_LEASE4_PAGE, inbind, result);
2878 
2879  return (result);
2880 }
2881 
2882 Lease6Ptr
2884  const IOAddress& addr) const {
2886  .arg(addr.toText())
2887  .arg(lease_type);
2888 
2889  // Set up the WHERE clause value
2890  MYSQL_BIND inbind[2];
2891  memset(inbind, 0, sizeof(inbind));
2892 
2893  // address: binary(16)
2894  std::vector<uint8_t>addr6 = addr.toBytes();
2895  if (addr6.size() != 16) {
2896  isc_throw(DbOperationError, "lease6 address is not 16 bytes long");
2897  }
2898 
2899  unsigned long addr6_length = 16;
2900  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2901  inbind[0].buffer = reinterpret_cast<char*>(&addr6[0]);
2902  inbind[0].buffer_length = 16;
2903  inbind[0].length = &addr6_length;
2904 
2905  // LEASE_TYPE
2906  inbind[1].buffer_type = MYSQL_TYPE_TINY;
2907  inbind[1].buffer = reinterpret_cast<char*>(&lease_type);
2908  inbind[1].is_unsigned = MLM_TRUE;
2909 
2910  Lease6Ptr result;
2911 
2912  // Get a context
2913  MySqlLeaseContextAlloc get_context(*this);
2914  MySqlLeaseContextPtr ctx = get_context.ctx_;
2915 
2916  getLease(ctx, GET_LEASE6_ADDR, inbind, result);
2917 
2918  return (result);
2919 }
2920 
2923  uint32_t iaid) const {
2925  .arg(iaid)
2926  .arg(duid.toText())
2927  .arg(lease_type);
2928 
2929  // Set up the WHERE clause value
2930  MYSQL_BIND inbind[3];
2931  memset(inbind, 0, sizeof(inbind));
2932 
2933  // In the following statement, the DUID is being read. However, the
2934  // MySQL C interface does not use "const", so the "buffer" element
2935  // is declared as "char*" instead of "const char*". To resolve this,
2936  // the "const" is discarded before the uint8_t* is cast to char*.
2937  //
2938  // Note that the const_cast could be avoided by copying the DUID to
2939  // a writable buffer and storing the address of that in the "buffer"
2940  // element. However, this introduces a copy operation (with additional
2941  // overhead) purely to get round the structures introduced by design of
2942  // the MySQL interface (which uses the area pointed to by "buffer" as
2943  // input when specifying query parameters and as output when retrieving
2944  // data). For that reason, "const_cast" has been used.
2945  const vector<uint8_t>& duid_vector = duid.getDuid();
2946  unsigned long duid_length = duid_vector.size();
2947 
2948  // Make sure that the buffer has at least length of 1, even if
2949  // empty client id is passed. This is required by some of the
2950  // MySQL connectors that the buffer is set to non-null value.
2951  // Otherwise, null value would be inserted into the database,
2952  // rather than empty string.
2953  uint8_t single_byte_data = 0;
2954  uint8_t* data = !duid_vector.empty() ? const_cast<uint8_t*>(&duid_vector[0])
2955  : &single_byte_data;
2956 
2957  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2958  inbind[0].buffer = reinterpret_cast<char*>(data);
2959  inbind[0].buffer_length = duid_length;
2960  inbind[0].length = &duid_length;
2961 
2962  // IAID
2963  inbind[1].buffer_type = MYSQL_TYPE_LONG;
2964  inbind[1].buffer = reinterpret_cast<char*>(&iaid);
2965  inbind[1].is_unsigned = MLM_TRUE;
2966 
2967  // LEASE_TYPE
2968  inbind[2].buffer_type = MYSQL_TYPE_TINY;
2969  inbind[2].buffer = reinterpret_cast<char*>(&lease_type);
2970  inbind[2].is_unsigned = MLM_TRUE;
2971 
2972  // ... and get the data
2973  Lease6Collection result;
2974 
2975  // Get a context
2976  MySqlLeaseContextAlloc get_context(*this);
2977  MySqlLeaseContextPtr ctx = get_context.ctx_;
2978 
2979  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID, inbind, result);
2980 
2981  return (result);
2982 }
2983 
2986  uint32_t iaid, SubnetID subnet_id) const {
2988  .arg(iaid)
2989  .arg(subnet_id)
2990  .arg(duid.toText())
2991  .arg(lease_type);
2992 
2993  // Set up the WHERE clause value
2994  MYSQL_BIND inbind[4];
2995  memset(inbind, 0, sizeof(inbind));
2996 
2997  // See the earlier description of the use of "const_cast" when accessing
2998  // the DUID for an explanation of the reason.
2999  const vector<uint8_t>& duid_vector = duid.getDuid();
3000  unsigned long duid_length = duid_vector.size();
3001  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
3002  inbind[0].buffer = reinterpret_cast<char*>(
3003  const_cast<uint8_t*>(&duid_vector[0]));
3004  inbind[0].buffer_length = duid_length;
3005  inbind[0].length = &duid_length;
3006 
3007  // IAID
3008  inbind[1].buffer_type = MYSQL_TYPE_LONG;
3009  inbind[1].buffer = reinterpret_cast<char*>(&iaid);
3010  inbind[1].is_unsigned = MLM_TRUE;
3011 
3012  // Subnet ID
3013  inbind[2].buffer_type = MYSQL_TYPE_LONG;
3014  inbind[2].buffer = reinterpret_cast<char*>(&subnet_id);
3015  inbind[2].is_unsigned = MLM_TRUE;
3016 
3017  // LEASE_TYPE
3018  inbind[3].buffer_type = MYSQL_TYPE_TINY;
3019  inbind[3].buffer = reinterpret_cast<char*>(&lease_type);
3020  inbind[3].is_unsigned = MLM_TRUE;
3021 
3022  // ... and get the data
3023  Lease6Collection result;
3024 
3025  // Get a context
3026  MySqlLeaseContextAlloc get_context(*this);
3027  MySqlLeaseContextPtr ctx = get_context.ctx_;
3028 
3029  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID_SUBID, inbind, result);
3030 
3031  return (result);
3032 }
3033 
3037  .arg(subnet_id);
3038 
3039  // Set up the WHERE clause value
3040  MYSQL_BIND inbind[1];
3041  memset(inbind, 0, sizeof(inbind));
3042 
3043  // Subnet ID
3044  inbind[0].buffer_type = MYSQL_TYPE_LONG;
3045  inbind[0].buffer = reinterpret_cast<char*>(&subnet_id);
3046  inbind[0].is_unsigned = MLM_TRUE;
3047 
3048  // ... and get the data
3049  Lease6Collection result;
3050 
3051  // Get a context
3052  MySqlLeaseContextAlloc get_context(*this);
3053  MySqlLeaseContextPtr ctx = get_context.ctx_;
3054 
3055  getLeaseCollection(ctx, GET_LEASE6_SUBID, inbind, result);
3056 
3057  return (result);
3058 }
3059 
3063 
3064  Lease6Collection result;
3065 
3066  // Get a context
3067  MySqlLeaseContextAlloc get_context(*this);
3068  MySqlLeaseContextPtr ctx = get_context.ctx_;
3069 
3070  getLeaseCollection(ctx, GET_LEASE6, 0, result);
3071 
3072  return (result);
3073 }
3074 
3076 MySqlLeaseMgr::getLeases6(const DUID& duid) const {
3078  .arg(duid.toText());
3079 
3080  // Set up the WHERE clause value
3081  MYSQL_BIND inbind[1];
3082  memset(inbind, 0, sizeof(inbind));
3083 
3084  const vector<uint8_t>& duid_vector = duid.getDuid();
3085  unsigned long duid_length = duid_vector.size();
3086 
3087  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
3088  inbind[0].buffer = reinterpret_cast<char*>(
3089  const_cast<uint8_t*>(&duid_vector[0]));
3090  inbind[0].buffer_length = duid_length;
3091  inbind[0].length = &duid_length;
3092 
3093  Lease6Collection result;
3094 
3095  // Get a context
3096  MySqlLeaseContextAlloc get_context(*this);
3097  MySqlLeaseContextPtr ctx = get_context.ctx_;
3098 
3099  getLeaseCollection(ctx, GET_LEASE6_DUID, inbind, result);
3100 
3101  return result;
3102 }
3103 
3105 MySqlLeaseMgr::getLeases6(const std::string& hostname) const {
3107  .arg(hostname);
3108 
3109  // Set up the WHERE clause value
3110  MYSQL_BIND inbind[1];
3111  memset(inbind, 0, sizeof(inbind));
3112 
3113  // Hostname
3114  inbind[0].buffer_type = MYSQL_TYPE_STRING;
3115  inbind[0].buffer = const_cast<char*>(hostname.c_str());
3116  inbind[0].buffer_length = hostname.length();
3117 
3118  // ... and get the data
3119  Lease6Collection result;
3120 
3121  // Get a context
3122  MySqlLeaseContextAlloc get_context(*this);
3123  MySqlLeaseContextPtr ctx = get_context.ctx_;
3124 
3125  getLeaseCollection(ctx, GET_LEASE6_HOSTNAME, inbind, result);
3126 
3127  return (result);
3128 }
3129 
3131 MySqlLeaseMgr::getLeases6(const IOAddress& lower_bound_address,
3132  const LeasePageSize& page_size) const {
3133  // Expecting IPv6 address.
3134  if (!lower_bound_address.isV6()) {
3135  isc_throw(InvalidAddressFamily, "expected IPv6 address while "
3136  "retrieving leases from the lease database, got "
3137  << lower_bound_address);
3138  }
3139 
3141  .arg(page_size.page_size_)
3142  .arg(lower_bound_address.toText());
3143 
3144  // Prepare WHERE clause
3145  MYSQL_BIND inbind[2];
3146  memset(inbind, 0, sizeof(inbind));
3147 
3148  // Bind lower bound address
3149  std::vector<uint8_t>lb_addr = lower_bound_address.toBytes();
3150  if (lb_addr.size() != 16) {
3151  isc_throw(DbOperationError, "getLeases6() - lower bound address is not 16 bytes long");
3152  }
3153 
3154  unsigned long lb_addr_length = 16;
3155  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
3156  inbind[0].buffer = reinterpret_cast<char*>(&lb_addr[0]);
3157  inbind[0].buffer_length = 16;
3158  inbind[0].length = &lb_addr_length;
3159 
3160  // Bind page size value
3161  uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
3162  inbind[1].buffer_type = MYSQL_TYPE_LONG;
3163  inbind[1].buffer = reinterpret_cast<char*>(&ps);
3164  inbind[1].is_unsigned = MLM_TRUE;
3165 
3166  // Get the leases
3167  Lease6Collection result;
3168 
3169  // Get a context
3170  MySqlLeaseContextAlloc get_context(*this);
3171  MySqlLeaseContextPtr ctx = get_context.ctx_;
3172 
3173  getLeaseCollection(ctx, GET_LEASE6_PAGE, inbind, result);
3174 
3175  return (result);
3176 }
3177 
3178 void
3180  const size_t max_leases) const {
3182  .arg(max_leases);
3183  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE4_EXPIRE);
3184 }
3185 
3186 void
3188  const size_t max_leases) const {
3190  .arg(max_leases);
3191  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE6_EXPIRE);
3192 }
3193 
3194 template<typename LeaseCollection>
3195 void
3196 MySqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases,
3197  const size_t max_leases,
3198  StatementIndex statement_index) const {
3199  // Set up the WHERE clause value
3200  MYSQL_BIND inbind[3];
3201  memset(inbind, 0, sizeof(inbind));
3202 
3203  // Exclude reclaimed leases.
3204  uint32_t state = static_cast<uint32_t>(Lease::STATE_EXPIRED_RECLAIMED);
3205  inbind[0].buffer_type = MYSQL_TYPE_LONG;
3206  inbind[0].buffer = reinterpret_cast<char*>(&state);
3207  inbind[0].is_unsigned = MLM_TRUE;
3208 
3209  // Expiration timestamp.
3210  MYSQL_TIME expire_time;
3211  MySqlConnection::convertToDatabaseTime(time(0), expire_time);
3212  inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
3213  inbind[1].buffer = reinterpret_cast<char*>(&expire_time);
3214  inbind[1].buffer_length = sizeof(expire_time);
3215 
3216  // If the number of leases is 0, we will return all leases. This is
3217  // achieved by setting the limit to a very high value.
3218  uint32_t limit = max_leases > 0 ? static_cast<uint32_t>(max_leases) :
3219  std::numeric_limits<uint32_t>::max();
3220  inbind[2].buffer_type = MYSQL_TYPE_LONG;
3221  inbind[2].buffer = reinterpret_cast<char*>(&limit);
3222  inbind[2].is_unsigned = MLM_TRUE;
3223 
3224  // Get a context
3225  MySqlLeaseContextAlloc get_context(*this);
3226  MySqlLeaseContextPtr ctx = get_context.ctx_;
3227 
3228  // Get the data
3229  getLeaseCollection(ctx, statement_index, inbind, expired_leases);
3230 }
3231 
3232 // Update lease methods. These comprise common code that handles the actual
3233 // update, and type-specific methods that set up the parameters for the prepared
3234 // statement depending on the type of lease.
3235 
3236 template <typename LeasePtr>
3237 void
3238 MySqlLeaseMgr::updateLeaseCommon(MySqlLeaseContextPtr& ctx,
3239  StatementIndex stindex,
3240  MYSQL_BIND* bind,
3241  const LeasePtr& lease) {
3242 
3243  // Bind the parameters to the statement
3244  int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
3245  checkError(ctx, status, stindex, "unable to bind parameters");
3246 
3247  // Execute
3248  status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
3249  checkError(ctx, status, stindex, "unable to execute");
3250 
3251  // See how many rows were affected. The statement should only update a
3252  // single row.
3253  int affected_rows = mysql_stmt_affected_rows(ctx->conn_.getStatement(stindex));
3254 
3255  // Check success case first as it is the most likely outcome.
3256  if (affected_rows == 1) {
3257  return;
3258  }
3259 
3260  // If no rows affected, lease doesn't exist.
3261  if (affected_rows == 0) {
3262  isc_throw(NoSuchLease, "unable to update lease for address " <<
3263  lease->addr_.toText() << " as it does not exist");
3264  }
3265 
3266  // Should not happen - primary key constraint should only have selected
3267  // one row.
3268  isc_throw(DbOperationError, "apparently updated more than one lease "
3269  "that had the address " << lease->addr_.toText());
3270 }
3271 
3272 void
3274  const StatementIndex stindex = UPDATE_LEASE4;
3275 
3277  .arg(lease->addr_.toText());
3278 
3279  // Get a context
3280  MySqlLeaseTrackingContextAlloc get_context(*this, lease);
3281  MySqlLeaseContextPtr ctx = get_context.ctx_;
3282 
3283  // Create the MYSQL_BIND array for the data being updated
3284  std::vector<MYSQL_BIND> bind = ctx->exchange4_->createBindForSend(lease);
3285 
3286  // Set up the WHERE clause and append it to the MYSQL_BIND array
3287  MYSQL_BIND inbind[2];
3288  memset(inbind, 0, sizeof(inbind));
3289 
3290  uint32_t addr4 = lease->addr_.toUint32();
3291  inbind[0].buffer_type = MYSQL_TYPE_LONG;
3292  inbind[0].buffer = reinterpret_cast<char*>(&addr4);
3293  inbind[0].is_unsigned = MLM_TRUE;
3294 
3295  bind.push_back(inbind[0]);
3296 
3297  // See the expire code of createBindForSend for the
3298  // infinite valid lifetime special case.
3299  MYSQL_TIME expire;
3300  uint32_t valid_lft = lease->current_valid_lft_;
3301  if (valid_lft == Lease::INFINITY_LFT) {
3302  valid_lft = 0;
3303  }
3304  MySqlConnection::convertToDatabaseTime(lease->current_cltt_, valid_lft,
3305  expire);
3306  inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
3307  inbind[1].buffer = reinterpret_cast<char*>(&expire);
3308  inbind[1].buffer_length = sizeof(expire);
3309 
3310  bind.push_back(inbind[1]);
3311 
3312  // Drop to common update code
3313  updateLeaseCommon(ctx, stindex, &bind[0], lease);
3314 
3315  // Update lease current expiration time.
3316  lease->updateCurrentExpirationTime();
3317 
3318  // Run installed callbacks.
3319  if (hasCallbacks()) {
3320  trackUpdateLease(lease, false);
3321  }
3322 }
3323 
3324 void
3326  const StatementIndex stindex = UPDATE_LEASE6;
3327 
3329  .arg(lease->addr_.toText())
3330  .arg(lease->type_);
3331 
3332  // Get the recorded action and reset it.
3333  Lease6::ExtendedInfoAction recorded_action = lease->extended_info_action_;
3334  lease->extended_info_action_ = Lease6::ACTION_IGNORE;
3335 
3336  // Get a context
3337  MySqlLeaseTrackingContextAlloc get_context(*this, lease);
3338  MySqlLeaseContextPtr ctx = get_context.ctx_;
3339 
3340  // Create the MYSQL_BIND array for the data being updated
3341  std::vector<MYSQL_BIND> bind = ctx->exchange6_->createBindForSend(lease);
3342 
3343  // Set up the WHERE clause and append it to the MYSQL_BIND array
3344  MYSQL_BIND inbind[2];
3345  memset(inbind, 0, sizeof(inbind));
3346 
3347  // Bind the where clause address parameter.
3348  std::vector<uint8_t>addr6 = lease->addr_.toBytes();
3349  if (addr6.size() != 16) {
3350  isc_throw(DbOperationError, "updateLease6() - address is not 16 bytes long");
3351  }
3352 
3353  unsigned long addr6_length = 16;
3354  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
3355  inbind[0].buffer = reinterpret_cast<char*>(&addr6[0]);
3356  inbind[0].buffer_length = 16;
3357  inbind[0].length = &addr6_length;
3358 
3359  bind.push_back(inbind[0]);
3360 
3361  // See the expire code of createBindForSend for the
3362  // infinite valid lifetime special case.
3363  MYSQL_TIME expire;
3364  uint32_t valid_lft = lease->current_valid_lft_;
3365  if (valid_lft == Lease::INFINITY_LFT) {
3366  valid_lft = 0;
3367  }
3368  MySqlConnection::convertToDatabaseTime(lease->current_cltt_, valid_lft,
3369  expire);
3370  inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
3371  inbind[1].buffer = reinterpret_cast<char*>(&expire);
3372  inbind[1].buffer_length = sizeof(expire);
3373 
3374  bind.push_back(inbind[1]);
3375 
3376  // Drop to common update code
3377  updateLeaseCommon(ctx, stindex, &bind[0], lease);
3378 
3379  // Update lease current expiration time.
3380  lease->updateCurrentExpirationTime();
3381 
3382  // Update extended info tables.
3384  switch (recorded_action) {
3385  case Lease6::ACTION_IGNORE:
3386  break;
3387 
3388  case Lease6::ACTION_DELETE:
3389  deleteExtendedInfo6(lease->addr_);
3390  break;
3391 
3392  case Lease6::ACTION_UPDATE:
3393  deleteExtendedInfo6(lease->addr_);
3394  static_cast<void>(addExtendedInfo6(lease));
3395  break;
3396  }
3397  }
3398 
3399  // Run installed callbacks.
3400  if (hasCallbacks()) {
3401  trackUpdateLease(lease, false);
3402  }
3403 }
3404 
3405 // Delete lease methods. Similar to other groups of methods, these comprise
3406 // a per-type method that sets up the relevant MYSQL_BIND array (in this
3407 // case, a single method for both V4 and V6 addresses) and a common method that
3408 // handles the common processing.
3409 
3410 uint64_t
3411 MySqlLeaseMgr::deleteLeaseCommon(MySqlLeaseContextPtr& ctx,
3412  StatementIndex stindex,
3413  MYSQL_BIND* bind) {
3414  // Bind the input parameters to the statement
3415  int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
3416  checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
3417 
3418  // Execute
3419  status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
3420  checkError(ctx, status, stindex, "unable to execute");
3421 
3422  // See how many rows were affected. Note that the statement may delete
3423  // multiple rows.
3424  return (static_cast<uint64_t>(mysql_stmt_affected_rows(ctx->conn_.getStatement(stindex))));
3425 }
3426 
3427 bool
3429  const IOAddress& addr = lease->addr_;
3431  .arg(addr.toText());
3432 
3433  // Set up the WHERE clause value
3434  MYSQL_BIND inbind[2];
3435  memset(inbind, 0, sizeof(inbind));
3436 
3437  uint32_t addr4 = addr.toUint32();
3438 
3439  inbind[0].buffer_type = MYSQL_TYPE_LONG;
3440  inbind[0].buffer = reinterpret_cast<char*>(&addr4);
3441  inbind[0].is_unsigned = MLM_TRUE;
3442 
3443  // See the expire code of createBindForSend for the
3444  // infinite valid lifetime special case.
3445  MYSQL_TIME expire;
3446  uint32_t valid_lft = lease->current_valid_lft_;
3447  if (valid_lft == Lease::INFINITY_LFT) {
3448  valid_lft = 0;
3449  }
3450  MySqlConnection::convertToDatabaseTime(lease->current_cltt_, valid_lft,
3451  expire);
3452  inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
3453  inbind[1].buffer = reinterpret_cast<char*>(&expire);
3454  inbind[1].buffer_length = sizeof(expire);
3455 
3456  // Get a context
3457  MySqlLeaseTrackingContextAlloc get_context(*this, lease);
3458  MySqlLeaseContextPtr ctx = get_context.ctx_;
3459 
3460  auto affected_rows = deleteLeaseCommon(ctx, DELETE_LEASE4, inbind);
3461 
3462  // Check success case first as it is the most likely outcome.
3463  if (affected_rows == 1) {
3464  if (hasCallbacks()) {
3465  trackDeleteLease(lease, false);
3466  }
3467  return (true);
3468  }
3469 
3470  // If no rows affected, lease doesn't exist.
3471  if (affected_rows == 0) {
3472  return (false);
3473  }
3474 
3475  // Should not happen - primary key constraint should only have selected
3476  // one row.
3477  isc_throw(DbOperationError, "apparently deleted more than one lease "
3478  "that had the address " << lease->addr_.toText());
3479 }
3480 
3481 bool
3483  const IOAddress& addr = lease->addr_;
3486  .arg(addr.toText());
3487 
3488  lease->extended_info_action_ = Lease6::ACTION_IGNORE;
3489 
3490  // Set up the WHERE clause value
3491  MYSQL_BIND inbind[2];
3492  memset(inbind, 0, sizeof(inbind));
3493 
3494  // Bind the where clause address parameter.
3495  std::vector<uint8_t>addr6 = addr.toBytes();
3496  if (addr6.size() != 16) {
3497  isc_throw(DbOperationError, "deleteLease6() - address is not 16 bytes long");
3498  }
3499 
3500  unsigned long addr6_length = 16;
3501  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
3502  inbind[0].buffer = reinterpret_cast<char*>(&addr6[0]);
3503  inbind[0].buffer_length = 16;
3504  inbind[0].length = &addr6_length;
3505 
3506  // See the expire code of createBindForSend for the
3507  // infinite valid lifetime special case.
3508  MYSQL_TIME expire;
3509  uint32_t valid_lft = lease->current_valid_lft_;
3510  if (valid_lft == Lease::INFINITY_LFT) {
3511  valid_lft = 0;
3512  }
3513  MySqlConnection::convertToDatabaseTime(lease->current_cltt_, valid_lft,
3514  expire);
3515  inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
3516  inbind[1].buffer = reinterpret_cast<char*>(&expire);
3517  inbind[1].buffer_length = sizeof(expire);
3518 
3519  // Get a context
3520  MySqlLeaseTrackingContextAlloc get_context(*this, lease);
3521  MySqlLeaseContextPtr ctx = get_context.ctx_;
3522 
3523  auto affected_rows = deleteLeaseCommon(ctx, DELETE_LEASE6, inbind);
3524 
3525  // Check success case first as it is the most likely outcome.
3526  if (affected_rows == 1) {
3527  // Delete references from extended info tables.
3528  // Performed by the delete cascade.
3529 
3530  // Run installed callbacks.
3531  if (hasCallbacks()) {
3532  trackDeleteLease(lease, false);
3533  }
3534  return (true);
3535  }
3536 
3537  // If no rows affected, lease doesn't exist.
3538  if (affected_rows == 0) {
3539  return (false);
3540  }
3541 
3542  // Should not happen - primary key constraint should only have selected
3543  // one row.
3544  isc_throw(DbOperationError, "apparently deleted more than one lease "
3545  "that had the address " << lease->addr_.toText());
3546 }
3547 
3548 uint64_t
3551  .arg(secs);
3552  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
3553 }
3554 
3555 uint64_t
3558  .arg(secs);
3559  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
3560 }
3561 
3562 uint64_t
3563 MySqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
3564  StatementIndex statement_index) {
3565  // Set up the WHERE clause value
3566  MYSQL_BIND inbind[2];
3567  memset(inbind, 0, sizeof(inbind));
3568 
3569  // State is reclaimed.
3570  uint32_t state = static_cast<uint32_t>(Lease::STATE_EXPIRED_RECLAIMED);
3571  inbind[0].buffer_type = MYSQL_TYPE_LONG;
3572  inbind[0].buffer = reinterpret_cast<char*>(&state);
3573  inbind[0].is_unsigned = MLM_TRUE;
3574 
3575  // Expiration timestamp.
3576  MYSQL_TIME expire_time;
3577  MySqlConnection::convertToDatabaseTime(time(0) - static_cast<time_t>(secs), expire_time);
3578  inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
3579  inbind[1].buffer = reinterpret_cast<char*>(&expire_time);
3580  inbind[1].buffer_length = sizeof(expire_time);
3581 
3582  // Get a context
3583  MySqlLeaseContextAlloc get_context(*this);
3584  MySqlLeaseContextPtr ctx = get_context.ctx_;
3585 
3586  // Get the number of deleted leases and log it.
3587  uint64_t deleted_leases = deleteLeaseCommon(ctx, statement_index, inbind);
3589  .arg(deleted_leases);
3590 
3591  return (deleted_leases);
3592 }
3593 
3594 string
3595 MySqlLeaseMgr::checkLimits(ConstElementPtr const& user_context, StatementIndex const stindex) const {
3596  // No user context means no limits means allocation allowed means empty string.
3597  if (!user_context) {
3598  return string();
3599  }
3600 
3601  // Get a context.
3602  MySqlLeaseContextAlloc get_context(*this);
3603  MySqlLeaseContextPtr ctx = get_context.ctx_;
3604 
3605  // Create bindings.
3606  MySqlBindingCollection in_bindings({
3607  MySqlBinding::createString(user_context->str())
3608  });
3609  MySqlBindingCollection out_bindings({
3610  MySqlBinding::createString(LIMITS_TEXT_MAX_LEN)
3611  });
3612 
3613  // Execute the select.
3614  std::string limit_text;
3615  ctx->conn_.selectQuery(stindex, in_bindings, out_bindings,
3616  [&limit_text] (MySqlBindingCollection const& result) {
3617  limit_text = result[0]->getString();
3618  });
3619 
3620  return limit_text;
3621 }
3622 
3623 string
3624 MySqlLeaseMgr::checkLimits4(ConstElementPtr const& user_context) const {
3625  return checkLimits(user_context, CHECK_LEASE4_LIMITS);
3626 }
3627 
3628 string
3629 MySqlLeaseMgr::checkLimits6(ConstElementPtr const& user_context) const {
3630  return checkLimits(user_context, CHECK_LEASE6_LIMITS);
3631 }
3632 
3633 bool
3634 MySqlLeaseMgr::isJsonSupported() const {
3635  // Get a context.
3636  MySqlLeaseContextAlloc get_context(*this);
3637  MySqlLeaseContextPtr ctx = get_context.ctx_;
3638 
3639  // Create bindings.
3640  MySqlBindingCollection in_bindings;
3641  MySqlBindingCollection out_bindings({
3643  });
3644 
3645  // Execute the select.
3646  bool json_supported(false);
3647  ctx->conn_.selectQuery(IS_JSON_SUPPORTED, in_bindings, out_bindings,
3648  [&json_supported] (MySqlBindingCollection const& result) {
3649  json_supported = result[0]->getBool();
3650  });
3651 
3652  return json_supported;
3653 }
3654 
3655 size_t
3656 MySqlLeaseMgr::getClassLeaseCount(const ClientClass& client_class,
3657  const Lease::Type& ltype /* = Lease::TYPE_V4*/) const {
3658  // Get a context.
3659  MySqlLeaseContextAlloc get_context(*this);
3660  MySqlLeaseContextPtr ctx = get_context.ctx_;
3661 
3662  // Create bindings.
3663  MySqlBindingCollection in_bindings({
3664  MySqlBinding::createString(client_class)
3665  });
3666  if (ltype != Lease::TYPE_V4) {
3667  in_bindings.push_back(MySqlBinding::createInteger<uint8_t>(ltype));
3668  }
3669  MySqlBindingCollection out_bindings({
3670  MySqlBinding::createInteger<int64_t>()
3671  });
3672 
3673  // Execute the select.
3674  StatementIndex const stindex(ltype == Lease::TYPE_V4 ? GET_LEASE4_COUNT_BY_CLASS :
3676  size_t count(0);
3677  ctx->conn_.selectQuery(stindex, in_bindings, out_bindings,
3678  [&count] (MySqlBindingCollection const& result) {
3679  count = result[0]->getInteger<int64_t>();
3680  });
3681 
3682  return count;
3683 }
3684 
3685 void
3686 MySqlLeaseMgr::recountClassLeases4() {
3687  isc_throw(NotImplemented, "MySqlLeaseMgr::recountClassLeases4() not implemented");
3688 }
3689 
3690 void
3691 MySqlLeaseMgr::recountClassLeases6() {
3692  isc_throw(NotImplemented, "MySqlLeaseMgr::recountClassLeases6() not implemented");
3693 }
3694 
3695 void
3696 MySqlLeaseMgr::clearClassLeaseCounts() {
3697  isc_throw(NotImplemented, "MySqlLeaseMgr::clearClassLeaseCounts() not implemented");
3698 }
3699 
3700 void
3701 MySqlLeaseMgr::writeLeases4(const std::string&) {
3702  isc_throw(NotImplemented, "MySqlLeaseMgr::writeLeases4() not implemented");
3703 }
3704 
3705 void
3706 MySqlLeaseMgr::writeLeases6(const std::string&) {
3707  isc_throw(NotImplemented, "MySqlLeaseMgr::writeLeases6() not implemented");
3708 }
3709 
3712  // Get a context
3713  MySqlLeaseContextAlloc get_context(*this);
3714  MySqlLeaseContextPtr ctx = get_context.ctx_;
3715 
3716  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3718  false));
3719  query->start();
3720  return(query);
3721 }
3722 
3725  // Get a context
3726  MySqlLeaseContextAlloc get_context(*this);
3727  MySqlLeaseContextPtr ctx = get_context.ctx_;
3728 
3729  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3731  false, true));
3732  query->start();
3733  return(query);
3734 }
3735 
3738  // Get a context
3739  MySqlLeaseContextAlloc get_context(*this);
3740  MySqlLeaseContextPtr ctx = get_context.ctx_;
3741 
3742  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3744  false,
3745  subnet_id));
3746  query->start();
3747  return(query);
3748 }
3749 
3752  const SubnetID& last_subnet_id) {
3753  // Get a context
3754  MySqlLeaseContextAlloc get_context(*this);
3755  MySqlLeaseContextPtr ctx = get_context.ctx_;
3756 
3757  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3759  false,
3760  first_subnet_id,
3761  last_subnet_id));
3762  query->start();
3763  return(query);
3764 }
3765 
3768  // Get a context
3769  MySqlLeaseContextAlloc get_context(*this);
3770  MySqlLeaseContextPtr ctx = get_context.ctx_;
3771 
3772  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3774  true));
3775  query->start();
3776  return(query);
3777 }
3778 
3781  // Get a context
3782  MySqlLeaseContextAlloc get_context(*this);
3783  MySqlLeaseContextPtr ctx = get_context.ctx_;
3784 
3785  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3787  true, true));
3788  query->start();
3789  return(query);
3790 }
3791 
3794  // Get a context
3795  MySqlLeaseContextAlloc get_context(*this);
3796  MySqlLeaseContextPtr ctx = get_context.ctx_;
3797 
3798  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3800  true,
3801  subnet_id));
3802  query->start();
3803  return(query);
3804 }
3805 
3808  const SubnetID& last_subnet_id) {
3809  // Get a context
3810  MySqlLeaseContextAlloc get_context(*this);
3811  MySqlLeaseContextPtr ctx = get_context.ctx_;
3812 
3813  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3815  true,
3816  first_subnet_id,
3817  last_subnet_id));
3818  query->start();
3819  return(query);
3820 }
3821 
3822 size_t
3823 MySqlLeaseMgr::wipeLeases4(const SubnetID& /*subnet_id*/) {
3824  isc_throw(NotImplemented, "wipeLeases4 is not implemented for MySQL backend");
3825 }
3826 
3827 size_t
3828 MySqlLeaseMgr::wipeLeases6(const SubnetID& /*subnet_id*/) {
3829  isc_throw(NotImplemented, "wipeLeases6 is not implemented for MySQL backend");
3830 }
3831 
3832 // Miscellaneous database methods.
3833 
3834 std::string
3836  // Get a context
3837  MySqlLeaseContextAlloc get_context(*this);
3838  MySqlLeaseContextPtr ctx = get_context.ctx_;
3839 
3840  std::string name = "";
3841  try {
3842  name = ctx->conn_.getParameter("name");
3843  } catch (...) {
3844  // Return an empty name
3845  }
3846  return (name);
3847 }
3848 
3849 std::string
3851  return (std::string("MySQL Database"));
3852 }
3853 
3854 std::pair<uint32_t, uint32_t>
3857 
3858  return (MySqlConnection::getVersion(parameters_));
3859 }
3860 
3861 void
3864 }
3865 
3866 void
3869 }
3870 
3871 void
3872 MySqlLeaseMgr::checkError(MySqlLeaseContextPtr& ctx,
3873  int status, StatementIndex index,
3874  const char* what) const {
3875  ctx->conn_.checkError(status, index, what);
3876 }
3877 
3878 void
3880  deleteRelayId6(addr);
3881  deleteRemoteId6(addr);
3882 }
3883 
3884 void
3885 MySqlLeaseMgr::deleteRelayId6(const IOAddress& addr) {
3886  // Get a context.
3887  MySqlLeaseContextAlloc get_context(*this);
3888  MySqlLeaseContextPtr ctx = get_context.ctx_;
3889 
3890  // Bind the lease address.
3891  MYSQL_BIND bind[1];
3892  memset(bind, 0, sizeof(bind));
3893 
3894  std::vector<uint8_t> addr_data = addr.toBytes();
3895  // Do not check the address length as it does not really matter.
3896  unsigned long addr_size = addr_data.size();
3897  bind[0].buffer_type = MYSQL_TYPE_BLOB;
3898  bind[0].buffer = reinterpret_cast<char*>(&addr_data[0]);
3899  bind[0].buffer_length = addr_size;
3900  bind[0].length = &addr_size;
3901 
3902  // Delete from lease6_relay_id table.
3903  StatementIndex stindex = DELETE_RELAY_ID6;
3904 
3905  // Bind the input parameters to the statement.
3906  int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
3907  checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
3908 
3909  // Execute.
3910  status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
3911  checkError(ctx, status, stindex, "unable to execute");
3912 }
3913 
3914 void
3915 MySqlLeaseMgr::deleteRemoteId6(const IOAddress& addr) {
3916  // Get a context.
3917  MySqlLeaseContextAlloc get_context(*this);
3918  MySqlLeaseContextPtr ctx = get_context.ctx_;
3919 
3920  // Bind the lease address.
3921  MYSQL_BIND bind[1];
3922  memset(bind, 0, sizeof(bind));
3923 
3924  std::vector<uint8_t> addr_data = addr.toBytes();
3925  // Do not check the address length as it does not really matter.
3926  unsigned long addr_size = addr_data.size();
3927  bind[0].buffer_type = MYSQL_TYPE_BLOB;
3928  bind[0].buffer = reinterpret_cast<char*>(&addr_data[0]);
3929  bind[0].buffer_length = addr_size;
3930  bind[0].length = &addr_size;
3931 
3932  // Delete from lease6_remote_id table.
3934 
3935  // Bind the input parameters to the statement.
3936  int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
3937  checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
3938 
3939  // Execute.
3940  status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
3941  checkError(ctx, status, stindex, "unable to execute");
3942 }
3943 
3944 void
3946  const vector<uint8_t>& relay_id) {
3947  // Get a context.
3948  MySqlLeaseContextAlloc get_context(*this);
3949  MySqlLeaseContextPtr ctx = get_context.ctx_;
3950 
3951  // Bind the relay id.
3952  MYSQL_BIND bind[2];
3953  memset(bind, 0, sizeof(bind));
3954 
3955  unsigned long relay_id_size = relay_id.size();
3956  if (relay_id_size == 0) {
3957  isc_throw(BadValue, "empty relay id");
3958  }
3959  std::vector<uint8_t> relay_id_data = relay_id;
3960  bind[0].buffer_type = MYSQL_TYPE_BLOB;
3961  bind[0].buffer = reinterpret_cast<char*>(&relay_id_data[0]);
3962  bind[0].buffer_length = relay_id_size;
3963  bind[0].length = &relay_id_size;
3964 
3965  // Bind the lease address.
3966  std::vector<uint8_t> lease_addr_data = lease_addr.toBytes();
3967  unsigned long lease_addr_length = lease_addr_data.size();
3968  if (lease_addr_length != 16) {
3969  isc_throw(DbOperationError, "lease6 address is not 16 bytes long");
3970  }
3971  bind[1].buffer_type = MYSQL_TYPE_BLOB;
3972  bind[1].buffer = reinterpret_cast<char*>(&lease_addr_data[0]);
3973  bind[1].buffer_length = lease_addr_length;
3974  bind[1].length = &lease_addr_length;
3975 
3976  // Add to lease6_relay_id table.
3977  StatementIndex stindex = ADD_RELAY_ID6;
3978 
3979  // Bind the input parameters to the statement.
3980  int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
3981  checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
3982 
3983  // Execute.
3984  status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
3985  checkError(ctx, status, stindex, "unable to execute");
3986 }
3987 
3988 void
3990  const vector<uint8_t>& remote_id) {
3991  // Get a context.
3992  MySqlLeaseContextAlloc get_context(*this);
3993  MySqlLeaseContextPtr ctx = get_context.ctx_;
3994 
3995  // Bind the remote id.
3996  MYSQL_BIND bind[2];
3997  memset(bind, 0, sizeof(bind));
3998 
3999  unsigned long remote_id_size = remote_id.size();
4000  if (remote_id_size == 0) {
4001  isc_throw(BadValue, "empty remote id");
4002  }
4003  std::vector<uint8_t> remote_id_data = remote_id;
4004  bind[0].buffer_type = MYSQL_TYPE_BLOB;
4005  bind[0].buffer = reinterpret_cast<char*>(&remote_id_data[0]);
4006  bind[0].buffer_length = remote_id_size;
4007  bind[0].length = &remote_id_size;
4008 
4009  // Bind the lease address.
4010  std::vector<uint8_t> lease_addr_data = lease_addr.toBytes();
4011  unsigned long lease_addr_length = lease_addr_data.size();
4012  if (lease_addr_length != 16) {
4013  isc_throw(DbOperationError, "lease6 address is not 16 bytes long");
4014  }
4015  bind[1].buffer_type = MYSQL_TYPE_BLOB;
4016  bind[1].buffer = reinterpret_cast<char*>(&lease_addr_data[0]);
4017  bind[1].buffer_length = lease_addr_length;
4018  bind[1].length = &lease_addr_length;
4019 
4020  // Add to lease6_remote_id table.
4021  StatementIndex stindex = ADD_REMOTE_ID6;
4022 
4023  // Bind the input parameters to the statement.
4024  int status = mysql_stmt_bind_param(ctx->conn_.getStatement(stindex), bind);
4025  checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
4026 
4027  // Execute.
4028  status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
4029  checkError(ctx, status, stindex, "unable to execute");
4030 }
4031 
4032 namespace {
4033 
4034 std::string
4035 idToText(const OptionBuffer& id) {
4036  std::stringstream tmp;
4037  tmp << std::hex;
4038  bool delim = false;
4039  for (std::vector<uint8_t>::const_iterator it = id.begin();
4040  it != id.end(); ++it) {
4041  if (delim) {
4042  tmp << ":";
4043  }
4044  tmp << std::setw(2) << std::setfill('0')
4045  << static_cast<unsigned int>(*it);
4046  delim = true;
4047  }
4048  return (tmp.str());
4049 }
4050 
4051 } // anonymous namespace
4052 
4055  const IOAddress& lower_bound_address,
4056  const LeasePageSize& page_size,
4057  const time_t& qry_start_time /* = 0 */,
4058  const time_t& qry_end_time /* = 0 */) {
4061  .arg(page_size.page_size_)
4062  .arg(lower_bound_address.toText())
4063  .arg(idToText(relay_id))
4064  .arg(qry_start_time)
4065  .arg(qry_end_time);
4066 
4067  // Expecting IPv4 address.
4068  if (!lower_bound_address.isV4()) {
4069  isc_throw(InvalidAddressFamily, "expected IPv4 address while "
4070  "retrieving leases from the lease database, got "
4071  << lower_bound_address);
4072  }
4073 
4074  // Catch 2038 bug with 32 bit time_t.
4075  if ((qry_start_time < 0) || (qry_end_time < 0)) {
4076  isc_throw(BadValue, "negative time value");
4077  }
4078 
4079  bool have_qst = (qry_start_time > 0);
4080  bool have_qet = (qry_end_time > 0);
4081 
4082  // Start time must be before end time.
4083  if (have_qst && have_qet && (qry_start_time > qry_end_time)) {
4084  isc_throw(BadValue, "start time must be before end time");
4085  }
4086 
4087  // Prepare WHERE clause
4088  size_t bindings = 3;
4089  if (have_qst) {
4090  ++bindings;
4091  }
4092  if (have_qet) {
4093  ++bindings;
4094  }
4095  MYSQL_BIND inbind[bindings];
4096  memset(inbind, 0, sizeof(inbind));
4097 
4098  std::vector<uint8_t> relay_id_data = relay_id;
4099  unsigned long relay_id_length = relay_id.size();
4100 
4101  // If the relay id happens to be empty, we have to create a
4102  // 1 byte dummy buffer and pass it to the binding.
4103  if (relay_id_data.empty()) {
4104  relay_id_data.resize(1);
4105  }
4106 
4107  // Bind relay id
4108  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
4109  inbind[0].buffer = reinterpret_cast<char*>(&relay_id_data[0]);
4110  inbind[0].buffer_length = relay_id_length;
4111  inbind[0].length = &relay_id_length;
4112 
4113  // Bind lower bound address
4114  uint32_t lb_address_data = lower_bound_address.toUint32();
4115  inbind[1].buffer_type = MYSQL_TYPE_LONG;
4116  inbind[1].buffer = reinterpret_cast<char*>(&lb_address_data);
4117  inbind[1].is_unsigned = MLM_TRUE;
4118 
4119  size_t index = 2;
4120  // Bind query start time.
4121  uint32_t start_time = static_cast<uint32_t>(qry_start_time);
4122  if (have_qst) {
4123  inbind[index].buffer_type = MYSQL_TYPE_LONG;
4124  inbind[index].buffer = reinterpret_cast<char*>(&start_time);
4125  inbind[index].is_unsigned = MLM_TRUE;
4126  ++index;
4127  }
4128 
4129  // Bind query end time.
4130  uint32_t end_time = static_cast<uint32_t>(qry_end_time);
4131  if (have_qet) {
4132  inbind[index].buffer_type = MYSQL_TYPE_LONG;
4133  inbind[index].buffer = reinterpret_cast<char*>(&end_time);
4134  inbind[index].is_unsigned = MLM_TRUE;
4135  ++index;
4136  }
4137 
4138  // Bind page size value
4139  uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
4140  inbind[index].buffer_type = MYSQL_TYPE_LONG;
4141  inbind[index].buffer = reinterpret_cast<char*>(&ps);
4142  inbind[index].is_unsigned = MLM_TRUE;
4143 
4145  if (have_qst && !have_qet) {
4146  stindex = GET_LEASE4_RELAYID_QST;
4147  } else if (have_qst && have_qet) {
4148  stindex = GET_LEASE4_RELAYID_QSET;
4149  } else if (!have_qst && have_qet) {
4150  stindex = GET_LEASE4_RELAYID_QET;
4151  }
4152 
4153  // Get the leases
4154  Lease4Collection result;
4155 
4156  // Get a context
4157  MySqlLeaseContextAlloc get_context(*this);
4158  MySqlLeaseContextPtr ctx = get_context.ctx_;
4159 
4160  getLeaseCollection(ctx, stindex, inbind, result);
4161 
4162  return (result);
4163 }
4164 
4167  const IOAddress& lower_bound_address,
4168  const LeasePageSize& page_size,
4169  const time_t& qry_start_time /* = 0 */,
4170  const time_t& qry_end_time /* = 0 */) {
4173  .arg(page_size.page_size_)
4174  .arg(lower_bound_address.toText())
4175  .arg(idToText(remote_id))
4176  .arg(qry_start_time)
4177  .arg(qry_end_time);
4178 
4179  // Expecting IPv4 address.
4180  if (!lower_bound_address.isV4()) {
4181  isc_throw(InvalidAddressFamily, "expected IPv4 address while "
4182  "retrieving leases from the lease database, got "
4183  << lower_bound_address);
4184  }
4185 
4186  // Catch 2038 bug with 32 bit time_t.
4187  if ((qry_start_time < 0) || (qry_end_time < 0)) {
4188  isc_throw(BadValue, "negative time value");
4189  }
4190 
4191  bool have_qst = (qry_start_time > 0);
4192  bool have_qet = (qry_end_time > 0);
4193 
4194  // Start time must be before end time.
4195  if (have_qst && have_qet && (qry_start_time > qry_end_time)) {
4196  isc_throw(BadValue, "start time must be before end time");
4197  }
4198 
4199  // Prepare WHERE clause
4200  size_t bindings = 3;
4201  if (have_qst) {
4202  ++bindings;
4203  }
4204  if (have_qet) {
4205  ++bindings;
4206  }
4207  MYSQL_BIND inbind[bindings];
4208  memset(inbind, 0, sizeof(inbind));
4209 
4210  std::vector<uint8_t> remote_id_data = remote_id;
4211  unsigned long remote_id_length = remote_id.size();
4212 
4213  // If the remote id happens to be empty, we have to create a
4214  // 1 byte dummy buffer and pass it to the binding.
4215  if (remote_id_data.empty()) {
4216  remote_id_data.resize(1);
4217  }
4218 
4219  // Bind remote id
4220  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
4221  inbind[0].buffer = reinterpret_cast<char*>(&remote_id_data[0]);
4222  inbind[0].buffer_length = remote_id_length;
4223  inbind[0].length = &remote_id_length;
4224 
4225  // Bind lower bound address
4226  uint32_t lb_address_data = lower_bound_address.toUint32();
4227  inbind[1].buffer_type = MYSQL_TYPE_LONG;
4228  inbind[1].buffer = reinterpret_cast<char*>(&lb_address_data);
4229  inbind[1].is_unsigned = MLM_TRUE;
4230 
4231  size_t index = 2;
4232  // Bind query start time.
4233  uint32_t start_time = static_cast<uint32_t>(qry_start_time);
4234  if (have_qst) {
4235  inbind[index].buffer_type = MYSQL_TYPE_LONG;
4236  inbind[index].buffer = reinterpret_cast<char*>(&start_time);
4237  inbind[index].is_unsigned = MLM_TRUE;
4238  ++index;
4239  }
4240 
4241  // Bind query end time.
4242  uint32_t end_time = static_cast<uint32_t>(qry_end_time);
4243  if (have_qet) {
4244  inbind[index].buffer_type = MYSQL_TYPE_LONG;
4245  inbind[index].buffer = reinterpret_cast<char*>(&end_time);
4246  inbind[index].is_unsigned = MLM_TRUE;
4247  ++index;
4248  }
4249 
4250  // Bind page size value
4251  uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
4252  inbind[index].buffer_type = MYSQL_TYPE_LONG;
4253  inbind[index].buffer = reinterpret_cast<char*>(&ps);
4254  inbind[index].is_unsigned = MLM_TRUE;
4255 
4257  if (have_qst && !have_qet) {
4258  stindex = GET_LEASE4_REMOTEID_QST;
4259  } else if (have_qst && have_qet) {
4260  stindex = GET_LEASE4_REMOTEID_QSET;
4261  } else if (!have_qst && have_qet) {
4262  stindex = GET_LEASE4_REMOTEID_QET;
4263  }
4264 
4265  // Get the leases
4266  Lease4Collection result;
4267 
4268  // Get a context
4269  MySqlLeaseContextAlloc get_context(*this);
4270  MySqlLeaseContextPtr ctx = get_context.ctx_;
4271 
4272  getLeaseCollection(ctx, stindex, inbind, result);
4273 
4274  return (result);
4275 }
4276 
4277 size_t
4279  auto check = CfgMgr::instance().getCurrentCfg()->
4280  getConsistency()->getExtendedInfoSanityCheck();
4281 
4282  size_t pages = 0;
4283  size_t updated = 0;
4284  IOAddress start_addr = IOAddress::IPV4_ZERO_ADDRESS();
4285  for (;;) {
4288  .arg(pages)
4289  .arg(start_addr.toText())
4290  .arg(updated);
4291 
4292  // Prepare WHERE clause.
4293  MYSQL_BIND inbind[2];
4294  memset(inbind, 0, sizeof(inbind));
4295 
4296  // Bind start address.
4297  uint32_t start_addr_data = start_addr.toUint32();
4298  inbind[0].buffer_type = MYSQL_TYPE_LONG;
4299  inbind[0].buffer = reinterpret_cast<char*>(&start_addr_data);
4300  inbind[0].is_unsigned = MLM_TRUE;
4301 
4302  // Bind page size value.
4303  uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
4304  inbind[1].buffer_type = MYSQL_TYPE_LONG;
4305  inbind[1].buffer = reinterpret_cast<char*>(&ps);
4306  inbind[1].is_unsigned = MLM_TRUE;
4307 
4308  Lease4Collection leases;
4309 
4310  // Get a context.
4311  {
4312  MySqlLeaseContextAlloc get_context(*this);
4313  MySqlLeaseContextPtr ctx = get_context.ctx_;
4314 
4315  getLeaseCollection(ctx, GET_LEASE4_UCTX_PAGE, inbind, leases);
4316  }
4317 
4318  if (leases.empty()) {
4319  // Done.
4320  break;
4321  }
4322 
4323  ++pages;
4324  start_addr = leases.back()->addr_;
4325  for (auto lease : leases) {
4326  ConstElementPtr previous_user_context = lease->getContext();
4327  vector<uint8_t> previous_relay_id = lease->relay_id_;
4328  vector<uint8_t> previous_remote_id = lease->remote_id_;
4329  if (!previous_user_context &&
4330  previous_relay_id.empty() &&
4331  previous_remote_id.empty()) {
4332  continue;
4333  }
4334  bool modified = upgradeLease4ExtendedInfo(lease, check);
4335  try {
4336  lease->relay_id_.clear();
4337  lease->remote_id_.clear();
4338  extractLease4ExtendedInfo(lease, false);
4339  if (modified ||
4340  (previous_relay_id != lease->relay_id_) ||
4341  (previous_remote_id != lease->remote_id_)) {
4342  updateLease4(lease);
4343  ++updated;
4344  }
4345  } catch (const NoSuchLease&) {
4346  // The lease was modified in parallel:
4347  // as its extended info was processed just ignore.
4348  continue;
4349  } catch (const std::exception& ex) {
4350  // Something when wrong, for instance extract failed.
4353  .arg(lease->addr_.toText())
4354  .arg(ex.what());
4355  }
4356  }
4357  }
4358 
4360  .arg(pages)
4361  .arg(updated);
4362 
4363  return (updated);
4364 }
4365 
4368  const IOAddress& link_addr,
4369  uint8_t link_len,
4370  const IOAddress& lower_bound_address,
4371  const LeasePageSize& page_size) {
4374  .arg(page_size.page_size_)
4375  .arg(lower_bound_address.toText())
4376  .arg(relay_id.toText())
4377  .arg(link_addr.toText())
4378  .arg(static_cast<unsigned>(link_len));
4379 
4380  // Expecting IPv6 valid prefix and address.
4381  if (!link_addr.isV6()) {
4382  isc_throw(InvalidAddressFamily, "expected IPv6 link address while "
4383  "retrieving leases from the lease database, got "
4384  << link_addr);
4385  }
4386  if (link_len > 128) {
4387  isc_throw(OutOfRange, "invalid IPv6 prefix length "
4388  << static_cast<unsigned>(link_len));
4389  }
4390  if (!lower_bound_address.isV6()) {
4391  isc_throw(InvalidAddressFamily, "expected IPv6 start address while "
4392  "retrieving leases from the lease database, got "
4393  << lower_bound_address);
4394  }
4395 
4396  std::vector<uint8_t> relay_id_data = relay_id.getDuid();
4397  unsigned long relay_id_size = relay_id_data.size();
4398  if (relay_id_size == 0) {
4399  isc_throw(BadValue, "empty relay id");
4400  }
4401 
4402  Lease6Collection result;
4403 
4404  if (!link_len) {
4405  // Bind the relay id.
4406  MYSQL_BIND inbind[3];
4407  memset(inbind, 0, sizeof(inbind));
4408 
4409  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
4410  inbind[0].buffer = reinterpret_cast<char*>(&relay_id_data[0]);
4411  inbind[0].buffer_length = relay_id_size;
4412  inbind[0].length = &relay_id_size;
4413 
4414  // Bind the lower bound address.
4415  std::vector<uint8_t> lb_addr_data = lower_bound_address.toBytes();
4416  unsigned long lb_addr_size = lb_addr_data.size();
4417  if (lb_addr_size != 16) {
4418  isc_throw(DbOperationError, "lower bound address is not 16 bytes long");
4419  }
4420  inbind[1].buffer_type = MYSQL_TYPE_BLOB;
4421  inbind[1].buffer = reinterpret_cast<char*>(&lb_addr_data[0]);
4422  inbind[1].buffer_length = lb_addr_size;
4423  inbind[1].length = &lb_addr_size;
4424 
4425  // Bind the size value.
4426  uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
4427  inbind[2].buffer_type = MYSQL_TYPE_LONG;
4428  inbind[2].buffer = reinterpret_cast<char*>(&ps);
4429  inbind[2].is_unsigned = MLM_TRUE;
4430 
4431  // Get a context.
4432  MySqlLeaseContextAlloc get_context(*this);
4433  MySqlLeaseContextPtr ctx = get_context.ctx_;
4434 
4435  getLeaseCollection(ctx, GET_RELAY_ID6, inbind, result);
4436  } else {
4437  const IOAddress& first_addr = firstAddrInPrefix(link_addr, link_len);
4438  const IOAddress& last_addr = lastAddrInPrefix(link_addr, link_len);
4439  IOAddress start_addr = lower_bound_address;
4440  if (lower_bound_address < first_addr) {
4441  start_addr = first_addr;
4442  } else if (last_addr <= lower_bound_address) {
4443  // Range was already done.
4444  return (result);
4445  } else {
4446  // The lower bound address is from the last call so skip it.
4447  start_addr = IOAddress::increase(lower_bound_address);
4448  }
4449 
4450  // Bind the relay id.
4451  MYSQL_BIND inbind[4];
4452  memset(inbind, 0, sizeof(inbind));
4453 
4454  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
4455  inbind[0].buffer = reinterpret_cast<char*>(&relay_id_data[0]);
4456  inbind[0].buffer_length = relay_id_size;
4457  inbind[0].length = &relay_id_size;
4458 
4459  // Bind the start address.
4460  std::vector<uint8_t> start_addr_data = start_addr.toBytes();
4461  unsigned long start_addr_size = start_addr_data.size();
4462  if (start_addr_size != 16) {
4463  isc_throw(DbOperationError, "start address is not 16 bytes long");
4464  }
4465  inbind[1].buffer_type = MYSQL_TYPE_BLOB;
4466  inbind[1].buffer = reinterpret_cast<char*>(&start_addr_data[0]);
4467  inbind[1].buffer_length = start_addr_size;
4468  inbind[1].length = &start_addr_size;
4469 
4470  // Bind the last address.
4471  std::vector<uint8_t> last_addr_data = last_addr.toBytes();
4472  unsigned long last_addr_size = last_addr_data.size();
4473  if (last_addr_size != 16) {
4474  isc_throw(DbOperationError, "last address is not 16 bytes long");
4475  }
4476  inbind[2].buffer_type = MYSQL_TYPE_BLOB;
4477  inbind[2].buffer = reinterpret_cast<char*>(&last_addr_data[0]);
4478  inbind[2].buffer_length = last_addr_size;
4479  inbind[2].length = &last_addr_size;
4480 
4481  // Bind the size value.
4482  uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
4483  inbind[3].buffer_type = MYSQL_TYPE_LONG;
4484  inbind[3].buffer = reinterpret_cast<char*>(&ps);
4485  inbind[3].is_unsigned = MLM_TRUE;
4486 
4487  // Get a context.
4488  MySqlLeaseContextAlloc get_context(*this);
4489  MySqlLeaseContextPtr ctx = get_context.ctx_;
4490 
4491  getLeaseCollection(ctx, GET_RELAY_ID6_LINK, inbind, result);
4492  }
4493 
4494  return (result);
4495 }
4496 
4499  const IOAddress& link_addr,
4500  uint8_t link_len,
4501  const IOAddress& lower_bound_address,
4502  const LeasePageSize& page_size) {
4505  .arg(page_size.page_size_)
4506  .arg(lower_bound_address.toText())
4507  .arg(idToText(remote_id))
4508  .arg(link_addr.toText())
4509  .arg(static_cast<unsigned>(link_len));
4510 
4511  // Expecting IPv6 valid prefix and address.
4512  if (!link_addr.isV6()) {
4513  isc_throw(InvalidAddressFamily, "expected IPv6 link address while "
4514  "retrieving leases from the lease database, got "
4515  << link_addr);
4516  }
4517  if (link_len > 128) {
4518  isc_throw(OutOfRange, "invalid IPv6 prefix length "
4519  << static_cast<unsigned>(link_len));
4520  }
4521  if (!lower_bound_address.isV6()) {
4522  isc_throw(InvalidAddressFamily, "expected IPv6 start address while "
4523  "retrieving leases from the lease database, got "
4524  << lower_bound_address);
4525  }
4526 
4527  std::vector<uint8_t> remote_id_data = remote_id;
4528  unsigned long remote_id_size = remote_id_data.size();
4529  if (remote_id_size == 0) {
4530  isc_throw(BadValue, "empty remote id");
4531  }
4532 
4533  Lease6Collection result;
4534 
4535  if (!link_len) {
4536  // Bind the remote id.
4537  MYSQL_BIND inbind[3];
4538  memset(inbind, 0, sizeof(inbind));
4539 
4540  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
4541  inbind[0].buffer = reinterpret_cast<char*>(&remote_id_data[0]);
4542  inbind[0].buffer_length = remote_id_size;
4543  inbind[0].length = &remote_id_size;
4544 
4545  // Bind the lower bound address.
4546  std::vector<uint8_t> lb_addr_data = lower_bound_address.toBytes();
4547  unsigned long lb_addr_size = lb_addr_data.size();
4548  if (lb_addr_size != 16) {
4549  isc_throw(DbOperationError, "lower bound address is not 16 bytes long");
4550  }
4551  inbind[1].buffer_type = MYSQL_TYPE_BLOB;
4552  inbind[1].buffer = reinterpret_cast<char*>(&lb_addr_data[0]);
4553  inbind[1].buffer_length = lb_addr_size;
4554  inbind[1].length = &lb_addr_size;
4555 
4556  // Bind the size value.
4557  uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
4558  inbind[2].buffer_type = MYSQL_TYPE_LONG;
4559  inbind[2].buffer = reinterpret_cast<char*>(&ps);
4560  inbind[2].is_unsigned = MLM_TRUE;
4561 
4562  // Get a context.
4563  MySqlLeaseContextAlloc get_context(*this);
4564  MySqlLeaseContextPtr ctx = get_context.ctx_;
4565 
4566  getLeaseCollection(ctx, GET_REMOTE_ID6, inbind, result);
4567  } else {
4568  const IOAddress& first_addr = firstAddrInPrefix(link_addr, link_len);
4569  const IOAddress& last_addr = lastAddrInPrefix(link_addr, link_len);
4570  IOAddress start_addr = lower_bound_address;
4571  if (lower_bound_address < first_addr) {
4572  start_addr = first_addr;
4573  } else if (last_addr <= lower_bound_address) {
4574  // Range was already done.
4575  return (result);
4576  } else {
4577  // The lower bound address is from the last call so skip it.
4578  start_addr = IOAddress::increase(lower_bound_address);
4579  }
4580 
4581  // Bind the remote id.
4582  MYSQL_BIND inbind[4];
4583  memset(inbind, 0, sizeof(inbind));
4584 
4585  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
4586  inbind[0].buffer = reinterpret_cast<char*>(&remote_id_data[0]);
4587  inbind[0].buffer_length = remote_id_size;
4588  inbind[0].length = &remote_id_size;
4589 
4590  // Bind the start address.
4591  std::vector<uint8_t> start_addr_data = start_addr.toBytes();
4592  unsigned long start_addr_size = start_addr_data.size();
4593  if (start_addr_size != 16) {
4594  isc_throw(DbOperationError, "start address is not 16 bytes long");
4595  }
4596  inbind[1].buffer_type = MYSQL_TYPE_BLOB;
4597  inbind[1].buffer = reinterpret_cast<char*>(&start_addr_data[0]);
4598  inbind[1].buffer_length = start_addr_size;
4599  inbind[1].length = &start_addr_size;
4600 
4601  // Bind the last address.
4602  std::vector<uint8_t> last_addr_data = last_addr.toBytes();
4603  unsigned long last_addr_size = last_addr_data.size();
4604  if (last_addr_size != 16) {
4605  isc_throw(DbOperationError, "last address is not 16 bytes long");
4606  }
4607  inbind[2].buffer_type = MYSQL_TYPE_BLOB;
4608  inbind[2].buffer = reinterpret_cast<char*>(&last_addr_data[0]);
4609  inbind[2].buffer_length = last_addr_size;
4610  inbind[2].length = &last_addr_size;
4611 
4612  // Bind the size value.
4613  uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
4614  inbind[3].buffer_type = MYSQL_TYPE_LONG;
4615  inbind[3].buffer = reinterpret_cast<char*>(&ps);
4616  inbind[3].is_unsigned = MLM_TRUE;
4617 
4618  // Get a context.
4619  MySqlLeaseContextAlloc get_context(*this);
4620  MySqlLeaseContextPtr ctx = get_context.ctx_;
4621 
4622  getLeaseCollection(ctx, GET_REMOTE_ID6_LINK, inbind, result);
4623  }
4624 
4625  return (result);
4626 }
4627 
4630  uint8_t link_len,
4631  const IOAddress& lower_bound_address,
4632  const LeasePageSize& page_size) {
4635  .arg(page_size.page_size_)
4636  .arg(lower_bound_address.toText())
4637  .arg(link_addr.toText())
4638  .arg(static_cast<unsigned>(link_len));
4639 
4640  // Expecting IPv6 valid prefix and address.
4641  if (!link_addr.isV6()) {
4642  isc_throw(InvalidAddressFamily, "expected IPv6 link address while "
4643  "retrieving leases from the lease database, got "
4644  << link_addr);
4645  }
4646  if ((link_len == 0) || (link_len > 128)) {
4647  isc_throw(OutOfRange, "invalid IPv6 prefix length "
4648  << static_cast<unsigned>(link_len));
4649  }
4650  if (!lower_bound_address.isV6()) {
4651  isc_throw(InvalidAddressFamily, "expected IPv6 start address while "
4652  "retrieving leases from the lease database, got "
4653  << lower_bound_address);
4654  }
4655 
4656  Lease6Collection result;
4657  const IOAddress& first_addr = firstAddrInPrefix(link_addr, link_len);
4658  const IOAddress& last_addr = lastAddrInPrefix(link_addr, link_len);
4659  IOAddress start_addr = lower_bound_address;
4660  if (lower_bound_address < first_addr) {
4661  start_addr = first_addr;
4662  } else if (last_addr <= lower_bound_address) {
4663  // Range was already done.
4664  return (result);
4665  } else {
4666  // The lower bound address is from the last call so skip it.
4667  start_addr = IOAddress::increase(lower_bound_address);
4668  }
4669 
4670  // Prepare WHERE clause
4671  MYSQL_BIND inbind[3];
4672  memset(inbind, 0, sizeof(inbind));
4673 
4674  // Bind start address
4675  std::vector<uint8_t> start_addr_data = start_addr.toBytes();
4676  if (start_addr_data.size() != 16) {
4677  isc_throw(DbOperationError, "start address is not 16 bytes long");
4678  }
4679  unsigned long start_addr_size = 16;
4680  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
4681  inbind[0].buffer = reinterpret_cast<char*>(&start_addr_data[0]);
4682  inbind[0].buffer_length = 16;
4683  inbind[0].length = &start_addr_size;
4684 
4685  // Bind last address
4686  std::vector<uint8_t> last_addr_data = last_addr.toBytes();
4687  if (last_addr_data.size() != 16) {
4688  isc_throw(DbOperationError, "last address is not 16 bytes long");
4689  }
4690  unsigned long last_addr_size = 16;
4691  inbind[1].buffer_type = MYSQL_TYPE_BLOB;
4692  inbind[1].buffer = reinterpret_cast<char*>(&last_addr_data[0]);
4693  inbind[1].buffer_length = 16;
4694  inbind[1].length = &last_addr_size;
4695 
4696  // Bind page size value
4697  uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
4698  inbind[2].buffer_type = MYSQL_TYPE_LONG;
4699  inbind[2].buffer = reinterpret_cast<char*>(&ps);
4700  inbind[2].is_unsigned = MLM_TRUE;
4701 
4702  // Get a context
4703  MySqlLeaseContextAlloc get_context(*this);
4704  MySqlLeaseContextPtr ctx = get_context.ctx_;
4705 
4706  // Get the leases
4707  getLeaseCollection(ctx, GET_LEASE6_LINK, inbind, result);
4708 
4709  return (result);
4710 }
4711 
4712 size_t
4714  auto check = CfgMgr::instance().getCurrentCfg()->
4715  getConsistency()->getExtendedInfoSanityCheck();
4716 
4717  // First step is to wipe tables if enabled.
4720  }
4721 
4722  size_t pages = 0;
4723  size_t updated = 0;
4724  IOAddress start_addr = IOAddress::IPV6_ZERO_ADDRESS();
4725  for (;;) {
4728  .arg(pages)
4729  .arg(start_addr.toText())
4730  .arg(updated);
4731 
4732  // Prepare WHERE clause.
4733  MYSQL_BIND inbind[2];
4734  memset(inbind, 0, sizeof(inbind));
4735 
4736  // Bind start address.
4737  std::vector<uint8_t>start_addr_bytes = start_addr.toBytes();
4738  if (start_addr_bytes.size() != 16) {
4739  isc_throw(DbOperationError, "start address is not 16 bytes long");
4740  }
4741 
4742  unsigned long start_addr_size = 16;
4743  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
4744  inbind[0].buffer = reinterpret_cast<char*>(&start_addr_bytes[0]);
4745  inbind[0].buffer_length = 16;
4746  inbind[0].length = &start_addr_size;
4747 
4748  // Bind page size value.
4749  uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
4750  inbind[1].buffer_type = MYSQL_TYPE_LONG;
4751  inbind[1].buffer = reinterpret_cast<char*>(&ps);
4752  inbind[1].is_unsigned = MLM_TRUE;
4753 
4754  Lease6Collection leases;
4755 
4756  // Get a context.
4757  {
4758  MySqlLeaseContextAlloc get_context(*this);
4759  MySqlLeaseContextPtr ctx = get_context.ctx_;
4760 
4761  getLeaseCollection(ctx, GET_LEASE6_UCTX_PAGE, inbind, leases);
4762  }
4763 
4764  if (leases.empty()) {
4765  // Done.
4766  break;
4767  }
4768 
4769  ++pages;
4770  start_addr = leases.back()->addr_;
4771  for (auto lease : leases) {
4772  try {
4773  bool modified = upgradeLease6ExtendedInfo(lease, check);
4774  if (modified) {
4775  updateLease6(lease);
4776  }
4777  bool added = (getExtendedInfoTablesEnabled() &&
4778  addExtendedInfo6(lease));
4779  if (modified || added) {
4780  ++updated;
4781  }
4782  } catch (const NoSuchLease&) {
4783  // The lease was modified in parallel:
4784  // as its extended info was processed just ignore.
4785  continue;
4786  } catch (const std::exception& ex) {
4787  // Something when wrong, for instance extract failed.
4790  .arg(lease->addr_.toText())
4791  .arg(ex.what());
4792  }
4793  }
4794  }
4795 
4797  .arg(pages)
4798  .arg(updated);
4799 
4800  return (updated);
4801 }
4802 
4803 void
4805  // Get a context.
4806  MySqlLeaseContextAlloc get_context(*this);
4807  MySqlLeaseContextPtr ctx = get_context.ctx_;
4808 
4809  StatementIndex stindex = WIPE_RELAY_ID6;
4810  int status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
4811  if (status != 0) {
4812  checkError(ctx, status, stindex, "unable to execute");
4813  }
4814 
4815  stindex = WIPE_REMOTE_ID6;
4816  status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
4817  if (status != 0) {
4818  checkError(ctx, status, stindex, "unable to execute");
4819  }
4820 }
4821 
4822 size_t
4824  // Get a context.
4825  MySqlLeaseContextAlloc get_context(*this);
4826  MySqlLeaseContextPtr ctx = get_context.ctx_;
4827 
4828  StatementIndex stindex = COUNT_RELAY_ID6;
4829 
4830  // Bind the output.
4831  MYSQL_BIND bind[1];
4832  memset(bind, 0, sizeof(bind));
4833 
4834  int64_t count = 0;
4835  bind[0].buffer_type = MYSQL_TYPE_LONGLONG;
4836  bind[0].buffer = reinterpret_cast<char*>(&count);
4837 
4838  int status = mysql_stmt_bind_result(ctx->conn_.getStatement(stindex), &bind[0]);
4839  checkError(ctx, status, stindex, "unable to bind SELECT clause parameters");
4840 
4841  // Execute.
4842  status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
4843  if (status != 0) {
4844  checkError(ctx, status, stindex, "unable to execute");
4845  }
4846 
4847  status = mysql_stmt_store_result(ctx->conn_.getStatement(stindex));
4848  checkError(ctx, status, stindex, "unable to store result");
4849 
4850  // Fetch the result.
4851  MySqlFreeResult fetch_release(ctx->conn_.getStatement(stindex));
4852 
4853  status = mysql_stmt_fetch(ctx->conn_.getStatement(stindex));
4854  if (status != 0) {
4855  checkError(ctx, status, stindex, "unable to fetch results");
4856  }
4857  return (static_cast<size_t>(count));
4858 }
4859 
4860 size_t
4862  // Get a context.
4863  MySqlLeaseContextAlloc get_context(*this);
4864  MySqlLeaseContextPtr ctx = get_context.ctx_;
4865 
4866  StatementIndex stindex = COUNT_REMOTE_ID6;
4867 
4868  // Bind the output.
4869  MYSQL_BIND bind[1];
4870  memset(bind, 0, sizeof(bind));
4871 
4872  int64_t count = 0;
4873  bind[0].buffer_type = MYSQL_TYPE_LONGLONG;
4874  bind[0].buffer = reinterpret_cast<char*>(&count);
4875 
4876  int status = mysql_stmt_bind_result(ctx->conn_.getStatement(stindex), &bind[0]);
4877  checkError(ctx, status, stindex, "unable to bind SELECT clause parameters");
4878 
4879  // Execute.
4880  status = MysqlExecuteStatement(ctx->conn_.getStatement(stindex));
4881  if (status != 0) {
4882  checkError(ctx, status, stindex, "unable to execute");
4883  }
4884 
4885  status = mysql_stmt_store_result(ctx->conn_.getStatement(stindex));
4886  checkError(ctx, status, stindex, "unable to store result");
4887 
4888  // Fetch the result.
4889  MySqlFreeResult fetch_release(ctx->conn_.getStatement(stindex));
4890 
4891  status = mysql_stmt_fetch(ctx->conn_.getStatement(stindex));
4892  if (status != 0) {
4893  checkError(ctx, status, stindex, "unable to fetch results");
4894  }
4895  return (static_cast<size_t>(count));
4896 }
4897 
4898 } // namespace dhcp
4899 } // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when a function is not implemented.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
Data is truncated.
Definition: db_exceptions.h:23
static bool invokeDbLostCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's lost connectivity callback.
static bool invokeDbFailedCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restore failed connectivity callback.
static bool invokeDbRecoveredCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restored connectivity callback.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Exception thrown on failure to open database.
Exception thrown on failure to execute a database function.
Invalid address family used as input to Lease Manager.
Definition: db_exceptions.h:59
Multiple lease records found where one expected.
Definition: db_exceptions.h:16
static MySqlBindingPtr createString(const unsigned long length)
Creates binding of text type for receiving data.
static MySqlBindingPtr createBool()
Creates binding having a bool type for receiving data.
Common MySQL Connector Pool.
static void convertToDatabaseTime(const time_t input_time, MYSQL_TIME &output_time)
Convert time_t value to database time.
static std::pair< uint32_t, uint32_t > getVersion(const ParameterMap &parameters)
Get the schema version.
Fetch and Release MySQL Results.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:161
Holds Client identifier or client IPv4 address.
Definition: duid.h:218
const std::vector< uint8_t > & getClientId() const
Returns reference to the client-id data.
Definition: duid.cc:70
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:138
const std::vector< uint8_t > & getDuid() const
Returns a const reference to the actual DUID value.
Definition: duid.cc:34
std::string toText() const
Returns textual representation of the identifier (e.g.
Definition: duid.h:84
static void recreate(const std::string &dbaccess, bool preserve_callbacks=true)
Recreate an instance of a lease manager with optionally preserving registered callbacks.
void setExtendedInfoTablesEnabled(const bool enabled)
Modifies the setting whether the lease6 extended info tables are enabled.
Definition: lease_mgr.h:1039
static bool upgradeLease6ExtendedInfo(const Lease6Ptr &lease, CfgConsistency::ExtendedInfoSanity check=CfgConsistency::EXTENDED_INFO_CHECK_FIX)
Upgrade a V6 lease user context to the new extended info entry.
Definition: lease_mgr.cc:771
bool getExtendedInfoTablesEnabled() const
Returns the setting indicating if lease6 extended info tables are enabled.
Definition: lease_mgr.h:1031
static isc::asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service.
Definition: lease_mgr.h:842
static void extractLease4ExtendedInfo(const Lease4Ptr &lease, bool ignore_errors=true)
Extract relay and remote identifiers from the extended info.
Definition: lease_mgr.cc:1123
static bool upgradeLease4ExtendedInfo(const Lease4Ptr &lease, CfgConsistency::ExtendedInfoSanity check=CfgConsistency::EXTENDED_INFO_CHECK_FIX)
The following queries are used to fulfill Bulk Lease Query queries.
Definition: lease_mgr.cc:539
virtual bool addExtendedInfo6(const Lease6Ptr &lease)
Extract extended info from a lease6 and add it into tables.
Definition: lease_mgr.cc:1209
Wraps value holding size of the page with leases.
Definition: lease_mgr.h:46
const size_t page_size_
Holds page size.
Definition: lease_mgr.h:56
Base class for fulfilling a statistical lease data query.
Definition: lease_mgr.h:149
Exchange MySQL and Lease4 Data.
std::vector< MYSQL_BIND > createBindForReceive()
Create BIND array to receive data.
std::vector< MYSQL_BIND > createBindForSend(const Lease4Ptr &lease)
Create MYSQL_BIND objects for Lease4 Pointer.
std::string getErrorColumns()
Return columns in error.
Lease4Ptr getLeaseData()
Copy Received Data into Lease4 Object.
Exchange MySQL and Lease6 Data.
std::vector< MYSQL_BIND > createBindForReceive()
Create BIND array to receive data.
std::string getErrorColumns()
Return columns in error.
Lease6Ptr getLeaseData()
Copy Received Data into Lease6 Object.
std::vector< MYSQL_BIND > createBindForSend(const Lease6Ptr &lease)
Create MYSQL_BIND objects for Lease6 Pointer.
MySQL Lease Context Pool.
MySQL Lease Context.
Common MySQL and Lease Data Methods.
static std::string getColumnsInError(my_bool *error, std::string *names, size_t count)
Return columns in error.
static void setErrorIndicators(MYSQL_BIND *bind, my_bool *error, size_t count)
Set error indicators.
MySQL Lease Manager.
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const override
Returns existing IPv6 lease for a given IPv6 address.
virtual std::string getDescription() const override
Returns description of the backend.
virtual size_t wipeLeases6(const SubnetID &subnet_id) override
Removed specified IPv6 leases.
virtual bool deleteLease(const Lease4Ptr &lease) override
Deletes an IPv4 lease.
virtual size_t byRemoteId6size() const override
Return the by-remote-id table size.
static std::string getDBVersion()
Local version of getDBVersion() class method.
virtual bool addLease(const Lease4Ptr &lease) override
Adds an IPv4 lease.
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs) override
Deletes all expired-reclaimed DHCPv6 leases.
virtual Lease4Collection getLeases4ByRemoteId(const OptionBuffer &remote_id, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size, const time_t &qry_start_time=0, const time_t &qry_end_time=0) override
Returns existing IPv4 leases with a given remote-id.
virtual LeaseStatsQueryPtr startLeaseStatsQuery4() override
Creates and runs the IPv4 lease stats query.
virtual Lease4Collection getLeases4ByRelayId(const OptionBuffer &relay_id, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size, const time_t &qry_start_time=0, const time_t &qry_end_time=0) override
The following queries are used to fulfill Bulk Lease Query queries.
virtual void rollback() override
Rollback Transactions.
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery4(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id) override
Creates and runs the IPv4 lease stats query for a single subnet.
virtual void wipeExtendedInfoTables6() override
Wipe by-relay-id table (v6).
virtual Lease6Collection getLeases6() const override
Returns all IPv6 leases.
virtual void getExpiredLeases4(Lease4Collection &expired_leases, const size_t max_leases) const override
Returns a collection of expired DHCPv4 leases.
virtual void addRemoteId6(const isc::asiolink::IOAddress &lease_addr, const std::vector< uint8_t > &remote_id) override
Add lease6 extended info into by-remote-id table.
virtual void commit() override
Commit Transactions.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID &subnet_id) override
Creates and runs the IPv6 lease stats query for a single subnet.
MySqlLeaseContextPtr createContext() const
Create a new context.
virtual void deleteExtendedInfo6(const isc::asiolink::IOAddress &addr) override
Extended information / Bulk Lease Query shared interface.
virtual LeaseStatsQueryPtr startPoolLeaseStatsQuery4() override
Creates and runs the IPv4 lease stats query for all subnets and pools.
virtual void getExpiredLeases6(Lease6Collection &expired_leases, const size_t max_leases) const override
Returns a collection of expired DHCPv6 leases.
virtual void updateLease6(const Lease6Ptr &lease6) override
Updates IPv6 lease.
MySqlLeaseMgr(const db::DatabaseConnection::ParameterMap &parameters)
Constructor.
virtual LeaseStatsQueryPtr startPoolLeaseStatsQuery6() override
Creates and runs the IPv6 lease stats query for all subnets and pools.
virtual std::string getName() const override
Returns backend name.
StatementIndex
Statement Tags.
virtual LeaseStatsQueryPtr startLeaseStatsQuery6() override
Creates and runs the IPv6 lease stats query.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const override
Returns an IPv4 lease for specified IPv4 address.
virtual size_t upgradeExtendedInfo4(const LeasePageSize &page_size) override
Upgrade extended info (v4).
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery6(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id) override
Creates and runs the IPv6 lease stats query for a single subnet.
virtual Lease6Collection getLeases6ByRemoteId(const OptionBuffer &remote_id, const asiolink::IOAddress &link_addr, uint8_t link_len, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size) override
Returns existing IPv6 leases with a given remote-id.
virtual void updateLease4(const Lease4Ptr &lease4) override
Updates IPv4 lease.
virtual std::pair< uint32_t, uint32_t > getVersion() const override
Returns backend version.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID &subnet_id) override
Creates and runs the IPv4 lease stats query for a single subnet.
virtual ~MySqlLeaseMgr()
Destructor (closes database)
virtual size_t upgradeExtendedInfo6(const LeasePageSize &page_size) override
Upgrade extended info (v6).
virtual void addRelayId6(const isc::asiolink::IOAddress &lease_addr, const std::vector< uint8_t > &relay_id) override
Add lease6 extended info into by-relay-id table.
virtual size_t wipeLeases4(const SubnetID &subnet_id) override
Removes specified IPv4 leases.
virtual Lease4Collection getLeases4() const override
Returns all IPv4 leases.
virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t secs) override
Deletes all expired-reclaimed DHCPv4 leases.
virtual Lease6Collection getLeases6ByRelayId(const DUID &relay_id, const asiolink::IOAddress &link_addr, uint8_t link_len, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size) override
Returns existing IPv6 leases with a given relay-id.
static bool dbReconnect(util::ReconnectCtlPtr db_reconnect_ctl)
Attempts to reconnect the server to the lease DB backend manager.
virtual Lease6Collection getLeases6ByLink(const asiolink::IOAddress &link_addr, uint8_t link_len, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size) override
Returns existing IPv6 leases with on a given link.
virtual size_t byRelayId6size() const override
Return the by-relay-id table size.
MySql derivation of the statistical lease data query.
void start()
Creates the IPv4 lease statistical data result set.
MySqlLeaseStatsQuery(MySqlConnection &conn, const size_t statement_index, const bool fetch_type, const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Constructor to query for the stats for a range of subnets.
MySqlLeaseStatsQuery(MySqlConnection &conn, const size_t statement_index, const bool fetch_type, const SubnetID &subnet_id)
Constructor to query for a single subnet's stats.
virtual ~MySqlLeaseStatsQuery()
Destructor.
bool getNextRow(LeaseStatsRow &row)
Fetches the next row in the result set.
MySqlLeaseStatsQuery(MySqlConnection &conn, const size_t statement_index, const bool fetch_type, const bool fetch_pool=false)
Constructor to query for all subnets' stats.
Attempt to update lease that was not there.
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition: timer_mgr.cc:449
Introduces callbacks into the LeaseMgr.
void trackUpdateLease(const LeasePtr &lease, bool mt_safe)
Invokes the callbacks when a lease is updated.
void trackAddLease(const LeasePtr &lease, bool mt_safe)
Invokes the callbacks when a new lease is added.
void trackDeleteLease(const LeasePtr &lease, bool mt_safe)
Invokes the callbacks when a lease is deleted.
bool hasCallbacks() const
Checks if any callbacks have been registered.
RAII class creating a critical section.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:29
const my_bool MLM_FALSE
MySQL false value.
const uint32_t MYSQL_SCHEMA_VERSION_MAJOR
boost::shared_ptr< IOServiceAccessor > IOServiceAccessorPtr
Pointer to an instance of IOServiceAccessor.
@ error
Definition: db_log.h:116
const uint32_t MYSQL_SCHEMA_VERSION_MINOR
const my_bool MLM_TRUE
MySQL true value.
bool my_bool
my_bool type in MySQL 8.x.
std::vector< MySqlBindingPtr > MySqlBindingCollection
Collection of bindings.
const int MLM_MYSQL_FETCH_SUCCESS
check for bool size
std::function< bool(util::ReconnectCtlPtr db_reconnect_ctl)> DbCallback
Defines a callback prototype for propagating events upward.
std::function< isc::asiolink::IOServicePtr()> IOServiceAccessor
Function which returns the IOService that can be used to recover the connection.
int MysqlExecuteStatement(MYSQL_STMT *stmt)
Execute a prepared statement.
const isc::log::MessageID DHCPSRV_MYSQL_GET_HOSTNAME4
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
const isc::log::MessageID DHCPSRV_MYSQL_GET_EXPIRED6
const isc::log::MessageID DHCPSRV_MYSQL_ADD_ADDR4
std::string ClientClass
Defines a single class name.
Definition: classify.h:42
const isc::log::MessageID DHCPSRV_MYSQL_COMMIT
const isc::log::MessageID DHCPSRV_MYSQL_DELETE_EXPIRED_RECLAIMED6
const isc::log::MessageID DHCPSRV_MYSQL_NEGATIVE_LEASES_STAT
const isc::log::MessageID DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO6
const isc::log::MessageID DHCPSRV_MYSQL_GET_IAID_DUID
const isc::log::MessageID DHCPSRV_MYSQL_GET_PAGE4
const isc::log::MessageID DHCPSRV_MYSQL_GET_CLIENTID
const isc::log::MessageID DHCPSRV_MYSQL_NO_TLS
const isc::log::MessageID DHCPSRV_MYSQL_GET4
boost::shared_ptr< CfgDbAccess > CfgDbAccessPtr
A pointer to the CfgDbAccess.
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:131
const isc::log::MessageID DHCPSRV_MYSQL_DELETE_ADDR
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition: lease.h:502
const isc::log::MessageID DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO6_ERROR
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:670
boost::shared_ptr< LeaseStatsQuery > LeaseStatsQueryPtr
Defines a pointer to a LeaseStatsQuery.
Definition: lease_mgr.h:233
const isc::log::MessageID DHCPSRV_MYSQL_LEASE_DB_RECONNECT_ATTEMPT_FAILED
const isc::log::MessageID DHCPSRV_MYSQL_GET_REMOTEID6
const isc::log::MessageID DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_PAGE
const isc::log::MessageID DHCPSRV_MYSQL_GET_ADDR4
const isc::log::MessageID DHCPSRV_MYSQL_GET_IAID_SUBID_DUID
const isc::log::MessageID DHCPSRV_MYSQL_UPDATE_ADDR6
const isc::log::MessageID DHCPSRV_MYSQL_GET_REMOTEID4
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
const isc::log::MessageID DHCPSRV_MYSQL_GET_SUBID6
const isc::log::MessageID DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4
const isc::log::MessageID DHCPSRV_MYSQL_GET_PAGE6
const isc::log::MessageID DHCPSRV_MYSQL_GET_EXPIRED4
const isc::log::MessageID DHCPSRV_MYSQL_UPDATE_ADDR4
const isc::log::MessageID DHCPSRV_MYSQL_GET_HWADDR
const isc::log::MessageID DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_ERROR
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:25
boost::shared_ptr< Lease > LeasePtr
Pointer to the lease object.
Definition: lease.h:22
const size_t ADDRESS6_TEXT_MAX_LEN
Maximum size of an IPv6 address represented as a text string.
Definition: host.h:32
const isc::log::MessageID DHCPSRV_MYSQL_ADD_ADDR6
const isc::log::MessageID DHCPSRV_MYSQL_GET_HOSTNAME6
const isc::log::MessageID DHCPSRV_MYSQL_GET_VERSION
const isc::log::MessageID DHCPSRV_MYSQL_LEASE_DB_RECONNECT_ATTEMPT_SCHEDULE
const size_t HOSTNAME_MAX_LEN
Maximum length of the hostname stored in DNS.
Definition: host.h:42
const isc::log::MessageID DHCPSRV_MYSQL_GET_RELAYID4
const isc::log::MessageID DHCPSRV_MYSQL_GET_SUBID4
const isc::log::MessageID DHCPSRV_MYSQL_GET6
const size_t USER_CONTEXT_MAX_LEN
Maximum length of user context.
Definition: host.h:54
const isc::log::MessageID DHCPSRV_MYSQL_LEASE_DB_RECONNECT_FAILED
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
const isc::log::MessageID DHCPSRV_MYSQL_GET_LINKADDR6
const isc::log::MessageID DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO6_PAGE
const isc::log::MessageID DHCPSRV_MYSQL_GET_SUBID_CLIENTID
const isc::log::MessageID DHCPSRV_MYSQL_DELETE_EXPIRED_RECLAIMED4
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition: lease.h:497
const isc::log::MessageID DHCPSRV_MYSQL_ROLLBACK
@ HTYPE_ETHER
Ethernet 10Mbps.
Definition: dhcp4.h:56
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:289
boost::shared_ptr< MySqlLeaseContext > MySqlLeaseContextPtr
Type of pointers to contexts.
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition: dhcpsrv_log.h:26
const isc::log::MessageID DHCPSRV_MYSQL_GET_ADDR6
const isc::log::MessageID DHCPSRV_MYSQL_GET_SUBID_HWADDR
const isc::log::MessageID DHCPSRV_MYSQL_DELETED_EXPIRED_RECLAIMED
const isc::log::MessageID DHCPSRV_MYSQL_GET_RELAYID6
const isc::log::MessageID DHCPSRV_MYSQL_GET_DUID
const isc::log::MessageID DHCPSRV_MYSQL_TLS_CIPHER
Definition: edns.h:19
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
Defines the logger used by the top-level component of kea-lfc.
Hardware type that represents information from DHCPv4 packet.
Definition: hwaddr.h:20
std::vector< uint8_t > hwaddr_
Definition: hwaddr.h:98
std::string toText(bool include_htype=true) const
Returns textual representation of a hardware address (e.g.
Definition: hwaddr.cc:51
ExtendedInfoAction
Action on extended info tables.
Definition: lease.h:550
@ ACTION_UPDATE
update extended info tables.
Definition: lease.h:553
@ ACTION_DELETE
delete reference to the lease
Definition: lease.h:552
@ ACTION_IGNORE
ignore extended info,
Definition: lease.h:551
Contains a single row of lease statistical data.
Definition: lease_mgr.h:64
uint32_t pool_id_
The pool ID to which this data applies.
Definition: lease_mgr.h:132
int64_t state_count_
state_count The count of leases in the lease state
Definition: lease_mgr.h:141
uint32_t lease_state_
The lease_state to which the count applies.
Definition: lease_mgr.h:138
SubnetID subnet_id_
The subnet ID to which this data applies.
Definition: lease_mgr.h:129
Lease::Type lease_type_
The lease_type to which the count applies.
Definition: lease_mgr.h:135
a common structure for IPv4 and IPv6 leases
Definition: lease.h:31
static const uint32_t INFINITY_LFT
Infinity (means static, i.e. never expire)
Definition: lease.h:34
static const uint32_t STATE_EXPIRED_RECLAIMED
Expired and reclaimed lease.
Definition: lease.h:75
Type
Type of lease or pool.
Definition: lease.h:46
@ TYPE_V4
IPv4 lease.
Definition: lease.h:50