Kea  2.3.1-git
pgsql_lease_mgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2022 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 
9 #include <asiolink/io_address.h>
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>
18 #include <dhcpsrv/timer_mgr.h>
20 
21 #include <boost/make_shared.hpp>
22 #include <boost/static_assert.hpp>
23 
24 #include <iomanip>
25 #include <limits>
26 #include <sstream>
27 #include <string>
28 #include <time.h>
29 
30 using namespace isc;
31 using namespace isc::asiolink;
32 using namespace isc::db;
33 using namespace isc::dhcp;
34 using namespace isc::data;
35 using namespace isc::util;
36 using namespace std;
37 
38 namespace {
39 
43 PgSqlTaggedStatement tagged_statements[] = {
44  // DELETE_LEASE4
45  { 2, { OID_INT8, OID_TIMESTAMP },
46  "delete_lease4",
47  "DELETE FROM lease4 WHERE address = $1 AND expire = $2"},
48 
49  // DELETE_LEASE4_STATE_EXPIRED
50  { 2, { OID_INT8, OID_TIMESTAMP },
51  "delete_lease4_state_expired",
52  "DELETE FROM lease4 "
53  "WHERE state = $1 AND expire < $2"},
54 
55  // DELETE_LEASE6
56  { 2, { OID_VARCHAR, OID_TIMESTAMP },
57  "delete_lease6",
58  "DELETE FROM lease6 WHERE address = $1 AND expire = $2"},
59 
60  // DELETE_LEASE6_STATE_EXPIRED
61  { 2, { OID_INT8, OID_TIMESTAMP },
62  "delete_lease6_state_expired",
63  "DELETE FROM lease6 "
64  "WHERE state = $1 AND expire < $2"},
65 
66  // GET_LEASE4
67  { 0, { OID_NONE },
68  "get_lease4",
69  "SELECT address, hwaddr, client_id, "
70  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
71  "fqdn_fwd, fqdn_rev, hostname, "
72  "state, user_context "
73  "FROM lease4"},
74 
75  // GET_LEASE4_ADDR
76  { 1, { OID_INT8 },
77  "get_lease4_addr",
78  "SELECT address, hwaddr, client_id, "
79  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
80  "fqdn_fwd, fqdn_rev, hostname, "
81  "state, user_context "
82  "FROM lease4 "
83  "WHERE address = $1"},
84 
85  // GET_LEASE4_CLIENTID
86  { 1, { OID_BYTEA },
87  "get_lease4_clientid",
88  "SELECT address, hwaddr, client_id, "
89  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
90  "fqdn_fwd, fqdn_rev, hostname, "
91  "state, user_context "
92  "FROM lease4 "
93  "WHERE client_id = $1"},
94 
95  // GET_LEASE4_CLIENTID_SUBID
96  { 2, { OID_BYTEA, OID_INT8 },
97  "get_lease4_clientid_subid",
98  "SELECT address, hwaddr, client_id, "
99  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
100  "fqdn_fwd, fqdn_rev, hostname, "
101  "state, user_context "
102  "FROM lease4 "
103  "WHERE client_id = $1 AND subnet_id = $2"},
104 
105  // GET_LEASE4_HWADDR
106  { 1, { OID_BYTEA },
107  "get_lease4_hwaddr",
108  "SELECT address, hwaddr, client_id, "
109  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
110  "fqdn_fwd, fqdn_rev, hostname, "
111  "state, user_context "
112  "FROM lease4 "
113  "WHERE hwaddr = $1"},
114 
115  // GET_LEASE4_HWADDR_SUBID
116  { 2, { OID_BYTEA, OID_INT8 },
117  "get_lease4_hwaddr_subid",
118  "SELECT address, hwaddr, client_id, "
119  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
120  "fqdn_fwd, fqdn_rev, hostname, "
121  "state, user_context "
122  "FROM lease4 "
123  "WHERE hwaddr = $1 AND subnet_id = $2"},
124 
125  // GET_LEASE4_PAGE
126  { 2, { OID_INT8, OID_INT8 },
127  "get_lease4_page",
128  "SELECT address, hwaddr, client_id, "
129  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
130  "fqdn_fwd, fqdn_rev, hostname, "
131  "state, user_context "
132  "FROM lease4 "
133  "WHERE address > $1 "
134  "ORDER BY address "
135  "LIMIT $2"},
136 
137  // GET_LEASE4_SUBID
138  { 1, { OID_INT8 },
139  "get_lease4_subid",
140  "SELECT address, hwaddr, client_id, "
141  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
142  "fqdn_fwd, fqdn_rev, hostname, "
143  "state, user_context "
144  "FROM lease4 "
145  "WHERE subnet_id = $1"},
146 
147  // GET_LEASE4_HOSTNAME
148  { 1, { OID_VARCHAR },
149  "get_lease4_hostname",
150  "SELECT address, hwaddr, client_id, "
151  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
152  "fqdn_fwd, fqdn_rev, hostname, "
153  "state, user_context "
154  "FROM lease4 "
155  "WHERE lower(hostname) = $1"},
156 
157  // GET_LEASE4_EXPIRE
158  { 3, { OID_INT8, OID_TIMESTAMP, OID_INT8 },
159  "get_lease4_expire",
160  "SELECT address, hwaddr, client_id, "
161  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
162  "fqdn_fwd, fqdn_rev, hostname, "
163  "state, user_context "
164  "FROM lease4 "
165  "WHERE state != $1 AND valid_lifetime != 4294967295 AND expire < $2 "
166  "ORDER BY expire "
167  "LIMIT $3"},
168 
169  // GET_LEASE6
170  { 0, { OID_NONE },
171  "get_lease6",
172  "SELECT address, duid, valid_lifetime, "
173  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
174  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
175  "hwaddr, hwtype, hwaddr_source, "
176  "state, user_context "
177  "FROM lease6"},
178 
179  // GET_LEASE6_ADDR
180  { 2, { OID_VARCHAR, OID_INT2 },
181  "get_lease6_addr",
182  "SELECT address, duid, valid_lifetime, "
183  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
184  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
185  "hwaddr, hwtype, hwaddr_source, "
186  "state, user_context "
187  "FROM lease6 "
188  "WHERE address = $1 AND lease_type = $2"},
189 
190  // GET_LEASE6_DUID_IAID
191  { 3, { OID_BYTEA, OID_INT8, OID_INT2 },
192  "get_lease6_duid_iaid",
193  "SELECT address, duid, valid_lifetime, "
194  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
195  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
196  "hwaddr, hwtype, hwaddr_source, "
197  "state, user_context "
198  "FROM lease6 "
199  "WHERE duid = $1 AND iaid = $2 AND lease_type = $3"},
200 
201  // GET_LEASE6_DUID_IAID_SUBID
202  { 4, { OID_INT2, OID_BYTEA, OID_INT8, OID_INT8 },
203  "get_lease6_duid_iaid_subid",
204  "SELECT address, duid, valid_lifetime, "
205  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
206  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
207  "hwaddr, hwtype, hwaddr_source, "
208  "state, user_context "
209  "FROM lease6 "
210  "WHERE lease_type = $1 "
211  "AND duid = $2 AND iaid = $3 AND subnet_id = $4"},
212 
213  // GET_LEASE6_PAGE
214  { 2, { OID_VARCHAR, OID_INT8 },
215  "get_lease6_page",
216  "SELECT address, duid, valid_lifetime, "
217  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
218  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
219  "hwaddr, hwtype, hwaddr_source, "
220  "state, user_context "
221  "FROM lease6 "
222  "WHERE address > $1 "
223  "ORDER BY address "
224  "LIMIT $2"},
225 
226  // GET_LEASE6_SUBID
227  { 1, { OID_INT8 },
228  "get_lease6_subid",
229  "SELECT address, duid, valid_lifetime, "
230  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
231  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
232  "hwaddr, hwtype, hwaddr_source, "
233  "state, user_context "
234  "FROM lease6 "
235  "WHERE subnet_id = $1"},
236 
237  // GET_LEASE6_DUID
238  { 1, { OID_BYTEA },
239  "get_lease6_duid",
240  "SELECT address, duid, valid_lifetime, "
241  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
242  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
243  "hwaddr, hwtype, hwaddr_source, "
244  "state, user_context "
245  "FROM lease6 "
246  "WHERE duid = $1"},
247 
248  // GET_LEASE6_HOSTNAME
249  { 1, { OID_VARCHAR },
250  "get_lease6_hostname",
251  "SELECT address, duid, valid_lifetime, "
252  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
253  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
254  "hwaddr, hwtype, hwaddr_source, "
255  "state, user_context "
256  "FROM lease6 "
257  "WHERE lower(hostname) = $1"},
258 
259  // GET_LEASE6_EXPIRE
260  { 3, { OID_INT8, OID_TIMESTAMP, OID_INT8 },
261  "get_lease6_expire",
262  "SELECT address, duid, valid_lifetime, "
263  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
264  "lease_type, iaid, prefix_len, "
265  "fqdn_fwd, fqdn_rev, hostname, "
266  "hwaddr, hwtype, hwaddr_source, "
267  "state, user_context "
268  "FROM lease6 "
269  "WHERE state != $1 AND valid_lifetime != 4294967295 AND expire < $2 "
270  "ORDER BY expire "
271  "LIMIT $3"},
272 
273  // INSERT_LEASE4
276  "insert_lease4",
277  "INSERT INTO lease4(address, hwaddr, client_id, "
278  "valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, "
279  "state, user_context) "
280  "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)"},
281 
282  // INSERT_LEASE6
286  "insert_lease6",
287  "INSERT INTO lease6(address, duid, valid_lifetime, "
288  "expire, subnet_id, pref_lifetime, "
289  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
290  "hwaddr, hwtype, hwaddr_source, "
291  "state, user_context) "
292  "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)"},
293 
294  // UPDATE_LEASE4
296  OID_BOOL, OID_BOOL, OID_VARCHAR, OID_INT8, OID_TEXT, OID_INT8, OID_TIMESTAMP },
297  "update_lease4",
298  "UPDATE lease4 SET address = $1, hwaddr = $2, "
299  "client_id = $3, valid_lifetime = $4, expire = $5, "
300  "subnet_id = $6, fqdn_fwd = $7, fqdn_rev = $8, hostname = $9, "
301  "state = $10, user_context = $11 "
302  "WHERE address = $12 AND expire = $13"},
303 
304  // UPDATE_LEASE6
308  OID_INT8, OID_TEXT, OID_VARCHAR, OID_TIMESTAMP },
309  "update_lease6",
310  "UPDATE lease6 SET address = $1, duid = $2, "
311  "valid_lifetime = $3, expire = $4, subnet_id = $5, "
312  "pref_lifetime = $6, lease_type = $7, iaid = $8, "
313  "prefix_len = $9, fqdn_fwd = $10, fqdn_rev = $11, hostname = $12, "
314  "hwaddr = $13, hwtype = $14, hwaddr_source = $15, "
315  "state = $16, user_context = $17 "
316  "WHERE address = $18 AND expire = $19"},
317 
318  // ALL_LEASE4_STATS
319  { 0, { OID_NONE },
320  "all_lease4_stats",
321  "SELECT subnet_id, state, leases as state_count"
322  " FROM lease4_stat ORDER BY subnet_id, state"},
323 
324  // SUBNET_LEASE4_STATS
325  { 1, { OID_INT8 },
326  "subnet_lease4_stats",
327  "SELECT subnet_id, state, leases as state_count"
328  " FROM lease4_stat "
329  " WHERE subnet_id = $1 "
330  " ORDER BY state"},
331 
332  // SUBNET_RANGE_LEASE4_STATS
333  { 2, { OID_INT8, OID_INT8 },
334  "subnet_range_lease4_stats",
335  "SELECT subnet_id, state, leases as state_count"
336  " FROM lease4_stat "
337  " WHERE subnet_id >= $1 and subnet_id <= $2 "
338  " ORDER BY subnet_id, state"},
339 
340  // ALL_LEASE6_STATS,
341  { 0, { OID_NONE },
342  "all_lease6_stats",
343  "SELECT subnet_id, lease_type, state, leases as state_count"
344  " FROM lease6_stat ORDER BY subnet_id, lease_type, state" },
345 
346  // SUBNET_LEASE6_STATS
347  { 1, { OID_INT8 },
348  "subnet_lease6_stats",
349  "SELECT subnet_id, lease_type, state, leases as state_count"
350  " FROM lease6_stat "
351  " WHERE subnet_id = $1 "
352  " ORDER BY lease_type, state" },
353 
354  // SUBNET_RANGE_LEASE6_STATS
355  { 2, { OID_INT8, OID_INT8 },
356  "subnet_range_lease6_stats",
357  "SELECT subnet_id, lease_type, state, leases as state_count"
358  " FROM lease6_stat "
359  " WHERE subnet_id >= $1 and subnet_id <= $2 "
360  " ORDER BY subnet_id, lease_type, state" },
361 
362  // CHECK_LEASE4_LIMITS
363  { 1, { OID_TEXT },
364  "check_lease4_limits",
365  "SELECT checkLease4Limits($1)" },
366 
367  // CHECK_LEASE6_LIMITS
368  { 1, { OID_TEXT },
369  "check_lease6_limits",
370  "SELECT checkLease6Limits($1)" },
371 
372  // IS_JSON_SUPPORTED
373  { 0, { OID_NONE },
374  "is_json_supported",
375  "SELECT isJsonSupported()" },
376 
377  // GET_LEASE4_COUNT_BY_CLASS
378  { 1, { OID_VARCHAR },
379  "get_lease4_count_by_class",
380  "SELECT leases "
381  "FROM lease4_stat_by_client_class "
382  "WHERE client_class = $1"},
383 
384  // GET_LEASE6_COUNT_BY_CLASS
385  { 2, { OID_VARCHAR, OID_INT2 },
386  "get_lease6_count_by_class",
387  "SELECT leases "
388  "FROM lease6_stat_by_client_class "
389  "WHERE client_class = $1 AND lease_type = $2"},
390 
391  // End of list sentinel
392  { 0, { 0 }, NULL, NULL}
393 };
394 
395 } // namespace
396 
397 namespace isc {
398 namespace dhcp {
399 
406 public:
407 
409  : addr_str_(""), hwaddr_length_(0), hwaddr_(hwaddr_length_),
410  valid_lifetime_(0), valid_lifetime_str_(""), expire_(0),
411  expire_str_(""), subnet_id_(0), subnet_id_str_(""), cltt_(0),
412  fqdn_fwd_(false), fqdn_rev_(false), hostname_(""), state_str_(""),
413  user_context_("") {
414  }
415 
417 
418 protected:
419 
421 
422  std::string addr_str_;
424  std::vector<uint8_t> hwaddr_;
425  uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
426  uint32_t valid_lifetime_;
427  std::string valid_lifetime_str_;
428  time_t expire_;
429  std::string expire_str_;
430  uint32_t subnet_id_;
431  std::string subnet_id_str_;
432  time_t cltt_;
433  bool fqdn_fwd_;
434  bool fqdn_rev_;
435  std::string hostname_;
436  std::string state_str_;
437  std::string user_context_;
439 };
440 
443 private:
444 
449  static const size_t ADDRESS_COL = 0;
450  static const size_t HWADDR_COL = 1;
451  static const size_t CLIENT_ID_COL = 2;
452  static const size_t VALID_LIFETIME_COL = 3;
453  static const size_t EXPIRE_COL = 4;
454  static const size_t SUBNET_ID_COL = 5;
455  static const size_t FQDN_FWD_COL = 6;
456  static const size_t FQDN_REV_COL = 7;
457  static const size_t HOSTNAME_COL = 8;
458  static const size_t STATE_COL = 9;
459  static const size_t USER_CONTEXT_COL = 10;
461  static const size_t LEASE_COLUMNS = 11;
462 
463 public:
464 
467  : lease_(), addr4_(0), client_id_length_(0) {
468 
469  BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
470 
471  memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
472  memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
473 
474  // Set the column names (for error messages)
475  columns_.push_back("address");
476  columns_.push_back("hwaddr");
477  columns_.push_back("client_id");
478  columns_.push_back("valid_lifetime");
479  columns_.push_back("expire");
480  columns_.push_back("subnet_id");
481  columns_.push_back("fqdn_fwd");
482  columns_.push_back("fqdn_rev");
483  columns_.push_back("hostname");
484  columns_.push_back("state");
485  columns_.push_back("user_context");
486  }
487 
500  void createBindForSend(const Lease4Ptr& lease, PsqlBindArray& bind_array) {
501  if (!lease) {
502  isc_throw(BadValue, "createBindForSend:: Lease4 object is NULL");
503  }
504 
505  // Store lease object to ensure it remains valid.
506  lease_ = lease;
507 
508  try {
509  addr_str_ = boost::lexical_cast<std::string>(lease->addr_.toUint32());
510  bind_array.add(addr_str_);
511 
512  if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) {
513  // PostgreSql does not provide MAX on variable length types
514  // so we have to enforce it ourselves.
515  if (lease->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
516  isc_throw(DbOperationError, "Hardware address length : "
517  << lease_->hwaddr_->hwaddr_.size()
518  << " exceeds maximum allowed of: "
519  << HWAddr::MAX_HWADDR_LEN);
520  }
521  bind_array.add(lease->hwaddr_->hwaddr_);
522  } else {
523  bind_array.add("");
524  }
525 
526  if (lease->client_id_) {
527  bind_array.add(lease->client_id_->getClientId());
528  } else {
529  bind_array.add("");
530  }
531 
532  valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
533  bind_array.add(valid_lifetime_str_);
534 
535  // The lease structure holds the client last transmission time (cltt_)
536  // For convenience for external tools, this is converted to lease
537  // expiry time (expire). The relationship is given by:
538  // expire = cltt_ + valid_lft_
539  // Avoid overflow with infinite valid lifetime by using
540  // expire = cltt_ when valid_lft_ = 0xffffffff
541  if (lease_->valid_lft_ == Lease::INFINITY_LFT) {
542  expire_str_ = convertToDatabaseTime(lease->cltt_, 0);
543  } else {
544  expire_str_ = convertToDatabaseTime(lease->cltt_,
545  lease_->valid_lft_);
546  }
547  bind_array.add(expire_str_);
548 
549  subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
550  bind_array.add(subnet_id_str_);
551 
552  bind_array.add(lease->fqdn_fwd_);
553 
554  bind_array.add(lease->fqdn_rev_);
555 
556  bind_array.add(lease->hostname_);
557 
558  state_str_ = boost::lexical_cast<std::string>(lease->state_);
559  bind_array.add(state_str_);
560 
561  ConstElementPtr ctx = lease->getContext();
562  if (ctx) {
563  user_context_ = ctx->str();
564  } else {
565  user_context_ = "";
566  }
567  bind_array.add(user_context_);
568  } catch (const std::exception& ex) {
570  "Could not create bind array from Lease4: "
571  << lease_->addr_.toText() << ", reason: " << ex.what());
572  }
573  }
574 
584  try {
585  getColumnValue(r, row, ADDRESS_COL, addr4_);
586 
587  convertFromBytea(r, row, HWADDR_COL, hwaddr_buffer_,
588  sizeof(hwaddr_buffer_), hwaddr_length_);
589 
590  convertFromBytea(r, row, CLIENT_ID_COL, client_id_buffer_,
591  sizeof(client_id_buffer_), client_id_length_);
592 
593  getColumnValue(r, row, VALID_LIFETIME_COL, valid_lifetime_);
594 
595  expire_ = convertFromDatabaseTime(getRawColumnValue(r, row,
596  EXPIRE_COL));
597 
598  getColumnValue(r, row , SUBNET_ID_COL, subnet_id_);
599 
600  // Recover from overflow (see createBindForSend)
601  if (valid_lifetime_ == Lease::INFINITY_LFT) {
602  cltt_ = expire_;
603  } else {
604  cltt_ = expire_ - valid_lifetime_;
605  }
606 
607  getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
608 
609  getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
610 
611  hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
612 
613  uint32_t state;
614  getColumnValue(r, row , STATE_COL, state);
615 
616  HWAddrPtr hwaddr(new HWAddr(hwaddr_buffer_, hwaddr_length_,
617  HTYPE_ETHER));
618 
619  user_context_ = getRawColumnValue(r, row, USER_CONTEXT_COL);
620  ConstElementPtr ctx;
621  if (!user_context_.empty()) {
622  ctx = Element::fromJSON(user_context_);
623  if (!ctx || (ctx->getType() != Element::map)) {
624  isc_throw(BadValue, "user context '" << user_context_
625  << "' is not a JSON map");
626  }
627  }
628 
629  Lease4Ptr result(boost::make_shared<Lease4>(addr4_, hwaddr,
630  client_id_buffer_,
631  client_id_length_,
632  valid_lifetime_, cltt_,
633  subnet_id_, fqdn_fwd_,
634  fqdn_rev_, hostname_));
635 
636  result->state_ = state;
637 
638  if (ctx) {
639  result->setContext(ctx);
640  }
641 
642  return (result);
643  } catch (const std::exception& ex) {
645  "Could not convert data to Lease4, reason: "
646  << ex.what());
647  }
648  }
649 
650 private:
651 
655  Lease4Ptr lease_;
656 
658  uint32_t addr4_;
659  size_t client_id_length_;
660  uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
661 };
662 
665 private:
666 
671 
672  static const int ADDRESS_COL = 0;
673  static const int DUID_COL = 1;
674  static const int VALID_LIFETIME_COL = 2;
675  static const int EXPIRE_COL = 3;
676  static const int SUBNET_ID_COL = 4;
677  static const int PREF_LIFETIME_COL = 5;
678  static const int LEASE_TYPE_COL = 6;
679  static const int IAID_COL = 7;
680  static const int PREFIX_LEN_COL = 8;
681  static const int FQDN_FWD_COL = 9;
682  static const int FQDN_REV_COL = 10;
683  static const int HOSTNAME_COL = 11;
684  static const int HWADDR_COL = 12;
685  static const int HWTYPE_COL = 13;
686  static const int HWADDR_SOURCE_COL = 14;
687  static const int STATE_COL = 15;
688  static const size_t USER_CONTEXT_COL = 16;
690  static const size_t LEASE_COLUMNS = 17;
692 
693 public:
694 
701  union Uiaid {
704  Uiaid(uint32_t val) : uval_(val){};
705 
708  Uiaid(int32_t val) : ival_(val){};
709 
711  std::string dbInputString() {
712  return (boost::lexical_cast<std::string>(ival_));
713  };
714 
715  uint32_t uval_;
716  int32_t ival_;
717  };
718 
720  : lease_(), duid_length_(0), duid_(duid_length_), iaid_u_(0),
721  iaid_str_(""), lease_type_(Lease6::TYPE_NA), lease_type_str_(""),
722  prefix_len_(0), prefix_len_str_(""), pref_lifetime_(0),
723  preferred_lifetime_str_(""), hwtype_(0), hwtype_str_(""),
724  hwaddr_source_(0), hwaddr_source_str_("") {
725 
726  BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
727 
728  memset(duid_buffer_, 0, sizeof(duid_buffer_));
729 
730  // Set the column names (for error messages)
731  columns_.push_back("address");
732  columns_.push_back("duid");
733  columns_.push_back("valid_lifetime");
734  columns_.push_back("expire");
735  columns_.push_back("subnet_id");
736  columns_.push_back("pref_lifetime");
737  columns_.push_back("lease_type");
738  columns_.push_back("iaid");
739  columns_.push_back("prefix_len");
740  columns_.push_back("fqdn_fwd");
741  columns_.push_back("fqdn_rev");
742  columns_.push_back("hostname");
743  columns_.push_back("hwaddr");
744  columns_.push_back("hwtype");
745  columns_.push_back("hwaddr_source");
746  columns_.push_back("state");
747  columns_.push_back("user_context");
748  }
749 
762  void createBindForSend(const Lease6Ptr& lease, PsqlBindArray& bind_array) {
763  if (!lease) {
764  isc_throw(BadValue, "createBindForSend:: Lease6 object is NULL");
765  }
766 
767  // Store lease object to ensure it remains valid.
768  lease_ = lease;
769  try {
770  addr_str_ = lease_->addr_.toText();
771  bind_array.add(addr_str_);
772 
773  if (lease_->duid_) {
774  bind_array.add(lease_->duid_->getDuid());
775  } else {
776  isc_throw (BadValue, "IPv6 Lease cannot have a null DUID");
777  }
778 
779  valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
780  bind_array.add(valid_lifetime_str_);
781 
782  // The lease structure holds the client last transmission time (cltt_)
783  // For convenience for external tools, this is converted to lease
784  // expiry time (expire). The relationship is given by:
785  // expire = cltt_ + valid_lft_
786  // Avoid overflow with infinite valid lifetime by using
787  // expire = cltt_ when valid_lft_ = 0xffffffff
788  if (lease_->valid_lft_ == Lease::INFINITY_LFT) {
789  expire_str_ = convertToDatabaseTime(lease->cltt_, 0);
790  } else {
791  expire_str_ = convertToDatabaseTime(lease->cltt_,
792  lease_->valid_lft_);
793  }
794  bind_array.add(expire_str_);
795 
796  subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
797  bind_array.add(subnet_id_str_);
798 
799  preferred_lifetime_str_ = boost::lexical_cast<std::string>(lease_->preferred_lft_);
800  bind_array.add(preferred_lifetime_str_);
801 
802  lease_type_str_ = boost::lexical_cast<std::string>(lease_->type_);
803  bind_array.add(lease_type_str_);
804 
805  // The iaid is stored as an INT in lease6 table, so we must
806  // lexically cast from an integer version to avoid out of range
807  // exception failure upon insert.
808  iaid_u_.uval_ = lease_->iaid_;
809  iaid_str_ = iaid_u_.dbInputString();
810  bind_array.add(iaid_str_);
811 
812  prefix_len_str_ = boost::lexical_cast<std::string>
813  (static_cast<unsigned int>(lease_->prefixlen_));
814  bind_array.add(prefix_len_str_);
815 
816  bind_array.add(lease->fqdn_fwd_);
817 
818  bind_array.add(lease->fqdn_rev_);
819 
820  bind_array.add(lease->hostname_);
821 
822  if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) {
823  // PostgreSql does not provide MAX on variable length types
824  // so we have to enforce it ourselves.
825  if (lease->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
826  isc_throw(DbOperationError, "Hardware address length : "
827  << lease_->hwaddr_->hwaddr_.size()
828  << " exceeds maximum allowed of: "
829  << HWAddr::MAX_HWADDR_LEN);
830  }
831  bind_array.add(lease->hwaddr_->hwaddr_);
832  } else {
833  bind_array.add("");
834  }
835 
836  if (lease->hwaddr_) {
837  hwtype_str_ = boost::lexical_cast<std::string>
838  (static_cast<unsigned int>(lease_->hwaddr_->htype_));
839  hwaddr_source_str_ = boost::lexical_cast<std::string>
840  (static_cast<unsigned int>(lease_->hwaddr_->source_));
841  } else {
842  hwtype_str_ = boost::lexical_cast<std::string>
843  (static_cast<unsigned int>(HTYPE_UNDEFINED));
844  hwaddr_source_str_ = boost::lexical_cast<std::string>
845  (static_cast<unsigned int>(HWAddr::HWADDR_SOURCE_UNKNOWN));
846  }
847 
848  bind_array.add(hwtype_str_);
849 
850  bind_array.add(hwaddr_source_str_);
851 
852  state_str_ = boost::lexical_cast<std::string>(lease->state_);
853  bind_array.add(state_str_);
854 
855  ConstElementPtr ctx = lease->getContext();
856  if (ctx) {
857  user_context_ = ctx->str();
858  } else {
859  user_context_ = "";
860  }
861  bind_array.add(user_context_);
862  } catch (const std::exception& ex) {
864  "Could not create bind array from Lease6: "
865  << lease_->addr_.toText() << ", reason: " << ex.what());
866  }
867  }
868 
878  try {
879 
887 
888  IOAddress addr(getIPv6Value(r, row, ADDRESS_COL));
889 
890  convertFromBytea(r, row, DUID_COL, duid_buffer_, sizeof(duid_buffer_), duid_length_);
891  DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_));
892 
893  getColumnValue(r, row, VALID_LIFETIME_COL, valid_lifetime_);
894 
895  expire_ = convertFromDatabaseTime(getRawColumnValue(r, row,
896  EXPIRE_COL));
897 
898  // Recover from overflow (see createBindForSend)
899  if (valid_lifetime_ == Lease::INFINITY_LFT) {
900  cltt_ = expire_;
901  } else {
902  cltt_ = expire_ - valid_lifetime_;
903  }
904 
905  getColumnValue(r, row , SUBNET_ID_COL, subnet_id_);
906 
907  getColumnValue(r, row , PREF_LIFETIME_COL, pref_lifetime_);
908 
909  getLeaseTypeColumnValue(r, row, LEASE_TYPE_COL, lease_type_);
910 
911  getColumnValue(r, row , IAID_COL, iaid_u_.ival_);
912 
913  getColumnValue(r, row , PREFIX_LEN_COL, prefix_len_);
914 
915  getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
916 
917  getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
918 
919  hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
920 
921  convertFromBytea(r, row, HWADDR_COL, hwaddr_buffer_,
922  sizeof(hwaddr_buffer_), hwaddr_length_);
923 
924  getColumnValue(r, row , HWTYPE_COL, hwtype_);
925 
926  getColumnValue(r, row , HWADDR_SOURCE_COL, hwaddr_source_);
927 
928  HWAddrPtr hwaddr;
929 
930  if (hwaddr_length_) {
931  hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_,
932  hwtype_));
933 
934  hwaddr->source_ = hwaddr_source_;
935  }
936 
937  uint32_t state;
938  getColumnValue(r, row , STATE_COL, state);
939 
940  user_context_ = getRawColumnValue(r, row, USER_CONTEXT_COL);
941  ConstElementPtr ctx;
942  if (!user_context_.empty()) {
943  ctx = Element::fromJSON(user_context_);
944  if (!ctx || (ctx->getType() != Element::map)) {
945  isc_throw(BadValue, "user context '" << user_context_
946  << "' is not a JSON map");
947  }
948  }
949 
950  Lease6Ptr result(boost::make_shared<Lease6>(lease_type_, addr,
951  duid_ptr,
952  iaid_u_.uval_,
953  pref_lifetime_,
954  valid_lifetime_,
955  subnet_id_, fqdn_fwd_,
956  fqdn_rev_, hostname_,
957  hwaddr, prefix_len_));
958  // Update cltt_ and current_cltt_ explicitly.
959  result->cltt_ = cltt_;
960  result->current_cltt_ = cltt_;
961 
962  result->state_ = state;
963 
964  if (ctx) {
965  result->setContext(ctx);
966  }
967 
968  return (result);
969  } catch (const std::exception& ex) {
971  "Could not convert data to Lease6, reason: "
972  << ex.what());
973  }
974  }
975 
988  void getLeaseTypeColumnValue(const PgSqlResult& r, const int row,
989  const size_t col, Lease6::Type& value) const {
990  uint32_t raw_value = 0;
991  getColumnValue(r, row , col, raw_value);
992  switch (raw_value) {
993  case Lease6::TYPE_NA:
994  case Lease6::TYPE_TA:
995  case Lease6::TYPE_PD:
996  value = static_cast<Lease6::Type>(raw_value);
997  break;
998 
999  default:
1000  isc_throw(DbOperationError, "Invalid lease type: " << raw_value
1001  << " for: " << getColumnLabel(r, col) << " row:" << row);
1002  }
1003  }
1004 
1005 private:
1009  Lease6Ptr lease_;
1010 
1012 
1013  size_t duid_length_;
1014  std::vector<uint8_t> duid_;
1015  uint8_t duid_buffer_[DUID::MAX_DUID_LEN];
1016  union Uiaid iaid_u_;
1017  std::string iaid_str_;
1018  Lease6::Type lease_type_;
1019  std::string lease_type_str_;
1020  uint8_t prefix_len_;
1021  std::string prefix_len_str_;
1022  uint32_t pref_lifetime_;
1023  std::string preferred_lifetime_str_;
1024  uint32_t hwtype_;
1025  std::string hwtype_str_;
1026  uint32_t hwaddr_source_;
1027  std::string hwaddr_source_str_;
1029 };
1030 
1037 public:
1038 
1048  const bool fetch_type)
1049  : conn_(conn), statement_(statement), result_set_(), next_row_(0),
1050  fetch_type_(fetch_type) {
1051  }
1052 
1062  const bool fetch_type, const SubnetID& subnet_id)
1063  : LeaseStatsQuery(subnet_id), conn_(conn), statement_(statement), result_set_(),
1064  next_row_(0), fetch_type_(fetch_type) {
1065  }
1066 
1078  const bool fetch_type, const SubnetID& first_subnet_id,
1079  const SubnetID& last_subnet_id)
1080  : LeaseStatsQuery(first_subnet_id, last_subnet_id), conn_(conn), statement_(statement),
1081  result_set_(), next_row_(0), fetch_type_(fetch_type) {
1082  }
1083 
1086 
1096  void start() {
1097 
1098  if (getSelectMode() == ALL_SUBNETS) {
1099  // Run the query with no where clause parameters.
1100  result_set_.reset(new PgSqlResult(PQexecPrepared(conn_, statement_.name,
1101  0, 0, 0, 0, 0)));
1102  } else {
1103  // Set up the WHERE clause values
1104  PsqlBindArray parms;
1105 
1106  // Add first_subnet_id used by both single and range.
1107  parms.addTempString(boost::lexical_cast<std::string>(getFirstSubnetID()));
1108 
1109  // Add last_subnet_id for range.
1110  if (getSelectMode() == SUBNET_RANGE) {
1111  // Add last_subnet_id used by range.
1112  parms.addTempString(boost::lexical_cast<std::string>(getLastSubnetID()));
1113  }
1114 
1115  // Run the query with where clause parameters.
1116  result_set_.reset(new PgSqlResult(PQexecPrepared(conn_, statement_.name,
1117  parms.size(), &parms.values_[0],
1118  &parms.lengths_[0], &parms.formats_[0], 0)));
1119  }
1120 
1121  conn_.checkStatementError(*result_set_, statement_);
1122  }
1123 
1139  // If we're past the end, punt.
1140  if (next_row_ >= result_set_->getRows()) {
1141  return (false);
1142  }
1143 
1144  // Fetch the subnet id.
1145  uint32_t col = 0;
1146  uint32_t subnet_id;
1147  PgSqlExchange::getColumnValue(*result_set_, next_row_, col, subnet_id);
1148  row.subnet_id_ = static_cast<SubnetID>(subnet_id);
1149  ++col;
1150 
1151  // Fetch the lease type if we were told to do so.
1152  if (fetch_type_) {
1153  uint32_t lease_type;
1154  PgSqlExchange::getColumnValue(*result_set_, next_row_ , col,
1155  lease_type);
1156  row.lease_type_ = static_cast<Lease::Type>(lease_type);
1157  ++col;
1158  } else {
1159  row.lease_type_ = Lease::TYPE_NA;
1160  }
1161 
1162  // Fetch the lease state.
1163  PgSqlExchange::getColumnValue(*result_set_, next_row_ , col,
1164  row.lease_state_);
1165  ++col;
1166 
1167  // Fetch the state count.
1168  PgSqlExchange::getColumnValue(*result_set_, next_row_, col,
1169  row.state_count_);
1170 
1171  // Protect against negative state count.a
1172  if (row.state_count_ < 0) {
1173  row.state_count_ = 0;
1174  if (!negative_count_) {
1175  negative_count_ = true;
1177  }
1178  }
1179 
1180  // Point to the next row.
1181  ++next_row_;
1182  return (true);
1183  }
1184 
1185 protected:
1186 
1189 
1192 
1194  boost::shared_ptr<PgSqlResult> result_set_;
1195 
1197  uint32_t next_row_;
1198 
1201 
1203  static bool negative_count_;
1204 };
1205 
1206 // Initialize negative state count flag to false.
1207 bool PgSqlLeaseStatsQuery::negative_count_ = false;
1208 
1209 // PgSqlLeaseContext Constructor
1210 
1211 PgSqlLeaseContext::PgSqlLeaseContext(const DatabaseConnection::ParameterMap& parameters,
1212  IOServiceAccessorPtr io_service_accessor,
1213  DbCallback db_reconnect_callback)
1214  : conn_(parameters, io_service_accessor, db_reconnect_callback) {
1215 }
1216 
1217 // PgSqlLeaseContextAlloc Constructor and Destructor
1218 
1219 PgSqlLeaseMgr::PgSqlLeaseContextAlloc::PgSqlLeaseContextAlloc(
1220  const PgSqlLeaseMgr& mgr) : ctx_(), mgr_(mgr) {
1221 
1222  if (MultiThreadingMgr::instance().getMode()) {
1223  // multi-threaded
1224  {
1225  // we need to protect the whole pool_ operation, hence extra scope {}
1226  lock_guard<mutex> lock(mgr_.pool_->mutex_);
1227  if (!mgr_.pool_->pool_.empty()) {
1228  ctx_ = mgr_.pool_->pool_.back();
1229  mgr_.pool_->pool_.pop_back();
1230  }
1231  }
1232  if (!ctx_) {
1233  ctx_ = mgr_.createContext();
1234  }
1235  } else {
1236  // single-threaded
1237  if (mgr_.pool_->pool_.empty()) {
1238  isc_throw(Unexpected, "No available PostgreSQL lease context?!");
1239  }
1240  ctx_ = mgr_.pool_->pool_.back();
1241  }
1242 }
1243 
1244 PgSqlLeaseMgr::PgSqlLeaseContextAlloc::~PgSqlLeaseContextAlloc() {
1245  if (MultiThreadingMgr::instance().getMode()) {
1246  // multi-threaded
1247  lock_guard<mutex> lock(mgr_.pool_->mutex_);
1248  mgr_.pool_->pool_.push_back(ctx_);
1249  }
1250  // If running in single-threaded mode, there's nothing to do here.
1251 }
1252 
1253 // PgSqlLeaseMgr Constructor and Destructor
1254 
1256  : parameters_(parameters), timer_name_("") {
1257 
1258  // Create unique timer name per instance.
1259  timer_name_ = "PgSqlLeaseMgr[";
1260  timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this));
1261  timer_name_ += "]DbReconnectTimer";
1262 
1263  // Check TLS support.
1264  size_t tls(0);
1265  tls += parameters.count("trust-anchor");
1266  tls += parameters.count("cert-file");
1267  tls += parameters.count("key-file");
1268  tls += parameters.count("cipher-list");
1269 #ifdef HAVE_PGSQL_SSL
1270  if ((tls > 0) && !PgSqlConnection::warned_about_tls) {
1273  .arg(DatabaseConnection::redactedAccessString(parameters_));
1274  PQinitSSL(1);
1275  }
1276 #else
1277  if (tls > 0) {
1279  .arg(DatabaseConnection::redactedAccessString(parameters_));
1280  isc_throw(DbOpenError, "Attempt to configure TLS for PostgreSQL "
1281  << "backend (built with this feature disabled)");
1282  }
1283 #endif
1284 
1285  // Validate schema version first.
1286  std::pair<uint32_t, uint32_t> code_version(PGSQL_SCHEMA_VERSION_MAJOR,
1288  std::pair<uint32_t, uint32_t> db_version = getVersion();
1289  if (code_version != db_version) {
1291  "PostgreSQL schema version mismatch: need version: "
1292  << code_version.first << "." << code_version.second
1293  << " found version: " << db_version.first << "."
1294  << db_version.second);
1295  }
1296 
1297  // Create an initial context.
1298  pool_.reset(new PgSqlLeaseContextPool());
1299  pool_->pool_.push_back(createContext());
1300 }
1301 
1303 }
1304 
1305 bool
1308 
1309  // Invoke application layer connection lost callback.
1310  if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) {
1311  return (false);
1312  }
1313 
1314  bool reopened = false;
1315 
1316  const std::string timer_name = db_reconnect_ctl->timerName();
1317 
1318  // At least one connection was lost.
1319  try {
1320  CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
1322  LeaseMgrFactory::create(cfg_db->getLeaseDbAccessString());
1323  reopened = true;
1324  } catch (const std::exception& ex) {
1326  .arg(ex.what());
1327  }
1328 
1329  if (reopened) {
1330  // Cancel the timer.
1331  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1332  TimerMgr::instance()->unregisterTimer(timer_name);
1333  }
1334 
1335  // Invoke application layer connection recovered callback.
1336  if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) {
1337  return (false);
1338  }
1339  } else {
1340  if (!db_reconnect_ctl->checkRetries()) {
1341  // We're out of retries, log it and initiate shutdown.
1343  .arg(db_reconnect_ctl->maxRetries());
1344 
1345  // Cancel the timer.
1346  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1347  TimerMgr::instance()->unregisterTimer(timer_name);
1348  }
1349 
1350  // Invoke application layer connection failed callback.
1352  return (false);
1353  }
1354 
1356  .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
1357  .arg(db_reconnect_ctl->maxRetries())
1358  .arg(db_reconnect_ctl->retryInterval());
1359 
1360  // Start the timer.
1361  if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
1362  TimerMgr::instance()->registerTimer(timer_name,
1363  std::bind(&PgSqlLeaseMgr::dbReconnect, db_reconnect_ctl),
1364  db_reconnect_ctl->retryInterval(),
1366  }
1367  TimerMgr::instance()->setup(timer_name);
1368  }
1369 
1370  return (true);
1371 }
1372 
1373 // Create context.
1374 
1377  PgSqlLeaseContextPtr ctx(new PgSqlLeaseContext(parameters_,
1380 
1381  // Open the database.
1382  ctx->conn_.openDatabase();
1383 
1384  // Now prepare the SQL statements.
1385  uint32_t i = 0;
1386  for (; tagged_statements[i].text != NULL; ++i) {
1387  ctx->conn_.prepareStatement(tagged_statements[i]);
1388  }
1389 
1390  // Just in case somebody foo-barred things
1391  if (i != NUM_STATEMENTS) {
1392  isc_throw(DbOpenError, "Number of statements prepared: " << i
1393  << " does not match expected count:" << NUM_STATEMENTS);
1394  }
1395 
1396  // Create the exchange objects for use in exchanging data between the
1397  // program and the database.
1398  ctx->exchange4_.reset(new PgSqlLease4Exchange());
1399  ctx->exchange6_.reset(new PgSqlLease6Exchange());
1400 
1401  // Create ReconnectCtl for this connection.
1402  ctx->conn_.makeReconnectCtl(timer_name_);
1403 
1404  return (ctx);
1405 }
1406 
1407 std::string
1409  std::stringstream tmp;
1410  tmp << "PostgreSQL backend " << PGSQL_SCHEMA_VERSION_MAJOR;
1411  tmp << "." << PGSQL_SCHEMA_VERSION_MINOR;
1412  tmp << ", library " << PQlibVersion();
1413  return (tmp.str());
1414 }
1415 
1416 bool
1417 PgSqlLeaseMgr::addLeaseCommon(PgSqlLeaseContextPtr& ctx,
1418  StatementIndex stindex,
1419  PsqlBindArray& bind_array) {
1420  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
1421  tagged_statements[stindex].nbparams,
1422  &bind_array.values_[0],
1423  &bind_array.lengths_[0],
1424  &bind_array.formats_[0], 0));
1425 
1426  int s = PQresultStatus(r);
1427 
1428  if (s != PGRES_COMMAND_OK) {
1429  // Failure: check for the special case of duplicate entry. If this is
1430  // the case, we return false to indicate that the row was not added.
1431  // Otherwise we throw an exception.
1432  if (ctx->conn_.compareError(r, PgSqlConnection::DUPLICATE_KEY)) {
1433  return (false);
1434  }
1435  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
1436  }
1437 
1438  return (true);
1439 }
1440 
1441 bool
1444  .arg(lease->addr_.toText());
1445 
1446  // Get a context
1447  PgSqlLeaseContextAlloc get_context(*this);
1448  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1449 
1450  PsqlBindArray bind_array;
1451  ctx->exchange4_->createBindForSend(lease, bind_array);
1452  auto result = addLeaseCommon(ctx, INSERT_LEASE4, bind_array);
1453 
1454  // Update lease current expiration time (allows update between the creation
1455  // of the Lease up to the point of insertion in the database).
1456  lease->updateCurrentExpirationTime();
1457 
1458  return (result);
1459 }
1460 
1461 bool
1464  .arg(lease->addr_.toText())
1465  .arg(lease->type_);
1466 
1467  // Get a context
1468  PgSqlLeaseContextAlloc get_context(*this);
1469  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1470 
1471  PsqlBindArray bind_array;
1472  ctx->exchange6_->createBindForSend(lease, bind_array);
1473 
1474  auto result = addLeaseCommon(ctx, INSERT_LEASE6, bind_array);
1475 
1476  // Update lease current expiration time (allows update between the creation
1477  // of the Lease up to the point of insertion in the database).
1478  lease->updateCurrentExpirationTime();
1479 
1480  return (result);
1481 }
1482 
1483 template <typename Exchange, typename LeaseCollection>
1484 void
1485 PgSqlLeaseMgr::getLeaseCollection(PgSqlLeaseContextPtr& ctx,
1486  StatementIndex stindex,
1487  PsqlBindArray& bind_array,
1488  Exchange& exchange,
1489  LeaseCollection& result,
1490  bool single) const {
1491  const int n = tagged_statements[stindex].nbparams;
1492  PgSqlResult r(PQexecPrepared(ctx->conn_,
1493  tagged_statements[stindex].name, n,
1494  n > 0 ? &bind_array.values_[0] : NULL,
1495  n > 0 ? &bind_array.lengths_[0] : NULL,
1496  n > 0 ? &bind_array.formats_[0] : NULL, 0));
1497 
1498  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
1499 
1500  int rows = PQntuples(r);
1501  if (single && rows > 1) {
1502  isc_throw(MultipleRecords, "multiple records were found in the "
1503  "database where only one was expected for query "
1504  << tagged_statements[stindex].name);
1505  }
1506 
1507  for(int i = 0; i < rows; ++ i) {
1508  result.push_back(exchange->convertFromDatabase(r, i));
1509  }
1510 }
1511 
1512 void
1513 PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr& ctx,
1514  StatementIndex stindex, PsqlBindArray& bind_array,
1515  Lease4Ptr& result) const {
1516  // Create appropriate collection object and get all leases matching
1517  // the selection criteria. The "single" parameter is true to indicate
1518  // that the called method should throw an exception if multiple
1519  // matching records are found: this particular method is called when only
1520  // one or zero matches is expected.
1521  Lease4Collection collection;
1522  getLeaseCollection(ctx, stindex, bind_array, ctx->exchange4_,
1523  collection, true);
1524 
1525  // Return single record if present, else clear the lease.
1526  if (collection.empty()) {
1527  result.reset();
1528  } else {
1529  result = *collection.begin();
1530  }
1531 }
1532 
1533 void
1534 PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr& ctx,
1535  StatementIndex stindex, PsqlBindArray& bind_array,
1536  Lease6Ptr& result) const {
1537  // Create appropriate collection object and get all leases matching
1538  // the selection criteria. The "single" parameter is true to indicate
1539  // that the called method should throw an exception if multiple
1540  // matching records are found: this particular method is called when only
1541  // one or zero matches is expected.
1542  Lease6Collection collection;
1543  getLeaseCollection(ctx, stindex, bind_array, ctx->exchange6_,
1544  collection, true);
1545 
1546  // Return single record if present, else clear the lease.
1547  if (collection.empty()) {
1548  result.reset();
1549  } else {
1550  result = *collection.begin();
1551  }
1552 }
1553 
1554 Lease4Ptr
1557  .arg(addr.toText());
1558 
1559  // Set up the WHERE clause value
1560  PsqlBindArray bind_array;
1561 
1562  // LEASE ADDRESS
1563  std::string addr_str = boost::lexical_cast<std::string>(addr.toUint32());
1564  bind_array.add(addr_str);
1565 
1566  // Get the data
1567  Lease4Ptr result;
1568 
1569  // Get a context
1570  PgSqlLeaseContextAlloc get_context(*this);
1571  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1572 
1573  getLease(ctx, GET_LEASE4_ADDR, bind_array, result);
1574 
1575  return (result);
1576 }
1577 
1579 PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
1581  .arg(hwaddr.toText());
1582 
1583  // Set up the WHERE clause value
1584  PsqlBindArray bind_array;
1585 
1586  // HWADDR
1587  if (!hwaddr.hwaddr_.empty()) {
1588  bind_array.add(hwaddr.hwaddr_);
1589  } else {
1590  bind_array.add("");
1591  }
1592 
1593  // Get the data
1594  Lease4Collection result;
1595 
1596  // Get a context
1597  PgSqlLeaseContextAlloc get_context(*this);
1598  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1599 
1600  getLeaseCollection(ctx, GET_LEASE4_HWADDR, bind_array, result);
1601 
1602  return (result);
1603 }
1604 
1605 Lease4Ptr
1606 PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
1608  .arg(subnet_id)
1609  .arg(hwaddr.toText());
1610 
1611  // Set up the WHERE clause value
1612  PsqlBindArray bind_array;
1613 
1614  // HWADDR
1615  if (!hwaddr.hwaddr_.empty()) {
1616  bind_array.add(hwaddr.hwaddr_);
1617  } else {
1618  bind_array.add("");
1619  }
1620 
1621  // SUBNET_ID
1622  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1623  bind_array.add(subnet_id_str);
1624 
1625  // Get the data
1626  Lease4Ptr result;
1627 
1628  // Get a context
1629  PgSqlLeaseContextAlloc get_context(*this);
1630  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1631 
1632  getLease(ctx, GET_LEASE4_HWADDR_SUBID, bind_array, result);
1633 
1634  return (result);
1635 }
1636 
1638 PgSqlLeaseMgr::getLease4(const ClientId& clientid) const {
1640  .arg(clientid.toText());
1641 
1642  // Set up the WHERE clause value
1643  PsqlBindArray bind_array;
1644 
1645  // CLIENT_ID
1646  bind_array.add(clientid.getClientId());
1647 
1648  // Get the data
1649  Lease4Collection result;
1650 
1651  // Get a context
1652  PgSqlLeaseContextAlloc get_context(*this);
1653  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1654 
1655  getLeaseCollection(ctx, GET_LEASE4_CLIENTID, bind_array, result);
1656 
1657  return (result);
1658 }
1659 
1660 Lease4Ptr
1661 PgSqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
1663  .arg(subnet_id)
1664  .arg(clientid.toText());
1665 
1666  // Set up the WHERE clause value
1667  PsqlBindArray bind_array;
1668 
1669  // CLIENT_ID
1670  bind_array.add(clientid.getClientId());
1671 
1672  // SUBNET_ID
1673  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1674  bind_array.add(subnet_id_str);
1675 
1676  // Get the data
1677  Lease4Ptr result;
1678 
1679  // Get a context
1680  PgSqlLeaseContextAlloc get_context(*this);
1681  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1682 
1683  getLease(ctx, GET_LEASE4_CLIENTID_SUBID, bind_array, result);
1684 
1685  return (result);
1686 }
1687 
1691  .arg(subnet_id);
1692 
1693  // Set up the WHERE clause value
1694  PsqlBindArray bind_array;
1695 
1696  // SUBNET_ID
1697  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1698  bind_array.add(subnet_id_str);
1699 
1700  // ... and get the data
1701  Lease4Collection result;
1702 
1703  // Get a context
1704  PgSqlLeaseContextAlloc get_context(*this);
1705  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1706 
1707  getLeaseCollection(ctx, GET_LEASE4_SUBID, bind_array, result);
1708 
1709  return (result);
1710 }
1711 
1713 PgSqlLeaseMgr::getLeases4(const std::string& hostname) const {
1715  .arg(hostname);
1716 
1717  // Set up the WHERE clause value
1718  PsqlBindArray bind_array;
1719 
1720  // Hostname
1721  bind_array.add(hostname);
1722 
1723  // ... and get the data
1724  Lease4Collection result;
1725 
1726  // Get a context
1727  PgSqlLeaseContextAlloc get_context(*this);
1728  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1729 
1730  getLeaseCollection(ctx, GET_LEASE4_HOSTNAME, bind_array, result);
1731 
1732  return (result);
1733 }
1734 
1738 
1739  // Provide empty binding array because our query has no parameters in
1740  // WHERE clause.
1741  PsqlBindArray bind_array;
1742  Lease4Collection result;
1743 
1744  // Get a context
1745  PgSqlLeaseContextAlloc get_context(*this);
1746  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1747 
1748  getLeaseCollection(ctx, GET_LEASE4, bind_array, result);
1749 
1750  return (result);
1751 }
1752 
1754 PgSqlLeaseMgr::getLeases4(const IOAddress& lower_bound_address,
1755  const LeasePageSize& page_size) const {
1756  // Expecting IPv4 address.
1757  if (!lower_bound_address.isV4()) {
1758  isc_throw(InvalidAddressFamily, "expected IPv4 address while "
1759  "retrieving leases from the lease database, got "
1760  << lower_bound_address);
1761  }
1762 
1764  .arg(page_size.page_size_)
1765  .arg(lower_bound_address.toText());
1766 
1767  // Prepare WHERE clause
1768  PsqlBindArray bind_array;
1769 
1770  // Bind lower bound address
1771  std::string lb_address_data = boost::lexical_cast<std::string>(lower_bound_address.toUint32());
1772  bind_array.add(lb_address_data);
1773 
1774  // Bind page size value
1775  std::string page_size_data = boost::lexical_cast<std::string>(page_size.page_size_);
1776  bind_array.add(page_size_data);
1777 
1778  // Get the leases
1779  Lease4Collection result;
1780 
1781  // Get a context
1782  PgSqlLeaseContextAlloc get_context(*this);
1783  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1784 
1785  getLeaseCollection(ctx, GET_LEASE4_PAGE, bind_array, result);
1786 
1787  return (result);
1788 }
1789 
1790 Lease6Ptr
1792  const IOAddress& addr) const {
1794  .arg(addr.toText())
1795  .arg(lease_type);
1796 
1797  // Set up the WHERE clause value
1798  PsqlBindArray bind_array;
1799 
1800  // LEASE ADDRESS
1801  std::string addr_str = addr.toText();
1802  bind_array.add(addr_str);
1803 
1804  // LEASE_TYPE
1805  std::string type_str_ = boost::lexical_cast<std::string>(lease_type);
1806  bind_array.add(type_str_);
1807 
1808  // ... and get the data
1809  Lease6Ptr result;
1810 
1811  // Get a context
1812  PgSqlLeaseContextAlloc get_context(*this);
1813  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1814 
1815  getLease(ctx, GET_LEASE6_ADDR, bind_array, result);
1816 
1817  return (result);
1818 }
1819 
1822  uint32_t iaid) const {
1824  .arg(iaid)
1825  .arg(duid.toText())
1826  .arg(lease_type);
1827 
1828  // Set up the WHERE clause value
1829  PsqlBindArray bind_array;
1830 
1831  // DUID
1832  bind_array.add(duid.getDuid());
1833 
1834  // IAID
1835  std::string iaid_str = PgSqlLease6Exchange::Uiaid(iaid).dbInputString();
1836  bind_array.add(iaid_str);
1837 
1838  // LEASE_TYPE
1839  std::string lease_type_str = boost::lexical_cast<std::string>(lease_type);
1840  bind_array.add(lease_type_str);
1841 
1842  // ... and get the data
1843  Lease6Collection result;
1844 
1845  // Get a context
1846  PgSqlLeaseContextAlloc get_context(*this);
1847  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1848 
1849  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID, bind_array, result);
1850 
1851  return (result);
1852 }
1853 
1856  uint32_t iaid, SubnetID subnet_id) const {
1858  .arg(iaid)
1859  .arg(subnet_id)
1860  .arg(duid.toText())
1861  .arg(lease_type);
1862 
1863  // Set up the WHERE clause value
1864  PsqlBindArray bind_array;
1865 
1866  // LEASE_TYPE
1867  std::string lease_type_str = boost::lexical_cast<std::string>(lease_type);
1868  bind_array.add(lease_type_str);
1869 
1870  // DUID
1871  bind_array.add(duid.getDuid());
1872 
1873  // IAID
1874  std::string iaid_str = PgSqlLease6Exchange::Uiaid(iaid).dbInputString();
1875  bind_array.add(iaid_str);
1876 
1877  // SUBNET ID
1878  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1879  bind_array.add(subnet_id_str);
1880 
1881  // ... and get the data
1882  Lease6Collection result;
1883 
1884  // Get a context
1885  PgSqlLeaseContextAlloc get_context(*this);
1886  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1887 
1888  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID_SUBID, bind_array, result);
1889 
1890  return (result);
1891 }
1892 
1896  .arg(subnet_id);
1897 
1898  // Set up the WHERE clause value
1899  PsqlBindArray bind_array;
1900 
1901  // SUBNET_ID
1902  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1903  bind_array.add(subnet_id_str);
1904 
1905  // ... and get the data
1906  Lease6Collection result;
1907 
1908  // Get a context
1909  PgSqlLeaseContextAlloc get_context(*this);
1910  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1911 
1912  getLeaseCollection(ctx, GET_LEASE6_SUBID, bind_array, result);
1913 
1914  return (result);
1915 }
1916 
1918 PgSqlLeaseMgr::getLeases6(const DUID& duid) const {
1920  .arg(duid.toText());
1921 
1922  // Set up the WHERE clause value
1923  PsqlBindArray bind_array;
1924 
1925  // DUID
1926  bind_array.add(duid.getDuid());
1927  Lease6Collection result;
1928 
1929  // Get a context
1930  PgSqlLeaseContextAlloc get_context(*this);
1931  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1932 
1933  // query to fetch the data
1934  getLeaseCollection(ctx, GET_LEASE6_DUID, bind_array, result);
1935 
1936  return (result);
1937 }
1938 
1940 PgSqlLeaseMgr::getLeases6(const std::string& hostname) const {
1942  .arg(hostname);
1943 
1944  // Set up the WHERE clause value
1945  PsqlBindArray bind_array;
1946 
1947  // Hostname
1948  bind_array.add(hostname);
1949 
1950  // ... and get the data
1951  Lease6Collection result;
1952 
1953  // Get a context
1954  PgSqlLeaseContextAlloc get_context(*this);
1955  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1956 
1957  getLeaseCollection(ctx, GET_LEASE6_HOSTNAME, bind_array, result);
1958 
1959  return (result);
1960 }
1961 
1965 
1966  // Provide empty binding array because our query has no parameters in
1967  // WHERE clause.
1968  PsqlBindArray bind_array;
1969  Lease6Collection result;
1970 
1971  // Get a context
1972  PgSqlLeaseContextAlloc get_context(*this);
1973  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1974 
1975  getLeaseCollection(ctx, GET_LEASE6, bind_array, result);
1976 
1977  return (result);
1978 }
1979 
1981 PgSqlLeaseMgr::getLeases6(const IOAddress& lower_bound_address,
1982  const LeasePageSize& page_size) const {
1983  // Expecting IPv6 address.
1984  if (!lower_bound_address.isV6()) {
1985  isc_throw(InvalidAddressFamily, "expected IPv6 address while "
1986  "retrieving leases from the lease database, got "
1987  << lower_bound_address);
1988  }
1989 
1991  .arg(page_size.page_size_)
1992  .arg(lower_bound_address.toText());
1993 
1994  // Prepare WHERE clause
1995  PsqlBindArray bind_array;
1996 
1997  // In IPv6 we compare addresses represented as strings. The IPv6 zero address
1998  // is ::, so it is greater than any other address. In this special case, we
1999  // just use 0 for comparison which should be lower than any real IPv6 address.
2000  std::string lb_address_data = "0";
2001  if (!lower_bound_address.isV6Zero()) {
2002  lb_address_data = lower_bound_address.toText();
2003  }
2004 
2005  // Bind lower bound address
2006  bind_array.add(lb_address_data);
2007 
2008  // Bind page size value
2009  std::string page_size_data = boost::lexical_cast<std::string>(page_size.page_size_);
2010  bind_array.add(page_size_data);
2011 
2012  // Get the leases
2013  Lease6Collection result;
2014 
2015  // Get a context
2016  PgSqlLeaseContextAlloc get_context(*this);
2017  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2018 
2019  getLeaseCollection(ctx, GET_LEASE6_PAGE, bind_array, result);
2020 
2021  return (result);
2022 }
2023 
2024 void
2026  const size_t max_leases) const {
2028  .arg(max_leases);
2029  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE4_EXPIRE);
2030 }
2031 
2032 void
2034  const size_t max_leases) const {
2036  .arg(max_leases);
2037  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE6_EXPIRE);
2038 }
2039 
2040 template<typename LeaseCollection>
2041 void
2042 PgSqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases,
2043  const size_t max_leases,
2044  StatementIndex statement_index) const {
2045  PsqlBindArray bind_array;
2046 
2047  // Exclude reclaimed leases.
2048  std::string state_str = boost::lexical_cast<std::string>(Lease::STATE_EXPIRED_RECLAIMED);
2049  bind_array.add(state_str);
2050 
2051  // Expiration timestamp.
2052  std::string timestamp_str = PgSqlLeaseExchange::convertToDatabaseTime(time(0));
2053  bind_array.add(timestamp_str);
2054 
2055  // If the number of leases is 0, we will return all leases. This is
2056  // achieved by setting the limit to a very high value.
2057  uint32_t limit = max_leases > 0 ? static_cast<uint32_t>(max_leases) :
2058  std::numeric_limits<uint32_t>::max();
2059  std::string limit_str = boost::lexical_cast<std::string>(limit);
2060  bind_array.add(limit_str);
2061 
2062  // Get a context
2063  PgSqlLeaseContextAlloc get_context(*this);
2064  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2065 
2066  // Retrieve leases from the database.
2067  getLeaseCollection(ctx, statement_index, bind_array, expired_leases);
2068 }
2069 
2070 template<typename LeasePtr>
2071 void
2072 PgSqlLeaseMgr::updateLeaseCommon(PgSqlLeaseContextPtr& ctx,
2073  StatementIndex stindex,
2074  PsqlBindArray& bind_array,
2075  const LeasePtr& lease) {
2076  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2077  tagged_statements[stindex].nbparams,
2078  &bind_array.values_[0],
2079  &bind_array.lengths_[0],
2080  &bind_array.formats_[0], 0));
2081 
2082  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2083 
2084  int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
2085 
2086  // Check success case first as it is the most likely outcome.
2087  if (affected_rows == 1) {
2088  return;
2089  }
2090 
2091  // If no rows affected, lease doesn't exist.
2092  if (affected_rows == 0) {
2093  isc_throw(NoSuchLease, "unable to update lease for address " <<
2094  lease->addr_.toText() << " as it does not exist");
2095  }
2096 
2097  // Should not happen - primary key constraint should only have selected
2098  // one row.
2099  isc_throw(DbOperationError, "apparently updated more than one lease "
2100  "that had the address " << lease->addr_.toText());
2101 }
2102 
2103 void
2105  const StatementIndex stindex = UPDATE_LEASE4;
2106 
2108  .arg(lease->addr_.toText());
2109 
2110  // Get a context
2111  PgSqlLeaseContextAlloc get_context(*this);
2112  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2113 
2114  // Create the BIND array for the data being updated
2115  PsqlBindArray bind_array;
2116  ctx->exchange4_->createBindForSend(lease, bind_array);
2117 
2118  // Set up the WHERE clause and append it to the SQL_BIND array
2119  std::string addr4_str = boost::lexical_cast<std::string>(lease->addr_.toUint32());
2120  bind_array.add(addr4_str);
2121 
2122  std::string expire_str;
2123  // Avoid overflow (see createBindForSend)
2124  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2125  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2126  } else {
2127  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2128  lease->current_valid_lft_);
2129  }
2130  bind_array.add(expire_str);
2131 
2132  // Drop to common update code
2133  updateLeaseCommon(ctx, stindex, bind_array, lease);
2134 
2135  // Update lease current expiration time.
2136  lease->updateCurrentExpirationTime();
2137 }
2138 
2139 void
2141  const StatementIndex stindex = UPDATE_LEASE6;
2142 
2144  .arg(lease->addr_.toText())
2145  .arg(lease->type_);
2146 
2147  // Get a context
2148  PgSqlLeaseContextAlloc get_context(*this);
2149  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2150 
2151  // Create the BIND array for the data being updated
2152  PsqlBindArray bind_array;
2153  ctx->exchange6_->createBindForSend(lease, bind_array);
2154 
2155  // Set up the WHERE clause and append it to the BIND array
2156  std::string addr_str = lease->addr_.toText();
2157  bind_array.add(addr_str);
2158 
2159  std::string expire_str;
2160  // Avoid overflow (see createBindForSend)
2161  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2162  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2163  } else {
2164  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2165  lease->current_valid_lft_);
2166  }
2167  bind_array.add(expire_str);
2168 
2169  // Drop to common update code
2170  updateLeaseCommon(ctx, stindex, bind_array, lease);
2171 
2172  // Update lease current expiration time.
2173  lease->updateCurrentExpirationTime();
2174 }
2175 
2176 uint64_t
2177 PgSqlLeaseMgr::deleteLeaseCommon(StatementIndex stindex,
2178  PsqlBindArray& bind_array) {
2179  // Get a context
2180  PgSqlLeaseContextAlloc get_context(*this);
2181  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2182 
2183  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2184  tagged_statements[stindex].nbparams,
2185  &bind_array.values_[0],
2186  &bind_array.lengths_[0],
2187  &bind_array.formats_[0], 0));
2188 
2189  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2190  int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
2191 
2192  return (affected_rows);
2193 }
2194 
2195 bool
2197  const IOAddress& addr = lease->addr_;
2199  .arg(addr.toText());
2200 
2201  // Set up the WHERE clause value
2202  PsqlBindArray bind_array;
2203 
2204  std::string addr4_str = boost::lexical_cast<std::string>(addr.toUint32());
2205  bind_array.add(addr4_str);
2206 
2207  std::string expire_str;
2208  // Avoid overflow (see createBindForSend)
2209  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2210  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2211  } else {
2212  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2213  lease->current_valid_lft_);
2214  }
2215  bind_array.add(expire_str);
2216 
2217  auto affected_rows = deleteLeaseCommon(DELETE_LEASE4, bind_array);
2218 
2219  // Check success case first as it is the most likely outcome.
2220  if (affected_rows == 1) {
2221  return (true);
2222  }
2223 
2224  // If no rows affected, lease doesn't exist.
2225  if (affected_rows == 0) {
2226  return (false);
2227  }
2228 
2229  // Should not happen - primary key constraint should only have selected
2230  // one row.
2231  isc_throw(DbOperationError, "apparently deleted more than one lease "
2232  "that had the address " << lease->addr_.toText());
2233 }
2234 
2235 bool
2237  const IOAddress& addr = lease->addr_;
2240  .arg(addr.toText());
2241 
2242  // Set up the WHERE clause value
2243  PsqlBindArray bind_array;
2244 
2245  std::string addr6_str = addr.toText();
2246  bind_array.add(addr6_str);
2247 
2248  std::string expire_str;
2249  // Avoid overflow (see createBindForSend)
2250  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2251  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2252  } else {
2253  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2254  lease->current_valid_lft_);
2255  }
2256  bind_array.add(expire_str);
2257 
2258  auto affected_rows = deleteLeaseCommon(DELETE_LEASE6, bind_array);
2259 
2260  // Check success case first as it is the most likely outcome.
2261  if (affected_rows == 1) {
2262  return (true);
2263  }
2264 
2265  // If no rows affected, lease doesn't exist.
2266  if (affected_rows == 0) {
2267  return (false);
2268  }
2269 
2270  // Should not happen - primary key constraint should only have selected
2271  // one row.
2272  isc_throw(DbOperationError, "apparently deleted more than one lease "
2273  "that had the address " << lease->addr_.toText());
2274 }
2275 
2276 uint64_t
2279  .arg(secs);
2280  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
2281 }
2282 
2283 uint64_t
2286  .arg(secs);
2287  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
2288 }
2289 
2290 uint64_t
2291 PgSqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
2292  StatementIndex statement_index) {
2293  PsqlBindArray bind_array;
2294 
2295  // State is reclaimed.
2296  std::string state_str = boost::lexical_cast<std::string>(Lease::STATE_EXPIRED_RECLAIMED);
2297  bind_array.add(state_str);
2298 
2299  // Expiration timestamp.
2300  std::string expiration_str = PgSqlLeaseExchange::convertToDatabaseTime(time(0) -
2301  static_cast<time_t>(secs));
2302  bind_array.add(expiration_str);
2303 
2304  // Delete leases.
2305  return (deleteLeaseCommon(statement_index, bind_array));
2306 }
2307 
2308 string
2309 PgSqlLeaseMgr::checkLimits(ConstElementPtr const& user_context, StatementIndex const stindex) const {
2310  // No user context means no limits means allocation allowed means empty string.
2311  if (!user_context) {
2312  return string();
2313  }
2314 
2315  // Get a context.
2316  PgSqlLeaseContextAlloc get_context(*this);
2317  PgSqlLeaseContextPtr ctx(get_context.ctx_);
2318 
2319  // Create bindings.
2320  PsqlBindArray bind_array;
2321  std::string const user_context_str(user_context->str());
2322  bind_array.add(user_context_str);
2323 
2324  // Execute the select.
2325  PgSqlResult r(PQexecPrepared(ctx->conn_,
2326  tagged_statements[stindex].name,
2327  tagged_statements[stindex].nbparams,
2328  &bind_array.values_[0],
2329  &bind_array.lengths_[0],
2330  &bind_array.formats_[0], 0));
2331  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2332 
2333  std::string limits;
2334  PgSqlExchange::getColumnValue(r, 0, 0, limits);
2335  return limits;
2336 }
2337 
2338 string
2339 PgSqlLeaseMgr::checkLimits4(ConstElementPtr const& user_context) const {
2340  return checkLimits(user_context, CHECK_LEASE4_LIMITS);
2341 }
2342 
2343 string
2344 PgSqlLeaseMgr::checkLimits6(ConstElementPtr const& user_context) const {
2345  return checkLimits(user_context, CHECK_LEASE6_LIMITS);
2346 }
2347 
2348 bool
2349 PgSqlLeaseMgr::isJsonSupported() const {
2350  // Get a context.
2351  PgSqlLeaseContextAlloc get_context(*this);
2352  PgSqlLeaseContextPtr ctx(get_context.ctx_);
2353 
2354  // Execute the select.
2355  StatementIndex const stindex(IS_JSON_SUPPORTED);
2356  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2357  0, 0, 0, 0, 0));
2358  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2359 
2360  bool json_supported;
2361  PgSqlExchange::getColumnValue(r, 0, 0, json_supported);
2362  return json_supported;
2363 }
2364 
2365 size_t
2366 PgSqlLeaseMgr::getClassLeaseCount(const ClientClass& client_class,
2367  const Lease::Type& ltype /* = Lease::TYPE_V4*/) const {
2368  // Get a context.
2369  PgSqlLeaseContextAlloc get_context(*this);
2370  PgSqlLeaseContextPtr ctx(get_context.ctx_);
2371 
2372  // Create bindings.
2373  PsqlBindArray bind_array;
2374  bind_array.add(client_class);
2375  if (ltype != Lease::TYPE_V4) {
2376  bind_array.add(ltype);
2377  }
2378 
2379  // Execute the select.
2380  StatementIndex const stindex(ltype == Lease::TYPE_V4 ? GET_LEASE4_COUNT_BY_CLASS :
2382  PgSqlResult r(PQexecPrepared(ctx->conn_,
2383  tagged_statements[stindex].name,
2384  tagged_statements[stindex].nbparams,
2385  &bind_array.values_[0],
2386  &bind_array.lengths_[0],
2387  &bind_array.formats_[0], 0));
2388  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2389 
2390  int rows = PQntuples(r);
2391  if (rows == 0) {
2392  // No entries means 0 leases.
2393  return 0;
2394  }
2395 
2396  size_t count;
2397  PgSqlExchange::getColumnValue(r, 0, 0, count);
2398  return count;
2399 }
2400 
2401 void
2402 PgSqlLeaseMgr::recountClassLeases4() {
2403  isc_throw(NotImplemented, "PgSqlLeaseMgr::recountClassLeases4() not implemented");
2404 }
2405 
2406 void
2407 PgSqlLeaseMgr::recountClassLeases6() {
2408  isc_throw(NotImplemented, "PgSqlLeaseMgr::recountClassLeases6() not implemented");
2409 }
2410 
2411 void
2412 PgSqlLeaseMgr::clearClassLeaseCounts() {
2413  isc_throw(NotImplemented, "PgSqlLeaseMgr::clearClassLeaseCounts() not implemented");
2414 }
2415 
2416 void
2417 PgSqlLeaseMgr::writeLeases4(const std::string&) {
2418  isc_throw(NotImplemented, "PgSqlLeaseMgr::writeLeases4() not implemented");
2419 }
2420 
2421 void
2422 PgSqlLeaseMgr::writeLeases6(const std::string&) {
2423  isc_throw(NotImplemented, "PgSqlLeaseMgr::writeLeases6() not implemented");
2424 }
2425 
2428  // Get a context
2429  PgSqlLeaseContextAlloc get_context(*this);
2430  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2431 
2432  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2433  tagged_statements[ALL_LEASE4_STATS],
2434  false));
2435  query->start();
2436  return(query);
2437 }
2438 
2441  // Get a context
2442  PgSqlLeaseContextAlloc get_context(*this);
2443  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2444 
2445  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2446  tagged_statements[SUBNET_LEASE4_STATS],
2447  false,
2448  subnet_id));
2449  query->start();
2450  return(query);
2451 }
2452 
2455  const SubnetID& last_subnet_id) {
2456  // Get a context
2457  PgSqlLeaseContextAlloc get_context(*this);
2458  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2459 
2460  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2461  tagged_statements[SUBNET_RANGE_LEASE4_STATS],
2462  false,
2463  first_subnet_id,
2464  last_subnet_id));
2465  query->start();
2466  return(query);
2467 }
2468 
2471  // Get a context
2472  PgSqlLeaseContextAlloc get_context(*this);
2473  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2474 
2475  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2476  tagged_statements[ALL_LEASE6_STATS],
2477  true));
2478  query->start();
2479  return(query);
2480 }
2481 
2484  // Get a context
2485  PgSqlLeaseContextAlloc get_context(*this);
2486  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2487 
2488  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2489  tagged_statements[SUBNET_LEASE6_STATS],
2490  true,
2491  subnet_id));
2492  query->start();
2493  return(query);
2494 }
2495 
2498  const SubnetID& last_subnet_id) {
2499  // Get a context
2500  PgSqlLeaseContextAlloc get_context(*this);
2501  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2502 
2503  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2504  tagged_statements[SUBNET_RANGE_LEASE6_STATS],
2505  true,
2506  first_subnet_id,
2507  last_subnet_id));
2508  query->start();
2509  return(query);
2510 }
2511 
2512 size_t
2513 PgSqlLeaseMgr::wipeLeases4(const SubnetID& /*subnet_id*/) {
2514  isc_throw(NotImplemented, "wipeLeases4 is not implemented for PostgreSQL backend");
2515 }
2516 
2517 size_t
2518 PgSqlLeaseMgr::wipeLeases6(const SubnetID& /*subnet_id*/) {
2519  isc_throw(NotImplemented, "wipeLeases6 is not implemented for PostgreSQL backend");
2520 }
2521 
2522 std::string
2524  // Get a context
2525  PgSqlLeaseContextAlloc get_context(*this);
2526  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2527 
2528  std::string name = "";
2529  try {
2530  name = ctx->conn_.getParameter("name");
2531  } catch (...) {
2532  // Return an empty name
2533  }
2534  return (name);
2535 }
2536 
2537 std::string
2539  return (std::string("PostgreSQL Database"));
2540 }
2541 
2542 std::pair<uint32_t, uint32_t>
2545 
2546  return (PgSqlConnection::getVersion(parameters_));
2547 }
2548 
2549 void
2552 }
2553 
2554 void
2557 }
2558 
2560 PgSqlLeaseMgr::getLeases4ByRelayId(const OptionBuffer& /* relay_id */,
2561  const IOAddress& /* lower_bound_address */,
2562  const LeasePageSize& /* page_size */,
2563  const time_t& /* qry_start_time = 0 */,
2564  const time_t& /* qry_end_time = 0 */) {
2565  isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases4ByRelayId not implemented");
2566 }
2567 
2569 PgSqlLeaseMgr::getLeases4ByRemoteId(const OptionBuffer& /* remote_id */,
2570  const IOAddress& /* lower_bound_address */,
2571  const LeasePageSize& /* page_size */,
2572  const time_t& /* qry_start_time = 0 */,
2573  const time_t& /* qry_end_time = 0 */) {
2574  isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases4ByRemoteId not implemented");
2575 }
2576 
2578 PgSqlLeaseMgr::getLeases6ByRelayId(const DUID& /* relay_id */,
2579  const IOAddress& /* link_addr */,
2580  const IOAddress& /* lower_bound_address */,
2581  const LeasePageSize& /* page_size */) {
2582  isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases6ByRelayId not implemented");
2583 }
2584 
2586 PgSqlLeaseMgr::getLeases6ByRemoteId(const OptionBuffer& /* remote_id */,
2587  const IOAddress& /* link_addr */,
2588  const IOAddress& /* lower_bound_address */,
2589  const LeasePageSize& /* page_size*/) {
2590  isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases6ByRemoteId not implemented");
2591 }
2592 
2594 PgSqlLeaseMgr::getLeases6ByLink(const IOAddress& /* link_addr */,
2595  const IOAddress& /* lower_bound_address */,
2596  const LeasePageSize& /* page_size */) {
2597  isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases6ByLink not implemented");
2598 }
2599 
2600 } // namespace dhcp
2601 } // namespace isc
const isc::log::MessageID DHCPSRV_PGSQL_GET_SUBID6
virtual ~PgSqlLeaseMgr()
Destructor (closes database)
PgSqlLeaseStatsQuery(PgSqlConnection &conn, PgSqlTaggedStatement &statement, const bool fetch_type, const SubnetID &subnet_id)
Constructor to query for a single subnet&#39;s stats.
RAII class creating a critical section.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
std::function< bool(util::ReconnectCtlPtr db_reconnect_ctl)> DbCallback
Defines a callback prototype for propagating events upward.
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:20
std::string toText() const
Dumps the contents of the array to a string.
const isc::log::MessageID DHCPSRV_PGSQL_LEASE_DB_RECONNECT_FAILED
RAII wrapper for PostgreSQL Result sets.
const isc::log::MessageID DHCPSRV_PGSQL_ROLLBACK
boost::shared_ptr< LeaseStatsQuery > LeaseStatsQueryPtr
Defines a pointer to a LeaseStatsQuery.
Definition: lease_mgr.h:208
const size_t OID_BOOL
void createBindForSend(const Lease6Ptr &lease, PsqlBindArray &bind_array)
Creates the bind array for sending Lease6 data to the database.
const size_t OID_INT2
PostgreSQL Lease Context.
virtual void rollback() override
Rollback Transactions.
const isc::log::MessageID DHCPSRV_PGSQL_GET_SUBID4
A generic exception that is thrown when a function is not implemented.
static const uint32_t STATE_EXPIRED_RECLAIMED
Expired and reclaimed lease.
Definition: lease.h:75
static bool negative_count_
Received negative state count showing a problem.
const std::vector< uint8_t > & getClientId() const
Returns reference to the client-id data.
Definition: duid.cc:117
static std::string convertToDatabaseTime(const time_t input_time)
Converts UTC time_t value to a text representation in local time.
const isc::log::MessageID DHCPSRV_PGSQL_GET_HOSTNAME4
void getLeaseTypeColumnValue(const PgSqlResult &r, const int row, const size_t col, Lease6::Type &value) const
Fetches an integer text column as a Lease6::Type.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
Uiaid(uint32_t val)
Constructor.
virtual bool addLease(const Lease4Ptr &lease) override
Adds an IPv4 lease.
const size_t OID_INT8
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
std::vector< int > formats_
Vector of "format" for each value.
boost::shared_ptr< PgSqlResult > result_set_
The result set returned by Postgres.
PostgreSQL Lease Manager.
uint32_t next_row_
Index of the next row to fetch.
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
const isc::log::MessageID DHCPSRV_PGSQL_LEASE_DB_RECONNECT_ATTEMPT_SCHEDULE
virtual void updateLease6(const Lease6Ptr &lease6) override
Updates IPv6 lease.
static void destroy()
Destroy lease manager.
const isc::log::MessageID DHCPSRV_PGSQL_NO_TLS_SUPPORT
bool getNextRow(LeaseStatsRow &row)
Fetches the next row in the result set.
Base class for marshalling leases to and from PostgreSQL.
const isc::log::MessageID DHCPSRV_PGSQL_GET_ADDR4
const isc::log::MessageID DHCPSRV_PGSQL_GET_EXPIRED4
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
std::vector< int > lengths_
Vector of data lengths for each value.
virtual std::string getDescription() const override
Returns description of the backend.
Attempt to update lease that was not there.
Union for marshalling IAID into and out of the database IAID is defined in the RFC as 4 octets...
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition: lease.h:498
const isc::log::MessageID DHCPSRV_PGSQL_GET_VERSION
static const char DUPLICATE_KEY[]
Define the PgSql error state for a duplicate key error.
virtual size_t wipeLeases4(const SubnetID &subnet_id) override
Removes specified IPv4 leases.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:161
std::vector< uint8_t > hwaddr_
Definition: hwaddr.h:98
STL namespace.
Base class for fulfilling a statistical lease data query.
Definition: lease_mgr.h:129
virtual void updateLease4(const Lease4Ptr &lease4) override
Updates IPv4 lease.
Base class for marshalling data to and from PostgreSQL.
const isc::log::MessageID DHCPSRV_PGSQL_DELETE_EXPIRED_RECLAIMED6
void createBindForSend(const Lease4Ptr &lease, PsqlBindArray &bind_array)
Creates the bind array for sending Lease4 data to the database.
const isc::log::MessageID DHCPSRV_PGSQL_GET_SUBID_HWADDR
virtual bool deleteLease(const Lease4Ptr &lease) override
Deletes an IPv4 lease.
std::vector< uint8_t > hwaddr_
boost::shared_ptr< Lease > LeasePtr
Pointer to the lease object.
Definition: lease.h:22
const size_t OID_TEXT
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
const isc::log::MessageID DHCPSRV_PGSQL_GET_EXPIRED6
Exception thrown on failure to open database.
virtual Lease6Collection getLeases6() const override
Returns all IPv6 leases.
const isc::log::MessageID DHCPSRV_PGSQL_GET_HOSTNAME6
static bool dbReconnect(util::ReconnectCtlPtr db_reconnect_ctl)
Attempts to reconnect the server to the lease DB backend manager.
not specified or undefined
Definition: dhcp4.h:55
static isc::asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service.
Definition: lease_mgr.h:791
virtual void getExpiredLeases4(Lease4Collection &expired_leases, const size_t max_leases) const override
Returns a collection of expired DHCPv4 leases.
std::vector< const char * > values_
Vector of pointers to the data values.
Multiple lease records found where one expected.
Definition: db_exceptions.h:16
Lease6Ptr convertFromDatabase(const PgSqlResult &r, int row)
Creates a Lease6 object from a given row in a result set.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
void addTempString(const std::string &str)
Binds the given string to the bind array.
virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t secs) override
Deletes all expired-reclaimed DHCPv4 leases.
PostgreSQL Lease Context Pool.
void add(const char *value)
Adds a char array to bind array based.
Definition: edns.h:19
const size_t page_size_
Holds page size.
Definition: lease_mgr.h:54
PgSqlLeaseContextPtr createContext() const
Create a new context.
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const override
Returns existing IPv6 lease for a given IPv6 address.
const isc::log::MessageID DHCPSRV_PGSQL_GET4
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:284
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
boost::shared_ptr< CfgDbAccess > CfgDbAccessPtr
A pointer to the CfgDbAccess.
const isc::log::MessageID DHCPSRV_PGSQL_GET_ADDR6
static bool warned_about_tls
Emit the TLS support warning only once.
const isc::log::MessageID DHCPSRV_PGSQL_GET_CLIENTID
const isc::log::MessageID DHCPSRV_PGSQL_LEASE_DB_RECONNECT_ATTEMPT_FAILED
SubnetID subnet_id_
The subnet ID to which this data applies.
Definition: lease_mgr.h:115
static std::string getDBVersion()
Local version of getDBVersion() class method.
A generic exception that is thrown when an unexpected error condition occurs.
IPv4 lease.
Definition: lease.h:50
virtual LeaseStatsQueryPtr startLeaseStatsQuery6() override
Creates and runs the IPv6 lease stats query.
const isc::log::MessageID DHCPSRV_PGSQL_GET_IAID_SUBID_DUID
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
Structure that holds a lease for IPv6 address and/or prefix.
Definition: lease.h:514
const isc::log::MessageID DHCPSRV_PGSQL_GET_PAGE6
PgSqlTaggedStatement & statement_
The query&#39;s prepared statement.
const isc::log::MessageID DHCPSRV_PGSQL_COMMIT
static void getColumnValue(const PgSqlResult &r, const int row, const size_t col, std::string &value)
Fetches text column value as a string.
const isc::log::MessageID DHCPSRV_PGSQL_GET_HWADDR
std::string addr_str_
Common Instance members used for binding and conversion.
Common PgSql Connector Pool.
static bool invokeDbRecoveredCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection&#39;s restored connectivity callback.
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:661
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs) override
Deletes all expired-reclaimed DHCPv6 leases.
virtual void commit() override
Commit Transactions.
const std::vector< uint8_t > & getDuid() const
Returns a const reference to the actual DUID value.
Definition: duid.cc:46
virtual size_t wipeLeases6(const SubnetID &subnet_id) override
Removed specified IPv6 leases.
Ethernet 10Mbps.
Definition: dhcp4.h:56
Invalid address family used as input to Lease Manager.
Definition: db_exceptions.h:59
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.
Defines the logger used by the top-level component of kea-lfc.
const isc::log::MessageID DHCPSRV_PGSQL_GET6
Lease4Ptr convertFromDatabase(const PgSqlResult &r, int row)
Creates a Lease4 object from a given row in a result set.
Define a PostgreSQL statement.
void start()
Creates the lease statistical data result set.
static bool invokeDbFailedCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection&#39;s restore failed connectivity callback.
size_t size() const
Fetches the number of entries in the array.
const isc::log::MessageID DHCPSRV_PGSQL_DELETE_ADDR
const isc::log::MessageID DHCPSRV_PGSQL_ADD_ADDR6
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const override
Returns an IPv4 lease for specified IPv4 address.
const size_t OID_BYTEA
PgSqlConnection & conn_
Database connection to use to execute the query.
boost::shared_ptr< PgSqlLeaseContext > PgSqlLeaseContextPtr
Type of pointers to contexts.
static const uint32_t INFINITY_LFT
Infinity (means static, i.e. never expire)
Definition: lease.h:34
const isc::log::MessageID DHCPSRV_PGSQL_DELETE_EXPIRED_RECLAIMED4
const isc::log::MessageID DHCPSRV_PGSQL_UPDATE_ADDR6
const isc::log::MessageID DHCPSRV_PGSQL_GET_PAGE4
uint32_t lease_state_
The lease_state to which the count applies.
Definition: lease_mgr.h:119
Type
Type of lease or pool.
Definition: lease.h:46
Holds Client identifier or client IPv4 address.
Definition: duid.h:111
static void create(const std::string &dbaccess)
Create an instance of a lease manager.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID &subnet_id) override
Creates and runs the IPv4 lease stats query for a single subnet.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
const isc::log::MessageID DHCPSRV_PGSQL_GET_DUID
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID &subnet_id) override
Creates and runs the IPv6 lease stats query for a single subnet.
StatementIndex
Statement Tags.
Hardware type that represents information from DHCPv4 packet.
Definition: hwaddr.h:20
PgSqlLeaseStatsQuery(PgSqlConnection &conn, PgSqlTaggedStatement &statement, 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.
int64_t state_count_
state_count The count of leases in the lease state
Definition: lease_mgr.h:121
const size_t OID_VARCHAR
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
Contains a single row of lease statistical data.
Definition: lease_mgr.h:62
const uint32_t PGSQL_SCHEMA_VERSION_MAJOR
Define the PostgreSQL backend version.
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:75
Wraps value holding size of the page with leases.
Definition: lease_mgr.h:44
static std::pair< uint32_t, uint32_t > getVersion(const ParameterMap &parameters)
Get the schema version.
const size_t OID_NONE
Constants for PostgreSQL data types These are defined by PostgreSQL in <catalog/pg_type.h>, but including this file is extraordinarily convoluted, so we&#39;ll use these to fill-in.
Lease::Type lease_type_
The lease_type to which the count applies.
Definition: lease_mgr.h:117
std::string ClientClass
Defines a single class name.
Definition: classify.h:42
std::function< isc::asiolink::IOServicePtr()> IOServiceAccessor
Function which returns the IOService that can be used to recover the connection.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition: timer_mgr.cc:449
static bool invokeDbLostCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection&#39;s lost connectivity callback.
const isc::log::MessageID DHCPSRV_PGSQL_UPDATE_ADDR4
virtual LeaseStatsQueryPtr startLeaseStatsQuery4() override
Creates and runs the IPv4 lease stats query.
virtual ~PgSqlLeaseStatsQuery()
Destructor.
Base PgSql derivation of the statistical lease data query.
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition: lease.h:503
static std::string redactedAccessString(const ParameterMap &parameters)
Redact database access string.
virtual void getExpiredLeases6(Lease6Collection &expired_leases, const size_t max_leases) const override
Returns a collection of expired DHCPv6 leases.
std::string dbInputString()
Return a string representing the signed 32-bit value.
PgSqlLeaseStatsQuery(PgSqlConnection &conn, PgSqlTaggedStatement &statement, const bool fetch_type)
Constructor to query for all subnets&#39; stats.
const size_t OID_TIMESTAMP
const isc::log::MessageID DHCPSRV_PGSQL_TLS_SUPPORT
Supports exchanging IPv6 leases with PostgreSQL.
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:122
Exception thrown on failure to execute a database function.
Supports exchanging IPv4 leases with PostgreSQL.
const isc::log::MessageID DHCPSRV_PGSQL_NEGATIVE_LEASES_STAT
boost::shared_ptr< IOServiceAccessor > IOServiceAccessorPtr
Pointer to an instance of IOServiceAccessor.
const isc::log::MessageID DHCPSRV_PGSQL_GET_IAID_DUID
const uint32_t PGSQL_SCHEMA_VERSION_MINOR
std::string toText(bool include_htype=true) const
Returns textual representation of a hardware address (e.g.
Definition: hwaddr.cc:51
const isc::log::MessageID DHCPSRV_PGSQL_ADD_ADDR4
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:24
bool fetch_type_
Indicates if query supplies lease type.
virtual std::string getName() const override
Returns backend name.
const isc::log::MessageID DHCPSRV_PGSQL_GET_SUBID_CLIENTID
virtual Lease4Collection getLeases4() const override
Returns all IPv4 leases.
PgSqlLeaseMgr(const db::DatabaseConnection::ParameterMap &parameters)
Constructor.
virtual std::pair< uint32_t, uint32_t > getVersion() const override
Returns backend version.
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.