Kea  2.1.7-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  // TODO: remove single quotes from the following two SELECTs when the functions are implemented
363 
364  // CHECK_LEASE4_LIMITS
365  { 1, { OID_TEXT },
366  "check_lease4_limits",
367  "SELECT 'checkLease4Limits($1)'" },
368 
369  // CHECK_LEASE6_LIMITS
370  { 1, { OID_TEXT },
371  "check_lease6_limits",
372  "SELECT 'checkLease6Limits($1)'" },
373 
374  // End of list sentinel
375  { 0, { 0 }, NULL, NULL}
376 };
377 
378 } // namespace
379 
380 namespace isc {
381 namespace dhcp {
382 
389 public:
390 
392  : addr_str_(""), hwaddr_length_(0), hwaddr_(hwaddr_length_),
393  valid_lifetime_(0), valid_lifetime_str_(""), expire_(0),
394  expire_str_(""), subnet_id_(0), subnet_id_str_(""), cltt_(0),
395  fqdn_fwd_(false), fqdn_rev_(false), hostname_(""), state_str_(""),
396  user_context_("") {
397  }
398 
400 
401 protected:
402 
404 
405  std::string addr_str_;
407  std::vector<uint8_t> hwaddr_;
408  uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
409  uint32_t valid_lifetime_;
410  std::string valid_lifetime_str_;
411  time_t expire_;
412  std::string expire_str_;
413  uint32_t subnet_id_;
414  std::string subnet_id_str_;
415  time_t cltt_;
416  bool fqdn_fwd_;
417  bool fqdn_rev_;
418  std::string hostname_;
419  std::string state_str_;
420  std::string user_context_;
422 };
423 
426 private:
427 
432  static const size_t ADDRESS_COL = 0;
433  static const size_t HWADDR_COL = 1;
434  static const size_t CLIENT_ID_COL = 2;
435  static const size_t VALID_LIFETIME_COL = 3;
436  static const size_t EXPIRE_COL = 4;
437  static const size_t SUBNET_ID_COL = 5;
438  static const size_t FQDN_FWD_COL = 6;
439  static const size_t FQDN_REV_COL = 7;
440  static const size_t HOSTNAME_COL = 8;
441  static const size_t STATE_COL = 9;
442  static const size_t USER_CONTEXT_COL = 10;
444  static const size_t LEASE_COLUMNS = 11;
445 
446 public:
447 
450  : lease_(), addr4_(0), client_id_length_(0) {
451 
452  BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
453 
454  memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
455  memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
456 
457  // Set the column names (for error messages)
458  columns_.push_back("address");
459  columns_.push_back("hwaddr");
460  columns_.push_back("client_id");
461  columns_.push_back("valid_lifetime");
462  columns_.push_back("expire");
463  columns_.push_back("subnet_id");
464  columns_.push_back("fqdn_fwd");
465  columns_.push_back("fqdn_rev");
466  columns_.push_back("hostname");
467  columns_.push_back("state");
468  columns_.push_back("user_context");
469  }
470 
483  void createBindForSend(const Lease4Ptr& lease, PsqlBindArray& bind_array) {
484  if (!lease) {
485  isc_throw(BadValue, "createBindForSend:: Lease4 object is NULL");
486  }
487 
488  // Store lease object to ensure it remains valid.
489  lease_ = lease;
490 
491  try {
492  addr_str_ = boost::lexical_cast<std::string>(lease->addr_.toUint32());
493  bind_array.add(addr_str_);
494 
495  if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) {
496  // PostgreSql does not provide MAX on variable length types
497  // so we have to enforce it ourselves.
498  if (lease->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
499  isc_throw(DbOperationError, "Hardware address length : "
500  << lease_->hwaddr_->hwaddr_.size()
501  << " exceeds maximum allowed of: "
502  << HWAddr::MAX_HWADDR_LEN);
503  }
504  bind_array.add(lease->hwaddr_->hwaddr_);
505  } else {
506  bind_array.add("");
507  }
508 
509  if (lease->client_id_) {
510  bind_array.add(lease->client_id_->getClientId());
511  } else {
512  bind_array.add("");
513  }
514 
515  valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
516  bind_array.add(valid_lifetime_str_);
517 
518  // The lease structure holds the client last transmission time (cltt_)
519  // For convenience for external tools, this is converted to lease
520  // expiry time (expire). The relationship is given by:
521  // expire = cltt_ + valid_lft_
522  // Avoid overflow with infinite valid lifetime by using
523  // expire = cltt_ when valid_lft_ = 0xffffffff
524  if (lease_->valid_lft_ == Lease::INFINITY_LFT) {
525  expire_str_ = convertToDatabaseTime(lease->cltt_, 0);
526  } else {
527  expire_str_ = convertToDatabaseTime(lease->cltt_,
528  lease_->valid_lft_);
529  }
530  bind_array.add(expire_str_);
531 
532  subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
533  bind_array.add(subnet_id_str_);
534 
535  bind_array.add(lease->fqdn_fwd_);
536 
537  bind_array.add(lease->fqdn_rev_);
538 
539  bind_array.add(lease->hostname_);
540 
541  state_str_ = boost::lexical_cast<std::string>(lease->state_);
542  bind_array.add(state_str_);
543 
544  ConstElementPtr ctx = lease->getContext();
545  if (ctx) {
546  user_context_ = ctx->str();
547  } else {
548  user_context_ = "";
549  }
550  bind_array.add(user_context_);
551  } catch (const std::exception& ex) {
553  "Could not create bind array from Lease4: "
554  << lease_->addr_.toText() << ", reason: " << ex.what());
555  }
556  }
557 
567  try {
568  getColumnValue(r, row, ADDRESS_COL, addr4_);
569 
570  convertFromBytea(r, row, HWADDR_COL, hwaddr_buffer_,
571  sizeof(hwaddr_buffer_), hwaddr_length_);
572 
573  convertFromBytea(r, row, CLIENT_ID_COL, client_id_buffer_,
574  sizeof(client_id_buffer_), client_id_length_);
575 
576  getColumnValue(r, row, VALID_LIFETIME_COL, valid_lifetime_);
577 
578  expire_ = convertFromDatabaseTime(getRawColumnValue(r, row,
579  EXPIRE_COL));
580 
581  getColumnValue(r, row , SUBNET_ID_COL, subnet_id_);
582 
583  // Recover from overflow (see createBindForSend)
584  if (valid_lifetime_ == Lease::INFINITY_LFT) {
585  cltt_ = expire_;
586  } else {
587  cltt_ = expire_ - valid_lifetime_;
588  }
589 
590  getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
591 
592  getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
593 
594  hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
595 
596  uint32_t state;
597  getColumnValue(r, row , STATE_COL, state);
598 
599  HWAddrPtr hwaddr(new HWAddr(hwaddr_buffer_, hwaddr_length_,
600  HTYPE_ETHER));
601 
602  user_context_ = getRawColumnValue(r, row, USER_CONTEXT_COL);
603  ConstElementPtr ctx;
604  if (!user_context_.empty()) {
605  ctx = Element::fromJSON(user_context_);
606  if (!ctx || (ctx->getType() != Element::map)) {
607  isc_throw(BadValue, "user context '" << user_context_
608  << "' is not a JSON map");
609  }
610  }
611 
612  Lease4Ptr result(boost::make_shared<Lease4>(addr4_, hwaddr,
613  client_id_buffer_,
614  client_id_length_,
615  valid_lifetime_, cltt_,
616  subnet_id_, fqdn_fwd_,
617  fqdn_rev_, hostname_));
618 
619  result->state_ = state;
620 
621  if (ctx) {
622  result->setContext(ctx);
623  }
624 
625  return (result);
626  } catch (const std::exception& ex) {
628  "Could not convert data to Lease4, reason: "
629  << ex.what());
630  }
631  }
632 
633 private:
634 
638  Lease4Ptr lease_;
639 
641  uint32_t addr4_;
642  size_t client_id_length_;
643  uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
644 };
645 
648 private:
649 
654 
655  static const int ADDRESS_COL = 0;
656  static const int DUID_COL = 1;
657  static const int VALID_LIFETIME_COL = 2;
658  static const int EXPIRE_COL = 3;
659  static const int SUBNET_ID_COL = 4;
660  static const int PREF_LIFETIME_COL = 5;
661  static const int LEASE_TYPE_COL = 6;
662  static const int IAID_COL = 7;
663  static const int PREFIX_LEN_COL = 8;
664  static const int FQDN_FWD_COL = 9;
665  static const int FQDN_REV_COL = 10;
666  static const int HOSTNAME_COL = 11;
667  static const int HWADDR_COL = 12;
668  static const int HWTYPE_COL = 13;
669  static const int HWADDR_SOURCE_COL = 14;
670  static const int STATE_COL = 15;
671  static const size_t USER_CONTEXT_COL = 16;
673  static const size_t LEASE_COLUMNS = 17;
675 
676 public:
677 
684  union Uiaid {
687  Uiaid(uint32_t val) : uval_(val){};
688 
691  Uiaid(int32_t val) : ival_(val){};
692 
694  std::string dbInputString() {
695  return (boost::lexical_cast<std::string>(ival_));
696  };
697 
698  uint32_t uval_;
699  int32_t ival_;
700  };
701 
703  : lease_(), duid_length_(0), duid_(duid_length_), iaid_u_(0),
704  iaid_str_(""), lease_type_(Lease6::TYPE_NA), lease_type_str_(""),
705  prefix_len_(0), prefix_len_str_(""), pref_lifetime_(0),
706  preferred_lifetime_str_(""), hwtype_(0), hwtype_str_(""),
707  hwaddr_source_(0), hwaddr_source_str_("") {
708 
709  BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
710 
711  memset(duid_buffer_, 0, sizeof(duid_buffer_));
712 
713  // Set the column names (for error messages)
714  columns_.push_back("address");
715  columns_.push_back("duid");
716  columns_.push_back("valid_lifetime");
717  columns_.push_back("expire");
718  columns_.push_back("subnet_id");
719  columns_.push_back("pref_lifetime");
720  columns_.push_back("lease_type");
721  columns_.push_back("iaid");
722  columns_.push_back("prefix_len");
723  columns_.push_back("fqdn_fwd");
724  columns_.push_back("fqdn_rev");
725  columns_.push_back("hostname");
726  columns_.push_back("hwaddr");
727  columns_.push_back("hwtype");
728  columns_.push_back("hwaddr_source");
729  columns_.push_back("state");
730  columns_.push_back("user_context");
731  }
732 
745  void createBindForSend(const Lease6Ptr& lease, PsqlBindArray& bind_array) {
746  if (!lease) {
747  isc_throw(BadValue, "createBindForSend:: Lease6 object is NULL");
748  }
749 
750  // Store lease object to ensure it remains valid.
751  lease_ = lease;
752  try {
753  addr_str_ = lease_->addr_.toText();
754  bind_array.add(addr_str_);
755 
756  if (lease_->duid_) {
757  bind_array.add(lease_->duid_->getDuid());
758  } else {
759  isc_throw (BadValue, "IPv6 Lease cannot have a null DUID");
760  }
761 
762  valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
763  bind_array.add(valid_lifetime_str_);
764 
765  // The lease structure holds the client last transmission time (cltt_)
766  // For convenience for external tools, this is converted to lease
767  // expiry time (expire). The relationship is given by:
768  // expire = cltt_ + valid_lft_
769  // Avoid overflow with infinite valid lifetime by using
770  // expire = cltt_ when valid_lft_ = 0xffffffff
771  if (lease_->valid_lft_ == Lease::INFINITY_LFT) {
772  expire_str_ = convertToDatabaseTime(lease->cltt_, 0);
773  } else {
774  expire_str_ = convertToDatabaseTime(lease->cltt_,
775  lease_->valid_lft_);
776  }
777  bind_array.add(expire_str_);
778 
779  subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
780  bind_array.add(subnet_id_str_);
781 
782  preferred_lifetime_str_ = boost::lexical_cast<std::string>(lease_->preferred_lft_);
783  bind_array.add(preferred_lifetime_str_);
784 
785  lease_type_str_ = boost::lexical_cast<std::string>(lease_->type_);
786  bind_array.add(lease_type_str_);
787 
788  // The iaid is stored as an INT in lease6 table, so we must
789  // lexically cast from an integer version to avoid out of range
790  // exception failure upon insert.
791  iaid_u_.uval_ = lease_->iaid_;
792  iaid_str_ = iaid_u_.dbInputString();
793  bind_array.add(iaid_str_);
794 
795  prefix_len_str_ = boost::lexical_cast<std::string>
796  (static_cast<unsigned int>(lease_->prefixlen_));
797  bind_array.add(prefix_len_str_);
798 
799  bind_array.add(lease->fqdn_fwd_);
800 
801  bind_array.add(lease->fqdn_rev_);
802 
803  bind_array.add(lease->hostname_);
804 
805  if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) {
806  // PostgreSql does not provide MAX on variable length types
807  // so we have to enforce it ourselves.
808  if (lease->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
809  isc_throw(DbOperationError, "Hardware address length : "
810  << lease_->hwaddr_->hwaddr_.size()
811  << " exceeds maximum allowed of: "
812  << HWAddr::MAX_HWADDR_LEN);
813  }
814  bind_array.add(lease->hwaddr_->hwaddr_);
815  } else {
816  bind_array.add("");
817  }
818 
819  if (lease->hwaddr_) {
820  hwtype_str_ = boost::lexical_cast<std::string>
821  (static_cast<unsigned int>(lease_->hwaddr_->htype_));
822  hwaddr_source_str_ = boost::lexical_cast<std::string>
823  (static_cast<unsigned int>(lease_->hwaddr_->source_));
824  } else {
825  hwtype_str_ = boost::lexical_cast<std::string>
826  (static_cast<unsigned int>(HTYPE_UNDEFINED));
827  hwaddr_source_str_ = boost::lexical_cast<std::string>
828  (static_cast<unsigned int>(HWAddr::HWADDR_SOURCE_UNKNOWN));
829  }
830 
831  bind_array.add(hwtype_str_);
832 
833  bind_array.add(hwaddr_source_str_);
834 
835  state_str_ = boost::lexical_cast<std::string>(lease->state_);
836  bind_array.add(state_str_);
837 
838  ConstElementPtr ctx = lease->getContext();
839  if (ctx) {
840  user_context_ = ctx->str();
841  } else {
842  user_context_ = "";
843  }
844  bind_array.add(user_context_);
845  } catch (const std::exception& ex) {
847  "Could not create bind array from Lease6: "
848  << lease_->addr_.toText() << ", reason: " << ex.what());
849  }
850  }
851 
861  try {
862 
870 
871  IOAddress addr(getIPv6Value(r, row, ADDRESS_COL));
872 
873  convertFromBytea(r, row, DUID_COL, duid_buffer_, sizeof(duid_buffer_), duid_length_);
874  DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_));
875 
876  getColumnValue(r, row, VALID_LIFETIME_COL, valid_lifetime_);
877 
878  expire_ = convertFromDatabaseTime(getRawColumnValue(r, row,
879  EXPIRE_COL));
880 
881  // Recover from overflow (see createBindForSend)
882  if (valid_lifetime_ == Lease::INFINITY_LFT) {
883  cltt_ = expire_;
884  } else {
885  cltt_ = expire_ - valid_lifetime_;
886  }
887 
888  getColumnValue(r, row , SUBNET_ID_COL, subnet_id_);
889 
890  getColumnValue(r, row , PREF_LIFETIME_COL, pref_lifetime_);
891 
892  getLeaseTypeColumnValue(r, row, LEASE_TYPE_COL, lease_type_);
893 
894  getColumnValue(r, row , IAID_COL, iaid_u_.ival_);
895 
896  getColumnValue(r, row , PREFIX_LEN_COL, prefix_len_);
897 
898  getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
899 
900  getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
901 
902  hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
903 
904  convertFromBytea(r, row, HWADDR_COL, hwaddr_buffer_,
905  sizeof(hwaddr_buffer_), hwaddr_length_);
906 
907  getColumnValue(r, row , HWTYPE_COL, hwtype_);
908 
909  getColumnValue(r, row , HWADDR_SOURCE_COL, hwaddr_source_);
910 
911  HWAddrPtr hwaddr;
912 
913  if (hwaddr_length_) {
914  hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_,
915  hwtype_));
916 
917  hwaddr->source_ = hwaddr_source_;
918  }
919 
920  uint32_t state;
921  getColumnValue(r, row , STATE_COL, state);
922 
923  user_context_ = getRawColumnValue(r, row, USER_CONTEXT_COL);
924  ConstElementPtr ctx;
925  if (!user_context_.empty()) {
926  ctx = Element::fromJSON(user_context_);
927  if (!ctx || (ctx->getType() != Element::map)) {
928  isc_throw(BadValue, "user context '" << user_context_
929  << "' is not a JSON map");
930  }
931  }
932 
933  Lease6Ptr result(boost::make_shared<Lease6>(lease_type_, addr,
934  duid_ptr,
935  iaid_u_.uval_,
936  pref_lifetime_,
937  valid_lifetime_,
938  subnet_id_, fqdn_fwd_,
939  fqdn_rev_, hostname_,
940  hwaddr, prefix_len_));
941  // Update cltt_ and current_cltt_ explicitly.
942  result->cltt_ = cltt_;
943  result->current_cltt_ = cltt_;
944 
945  result->state_ = state;
946 
947  if (ctx) {
948  result->setContext(ctx);
949  }
950 
951  return (result);
952  } catch (const std::exception& ex) {
954  "Could not convert data to Lease6, reason: "
955  << ex.what());
956  }
957  }
958 
971  void getLeaseTypeColumnValue(const PgSqlResult& r, const int row,
972  const size_t col, Lease6::Type& value) const {
973  uint32_t raw_value = 0;
974  getColumnValue(r, row , col, raw_value);
975  switch (raw_value) {
976  case Lease6::TYPE_NA:
977  case Lease6::TYPE_TA:
978  case Lease6::TYPE_PD:
979  value = static_cast<Lease6::Type>(raw_value);
980  break;
981 
982  default:
983  isc_throw(DbOperationError, "Invalid lease type: " << raw_value
984  << " for: " << getColumnLabel(r, col) << " row:" << row);
985  }
986  }
987 
988 private:
992  Lease6Ptr lease_;
993 
995 
996  size_t duid_length_;
997  std::vector<uint8_t> duid_;
998  uint8_t duid_buffer_[DUID::MAX_DUID_LEN];
999  union Uiaid iaid_u_;
1000  std::string iaid_str_;
1001  Lease6::Type lease_type_;
1002  std::string lease_type_str_;
1003  uint8_t prefix_len_;
1004  std::string prefix_len_str_;
1005  uint32_t pref_lifetime_;
1006  std::string preferred_lifetime_str_;
1007  uint32_t hwtype_;
1008  std::string hwtype_str_;
1009  uint32_t hwaddr_source_;
1010  std::string hwaddr_source_str_;
1012 };
1013 
1020 public:
1021 
1031  const bool fetch_type)
1032  : conn_(conn), statement_(statement), result_set_(), next_row_(0),
1033  fetch_type_(fetch_type) {
1034  }
1035 
1045  const bool fetch_type, const SubnetID& subnet_id)
1046  : LeaseStatsQuery(subnet_id), conn_(conn), statement_(statement), result_set_(),
1047  next_row_(0), fetch_type_(fetch_type) {
1048  }
1049 
1061  const bool fetch_type, const SubnetID& first_subnet_id,
1062  const SubnetID& last_subnet_id)
1063  : LeaseStatsQuery(first_subnet_id, last_subnet_id), conn_(conn), statement_(statement),
1064  result_set_(), next_row_(0), fetch_type_(fetch_type) {
1065  }
1066 
1069 
1079  void start() {
1080 
1081  if (getSelectMode() == ALL_SUBNETS) {
1082  // Run the query with no where clause parameters.
1083  result_set_.reset(new PgSqlResult(PQexecPrepared(conn_, statement_.name,
1084  0, 0, 0, 0, 0)));
1085  } else {
1086  // Set up the WHERE clause values
1087  PsqlBindArray parms;
1088 
1089  // Add first_subnet_id used by both single and range.
1090  parms.addTempString(boost::lexical_cast<std::string>(getFirstSubnetID()));
1091 
1092  // Add last_subnet_id for range.
1093  if (getSelectMode() == SUBNET_RANGE) {
1094  // Add last_subnet_id used by range.
1095  parms.addTempString(boost::lexical_cast<std::string>(getLastSubnetID()));
1096  }
1097 
1098  // Run the query with where clause parameters.
1099  result_set_.reset(new PgSqlResult(PQexecPrepared(conn_, statement_.name,
1100  parms.size(), &parms.values_[0],
1101  &parms.lengths_[0], &parms.formats_[0], 0)));
1102  }
1103 
1104  conn_.checkStatementError(*result_set_, statement_);
1105  }
1106 
1122  // If we're past the end, punt.
1123  if (next_row_ >= result_set_->getRows()) {
1124  return (false);
1125  }
1126 
1127  // Fetch the subnet id.
1128  uint32_t col = 0;
1129  uint32_t subnet_id;
1130  PgSqlExchange::getColumnValue(*result_set_, next_row_, col, subnet_id);
1131  row.subnet_id_ = static_cast<SubnetID>(subnet_id);
1132  ++col;
1133 
1134  // Fetch the lease type if we were told to do so.
1135  if (fetch_type_) {
1136  uint32_t lease_type;
1137  PgSqlExchange::getColumnValue(*result_set_, next_row_ , col,
1138  lease_type);
1139  row.lease_type_ = static_cast<Lease::Type>(lease_type);
1140  ++col;
1141  } else {
1142  row.lease_type_ = Lease::TYPE_NA;
1143  }
1144 
1145  // Fetch the lease state.
1146  PgSqlExchange::getColumnValue(*result_set_, next_row_ , col,
1147  row.lease_state_);
1148  ++col;
1149 
1150  // Fetch the state count.
1151  PgSqlExchange::getColumnValue(*result_set_, next_row_, col,
1152  row.state_count_);
1153 
1154  // Protect against negative state count.a
1155  if (row.state_count_ < 0) {
1156  row.state_count_ = 0;
1157  if (!negative_count_) {
1158  negative_count_ = true;
1160  }
1161  }
1162 
1163  // Point to the next row.
1164  ++next_row_;
1165  return (true);
1166  }
1167 
1168 protected:
1169 
1172 
1175 
1177  boost::shared_ptr<PgSqlResult> result_set_;
1178 
1180  uint32_t next_row_;
1181 
1184 
1186  static bool negative_count_;
1187 };
1188 
1189 // Initialize negative state count flag to false.
1190 bool PgSqlLeaseStatsQuery::negative_count_ = false;
1191 
1192 // PgSqlLeaseContext Constructor
1193 
1194 PgSqlLeaseContext::PgSqlLeaseContext(const DatabaseConnection::ParameterMap& parameters,
1195  IOServiceAccessorPtr io_service_accessor,
1196  DbCallback db_reconnect_callback)
1197  : conn_(parameters, io_service_accessor, db_reconnect_callback) {
1198 }
1199 
1200 // PgSqlLeaseContextAlloc Constructor and Destructor
1201 
1202 PgSqlLeaseMgr::PgSqlLeaseContextAlloc::PgSqlLeaseContextAlloc(
1203  const PgSqlLeaseMgr& mgr) : ctx_(), mgr_(mgr) {
1204 
1205  if (MultiThreadingMgr::instance().getMode()) {
1206  // multi-threaded
1207  {
1208  // we need to protect the whole pool_ operation, hence extra scope {}
1209  lock_guard<mutex> lock(mgr_.pool_->mutex_);
1210  if (!mgr_.pool_->pool_.empty()) {
1211  ctx_ = mgr_.pool_->pool_.back();
1212  mgr_.pool_->pool_.pop_back();
1213  }
1214  }
1215  if (!ctx_) {
1216  ctx_ = mgr_.createContext();
1217  }
1218  } else {
1219  // single-threaded
1220  if (mgr_.pool_->pool_.empty()) {
1221  isc_throw(Unexpected, "No available PostgreSQL lease context?!");
1222  }
1223  ctx_ = mgr_.pool_->pool_.back();
1224  }
1225 }
1226 
1227 PgSqlLeaseMgr::PgSqlLeaseContextAlloc::~PgSqlLeaseContextAlloc() {
1228  if (MultiThreadingMgr::instance().getMode()) {
1229  // multi-threaded
1230  lock_guard<mutex> lock(mgr_.pool_->mutex_);
1231  mgr_.pool_->pool_.push_back(ctx_);
1232  }
1233  // If running in single-threaded mode, there's nothing to do here.
1234 }
1235 
1236 // PgSqlLeaseMgr Constructor and Destructor
1237 
1239  : parameters_(parameters), timer_name_("") {
1240 
1241  // Create unique timer name per instance.
1242  timer_name_ = "PgSqlLeaseMgr[";
1243  timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this));
1244  timer_name_ += "]DbReconnectTimer";
1245 
1246  // Check TLS support.
1247  size_t tls(0);
1248  tls += parameters.count("trust-anchor");
1249  tls += parameters.count("cert-file");
1250  tls += parameters.count("key-file");
1251  tls += parameters.count("cipher-list");
1252 #ifdef HAVE_PGSQL_SSL
1253  if ((tls > 0) && !PgSqlConnection::warned_about_tls) {
1256  .arg(DatabaseConnection::redactedAccessString(parameters_));
1257  PQinitSSL(1);
1258  }
1259 #else
1260  if (tls > 0) {
1262  .arg(DatabaseConnection::redactedAccessString(parameters_));
1263  isc_throw(DbOpenError, "Attempt to configure TLS for PostgreSQL "
1264  << "backend (built with this feature disabled)");
1265  }
1266 #endif
1267 
1268  // Validate schema version first.
1269  std::pair<uint32_t, uint32_t> code_version(PGSQL_SCHEMA_VERSION_MAJOR,
1271  std::pair<uint32_t, uint32_t> db_version = getVersion();
1272  if (code_version != db_version) {
1274  "PostgreSQL schema version mismatch: need version: "
1275  << code_version.first << "." << code_version.second
1276  << " found version: " << db_version.first << "."
1277  << db_version.second);
1278  }
1279 
1280  // Create an initial context.
1281  pool_.reset(new PgSqlLeaseContextPool());
1282  pool_->pool_.push_back(createContext());
1283 }
1284 
1286 }
1287 
1288 bool
1291 
1292  // Invoke application layer connection lost callback.
1293  if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) {
1294  return (false);
1295  }
1296 
1297  bool reopened = false;
1298 
1299  const std::string timer_name = db_reconnect_ctl->timerName();
1300 
1301  // At least one connection was lost.
1302  try {
1303  CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
1305  LeaseMgrFactory::create(cfg_db->getLeaseDbAccessString());
1306  reopened = true;
1307  } catch (const std::exception& ex) {
1309  .arg(ex.what());
1310  }
1311 
1312  if (reopened) {
1313  // Cancel the timer.
1314  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1315  TimerMgr::instance()->unregisterTimer(timer_name);
1316  }
1317 
1318  // Invoke application layer connection recovered callback.
1319  if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) {
1320  return (false);
1321  }
1322  } else {
1323  if (!db_reconnect_ctl->checkRetries()) {
1324  // We're out of retries, log it and initiate shutdown.
1326  .arg(db_reconnect_ctl->maxRetries());
1327 
1328  // Cancel the timer.
1329  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1330  TimerMgr::instance()->unregisterTimer(timer_name);
1331  }
1332 
1333  // Invoke application layer connection failed callback.
1335  return (false);
1336  }
1337 
1339  .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
1340  .arg(db_reconnect_ctl->maxRetries())
1341  .arg(db_reconnect_ctl->retryInterval());
1342 
1343  // Start the timer.
1344  if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
1345  TimerMgr::instance()->registerTimer(timer_name,
1346  std::bind(&PgSqlLeaseMgr::dbReconnect, db_reconnect_ctl),
1347  db_reconnect_ctl->retryInterval(),
1349  }
1350  TimerMgr::instance()->setup(timer_name);
1351  }
1352 
1353  return (true);
1354 }
1355 
1356 // Create context.
1357 
1360  PgSqlLeaseContextPtr ctx(new PgSqlLeaseContext(parameters_,
1363 
1364  // Open the database.
1365  ctx->conn_.openDatabase();
1366 
1367  // Now prepare the SQL statements.
1368  uint32_t i = 0;
1369  for (; tagged_statements[i].text != NULL; ++i) {
1370  ctx->conn_.prepareStatement(tagged_statements[i]);
1371  }
1372 
1373  // Just in case somebody foo-barred things
1374  if (i != NUM_STATEMENTS) {
1375  isc_throw(DbOpenError, "Number of statements prepared: " << i
1376  << " does not match expected count:" << NUM_STATEMENTS);
1377  }
1378 
1379  // Create the exchange objects for use in exchanging data between the
1380  // program and the database.
1381  ctx->exchange4_.reset(new PgSqlLease4Exchange());
1382  ctx->exchange6_.reset(new PgSqlLease6Exchange());
1383 
1384  // Create ReconnectCtl for this connection.
1385  ctx->conn_.makeReconnectCtl(timer_name_);
1386 
1387  return (ctx);
1388 }
1389 
1390 std::string
1392  std::stringstream tmp;
1393  tmp << "PostgreSQL backend " << PGSQL_SCHEMA_VERSION_MAJOR;
1394  tmp << "." << PGSQL_SCHEMA_VERSION_MINOR;
1395  tmp << ", library " << PQlibVersion();
1396  return (tmp.str());
1397 }
1398 
1399 bool
1400 PgSqlLeaseMgr::addLeaseCommon(PgSqlLeaseContextPtr& ctx,
1401  StatementIndex stindex,
1402  PsqlBindArray& bind_array) {
1403  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
1404  tagged_statements[stindex].nbparams,
1405  &bind_array.values_[0],
1406  &bind_array.lengths_[0],
1407  &bind_array.formats_[0], 0));
1408 
1409  int s = PQresultStatus(r);
1410 
1411  if (s != PGRES_COMMAND_OK) {
1412  // Failure: check for the special case of duplicate entry. If this is
1413  // the case, we return false to indicate that the row was not added.
1414  // Otherwise we throw an exception.
1415  if (ctx->conn_.compareError(r, PgSqlConnection::DUPLICATE_KEY)) {
1416  return (false);
1417  }
1418  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
1419  }
1420 
1421  return (true);
1422 }
1423 
1424 bool
1427  .arg(lease->addr_.toText());
1428 
1429  // Get a context
1430  PgSqlLeaseContextAlloc get_context(*this);
1431  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1432 
1433  PsqlBindArray bind_array;
1434  ctx->exchange4_->createBindForSend(lease, bind_array);
1435  auto result = addLeaseCommon(ctx, INSERT_LEASE4, bind_array);
1436 
1437  // Update lease current expiration time (allows update between the creation
1438  // of the Lease up to the point of insertion in the database).
1439  lease->updateCurrentExpirationTime();
1440 
1441  return (result);
1442 }
1443 
1444 bool
1447  .arg(lease->addr_.toText())
1448  .arg(lease->type_);
1449 
1450  // Get a context
1451  PgSqlLeaseContextAlloc get_context(*this);
1452  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1453 
1454  PsqlBindArray bind_array;
1455  ctx->exchange6_->createBindForSend(lease, bind_array);
1456 
1457  auto result = addLeaseCommon(ctx, INSERT_LEASE6, bind_array);
1458 
1459  // Update lease current expiration time (allows update between the creation
1460  // of the Lease up to the point of insertion in the database).
1461  lease->updateCurrentExpirationTime();
1462 
1463  return (result);
1464 }
1465 
1466 template <typename Exchange, typename LeaseCollection>
1467 void
1468 PgSqlLeaseMgr::getLeaseCollection(PgSqlLeaseContextPtr& ctx,
1469  StatementIndex stindex,
1470  PsqlBindArray& bind_array,
1471  Exchange& exchange,
1472  LeaseCollection& result,
1473  bool single) const {
1474  const int n = tagged_statements[stindex].nbparams;
1475  PgSqlResult r(PQexecPrepared(ctx->conn_,
1476  tagged_statements[stindex].name, n,
1477  n > 0 ? &bind_array.values_[0] : NULL,
1478  n > 0 ? &bind_array.lengths_[0] : NULL,
1479  n > 0 ? &bind_array.formats_[0] : NULL, 0));
1480 
1481  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
1482 
1483  int rows = PQntuples(r);
1484  if (single && rows > 1) {
1485  isc_throw(MultipleRecords, "multiple records were found in the "
1486  "database where only one was expected for query "
1487  << tagged_statements[stindex].name);
1488  }
1489 
1490  for(int i = 0; i < rows; ++ i) {
1491  result.push_back(exchange->convertFromDatabase(r, i));
1492  }
1493 }
1494 
1495 void
1496 PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr& ctx,
1497  StatementIndex stindex, PsqlBindArray& bind_array,
1498  Lease4Ptr& result) const {
1499  // Create appropriate collection object and get all leases matching
1500  // the selection criteria. The "single" parameter is true to indicate
1501  // that the called method should throw an exception if multiple
1502  // matching records are found: this particular method is called when only
1503  // one or zero matches is expected.
1504  Lease4Collection collection;
1505  getLeaseCollection(ctx, stindex, bind_array, ctx->exchange4_,
1506  collection, true);
1507 
1508  // Return single record if present, else clear the lease.
1509  if (collection.empty()) {
1510  result.reset();
1511  } else {
1512  result = *collection.begin();
1513  }
1514 }
1515 
1516 void
1517 PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr& ctx,
1518  StatementIndex stindex, PsqlBindArray& bind_array,
1519  Lease6Ptr& result) const {
1520  // Create appropriate collection object and get all leases matching
1521  // the selection criteria. The "single" parameter is true to indicate
1522  // that the called method should throw an exception if multiple
1523  // matching records are found: this particular method is called when only
1524  // one or zero matches is expected.
1525  Lease6Collection collection;
1526  getLeaseCollection(ctx, stindex, bind_array, ctx->exchange6_,
1527  collection, true);
1528 
1529  // Return single record if present, else clear the lease.
1530  if (collection.empty()) {
1531  result.reset();
1532  } else {
1533  result = *collection.begin();
1534  }
1535 }
1536 
1537 Lease4Ptr
1540  .arg(addr.toText());
1541 
1542  // Set up the WHERE clause value
1543  PsqlBindArray bind_array;
1544 
1545  // LEASE ADDRESS
1546  std::string addr_str = boost::lexical_cast<std::string>(addr.toUint32());
1547  bind_array.add(addr_str);
1548 
1549  // Get the data
1550  Lease4Ptr result;
1551 
1552  // Get a context
1553  PgSqlLeaseContextAlloc get_context(*this);
1554  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1555 
1556  getLease(ctx, GET_LEASE4_ADDR, bind_array, result);
1557 
1558  return (result);
1559 }
1560 
1562 PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
1564  .arg(hwaddr.toText());
1565 
1566  // Set up the WHERE clause value
1567  PsqlBindArray bind_array;
1568 
1569  // HWADDR
1570  if (!hwaddr.hwaddr_.empty()) {
1571  bind_array.add(hwaddr.hwaddr_);
1572  } else {
1573  bind_array.add("");
1574  }
1575 
1576  // Get the data
1577  Lease4Collection result;
1578 
1579  // Get a context
1580  PgSqlLeaseContextAlloc get_context(*this);
1581  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1582 
1583  getLeaseCollection(ctx, GET_LEASE4_HWADDR, bind_array, result);
1584 
1585  return (result);
1586 }
1587 
1588 Lease4Ptr
1589 PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
1591  .arg(subnet_id)
1592  .arg(hwaddr.toText());
1593 
1594  // Set up the WHERE clause value
1595  PsqlBindArray bind_array;
1596 
1597  // HWADDR
1598  if (!hwaddr.hwaddr_.empty()) {
1599  bind_array.add(hwaddr.hwaddr_);
1600  } else {
1601  bind_array.add("");
1602  }
1603 
1604  // SUBNET_ID
1605  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1606  bind_array.add(subnet_id_str);
1607 
1608  // Get the data
1609  Lease4Ptr result;
1610 
1611  // Get a context
1612  PgSqlLeaseContextAlloc get_context(*this);
1613  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1614 
1615  getLease(ctx, GET_LEASE4_HWADDR_SUBID, bind_array, result);
1616 
1617  return (result);
1618 }
1619 
1621 PgSqlLeaseMgr::getLease4(const ClientId& clientid) const {
1623  .arg(clientid.toText());
1624 
1625  // Set up the WHERE clause value
1626  PsqlBindArray bind_array;
1627 
1628  // CLIENT_ID
1629  bind_array.add(clientid.getClientId());
1630 
1631  // Get the data
1632  Lease4Collection result;
1633 
1634  // Get a context
1635  PgSqlLeaseContextAlloc get_context(*this);
1636  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1637 
1638  getLeaseCollection(ctx, GET_LEASE4_CLIENTID, bind_array, result);
1639 
1640  return (result);
1641 }
1642 
1643 Lease4Ptr
1644 PgSqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
1646  .arg(subnet_id)
1647  .arg(clientid.toText());
1648 
1649  // Set up the WHERE clause value
1650  PsqlBindArray bind_array;
1651 
1652  // CLIENT_ID
1653  bind_array.add(clientid.getClientId());
1654 
1655  // SUBNET_ID
1656  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1657  bind_array.add(subnet_id_str);
1658 
1659  // Get the data
1660  Lease4Ptr result;
1661 
1662  // Get a context
1663  PgSqlLeaseContextAlloc get_context(*this);
1664  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1665 
1666  getLease(ctx, GET_LEASE4_CLIENTID_SUBID, bind_array, result);
1667 
1668  return (result);
1669 }
1670 
1674  .arg(subnet_id);
1675 
1676  // Set up the WHERE clause value
1677  PsqlBindArray bind_array;
1678 
1679  // SUBNET_ID
1680  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1681  bind_array.add(subnet_id_str);
1682 
1683  // ... and get the data
1684  Lease4Collection result;
1685 
1686  // Get a context
1687  PgSqlLeaseContextAlloc get_context(*this);
1688  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1689 
1690  getLeaseCollection(ctx, GET_LEASE4_SUBID, bind_array, result);
1691 
1692  return (result);
1693 }
1694 
1696 PgSqlLeaseMgr::getLeases4(const std::string& hostname) const {
1698  .arg(hostname);
1699 
1700  // Set up the WHERE clause value
1701  PsqlBindArray bind_array;
1702 
1703  // Hostname
1704  bind_array.add(hostname);
1705 
1706  // ... and get the data
1707  Lease4Collection result;
1708 
1709  // Get a context
1710  PgSqlLeaseContextAlloc get_context(*this);
1711  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1712 
1713  getLeaseCollection(ctx, GET_LEASE4_HOSTNAME, bind_array, result);
1714 
1715  return (result);
1716 }
1717 
1721 
1722  // Provide empty binding array because our query has no parameters in
1723  // WHERE clause.
1724  PsqlBindArray bind_array;
1725  Lease4Collection result;
1726 
1727  // Get a context
1728  PgSqlLeaseContextAlloc get_context(*this);
1729  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1730 
1731  getLeaseCollection(ctx, GET_LEASE4, bind_array, result);
1732 
1733  return (result);
1734 }
1735 
1737 PgSqlLeaseMgr::getLeases4(const IOAddress& lower_bound_address,
1738  const LeasePageSize& page_size) const {
1739  // Expecting IPv4 address.
1740  if (!lower_bound_address.isV4()) {
1741  isc_throw(InvalidAddressFamily, "expected IPv4 address while "
1742  "retrieving leases from the lease database, got "
1743  << lower_bound_address);
1744  }
1745 
1747  .arg(page_size.page_size_)
1748  .arg(lower_bound_address.toText());
1749 
1750  // Prepare WHERE clause
1751  PsqlBindArray bind_array;
1752 
1753  // Bind lower bound address
1754  std::string lb_address_data = boost::lexical_cast<std::string>(lower_bound_address.toUint32());
1755  bind_array.add(lb_address_data);
1756 
1757  // Bind page size value
1758  std::string page_size_data = boost::lexical_cast<std::string>(page_size.page_size_);
1759  bind_array.add(page_size_data);
1760 
1761  // Get the leases
1762  Lease4Collection result;
1763 
1764  // Get a context
1765  PgSqlLeaseContextAlloc get_context(*this);
1766  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1767 
1768  getLeaseCollection(ctx, GET_LEASE4_PAGE, bind_array, result);
1769 
1770  return (result);
1771 }
1772 
1773 Lease6Ptr
1775  const IOAddress& addr) const {
1777  .arg(addr.toText())
1778  .arg(lease_type);
1779 
1780  // Set up the WHERE clause value
1781  PsqlBindArray bind_array;
1782 
1783  // LEASE ADDRESS
1784  std::string addr_str = addr.toText();
1785  bind_array.add(addr_str);
1786 
1787  // LEASE_TYPE
1788  std::string type_str_ = boost::lexical_cast<std::string>(lease_type);
1789  bind_array.add(type_str_);
1790 
1791  // ... and get the data
1792  Lease6Ptr result;
1793 
1794  // Get a context
1795  PgSqlLeaseContextAlloc get_context(*this);
1796  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1797 
1798  getLease(ctx, GET_LEASE6_ADDR, bind_array, result);
1799 
1800  return (result);
1801 }
1802 
1805  uint32_t iaid) const {
1807  .arg(iaid)
1808  .arg(duid.toText())
1809  .arg(lease_type);
1810 
1811  // Set up the WHERE clause value
1812  PsqlBindArray bind_array;
1813 
1814  // DUID
1815  bind_array.add(duid.getDuid());
1816 
1817  // IAID
1818  std::string iaid_str = PgSqlLease6Exchange::Uiaid(iaid).dbInputString();
1819  bind_array.add(iaid_str);
1820 
1821  // LEASE_TYPE
1822  std::string lease_type_str = boost::lexical_cast<std::string>(lease_type);
1823  bind_array.add(lease_type_str);
1824 
1825  // ... and get the data
1826  Lease6Collection result;
1827 
1828  // Get a context
1829  PgSqlLeaseContextAlloc get_context(*this);
1830  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1831 
1832  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID, bind_array, result);
1833 
1834  return (result);
1835 }
1836 
1839  uint32_t iaid, SubnetID subnet_id) const {
1841  .arg(iaid)
1842  .arg(subnet_id)
1843  .arg(duid.toText())
1844  .arg(lease_type);
1845 
1846  // Set up the WHERE clause value
1847  PsqlBindArray bind_array;
1848 
1849  // LEASE_TYPE
1850  std::string lease_type_str = boost::lexical_cast<std::string>(lease_type);
1851  bind_array.add(lease_type_str);
1852 
1853  // DUID
1854  bind_array.add(duid.getDuid());
1855 
1856  // IAID
1857  std::string iaid_str = PgSqlLease6Exchange::Uiaid(iaid).dbInputString();
1858  bind_array.add(iaid_str);
1859 
1860  // SUBNET ID
1861  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1862  bind_array.add(subnet_id_str);
1863 
1864  // ... and get the data
1865  Lease6Collection result;
1866 
1867  // Get a context
1868  PgSqlLeaseContextAlloc get_context(*this);
1869  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1870 
1871  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID_SUBID, bind_array, result);
1872 
1873  return (result);
1874 }
1875 
1879  .arg(subnet_id);
1880 
1881  // Set up the WHERE clause value
1882  PsqlBindArray bind_array;
1883 
1884  // SUBNET_ID
1885  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1886  bind_array.add(subnet_id_str);
1887 
1888  // ... and get the data
1889  Lease6Collection result;
1890 
1891  // Get a context
1892  PgSqlLeaseContextAlloc get_context(*this);
1893  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1894 
1895  getLeaseCollection(ctx, GET_LEASE6_SUBID, bind_array, result);
1896 
1897  return (result);
1898 }
1899 
1901 PgSqlLeaseMgr::getLeases6(const DUID& duid) const {
1903  .arg(duid.toText());
1904 
1905  // Set up the WHERE clause value
1906  PsqlBindArray bind_array;
1907 
1908  // DUID
1909  bind_array.add(duid.getDuid());
1910  Lease6Collection result;
1911 
1912  // Get a context
1913  PgSqlLeaseContextAlloc get_context(*this);
1914  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1915 
1916  // query to fetch the data
1917  getLeaseCollection(ctx, GET_LEASE6_DUID, bind_array, result);
1918 
1919  return (result);
1920 }
1921 
1923 PgSqlLeaseMgr::getLeases6(const std::string& hostname) const {
1925  .arg(hostname);
1926 
1927  // Set up the WHERE clause value
1928  PsqlBindArray bind_array;
1929 
1930  // Hostname
1931  bind_array.add(hostname);
1932 
1933  // ... and get the data
1934  Lease6Collection result;
1935 
1936  // Get a context
1937  PgSqlLeaseContextAlloc get_context(*this);
1938  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1939 
1940  getLeaseCollection(ctx, GET_LEASE6_HOSTNAME, bind_array, result);
1941 
1942  return (result);
1943 }
1944 
1948 
1949  // Provide empty binding array because our query has no parameters in
1950  // WHERE clause.
1951  PsqlBindArray bind_array;
1952  Lease6Collection result;
1953 
1954  // Get a context
1955  PgSqlLeaseContextAlloc get_context(*this);
1956  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1957 
1958  getLeaseCollection(ctx, GET_LEASE6, bind_array, result);
1959 
1960  return (result);
1961 }
1962 
1964 PgSqlLeaseMgr::getLeases6(const IOAddress& lower_bound_address,
1965  const LeasePageSize& page_size) const {
1966  // Expecting IPv6 address.
1967  if (!lower_bound_address.isV6()) {
1968  isc_throw(InvalidAddressFamily, "expected IPv6 address while "
1969  "retrieving leases from the lease database, got "
1970  << lower_bound_address);
1971  }
1972 
1974  .arg(page_size.page_size_)
1975  .arg(lower_bound_address.toText());
1976 
1977  // Prepare WHERE clause
1978  PsqlBindArray bind_array;
1979 
1980  // In IPv6 we compare addresses represented as strings. The IPv6 zero address
1981  // is ::, so it is greater than any other address. In this special case, we
1982  // just use 0 for comparison which should be lower than any real IPv6 address.
1983  std::string lb_address_data = "0";
1984  if (!lower_bound_address.isV6Zero()) {
1985  lb_address_data = lower_bound_address.toText();
1986  }
1987 
1988  // Bind lower bound address
1989  bind_array.add(lb_address_data);
1990 
1991  // Bind page size value
1992  std::string page_size_data = boost::lexical_cast<std::string>(page_size.page_size_);
1993  bind_array.add(page_size_data);
1994 
1995  // Get the leases
1996  Lease6Collection result;
1997 
1998  // Get a context
1999  PgSqlLeaseContextAlloc get_context(*this);
2000  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2001 
2002  getLeaseCollection(ctx, GET_LEASE6_PAGE, bind_array, result);
2003 
2004  return (result);
2005 }
2006 
2007 void
2009  const size_t max_leases) const {
2011  .arg(max_leases);
2012  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE4_EXPIRE);
2013 }
2014 
2015 void
2017  const size_t max_leases) const {
2019  .arg(max_leases);
2020  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE6_EXPIRE);
2021 }
2022 
2023 template<typename LeaseCollection>
2024 void
2025 PgSqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases,
2026  const size_t max_leases,
2027  StatementIndex statement_index) const {
2028  PsqlBindArray bind_array;
2029 
2030  // Exclude reclaimed leases.
2031  std::string state_str = boost::lexical_cast<std::string>(Lease::STATE_EXPIRED_RECLAIMED);
2032  bind_array.add(state_str);
2033 
2034  // Expiration timestamp.
2035  std::string timestamp_str = PgSqlLeaseExchange::convertToDatabaseTime(time(0));
2036  bind_array.add(timestamp_str);
2037 
2038  // If the number of leases is 0, we will return all leases. This is
2039  // achieved by setting the limit to a very high value.
2040  uint32_t limit = max_leases > 0 ? static_cast<uint32_t>(max_leases) :
2041  std::numeric_limits<uint32_t>::max();
2042  std::string limit_str = boost::lexical_cast<std::string>(limit);
2043  bind_array.add(limit_str);
2044 
2045  // Get a context
2046  PgSqlLeaseContextAlloc get_context(*this);
2047  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2048 
2049  // Retrieve leases from the database.
2050  getLeaseCollection(ctx, statement_index, bind_array, expired_leases);
2051 }
2052 
2053 template<typename LeasePtr>
2054 void
2055 PgSqlLeaseMgr::updateLeaseCommon(PgSqlLeaseContextPtr& ctx,
2056  StatementIndex stindex,
2057  PsqlBindArray& bind_array,
2058  const LeasePtr& lease) {
2059  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2060  tagged_statements[stindex].nbparams,
2061  &bind_array.values_[0],
2062  &bind_array.lengths_[0],
2063  &bind_array.formats_[0], 0));
2064 
2065  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2066 
2067  int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
2068 
2069  // Check success case first as it is the most likely outcome.
2070  if (affected_rows == 1) {
2071  return;
2072  }
2073 
2074  // If no rows affected, lease doesn't exist.
2075  if (affected_rows == 0) {
2076  isc_throw(NoSuchLease, "unable to update lease for address " <<
2077  lease->addr_.toText() << " as it does not exist");
2078  }
2079 
2080  // Should not happen - primary key constraint should only have selected
2081  // one row.
2082  isc_throw(DbOperationError, "apparently updated more than one lease "
2083  "that had the address " << lease->addr_.toText());
2084 }
2085 
2086 void
2088  const StatementIndex stindex = UPDATE_LEASE4;
2089 
2091  .arg(lease->addr_.toText());
2092 
2093  // Get a context
2094  PgSqlLeaseContextAlloc get_context(*this);
2095  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2096 
2097  // Create the BIND array for the data being updated
2098  PsqlBindArray bind_array;
2099  ctx->exchange4_->createBindForSend(lease, bind_array);
2100 
2101  // Set up the WHERE clause and append it to the SQL_BIND array
2102  std::string addr4_str = boost::lexical_cast<std::string>(lease->addr_.toUint32());
2103  bind_array.add(addr4_str);
2104 
2105  std::string expire_str;
2106  // Avoid overflow (see createBindForSend)
2107  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2108  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2109  } else {
2110  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2111  lease->current_valid_lft_);
2112  }
2113  bind_array.add(expire_str);
2114 
2115  // Drop to common update code
2116  updateLeaseCommon(ctx, stindex, bind_array, lease);
2117 
2118  // Update lease current expiration time.
2119  lease->updateCurrentExpirationTime();
2120 }
2121 
2122 void
2124  const StatementIndex stindex = UPDATE_LEASE6;
2125 
2127  .arg(lease->addr_.toText())
2128  .arg(lease->type_);
2129 
2130  // Get a context
2131  PgSqlLeaseContextAlloc get_context(*this);
2132  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2133 
2134  // Create the BIND array for the data being updated
2135  PsqlBindArray bind_array;
2136  ctx->exchange6_->createBindForSend(lease, bind_array);
2137 
2138  // Set up the WHERE clause and append it to the BIND array
2139  std::string addr_str = lease->addr_.toText();
2140  bind_array.add(addr_str);
2141 
2142  std::string expire_str;
2143  // Avoid overflow (see createBindForSend)
2144  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2145  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2146  } else {
2147  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2148  lease->current_valid_lft_);
2149  }
2150  bind_array.add(expire_str);
2151 
2152  // Drop to common update code
2153  updateLeaseCommon(ctx, stindex, bind_array, lease);
2154 
2155  // Update lease current expiration time.
2156  lease->updateCurrentExpirationTime();
2157 }
2158 
2159 uint64_t
2160 PgSqlLeaseMgr::deleteLeaseCommon(StatementIndex stindex,
2161  PsqlBindArray& bind_array) {
2162  // Get a context
2163  PgSqlLeaseContextAlloc get_context(*this);
2164  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2165 
2166  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2167  tagged_statements[stindex].nbparams,
2168  &bind_array.values_[0],
2169  &bind_array.lengths_[0],
2170  &bind_array.formats_[0], 0));
2171 
2172  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2173  int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
2174 
2175  return (affected_rows);
2176 }
2177 
2178 bool
2180  const IOAddress& addr = lease->addr_;
2182  .arg(addr.toText());
2183 
2184  // Set up the WHERE clause value
2185  PsqlBindArray bind_array;
2186 
2187  std::string addr4_str = boost::lexical_cast<std::string>(addr.toUint32());
2188  bind_array.add(addr4_str);
2189 
2190  std::string expire_str;
2191  // Avoid overflow (see createBindForSend)
2192  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2193  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2194  } else {
2195  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2196  lease->current_valid_lft_);
2197  }
2198  bind_array.add(expire_str);
2199 
2200  auto affected_rows = deleteLeaseCommon(DELETE_LEASE4, bind_array);
2201 
2202  // Check success case first as it is the most likely outcome.
2203  if (affected_rows == 1) {
2204  return (true);
2205  }
2206 
2207  // If no rows affected, lease doesn't exist.
2208  if (affected_rows == 0) {
2209  return (false);
2210  }
2211 
2212  // Should not happen - primary key constraint should only have selected
2213  // one row.
2214  isc_throw(DbOperationError, "apparently deleted more than one lease "
2215  "that had the address " << lease->addr_.toText());
2216 }
2217 
2218 bool
2220  const IOAddress& addr = lease->addr_;
2223  .arg(addr.toText());
2224 
2225  // Set up the WHERE clause value
2226  PsqlBindArray bind_array;
2227 
2228  std::string addr6_str = addr.toText();
2229  bind_array.add(addr6_str);
2230 
2231  std::string expire_str;
2232  // Avoid overflow (see createBindForSend)
2233  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2234  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2235  } else {
2236  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2237  lease->current_valid_lft_);
2238  }
2239  bind_array.add(expire_str);
2240 
2241  auto affected_rows = deleteLeaseCommon(DELETE_LEASE6, bind_array);
2242 
2243  // Check success case first as it is the most likely outcome.
2244  if (affected_rows == 1) {
2245  return (true);
2246  }
2247 
2248  // If no rows affected, lease doesn't exist.
2249  if (affected_rows == 0) {
2250  return (false);
2251  }
2252 
2253  // Should not happen - primary key constraint should only have selected
2254  // one row.
2255  isc_throw(DbOperationError, "apparently deleted more than one lease "
2256  "that had the address " << lease->addr_.toText());
2257 }
2258 
2259 uint64_t
2262  .arg(secs);
2263  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
2264 }
2265 
2266 uint64_t
2269  .arg(secs);
2270  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
2271 }
2272 
2273 uint64_t
2274 PgSqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
2275  StatementIndex statement_index) {
2276  PsqlBindArray bind_array;
2277 
2278  // State is reclaimed.
2279  std::string state_str = boost::lexical_cast<std::string>(Lease::STATE_EXPIRED_RECLAIMED);
2280  bind_array.add(state_str);
2281 
2282  // Expiration timestamp.
2283  std::string expiration_str = PgSqlLeaseExchange::convertToDatabaseTime(time(0) -
2284  static_cast<time_t>(secs));
2285  bind_array.add(expiration_str);
2286 
2287  // Delete leases.
2288  return (deleteLeaseCommon(statement_index, bind_array));
2289 }
2290 
2291 string
2292 PgSqlLeaseMgr::checkLimits(ConstElementPtr const& user_context, StatementIndex const stindex) const {
2293  // Bindings
2294  PsqlBindArray bind_array;
2295  std::string const user_context_str(user_context->str());
2296  bind_array.add(user_context_str);
2297 
2298  // Get a context.
2299  PgSqlLeaseContextAlloc get_context(*this);
2300  PgSqlLeaseContextPtr ctx(get_context.ctx_);
2301 
2302  PgSqlResult r(PQexecPrepared(ctx->conn_,
2303  tagged_statements[stindex].name,
2304  tagged_statements[stindex].nbparams,
2305  &bind_array.values_[0],
2306  &bind_array.lengths_[0],
2307  &bind_array.formats_[0], 0));
2308 
2309  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2310 
2311  int rows = PQntuples(r);
2312  if (rows > 1) {
2313  isc_throw(MultipleRecords, "multiple records were found in the "
2314  "database where only one was expected for query "
2315  << tagged_statements[stindex].name);
2316  }
2317 
2318  std::string const limits(PgSqlExchange::getRawColumnValue(r, 0, 0));
2319  return limits;
2320 }
2321 
2322 string
2323 PgSqlLeaseMgr::checkLimits4(ConstElementPtr const& user_context) const {
2324  return checkLimits(user_context, CHECK_LEASE4_LIMITS);
2325 }
2326 
2327 string
2328 PgSqlLeaseMgr::checkLimits6(ConstElementPtr const& user_context) const {
2329  return checkLimits(user_context, CHECK_LEASE6_LIMITS);
2330 }
2331 
2334  // Get a context
2335  PgSqlLeaseContextAlloc get_context(*this);
2336  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2337 
2338  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2339  tagged_statements[ALL_LEASE4_STATS],
2340  false));
2341  query->start();
2342  return(query);
2343 }
2344 
2347  // Get a context
2348  PgSqlLeaseContextAlloc get_context(*this);
2349  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2350 
2351  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2352  tagged_statements[SUBNET_LEASE4_STATS],
2353  false,
2354  subnet_id));
2355  query->start();
2356  return(query);
2357 }
2358 
2361  const SubnetID& last_subnet_id) {
2362  // Get a context
2363  PgSqlLeaseContextAlloc get_context(*this);
2364  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2365 
2366  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2367  tagged_statements[SUBNET_RANGE_LEASE4_STATS],
2368  false,
2369  first_subnet_id,
2370  last_subnet_id));
2371  query->start();
2372  return(query);
2373 }
2374 
2377  // Get a context
2378  PgSqlLeaseContextAlloc get_context(*this);
2379  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2380 
2381  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2382  tagged_statements[ALL_LEASE6_STATS],
2383  true));
2384  query->start();
2385  return(query);
2386 }
2387 
2390  // Get a context
2391  PgSqlLeaseContextAlloc get_context(*this);
2392  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2393 
2394  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2395  tagged_statements[SUBNET_LEASE6_STATS],
2396  true,
2397  subnet_id));
2398  query->start();
2399  return(query);
2400 }
2401 
2404  const SubnetID& last_subnet_id) {
2405  // Get a context
2406  PgSqlLeaseContextAlloc get_context(*this);
2407  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2408 
2409  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2410  tagged_statements[SUBNET_RANGE_LEASE6_STATS],
2411  true,
2412  first_subnet_id,
2413  last_subnet_id));
2414  query->start();
2415  return(query);
2416 }
2417 
2418 size_t
2419 PgSqlLeaseMgr::wipeLeases4(const SubnetID& /*subnet_id*/) {
2420  isc_throw(NotImplemented, "wipeLeases4 is not implemented for PostgreSQL backend");
2421 }
2422 
2423 size_t
2424 PgSqlLeaseMgr::wipeLeases6(const SubnetID& /*subnet_id*/) {
2425  isc_throw(NotImplemented, "wipeLeases6 is not implemented for PostgreSQL backend");
2426 }
2427 
2428 bool
2430  isc_throw(NotImplemented, "PgSqlLeaseMgr::isJsonSupported() not implemented");
2431 }
2432 
2433 std::string
2435  // Get a context
2436  PgSqlLeaseContextAlloc get_context(*this);
2437  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2438 
2439  std::string name = "";
2440  try {
2441  name = ctx->conn_.getParameter("name");
2442  } catch (...) {
2443  // Return an empty name
2444  }
2445  return (name);
2446 }
2447 
2448 std::string
2450  return (std::string("PostgreSQL Database"));
2451 }
2452 
2453 std::pair<uint32_t, uint32_t>
2456 
2457  return (PgSqlConnection::getVersion(parameters_));
2458 }
2459 
2460 void
2463 }
2464 
2465 void
2468 }
2469 
2470 } // namespace dhcp
2471 } // 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.
bool isJsonSupported() const override
Checks if JSON support is enabled in the database.
#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.
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:74
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.
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
static void destroy()
Destroy lease manager.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID &subnet_id)
Creates and runs the IPv6 lease stats query for a single subnet.
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.
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:482
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs)
Deletes all expired-reclaimed DHCPv6 leases.
const isc::log::MessageID DHCPSRV_PGSQL_GET_VERSION
static const char DUPLICATE_KEY[]
Define the PgSql error state for a duplicate key error.
#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
Base class for marshalling data to and from PostgreSQL.
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery6(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Creates and runs the IPv6 lease stats query for a single subnet.
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
std::vector< uint8_t > hwaddr_
boost::shared_ptr< Lease > LeasePtr
Pointer to the lease object.
Definition: lease.h:21
const size_t OID_TEXT
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
const isc::log::MessageID DHCPSRV_PGSQL_GET_EXPIRED6
Exception thrown on failure to open database.
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 LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery4(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Creates and runs the IPv4 lease stats query for a single subnet.
std::vector< const char * > values_
Vector of pointers to the data values.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID &subnet_id)
Creates and runs the IPv4 lease stats query for a single subnet.
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.
virtual void getExpiredLeases6(Lease6Collection &expired_leases, const size_t max_leases) const
Returns a collection of expired DHCPv6 leases.
#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.
PostgreSQL Lease Context Pool.
void add(const char *value)
Adds a char array to bind array based.
Definition: edns.h:19
virtual void updateLease4(const Lease4Ptr &lease4)
Updates IPv4 lease.
const size_t page_size_
Holds page size.
Definition: lease_mgr.h:54
PgSqlLeaseContextPtr createContext() const
Create a new context.
const isc::log::MessageID DHCPSRV_PGSQL_GET4
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:278
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
virtual std::string getDescription() const
Returns description of the backend.
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.
virtual void updateLease6(const Lease6Ptr &lease6)
Updates IPv6 lease.
virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t secs)
Deletes all expired-reclaimed DHCPv4 leases.
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:498
const isc::log::MessageID DHCPSRV_PGSQL_GET_PAGE6
PgSqlTaggedStatement & statement_
The query&#39;s prepared statement.
const isc::log::MessageID DHCPSRV_PGSQL_COMMIT
virtual size_t wipeLeases6(const SubnetID &subnet_id)
Removed specified IPv6 leases.
virtual LeaseStatsQueryPtr startLeaseStatsQuery4()
Creates and runs the IPv4 lease stats query.
const isc::log::MessageID DHCPSRV_PGSQL_GET_HWADDR
virtual void rollback()
Rollback Transactions.
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:635
virtual std::pair< uint32_t, uint32_t > getVersion() const
Returns backend version.
const std::vector< uint8_t > & getDuid() const
Returns a const reference to the actual DUID value.
Definition: duid.cc:46
Ethernet 10Mbps.
Definition: dhcp4.h:56
virtual void getExpiredLeases4(Lease4Collection &expired_leases, const size_t max_leases) const
Returns a collection of expired DHCPv4 leases.
Invalid address family used as input to Lease Manager.
Definition: db_exceptions.h:59
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
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:33
virtual Lease6Collection getLeases6() const
Returns all IPv6 leases.
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:45
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 Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const
Returns an IPv4 lease for specified IPv4 address.
#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
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.
virtual bool addLease(const Lease4Ptr &lease)
Adds an IPv4 lease.
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 PostgreSQL backend version: 12.0.
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
virtual void commit()
Commit Transactions.
virtual bool deleteLease(const Lease4Ptr &lease)
Deletes an IPv4 lease.
virtual std::string getName() const
Returns backend name.
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.
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const
Returns existing IPv6 lease for a given IPv6 address.
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition: timer_mgr.cc:449
virtual size_t wipeLeases4(const SubnetID &subnet_id)
Removes specified IPv4 leases.
static bool invokeDbLostCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection&#39;s lost connectivity callback.
static const char * getRawColumnValue(const PgSqlResult &r, const int row, const size_t col)
Gets a pointer to the raw column value in a result set row.
const isc::log::MessageID DHCPSRV_PGSQL_UPDATE_ADDR4
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:487
static std::string redactedAccessString(const ParameterMap &parameters)
Redact database access string.
virtual Lease4Collection getLeases4() const
Returns all IPv4 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
virtual LeaseStatsQueryPtr startLeaseStatsQuery6()
Creates and runs the IPv6 lease stats query.
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.
const isc::log::MessageID DHCPSRV_PGSQL_GET_SUBID_CLIENTID
PgSqlLeaseMgr(const db::DatabaseConnection::ParameterMap &parameters)
Constructor.