Kea  2.3.5-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 void
1255  isc_throw(isc::NotImplemented, "extended info tables are not yet supported by mysql");
1256 }
1257 
1258 // PgSqlLeaseMgr Constructor and Destructor
1259 
1261  : parameters_(parameters), timer_name_("") {
1262 
1263  // Check if the extended info tables are enabled.
1265 
1266  // Create unique timer name per instance.
1267  timer_name_ = "PgSqlLeaseMgr[";
1268  timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this));
1269  timer_name_ += "]DbReconnectTimer";
1270 
1271  // Check TLS support.
1272  size_t tls(0);
1273  tls += parameters.count("trust-anchor");
1274  tls += parameters.count("cert-file");
1275  tls += parameters.count("key-file");
1276  tls += parameters.count("cipher-list");
1277 #ifdef HAVE_PGSQL_SSL
1278  if ((tls > 0) && !PgSqlConnection::warned_about_tls) {
1281  .arg(DatabaseConnection::redactedAccessString(parameters_));
1282  PQinitSSL(1);
1283  }
1284 #else
1285  if (tls > 0) {
1287  .arg(DatabaseConnection::redactedAccessString(parameters_));
1288  isc_throw(DbOpenError, "Attempt to configure TLS for PostgreSQL "
1289  << "backend (built with this feature disabled)");
1290  }
1291 #endif
1292 
1293  // Validate schema version first.
1294  std::pair<uint32_t, uint32_t> code_version(PGSQL_SCHEMA_VERSION_MAJOR,
1296  std::pair<uint32_t, uint32_t> db_version = getVersion();
1297  if (code_version != db_version) {
1299  "PostgreSQL schema version mismatch: need version: "
1300  << code_version.first << "." << code_version.second
1301  << " found version: " << db_version.first << "."
1302  << db_version.second);
1303  }
1304 
1305  // Create an initial context.
1306  pool_.reset(new PgSqlLeaseContextPool());
1307  pool_->pool_.push_back(createContext());
1308 }
1309 
1311 }
1312 
1313 bool
1316 
1317  // Invoke application layer connection lost callback.
1318  if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) {
1319  return (false);
1320  }
1321 
1322  bool reopened = false;
1323 
1324  const std::string timer_name = db_reconnect_ctl->timerName();
1325 
1326  // At least one connection was lost.
1327  try {
1328  CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
1330  LeaseMgrFactory::create(cfg_db->getLeaseDbAccessString());
1331  reopened = true;
1332  } catch (const std::exception& ex) {
1334  .arg(ex.what());
1335  }
1336 
1337  if (reopened) {
1338  // Cancel the timer.
1339  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1340  TimerMgr::instance()->unregisterTimer(timer_name);
1341  }
1342 
1343  // Invoke application layer connection recovered callback.
1344  if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) {
1345  return (false);
1346  }
1347  } else {
1348  if (!db_reconnect_ctl->checkRetries()) {
1349  // We're out of retries, log it and initiate shutdown.
1351  .arg(db_reconnect_ctl->maxRetries());
1352 
1353  // Cancel the timer.
1354  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1355  TimerMgr::instance()->unregisterTimer(timer_name);
1356  }
1357 
1358  // Invoke application layer connection failed callback.
1360  return (false);
1361  }
1362 
1364  .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
1365  .arg(db_reconnect_ctl->maxRetries())
1366  .arg(db_reconnect_ctl->retryInterval());
1367 
1368  // Start the timer.
1369  if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
1370  TimerMgr::instance()->registerTimer(timer_name,
1371  std::bind(&PgSqlLeaseMgr::dbReconnect, db_reconnect_ctl),
1372  db_reconnect_ctl->retryInterval(),
1374  }
1375  TimerMgr::instance()->setup(timer_name);
1376  }
1377 
1378  return (true);
1379 }
1380 
1381 // Create context.
1382 
1385  PgSqlLeaseContextPtr ctx(new PgSqlLeaseContext(parameters_,
1388 
1389  // Open the database.
1390  ctx->conn_.openDatabase();
1391 
1392  // Now prepare the SQL statements.
1393  uint32_t i = 0;
1394  for (; tagged_statements[i].text != NULL; ++i) {
1395  ctx->conn_.prepareStatement(tagged_statements[i]);
1396  }
1397 
1398  // Just in case somebody foo-barred things
1399  if (i != NUM_STATEMENTS) {
1400  isc_throw(DbOpenError, "Number of statements prepared: " << i
1401  << " does not match expected count:" << NUM_STATEMENTS);
1402  }
1403 
1404  // Create the exchange objects for use in exchanging data between the
1405  // program and the database.
1406  ctx->exchange4_.reset(new PgSqlLease4Exchange());
1407  ctx->exchange6_.reset(new PgSqlLease6Exchange());
1408 
1409  // Create ReconnectCtl for this connection.
1410  ctx->conn_.makeReconnectCtl(timer_name_);
1411 
1412  return (ctx);
1413 }
1414 
1415 std::string
1417  std::stringstream tmp;
1418  tmp << "PostgreSQL backend " << PGSQL_SCHEMA_VERSION_MAJOR;
1419  tmp << "." << PGSQL_SCHEMA_VERSION_MINOR;
1420  tmp << ", library " << PQlibVersion();
1421  return (tmp.str());
1422 }
1423 
1424 bool
1425 PgSqlLeaseMgr::addLeaseCommon(PgSqlLeaseContextPtr& ctx,
1426  StatementIndex stindex,
1427  PsqlBindArray& bind_array) {
1428  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
1429  tagged_statements[stindex].nbparams,
1430  &bind_array.values_[0],
1431  &bind_array.lengths_[0],
1432  &bind_array.formats_[0], 0));
1433 
1434  int s = PQresultStatus(r);
1435 
1436  if (s != PGRES_COMMAND_OK) {
1437  // Failure: check for the special case of duplicate entry. If this is
1438  // the case, we return false to indicate that the row was not added.
1439  // Otherwise we throw an exception.
1440  if (ctx->conn_.compareError(r, PgSqlConnection::DUPLICATE_KEY)) {
1441  return (false);
1442  }
1443  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
1444  }
1445 
1446  return (true);
1447 }
1448 
1449 bool
1452  .arg(lease->addr_.toText());
1453 
1454  // Get a context
1455  PgSqlLeaseContextAlloc get_context(*this);
1456  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1457 
1458  PsqlBindArray bind_array;
1459  ctx->exchange4_->createBindForSend(lease, bind_array);
1460  auto result = addLeaseCommon(ctx, INSERT_LEASE4, bind_array);
1461 
1462  // Update lease current expiration time (allows update between the creation
1463  // of the Lease up to the point of insertion in the database).
1464  lease->updateCurrentExpirationTime();
1465 
1466  return (result);
1467 }
1468 
1469 bool
1472  .arg(lease->addr_.toText())
1473  .arg(lease->type_);
1474 
1475  // Get a context
1476  PgSqlLeaseContextAlloc get_context(*this);
1477  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1478 
1479  PsqlBindArray bind_array;
1480  ctx->exchange6_->createBindForSend(lease, bind_array);
1481 
1482  auto result = addLeaseCommon(ctx, INSERT_LEASE6, bind_array);
1483 
1484  // Update lease current expiration time (allows update between the creation
1485  // of the Lease up to the point of insertion in the database).
1486  lease->updateCurrentExpirationTime();
1487 
1488  return (result);
1489 }
1490 
1491 template <typename Exchange, typename LeaseCollection>
1492 void
1493 PgSqlLeaseMgr::getLeaseCollection(PgSqlLeaseContextPtr& ctx,
1494  StatementIndex stindex,
1495  PsqlBindArray& bind_array,
1496  Exchange& exchange,
1497  LeaseCollection& result,
1498  bool single) const {
1499  const int n = tagged_statements[stindex].nbparams;
1500  PgSqlResult r(PQexecPrepared(ctx->conn_,
1501  tagged_statements[stindex].name, n,
1502  n > 0 ? &bind_array.values_[0] : NULL,
1503  n > 0 ? &bind_array.lengths_[0] : NULL,
1504  n > 0 ? &bind_array.formats_[0] : NULL, 0));
1505 
1506  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
1507 
1508  int rows = PQntuples(r);
1509  if (single && rows > 1) {
1510  isc_throw(MultipleRecords, "multiple records were found in the "
1511  "database where only one was expected for query "
1512  << tagged_statements[stindex].name);
1513  }
1514 
1515  for(int i = 0; i < rows; ++ i) {
1516  result.push_back(exchange->convertFromDatabase(r, i));
1517  }
1518 }
1519 
1520 void
1521 PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr& ctx,
1522  StatementIndex stindex, PsqlBindArray& bind_array,
1523  Lease4Ptr& result) const {
1524  // Create appropriate collection object and get all leases matching
1525  // the selection criteria. The "single" parameter is true to indicate
1526  // that the called method should throw an exception if multiple
1527  // matching records are found: this particular method is called when only
1528  // one or zero matches is expected.
1529  Lease4Collection collection;
1530  getLeaseCollection(ctx, stindex, bind_array, ctx->exchange4_,
1531  collection, true);
1532 
1533  // Return single record if present, else clear the lease.
1534  if (collection.empty()) {
1535  result.reset();
1536  } else {
1537  result = *collection.begin();
1538  }
1539 }
1540 
1541 void
1542 PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr& ctx,
1543  StatementIndex stindex, PsqlBindArray& bind_array,
1544  Lease6Ptr& result) const {
1545  // Create appropriate collection object and get all leases matching
1546  // the selection criteria. The "single" parameter is true to indicate
1547  // that the called method should throw an exception if multiple
1548  // matching records are found: this particular method is called when only
1549  // one or zero matches is expected.
1550  Lease6Collection collection;
1551  getLeaseCollection(ctx, stindex, bind_array, ctx->exchange6_,
1552  collection, true);
1553 
1554  // Return single record if present, else clear the lease.
1555  if (collection.empty()) {
1556  result.reset();
1557  } else {
1558  result = *collection.begin();
1559  }
1560 }
1561 
1562 Lease4Ptr
1565  .arg(addr.toText());
1566 
1567  // Set up the WHERE clause value
1568  PsqlBindArray bind_array;
1569 
1570  // LEASE ADDRESS
1571  std::string addr_str = boost::lexical_cast<std::string>(addr.toUint32());
1572  bind_array.add(addr_str);
1573 
1574  // Get the data
1575  Lease4Ptr result;
1576 
1577  // Get a context
1578  PgSqlLeaseContextAlloc get_context(*this);
1579  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1580 
1581  getLease(ctx, GET_LEASE4_ADDR, bind_array, result);
1582 
1583  return (result);
1584 }
1585 
1587 PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
1589  .arg(hwaddr.toText());
1590 
1591  // Set up the WHERE clause value
1592  PsqlBindArray bind_array;
1593 
1594  // HWADDR
1595  if (!hwaddr.hwaddr_.empty()) {
1596  bind_array.add(hwaddr.hwaddr_);
1597  } else {
1598  bind_array.add("");
1599  }
1600 
1601  // Get the data
1602  Lease4Collection result;
1603 
1604  // Get a context
1605  PgSqlLeaseContextAlloc get_context(*this);
1606  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1607 
1608  getLeaseCollection(ctx, GET_LEASE4_HWADDR, bind_array, result);
1609 
1610  return (result);
1611 }
1612 
1613 Lease4Ptr
1614 PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
1616  .arg(subnet_id)
1617  .arg(hwaddr.toText());
1618 
1619  // Set up the WHERE clause value
1620  PsqlBindArray bind_array;
1621 
1622  // HWADDR
1623  if (!hwaddr.hwaddr_.empty()) {
1624  bind_array.add(hwaddr.hwaddr_);
1625  } else {
1626  bind_array.add("");
1627  }
1628 
1629  // SUBNET_ID
1630  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1631  bind_array.add(subnet_id_str);
1632 
1633  // Get the data
1634  Lease4Ptr result;
1635 
1636  // Get a context
1637  PgSqlLeaseContextAlloc get_context(*this);
1638  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1639 
1640  getLease(ctx, GET_LEASE4_HWADDR_SUBID, bind_array, result);
1641 
1642  return (result);
1643 }
1644 
1646 PgSqlLeaseMgr::getLease4(const ClientId& clientid) const {
1648  .arg(clientid.toText());
1649 
1650  // Set up the WHERE clause value
1651  PsqlBindArray bind_array;
1652 
1653  // CLIENT_ID
1654  bind_array.add(clientid.getClientId());
1655 
1656  // Get the data
1657  Lease4Collection result;
1658 
1659  // Get a context
1660  PgSqlLeaseContextAlloc get_context(*this);
1661  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1662 
1663  getLeaseCollection(ctx, GET_LEASE4_CLIENTID, bind_array, result);
1664 
1665  return (result);
1666 }
1667 
1668 Lease4Ptr
1669 PgSqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
1671  .arg(subnet_id)
1672  .arg(clientid.toText());
1673 
1674  // Set up the WHERE clause value
1675  PsqlBindArray bind_array;
1676 
1677  // CLIENT_ID
1678  bind_array.add(clientid.getClientId());
1679 
1680  // SUBNET_ID
1681  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1682  bind_array.add(subnet_id_str);
1683 
1684  // Get the data
1685  Lease4Ptr result;
1686 
1687  // Get a context
1688  PgSqlLeaseContextAlloc get_context(*this);
1689  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1690 
1691  getLease(ctx, GET_LEASE4_CLIENTID_SUBID, bind_array, result);
1692 
1693  return (result);
1694 }
1695 
1699  .arg(subnet_id);
1700 
1701  // Set up the WHERE clause value
1702  PsqlBindArray bind_array;
1703 
1704  // SUBNET_ID
1705  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1706  bind_array.add(subnet_id_str);
1707 
1708  // ... and get the data
1709  Lease4Collection result;
1710 
1711  // Get a context
1712  PgSqlLeaseContextAlloc get_context(*this);
1713  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1714 
1715  getLeaseCollection(ctx, GET_LEASE4_SUBID, bind_array, result);
1716 
1717  return (result);
1718 }
1719 
1721 PgSqlLeaseMgr::getLeases4(const std::string& hostname) const {
1723  .arg(hostname);
1724 
1725  // Set up the WHERE clause value
1726  PsqlBindArray bind_array;
1727 
1728  // Hostname
1729  bind_array.add(hostname);
1730 
1731  // ... and get the data
1732  Lease4Collection result;
1733 
1734  // Get a context
1735  PgSqlLeaseContextAlloc get_context(*this);
1736  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1737 
1738  getLeaseCollection(ctx, GET_LEASE4_HOSTNAME, bind_array, result);
1739 
1740  return (result);
1741 }
1742 
1746 
1747  // Provide empty binding array because our query has no parameters in
1748  // WHERE clause.
1749  PsqlBindArray bind_array;
1750  Lease4Collection result;
1751 
1752  // Get a context
1753  PgSqlLeaseContextAlloc get_context(*this);
1754  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1755 
1756  getLeaseCollection(ctx, GET_LEASE4, bind_array, result);
1757 
1758  return (result);
1759 }
1760 
1762 PgSqlLeaseMgr::getLeases4(const IOAddress& lower_bound_address,
1763  const LeasePageSize& page_size) const {
1764  // Expecting IPv4 address.
1765  if (!lower_bound_address.isV4()) {
1766  isc_throw(InvalidAddressFamily, "expected IPv4 address while "
1767  "retrieving leases from the lease database, got "
1768  << lower_bound_address);
1769  }
1770 
1772  .arg(page_size.page_size_)
1773  .arg(lower_bound_address.toText());
1774 
1775  // Prepare WHERE clause
1776  PsqlBindArray bind_array;
1777 
1778  // Bind lower bound address
1779  std::string lb_address_data = boost::lexical_cast<std::string>(lower_bound_address.toUint32());
1780  bind_array.add(lb_address_data);
1781 
1782  // Bind page size value
1783  std::string page_size_data = boost::lexical_cast<std::string>(page_size.page_size_);
1784  bind_array.add(page_size_data);
1785 
1786  // Get the leases
1787  Lease4Collection result;
1788 
1789  // Get a context
1790  PgSqlLeaseContextAlloc get_context(*this);
1791  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1792 
1793  getLeaseCollection(ctx, GET_LEASE4_PAGE, bind_array, result);
1794 
1795  return (result);
1796 }
1797 
1798 Lease6Ptr
1800  const IOAddress& addr) const {
1802  .arg(addr.toText())
1803  .arg(lease_type);
1804 
1805  // Set up the WHERE clause value
1806  PsqlBindArray bind_array;
1807 
1808  // LEASE ADDRESS
1809  std::string addr_str = addr.toText();
1810  bind_array.add(addr_str);
1811 
1812  // LEASE_TYPE
1813  std::string type_str_ = boost::lexical_cast<std::string>(lease_type);
1814  bind_array.add(type_str_);
1815 
1816  // ... and get the data
1817  Lease6Ptr result;
1818 
1819  // Get a context
1820  PgSqlLeaseContextAlloc get_context(*this);
1821  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1822 
1823  getLease(ctx, GET_LEASE6_ADDR, bind_array, result);
1824 
1825  return (result);
1826 }
1827 
1830  uint32_t iaid) const {
1832  .arg(iaid)
1833  .arg(duid.toText())
1834  .arg(lease_type);
1835 
1836  // Set up the WHERE clause value
1837  PsqlBindArray bind_array;
1838 
1839  // DUID
1840  bind_array.add(duid.getDuid());
1841 
1842  // IAID
1843  std::string iaid_str = PgSqlLease6Exchange::Uiaid(iaid).dbInputString();
1844  bind_array.add(iaid_str);
1845 
1846  // LEASE_TYPE
1847  std::string lease_type_str = boost::lexical_cast<std::string>(lease_type);
1848  bind_array.add(lease_type_str);
1849 
1850  // ... and get the data
1851  Lease6Collection result;
1852 
1853  // Get a context
1854  PgSqlLeaseContextAlloc get_context(*this);
1855  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1856 
1857  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID, bind_array, result);
1858 
1859  return (result);
1860 }
1861 
1864  uint32_t iaid, SubnetID subnet_id) const {
1866  .arg(iaid)
1867  .arg(subnet_id)
1868  .arg(duid.toText())
1869  .arg(lease_type);
1870 
1871  // Set up the WHERE clause value
1872  PsqlBindArray bind_array;
1873 
1874  // LEASE_TYPE
1875  std::string lease_type_str = boost::lexical_cast<std::string>(lease_type);
1876  bind_array.add(lease_type_str);
1877 
1878  // DUID
1879  bind_array.add(duid.getDuid());
1880 
1881  // IAID
1882  std::string iaid_str = PgSqlLease6Exchange::Uiaid(iaid).dbInputString();
1883  bind_array.add(iaid_str);
1884 
1885  // SUBNET ID
1886  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1887  bind_array.add(subnet_id_str);
1888 
1889  // ... and get the data
1890  Lease6Collection result;
1891 
1892  // Get a context
1893  PgSqlLeaseContextAlloc get_context(*this);
1894  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1895 
1896  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID_SUBID, bind_array, result);
1897 
1898  return (result);
1899 }
1900 
1904  .arg(subnet_id);
1905 
1906  // Set up the WHERE clause value
1907  PsqlBindArray bind_array;
1908 
1909  // SUBNET_ID
1910  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1911  bind_array.add(subnet_id_str);
1912 
1913  // ... and get the data
1914  Lease6Collection result;
1915 
1916  // Get a context
1917  PgSqlLeaseContextAlloc get_context(*this);
1918  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1919 
1920  getLeaseCollection(ctx, GET_LEASE6_SUBID, bind_array, result);
1921 
1922  return (result);
1923 }
1924 
1926 PgSqlLeaseMgr::getLeases6(const DUID& duid) const {
1928  .arg(duid.toText());
1929 
1930  // Set up the WHERE clause value
1931  PsqlBindArray bind_array;
1932 
1933  // DUID
1934  bind_array.add(duid.getDuid());
1935  Lease6Collection result;
1936 
1937  // Get a context
1938  PgSqlLeaseContextAlloc get_context(*this);
1939  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1940 
1941  // query to fetch the data
1942  getLeaseCollection(ctx, GET_LEASE6_DUID, bind_array, result);
1943 
1944  return (result);
1945 }
1946 
1948 PgSqlLeaseMgr::getLeases6(const std::string& hostname) const {
1950  .arg(hostname);
1951 
1952  // Set up the WHERE clause value
1953  PsqlBindArray bind_array;
1954 
1955  // Hostname
1956  bind_array.add(hostname);
1957 
1958  // ... and get the data
1959  Lease6Collection result;
1960 
1961  // Get a context
1962  PgSqlLeaseContextAlloc get_context(*this);
1963  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1964 
1965  getLeaseCollection(ctx, GET_LEASE6_HOSTNAME, bind_array, result);
1966 
1967  return (result);
1968 }
1969 
1973 
1974  // Provide empty binding array because our query has no parameters in
1975  // WHERE clause.
1976  PsqlBindArray bind_array;
1977  Lease6Collection result;
1978 
1979  // Get a context
1980  PgSqlLeaseContextAlloc get_context(*this);
1981  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1982 
1983  getLeaseCollection(ctx, GET_LEASE6, bind_array, result);
1984 
1985  return (result);
1986 }
1987 
1989 PgSqlLeaseMgr::getLeases6(const IOAddress& lower_bound_address,
1990  const LeasePageSize& page_size) const {
1991  // Expecting IPv6 address.
1992  if (!lower_bound_address.isV6()) {
1993  isc_throw(InvalidAddressFamily, "expected IPv6 address while "
1994  "retrieving leases from the lease database, got "
1995  << lower_bound_address);
1996  }
1997 
1999  .arg(page_size.page_size_)
2000  .arg(lower_bound_address.toText());
2001 
2002  // Prepare WHERE clause
2003  PsqlBindArray bind_array;
2004 
2005  // In IPv6 we compare addresses represented as strings. The IPv6 zero address
2006  // is ::, so it is greater than any other address. In this special case, we
2007  // just use 0 for comparison which should be lower than any real IPv6 address.
2008  std::string lb_address_data = "0";
2009  if (!lower_bound_address.isV6Zero()) {
2010  lb_address_data = lower_bound_address.toText();
2011  }
2012 
2013  // Bind lower bound address
2014  bind_array.add(lb_address_data);
2015 
2016  // Bind page size value
2017  std::string page_size_data = boost::lexical_cast<std::string>(page_size.page_size_);
2018  bind_array.add(page_size_data);
2019 
2020  // Get the leases
2021  Lease6Collection result;
2022 
2023  // Get a context
2024  PgSqlLeaseContextAlloc get_context(*this);
2025  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2026 
2027  getLeaseCollection(ctx, GET_LEASE6_PAGE, bind_array, result);
2028 
2029  return (result);
2030 }
2031 
2032 void
2034  const size_t max_leases) const {
2036  .arg(max_leases);
2037  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE4_EXPIRE);
2038 }
2039 
2040 void
2042  const size_t max_leases) const {
2044  .arg(max_leases);
2045  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE6_EXPIRE);
2046 }
2047 
2048 template<typename LeaseCollection>
2049 void
2050 PgSqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases,
2051  const size_t max_leases,
2052  StatementIndex statement_index) const {
2053  PsqlBindArray bind_array;
2054 
2055  // Exclude reclaimed leases.
2056  std::string state_str = boost::lexical_cast<std::string>(Lease::STATE_EXPIRED_RECLAIMED);
2057  bind_array.add(state_str);
2058 
2059  // Expiration timestamp.
2060  std::string timestamp_str = PgSqlLeaseExchange::convertToDatabaseTime(time(0));
2061  bind_array.add(timestamp_str);
2062 
2063  // If the number of leases is 0, we will return all leases. This is
2064  // achieved by setting the limit to a very high value.
2065  uint32_t limit = max_leases > 0 ? static_cast<uint32_t>(max_leases) :
2066  std::numeric_limits<uint32_t>::max();
2067  std::string limit_str = boost::lexical_cast<std::string>(limit);
2068  bind_array.add(limit_str);
2069 
2070  // Get a context
2071  PgSqlLeaseContextAlloc get_context(*this);
2072  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2073 
2074  // Retrieve leases from the database.
2075  getLeaseCollection(ctx, statement_index, bind_array, expired_leases);
2076 }
2077 
2078 template<typename LeasePtr>
2079 void
2080 PgSqlLeaseMgr::updateLeaseCommon(PgSqlLeaseContextPtr& ctx,
2081  StatementIndex stindex,
2082  PsqlBindArray& bind_array,
2083  const LeasePtr& lease) {
2084  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2085  tagged_statements[stindex].nbparams,
2086  &bind_array.values_[0],
2087  &bind_array.lengths_[0],
2088  &bind_array.formats_[0], 0));
2089 
2090  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2091 
2092  int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
2093 
2094  // Check success case first as it is the most likely outcome.
2095  if (affected_rows == 1) {
2096  return;
2097  }
2098 
2099  // If no rows affected, lease doesn't exist.
2100  if (affected_rows == 0) {
2101  isc_throw(NoSuchLease, "unable to update lease for address " <<
2102  lease->addr_.toText() << " as it does not exist");
2103  }
2104 
2105  // Should not happen - primary key constraint should only have selected
2106  // one row.
2107  isc_throw(DbOperationError, "apparently updated more than one lease "
2108  "that had the address " << lease->addr_.toText());
2109 }
2110 
2111 void
2113  const StatementIndex stindex = UPDATE_LEASE4;
2114 
2116  .arg(lease->addr_.toText());
2117 
2118  // Get a context
2119  PgSqlLeaseContextAlloc get_context(*this);
2120  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2121 
2122  // Create the BIND array for the data being updated
2123  PsqlBindArray bind_array;
2124  ctx->exchange4_->createBindForSend(lease, bind_array);
2125 
2126  // Set up the WHERE clause and append it to the SQL_BIND array
2127  std::string addr4_str = boost::lexical_cast<std::string>(lease->addr_.toUint32());
2128  bind_array.add(addr4_str);
2129 
2130  std::string expire_str;
2131  // Avoid overflow (see createBindForSend)
2132  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2133  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2134  } else {
2135  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2136  lease->current_valid_lft_);
2137  }
2138  bind_array.add(expire_str);
2139 
2140  // Drop to common update code
2141  updateLeaseCommon(ctx, stindex, bind_array, lease);
2142 
2143  // Update lease current expiration time.
2144  lease->updateCurrentExpirationTime();
2145 }
2146 
2147 void
2149  const StatementIndex stindex = UPDATE_LEASE6;
2150 
2152  .arg(lease->addr_.toText())
2153  .arg(lease->type_);
2154 
2155  // Get a context
2156  PgSqlLeaseContextAlloc get_context(*this);
2157  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2158 
2159  // Create the BIND array for the data being updated
2160  PsqlBindArray bind_array;
2161  ctx->exchange6_->createBindForSend(lease, bind_array);
2162 
2163  // Set up the WHERE clause and append it to the BIND array
2164  std::string addr_str = lease->addr_.toText();
2165  bind_array.add(addr_str);
2166 
2167  std::string expire_str;
2168  // Avoid overflow (see createBindForSend)
2169  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2170  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2171  } else {
2172  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2173  lease->current_valid_lft_);
2174  }
2175  bind_array.add(expire_str);
2176 
2177  // Drop to common update code
2178  updateLeaseCommon(ctx, stindex, bind_array, lease);
2179 
2180  // Update lease current expiration time.
2181  lease->updateCurrentExpirationTime();
2182 }
2183 
2184 uint64_t
2185 PgSqlLeaseMgr::deleteLeaseCommon(StatementIndex stindex,
2186  PsqlBindArray& bind_array) {
2187  // Get a context
2188  PgSqlLeaseContextAlloc get_context(*this);
2189  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2190 
2191  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2192  tagged_statements[stindex].nbparams,
2193  &bind_array.values_[0],
2194  &bind_array.lengths_[0],
2195  &bind_array.formats_[0], 0));
2196 
2197  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2198  int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
2199 
2200  return (affected_rows);
2201 }
2202 
2203 bool
2205  const IOAddress& addr = lease->addr_;
2207  .arg(addr.toText());
2208 
2209  // Set up the WHERE clause value
2210  PsqlBindArray bind_array;
2211 
2212  std::string addr4_str = boost::lexical_cast<std::string>(addr.toUint32());
2213  bind_array.add(addr4_str);
2214 
2215  std::string expire_str;
2216  // Avoid overflow (see createBindForSend)
2217  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2218  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2219  } else {
2220  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2221  lease->current_valid_lft_);
2222  }
2223  bind_array.add(expire_str);
2224 
2225  auto affected_rows = deleteLeaseCommon(DELETE_LEASE4, bind_array);
2226 
2227  // Check success case first as it is the most likely outcome.
2228  if (affected_rows == 1) {
2229  return (true);
2230  }
2231 
2232  // If no rows affected, lease doesn't exist.
2233  if (affected_rows == 0) {
2234  return (false);
2235  }
2236 
2237  // Should not happen - primary key constraint should only have selected
2238  // one row.
2239  isc_throw(DbOperationError, "apparently deleted more than one lease "
2240  "that had the address " << lease->addr_.toText());
2241 }
2242 
2243 bool
2245  const IOAddress& addr = lease->addr_;
2248  .arg(addr.toText());
2249 
2250  // Set up the WHERE clause value
2251  PsqlBindArray bind_array;
2252 
2253  std::string addr6_str = addr.toText();
2254  bind_array.add(addr6_str);
2255 
2256  std::string expire_str;
2257  // Avoid overflow (see createBindForSend)
2258  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2259  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2260  } else {
2261  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2262  lease->current_valid_lft_);
2263  }
2264  bind_array.add(expire_str);
2265 
2266  auto affected_rows = deleteLeaseCommon(DELETE_LEASE6, bind_array);
2267 
2268  // Check success case first as it is the most likely outcome.
2269  if (affected_rows == 1) {
2270  return (true);
2271  }
2272 
2273  // If no rows affected, lease doesn't exist.
2274  if (affected_rows == 0) {
2275  return (false);
2276  }
2277 
2278  // Should not happen - primary key constraint should only have selected
2279  // one row.
2280  isc_throw(DbOperationError, "apparently deleted more than one lease "
2281  "that had the address " << lease->addr_.toText());
2282 }
2283 
2284 uint64_t
2287  .arg(secs);
2288  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
2289 }
2290 
2291 uint64_t
2294  .arg(secs);
2295  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
2296 }
2297 
2298 uint64_t
2299 PgSqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
2300  StatementIndex statement_index) {
2301  PsqlBindArray bind_array;
2302 
2303  // State is reclaimed.
2304  std::string state_str = boost::lexical_cast<std::string>(Lease::STATE_EXPIRED_RECLAIMED);
2305  bind_array.add(state_str);
2306 
2307  // Expiration timestamp.
2308  std::string expiration_str = PgSqlLeaseExchange::convertToDatabaseTime(time(0) -
2309  static_cast<time_t>(secs));
2310  bind_array.add(expiration_str);
2311 
2312  // Delete leases.
2313  return (deleteLeaseCommon(statement_index, bind_array));
2314 }
2315 
2316 string
2317 PgSqlLeaseMgr::checkLimits(ConstElementPtr const& user_context, StatementIndex const stindex) const {
2318  // No user context means no limits means allocation allowed means empty string.
2319  if (!user_context) {
2320  return string();
2321  }
2322 
2323  // Get a context.
2324  PgSqlLeaseContextAlloc get_context(*this);
2325  PgSqlLeaseContextPtr ctx(get_context.ctx_);
2326 
2327  // Create bindings.
2328  PsqlBindArray bind_array;
2329  std::string const user_context_str(user_context->str());
2330  bind_array.add(user_context_str);
2331 
2332  // Execute the select.
2333  PgSqlResult r(PQexecPrepared(ctx->conn_,
2334  tagged_statements[stindex].name,
2335  tagged_statements[stindex].nbparams,
2336  &bind_array.values_[0],
2337  &bind_array.lengths_[0],
2338  &bind_array.formats_[0], 0));
2339  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2340 
2341  std::string limits;
2342  PgSqlExchange::getColumnValue(r, 0, 0, limits);
2343  return limits;
2344 }
2345 
2346 string
2347 PgSqlLeaseMgr::checkLimits4(ConstElementPtr const& user_context) const {
2348  return checkLimits(user_context, CHECK_LEASE4_LIMITS);
2349 }
2350 
2351 string
2352 PgSqlLeaseMgr::checkLimits6(ConstElementPtr const& user_context) const {
2353  return checkLimits(user_context, CHECK_LEASE6_LIMITS);
2354 }
2355 
2356 bool
2357 PgSqlLeaseMgr::isJsonSupported() const {
2358  // Get a context.
2359  PgSqlLeaseContextAlloc get_context(*this);
2360  PgSqlLeaseContextPtr ctx(get_context.ctx_);
2361 
2362  // Execute the select.
2363  StatementIndex const stindex(IS_JSON_SUPPORTED);
2364  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2365  0, 0, 0, 0, 0));
2366  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2367 
2368  bool json_supported;
2369  PgSqlExchange::getColumnValue(r, 0, 0, json_supported);
2370  return json_supported;
2371 }
2372 
2373 size_t
2374 PgSqlLeaseMgr::getClassLeaseCount(const ClientClass& client_class,
2375  const Lease::Type& ltype /* = Lease::TYPE_V4*/) const {
2376  // Get a context.
2377  PgSqlLeaseContextAlloc get_context(*this);
2378  PgSqlLeaseContextPtr ctx(get_context.ctx_);
2379 
2380  // Create bindings.
2381  PsqlBindArray bind_array;
2382  bind_array.add(client_class);
2383  if (ltype != Lease::TYPE_V4) {
2384  bind_array.add(ltype);
2385  }
2386 
2387  // Execute the select.
2388  StatementIndex const stindex(ltype == Lease::TYPE_V4 ? GET_LEASE4_COUNT_BY_CLASS :
2390  PgSqlResult r(PQexecPrepared(ctx->conn_,
2391  tagged_statements[stindex].name,
2392  tagged_statements[stindex].nbparams,
2393  &bind_array.values_[0],
2394  &bind_array.lengths_[0],
2395  &bind_array.formats_[0], 0));
2396  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2397 
2398  int rows = PQntuples(r);
2399  if (rows == 0) {
2400  // No entries means 0 leases.
2401  return 0;
2402  }
2403 
2404  size_t count;
2405  PgSqlExchange::getColumnValue(r, 0, 0, count);
2406  return count;
2407 }
2408 
2409 void
2410 PgSqlLeaseMgr::recountClassLeases4() {
2411  isc_throw(NotImplemented, "PgSqlLeaseMgr::recountClassLeases4() not implemented");
2412 }
2413 
2414 void
2415 PgSqlLeaseMgr::recountClassLeases6() {
2416  isc_throw(NotImplemented, "PgSqlLeaseMgr::recountClassLeases6() not implemented");
2417 }
2418 
2419 void
2420 PgSqlLeaseMgr::clearClassLeaseCounts() {
2421  isc_throw(NotImplemented, "PgSqlLeaseMgr::clearClassLeaseCounts() not implemented");
2422 }
2423 
2424 void
2425 PgSqlLeaseMgr::writeLeases4(const std::string&) {
2426  isc_throw(NotImplemented, "PgSqlLeaseMgr::writeLeases4() not implemented");
2427 }
2428 
2429 void
2430 PgSqlLeaseMgr::writeLeases6(const std::string&) {
2431  isc_throw(NotImplemented, "PgSqlLeaseMgr::writeLeases6() not implemented");
2432 }
2433 
2436  // Get a context
2437  PgSqlLeaseContextAlloc get_context(*this);
2438  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2439 
2440  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2441  tagged_statements[ALL_LEASE4_STATS],
2442  false));
2443  query->start();
2444  return(query);
2445 }
2446 
2449  // Get a context
2450  PgSqlLeaseContextAlloc get_context(*this);
2451  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2452 
2453  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2454  tagged_statements[SUBNET_LEASE4_STATS],
2455  false,
2456  subnet_id));
2457  query->start();
2458  return(query);
2459 }
2460 
2463  const SubnetID& last_subnet_id) {
2464  // Get a context
2465  PgSqlLeaseContextAlloc get_context(*this);
2466  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2467 
2468  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2469  tagged_statements[SUBNET_RANGE_LEASE4_STATS],
2470  false,
2471  first_subnet_id,
2472  last_subnet_id));
2473  query->start();
2474  return(query);
2475 }
2476 
2479  // Get a context
2480  PgSqlLeaseContextAlloc get_context(*this);
2481  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2482 
2483  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2484  tagged_statements[ALL_LEASE6_STATS],
2485  true));
2486  query->start();
2487  return(query);
2488 }
2489 
2492  // Get a context
2493  PgSqlLeaseContextAlloc get_context(*this);
2494  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2495 
2496  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2497  tagged_statements[SUBNET_LEASE6_STATS],
2498  true,
2499  subnet_id));
2500  query->start();
2501  return(query);
2502 }
2503 
2506  const SubnetID& last_subnet_id) {
2507  // Get a context
2508  PgSqlLeaseContextAlloc get_context(*this);
2509  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2510 
2511  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2512  tagged_statements[SUBNET_RANGE_LEASE6_STATS],
2513  true,
2514  first_subnet_id,
2515  last_subnet_id));
2516  query->start();
2517  return(query);
2518 }
2519 
2520 size_t
2521 PgSqlLeaseMgr::wipeLeases4(const SubnetID& /*subnet_id*/) {
2522  isc_throw(NotImplemented, "wipeLeases4 is not implemented for PostgreSQL backend");
2523 }
2524 
2525 size_t
2526 PgSqlLeaseMgr::wipeLeases6(const SubnetID& /*subnet_id*/) {
2527  isc_throw(NotImplemented, "wipeLeases6 is not implemented for PostgreSQL backend");
2528 }
2529 
2530 std::string
2532  // Get a context
2533  PgSqlLeaseContextAlloc get_context(*this);
2534  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2535 
2536  std::string name = "";
2537  try {
2538  name = ctx->conn_.getParameter("name");
2539  } catch (...) {
2540  // Return an empty name
2541  }
2542  return (name);
2543 }
2544 
2545 std::string
2547  return (std::string("PostgreSQL Database"));
2548 }
2549 
2550 std::pair<uint32_t, uint32_t>
2553 
2554  return (PgSqlConnection::getVersion(parameters_));
2555 }
2556 
2557 void
2560 }
2561 
2562 void
2565 }
2566 
2567 void
2569  isc_throw(NotImplemented, "PgSqlLeaseMgr::deleteExtendedInfo6 not implemented");
2570 }
2571 
2572 void
2573 PgSqlLeaseMgr::addRelayId6(const IOAddress& /* lease_addr */,
2574  const vector<uint8_t>& /* relay_id */) {
2575  isc_throw(NotImplemented, "PgSqlLeaseMgr::addRelayId6 not implemented");
2576 }
2577 
2578 void
2579 PgSqlLeaseMgr::addRemoteId6(const IOAddress& /* lease_addr */,
2580  const vector<uint8_t>& /* remote_id */) {
2581  isc_throw(NotImplemented, "PgSqlLeaseMgr::addRemoteId6 not implemented");
2582 }
2583 
2585 PgSqlLeaseMgr::getLeases4ByRelayId(const OptionBuffer& /* relay_id */,
2586  const IOAddress& /* lower_bound_address */,
2587  const LeasePageSize& /* page_size */,
2588  const time_t& /* qry_start_time = 0 */,
2589  const time_t& /* qry_end_time = 0 */) {
2590  isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases4ByRelayId not implemented");
2591 }
2592 
2594 PgSqlLeaseMgr::getLeases4ByRemoteId(const OptionBuffer& /* remote_id */,
2595  const IOAddress& /* lower_bound_address */,
2596  const LeasePageSize& /* page_size */,
2597  const time_t& /* qry_start_time = 0 */,
2598  const time_t& /* qry_end_time = 0 */) {
2599  isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases4ByRemoteId not implemented");
2600 }
2601 
2603 PgSqlLeaseMgr::getLeases6ByRelayId(const DUID& /* relay_id */,
2604  const IOAddress& /* link_addr */,
2605  uint8_t /* link_len */,
2606  const IOAddress& /* lower_bound_address */,
2607  const LeasePageSize& /* page_size */) {
2608  isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases6ByRelayId not implemented");
2609 }
2610 
2612 PgSqlLeaseMgr::getLeases6ByRemoteId(const OptionBuffer& /* remote_id */,
2613  const IOAddress& /* link_addr */,
2614  uint8_t /* link_len */,
2615  const IOAddress& /* lower_bound_address */,
2616  const LeasePageSize& /* page_size*/) {
2617  isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases6ByRemoteId not implemented");
2618 }
2619 
2621 PgSqlLeaseMgr::getLeases6ByLink(const IOAddress& /* link_addr */,
2622  uint8_t /* link_len */,
2623  const IOAddress& /* lower_bound_address */,
2624  const LeasePageSize& /* page_size */) {
2625  isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases6ByLink not implemented");
2626 }
2627 
2628 size_t
2629 PgSqlLeaseMgr::buildExtendedInfoTables6(bool /* update */, bool /* current */) {
2631  "PgSqlLeaseMgr::buildExtendedInfoTables6 not implemented");
2632 }
2633 
2634 } // namespace dhcp
2635 } // 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:210
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.
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.
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.
virtual void setExtendedInfoTablesEnabled(const bool enabled)
Extended information / Bulk Lease Query shared interface.
Definition: lease_mgr.h:983
virtual void setExtendedInfoTablesEnabled(const bool enabled) override
Extended information / Bulk Lease Query shared interface.
virtual void deleteExtendedInfo6(const isc::asiolink::IOAddress &addr) override
Delete lease6 extended info from tables.
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:514
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:131
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:793
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:56
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:294
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:117
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:530
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:677
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:121
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:123
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:64
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:46
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:119
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:519
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:25
bool fetch_type_
Indicates if query supplies lease type.
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 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.