Kea  1.9.9-git
pgsql_lease_mgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2021 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  // End of list sentinel
362  { 0, { 0 }, NULL, NULL}
363 };
364 
365 } // namespace
366 
367 namespace isc {
368 namespace dhcp {
369 
376 public:
377 
379  : addr_str_(""), hwaddr_length_(0), hwaddr_(hwaddr_length_),
380  valid_lifetime_(0), valid_lifetime_str_(""), expire_(0),
381  expire_str_(""), subnet_id_(0), subnet_id_str_(""), cltt_(0),
382  fqdn_fwd_(false), fqdn_rev_(false), hostname_(""), state_str_(""),
383  user_context_("") {
384  }
385 
387 
388 protected:
389 
391 
392  std::string addr_str_;
394  std::vector<uint8_t> hwaddr_;
395  uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
396  uint32_t valid_lifetime_;
397  std::string valid_lifetime_str_;
398  time_t expire_;
399  std::string expire_str_;
400  uint32_t subnet_id_;
401  std::string subnet_id_str_;
402  time_t cltt_;
403  bool fqdn_fwd_;
404  bool fqdn_rev_;
405  std::string hostname_;
406  std::string state_str_;
407  std::string user_context_;
409 };
410 
413 private:
414 
419  static const size_t ADDRESS_COL = 0;
420  static const size_t HWADDR_COL = 1;
421  static const size_t CLIENT_ID_COL = 2;
422  static const size_t VALID_LIFETIME_COL = 3;
423  static const size_t EXPIRE_COL = 4;
424  static const size_t SUBNET_ID_COL = 5;
425  static const size_t FQDN_FWD_COL = 6;
426  static const size_t FQDN_REV_COL = 7;
427  static const size_t HOSTNAME_COL = 8;
428  static const size_t STATE_COL = 9;
429  static const size_t USER_CONTEXT_COL = 10;
431  static const size_t LEASE_COLUMNS = 11;
432 
433 public:
434 
437  : lease_(), addr4_(0), client_id_length_(0) {
438 
439  BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
440 
441  memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
442  memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
443 
444  // Set the column names (for error messages)
445  columns_.push_back("address");
446  columns_.push_back("hwaddr");
447  columns_.push_back("client_id");
448  columns_.push_back("valid_lifetime");
449  columns_.push_back("expire");
450  columns_.push_back("subnet_id");
451  columns_.push_back("fqdn_fwd");
452  columns_.push_back("fqdn_rev");
453  columns_.push_back("hostname");
454  columns_.push_back("state");
455  columns_.push_back("user_context");
456  }
457 
470  void createBindForSend(const Lease4Ptr& lease, PsqlBindArray& bind_array) {
471  if (!lease) {
472  isc_throw(BadValue, "createBindForSend:: Lease4 object is NULL");
473  }
474 
475  // Store lease object to ensure it remains valid.
476  lease_ = lease;
477 
478  try {
479  addr_str_ = boost::lexical_cast<std::string>(lease->addr_.toUint32());
480  bind_array.add(addr_str_);
481 
482  if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) {
483  // PostgreSql does not provide MAX on variable length types
484  // so we have to enforce it ourselves.
485  if (lease->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
486  isc_throw(DbOperationError, "Hardware address length : "
487  << lease_->hwaddr_->hwaddr_.size()
488  << " exceeds maximum allowed of: "
489  << HWAddr::MAX_HWADDR_LEN);
490  }
491  bind_array.add(lease->hwaddr_->hwaddr_);
492  } else {
493  bind_array.add("");
494  }
495 
496  if (lease->client_id_) {
497  bind_array.add(lease->client_id_->getClientId());
498  } else {
499  bind_array.add("");
500  }
501 
502  valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
503  bind_array.add(valid_lifetime_str_);
504 
505  // Avoid overflow
506  if (lease_->valid_lft_ == Lease::INFINITY_LFT) {
507  expire_str_ = convertToDatabaseTime(lease->cltt_, 0);
508  } else {
509  expire_str_ = convertToDatabaseTime(lease->cltt_,
510  lease_->valid_lft_);
511  }
512  bind_array.add(expire_str_);
513 
514  subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
515  bind_array.add(subnet_id_str_);
516 
517  bind_array.add(lease->fqdn_fwd_);
518 
519  bind_array.add(lease->fqdn_rev_);
520 
521  bind_array.add(lease->hostname_);
522 
523  state_str_ = boost::lexical_cast<std::string>(lease->state_);
524  bind_array.add(state_str_);
525 
526  ConstElementPtr ctx = lease->getContext();
527  if (ctx) {
528  user_context_ = ctx->str();
529  } else {
530  user_context_ = "";
531  }
532  bind_array.add(user_context_);
533  } catch (const std::exception& ex) {
535  "Could not create bind array from Lease4: "
536  << lease_->addr_.toText() << ", reason: " << ex.what());
537  }
538  }
539 
549  try {
550  getColumnValue(r, row, ADDRESS_COL, addr4_);
551 
552  convertFromBytea(r, row, HWADDR_COL, hwaddr_buffer_,
553  sizeof(hwaddr_buffer_), hwaddr_length_);
554 
555  convertFromBytea(r, row, CLIENT_ID_COL, client_id_buffer_,
556  sizeof(client_id_buffer_), client_id_length_);
557 
558  getColumnValue(r, row, VALID_LIFETIME_COL, valid_lifetime_);
559 
560  expire_ = convertFromDatabaseTime(getRawColumnValue(r, row,
561  EXPIRE_COL));
562 
563  getColumnValue(r, row , SUBNET_ID_COL, subnet_id_);
564 
565  // Recover from overflow
566  if (valid_lifetime_ == Lease::INFINITY_LFT) {
567  cltt_ = expire_;
568  } else {
569  cltt_ = expire_ - valid_lifetime_;
570  }
571 
572  getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
573 
574  getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
575 
576  hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
577 
578  uint32_t state;
579  getColumnValue(r, row , STATE_COL, state);
580 
581  HWAddrPtr hwaddr(new HWAddr(hwaddr_buffer_, hwaddr_length_,
582  HTYPE_ETHER));
583 
584  user_context_ = getRawColumnValue(r, row, USER_CONTEXT_COL);
585  ConstElementPtr ctx;
586  if (!user_context_.empty()) {
587  ctx = Element::fromJSON(user_context_);
588  if (!ctx || (ctx->getType() != Element::map)) {
589  isc_throw(BadValue, "user context '" << user_context_
590  << "' is not a JSON map");
591  }
592  }
593 
594  Lease4Ptr result(boost::make_shared<Lease4>(addr4_, hwaddr,
595  client_id_buffer_,
596  client_id_length_,
597  valid_lifetime_, cltt_,
598  subnet_id_, fqdn_fwd_,
599  fqdn_rev_, hostname_));
600 
601  result->state_ = state;
602 
603  if (ctx) {
604  result->setContext(ctx);
605  }
606 
607  return (result);
608  } catch (const std::exception& ex) {
610  "Could not convert data to Lease4, reason: "
611  << ex.what());
612  }
613  }
614 
615 private:
616 
620  Lease4Ptr lease_;
621 
623  uint32_t addr4_;
624  size_t client_id_length_;
625  uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
626 };
627 
630 private:
631 
636 
637  static const int ADDRESS_COL = 0;
638  static const int DUID_COL = 1;
639  static const int VALID_LIFETIME_COL = 2;
640  static const int EXPIRE_COL = 3;
641  static const int SUBNET_ID_COL = 4;
642  static const int PREF_LIFETIME_COL = 5;
643  static const int LEASE_TYPE_COL = 6;
644  static const int IAID_COL = 7;
645  static const int PREFIX_LEN_COL = 8;
646  static const int FQDN_FWD_COL = 9;
647  static const int FQDN_REV_COL = 10;
648  static const int HOSTNAME_COL = 11;
649  static const int HWADDR_COL = 12;
650  static const int HWTYPE_COL = 13;
651  static const int HWADDR_SOURCE_COL = 14;
652  static const int STATE_COL = 15;
653  static const size_t USER_CONTEXT_COL = 16;
655  static const size_t LEASE_COLUMNS = 17;
657 
658 public:
659 
666  union Uiaid {
669  Uiaid(uint32_t val) : uval_(val){};
670 
673  Uiaid(int32_t val) : ival_(val){};
674 
676  std::string dbInputString() {
677  return (boost::lexical_cast<std::string>(ival_));
678  };
679 
680  uint32_t uval_;
681  int32_t ival_;
682  };
683 
685  : lease_(), duid_length_(0), duid_(duid_length_), iaid_u_(0),
686  iaid_str_(""), lease_type_(Lease6::TYPE_NA), lease_type_str_(""),
687  prefix_len_(0), prefix_len_str_(""), pref_lifetime_(0),
688  preferred_lifetime_str_(""), hwtype_(0), hwtype_str_(""),
689  hwaddr_source_(0), hwaddr_source_str_("") {
690 
691  BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
692 
693  memset(duid_buffer_, 0, sizeof(duid_buffer_));
694 
695  // Set the column names (for error messages)
696  columns_.push_back("address");
697  columns_.push_back("duid");
698  columns_.push_back("valid_lifetime");
699  columns_.push_back("expire");
700  columns_.push_back("subnet_id");
701  columns_.push_back("pref_lifetime");
702  columns_.push_back("lease_type");
703  columns_.push_back("iaid");
704  columns_.push_back("prefix_len");
705  columns_.push_back("fqdn_fwd");
706  columns_.push_back("fqdn_rev");
707  columns_.push_back("hostname");
708  columns_.push_back("hwaddr");
709  columns_.push_back("hwtype");
710  columns_.push_back("hwaddr_source");
711  columns_.push_back("state");
712  columns_.push_back("user_context");
713  }
714 
727  void createBindForSend(const Lease6Ptr& lease, PsqlBindArray& bind_array) {
728  if (!lease) {
729  isc_throw(BadValue, "createBindForSend:: Lease6 object is NULL");
730  }
731 
732  // Store lease object to ensure it remains valid.
733  lease_ = lease;
734  try {
735  addr_str_ = lease_->addr_.toText();
736  bind_array.add(addr_str_);
737 
738  if (lease_->duid_) {
739  bind_array.add(lease_->duid_->getDuid());
740  } else {
741  isc_throw (BadValue, "IPv6 Lease cannot have a null DUID");
742  }
743 
744  valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
745  bind_array.add(valid_lifetime_str_);
746 
747  // Avoid overflow
748  if (lease_->valid_lft_ == Lease::INFINITY_LFT) {
749  expire_str_ = convertToDatabaseTime(lease->cltt_, 0);
750  } else {
751  expire_str_ = convertToDatabaseTime(lease->cltt_,
752  lease_->valid_lft_);
753  }
754  bind_array.add(expire_str_);
755 
756  subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
757  bind_array.add(subnet_id_str_);
758 
759  preferred_lifetime_str_ = boost::lexical_cast<std::string>(lease_->preferred_lft_);
760  bind_array.add(preferred_lifetime_str_);
761 
762  lease_type_str_ = boost::lexical_cast<std::string>(lease_->type_);
763  bind_array.add(lease_type_str_);
764 
765  // The iaid is stored as an INT in lease6 table, so we must
766  // lexically cast from an integer version to avoid out of range
767  // exception failure upon insert.
768  iaid_u_.uval_ = lease_->iaid_;
769  iaid_str_ = iaid_u_.dbInputString();
770  bind_array.add(iaid_str_);
771 
772  prefix_len_str_ = boost::lexical_cast<std::string>
773  (static_cast<unsigned int>(lease_->prefixlen_));
774  bind_array.add(prefix_len_str_);
775 
776  bind_array.add(lease->fqdn_fwd_);
777 
778  bind_array.add(lease->fqdn_rev_);
779 
780  bind_array.add(lease->hostname_);
781 
782  if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) {
783  // PostgreSql does not provide MAX on variable length types
784  // so we have to enforce it ourselves.
785  if (lease->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
786  isc_throw(DbOperationError, "Hardware address length : "
787  << lease_->hwaddr_->hwaddr_.size()
788  << " exceeds maximum allowed of: "
789  << HWAddr::MAX_HWADDR_LEN);
790  }
791  bind_array.add(lease->hwaddr_->hwaddr_);
792  } else {
793  bind_array.add("");
794  }
795 
796  if (lease->hwaddr_) {
797  hwtype_str_ = boost::lexical_cast<std::string>
798  (static_cast<unsigned int>(lease_->hwaddr_->htype_));
799  hwaddr_source_str_ = boost::lexical_cast<std::string>
800  (static_cast<unsigned int>(lease_->hwaddr_->source_));
801  } else {
802  hwtype_str_ = boost::lexical_cast<std::string>
803  (static_cast<unsigned int>(HTYPE_UNDEFINED));
804  hwaddr_source_str_ = boost::lexical_cast<std::string>
805  (static_cast<unsigned int>(HWAddr::HWADDR_SOURCE_UNKNOWN));
806  }
807 
808  bind_array.add(hwtype_str_);
809 
810  bind_array.add(hwaddr_source_str_);
811 
812  state_str_ = boost::lexical_cast<std::string>(lease->state_);
813  bind_array.add(state_str_);
814 
815  ConstElementPtr ctx = lease->getContext();
816  if (ctx) {
817  user_context_ = ctx->str();
818  } else {
819  user_context_ = "";
820  }
821  bind_array.add(user_context_);
822  } catch (const std::exception& ex) {
824  "Could not create bind array from Lease6: "
825  << lease_->addr_.toText() << ", reason: " << ex.what());
826  }
827  }
828 
838  try {
839 
847 
848  IOAddress addr(getIPv6Value(r, row, ADDRESS_COL));
849 
850  convertFromBytea(r, row, DUID_COL, duid_buffer_, sizeof(duid_buffer_), duid_length_);
851  DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_));
852 
853  getColumnValue(r, row, VALID_LIFETIME_COL, valid_lifetime_);
854 
855  expire_ = convertFromDatabaseTime(getRawColumnValue(r, row,
856  EXPIRE_COL));
857 
858  // Recover from overflow
859  if (valid_lifetime_ == Lease::INFINITY_LFT) {
860  cltt_ = expire_;
861  } else {
862  cltt_ = expire_ - valid_lifetime_;
863  }
864 
865  getColumnValue(r, row , SUBNET_ID_COL, subnet_id_);
866 
867  getColumnValue(r, row , PREF_LIFETIME_COL, pref_lifetime_);
868 
869  getLeaseTypeColumnValue(r, row, LEASE_TYPE_COL, lease_type_);
870 
871  getColumnValue(r, row , IAID_COL, iaid_u_.ival_);
872 
873  getColumnValue(r, row , PREFIX_LEN_COL, prefix_len_);
874 
875  getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
876 
877  getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
878 
879  hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
880 
881  convertFromBytea(r, row, HWADDR_COL, hwaddr_buffer_,
882  sizeof(hwaddr_buffer_), hwaddr_length_);
883 
884  getColumnValue(r, row , HWTYPE_COL, hwtype_);
885 
886  getColumnValue(r, row , HWADDR_SOURCE_COL, hwaddr_source_);
887 
888  HWAddrPtr hwaddr;
889 
890  if (hwaddr_length_) {
891  hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_,
892  hwtype_));
893 
894  hwaddr->source_ = hwaddr_source_;
895  }
896 
897  uint32_t state;
898  getColumnValue(r, row , STATE_COL, state);
899 
900  user_context_ = getRawColumnValue(r, row, USER_CONTEXT_COL);
901  ConstElementPtr ctx;
902  if (!user_context_.empty()) {
903  ctx = Element::fromJSON(user_context_);
904  if (!ctx || (ctx->getType() != Element::map)) {
905  isc_throw(BadValue, "user context '" << user_context_
906  << "' is not a JSON map");
907  }
908  }
909 
910  Lease6Ptr result(boost::make_shared<Lease6>(lease_type_, addr,
911  duid_ptr,
912  iaid_u_.uval_,
913  pref_lifetime_,
914  valid_lifetime_,
915  subnet_id_, fqdn_fwd_,
916  fqdn_rev_, hostname_,
917  hwaddr, prefix_len_));
918  // Update cltt_ and current_cltt_ explicitly.
919  result->cltt_ = cltt_;
920  result->current_cltt_ = cltt_;
921 
922  result->state_ = state;
923 
924  if (ctx) {
925  result->setContext(ctx);
926  }
927 
928  return (result);
929  } catch (const std::exception& ex) {
931  "Could not convert data to Lease6, reason: "
932  << ex.what());
933  }
934  }
935 
948  void getLeaseTypeColumnValue(const PgSqlResult& r, const int row,
949  const size_t col, Lease6::Type& value) const {
950  uint32_t raw_value = 0;
951  getColumnValue(r, row , col, raw_value);
952  switch (raw_value) {
953  case Lease6::TYPE_NA:
954  case Lease6::TYPE_TA:
955  case Lease6::TYPE_PD:
956  value = static_cast<Lease6::Type>(raw_value);
957  break;
958 
959  default:
960  isc_throw(DbOperationError, "Invalid lease type: " << raw_value
961  << " for: " << getColumnLabel(r, col) << " row:" << row);
962  }
963  }
964 
965 private:
969  Lease6Ptr lease_;
970 
972 
973  size_t duid_length_;
974  std::vector<uint8_t> duid_;
975  uint8_t duid_buffer_[DUID::MAX_DUID_LEN];
976  union Uiaid iaid_u_;
977  std::string iaid_str_;
978  Lease6::Type lease_type_;
979  std::string lease_type_str_;
980  uint8_t prefix_len_;
981  std::string prefix_len_str_;
982  uint32_t pref_lifetime_;
983  std::string preferred_lifetime_str_;
984  uint32_t hwtype_;
985  std::string hwtype_str_;
986  uint32_t hwaddr_source_;
987  std::string hwaddr_source_str_;
989 };
990 
997 public:
998 
1008  const bool fetch_type)
1009  : conn_(conn), statement_(statement), result_set_(), next_row_(0),
1010  fetch_type_(fetch_type) {
1011  }
1012 
1022  const bool fetch_type, const SubnetID& subnet_id)
1023  : LeaseStatsQuery(subnet_id), conn_(conn), statement_(statement), result_set_(),
1024  next_row_(0), fetch_type_(fetch_type) {
1025  }
1026 
1038  const bool fetch_type, const SubnetID& first_subnet_id,
1039  const SubnetID& last_subnet_id)
1040  : LeaseStatsQuery(first_subnet_id, last_subnet_id), conn_(conn), statement_(statement),
1041  result_set_(), next_row_(0), fetch_type_(fetch_type) {
1042  }
1043 
1046 
1056  void start() {
1057 
1058  if (getSelectMode() == ALL_SUBNETS) {
1059  // Run the query with no where clause parameters.
1060  result_set_.reset(new PgSqlResult(PQexecPrepared(conn_, statement_.name,
1061  0, 0, 0, 0, 0)));
1062  } else {
1063  // Set up the WHERE clause values
1064  PsqlBindArray parms;
1065 
1066  // Add first_subnet_id used by both single and range.
1067  std::string subnet_id_str = boost::lexical_cast<std::string>(getFirstSubnetID());
1068  parms.add(subnet_id_str);
1069 
1070  // Add last_subnet_id for range.
1071  if (getSelectMode() == SUBNET_RANGE) {
1072  // Add last_subnet_id used by range.
1073  std::string subnet_id_str = boost::lexical_cast<std::string>(getLastSubnetID());
1074  parms.add(subnet_id_str);
1075  }
1076 
1077  // Run the query with where clause parameters.
1078  result_set_.reset(new PgSqlResult(PQexecPrepared(conn_, statement_.name,
1079  parms.size(), &parms.values_[0],
1080  &parms.lengths_[0], &parms.formats_[0], 0)));
1081  }
1082 
1083  conn_.checkStatementError(*result_set_, statement_);
1084  }
1085 
1101  // If we're past the end, punt.
1102  if (next_row_ >= result_set_->getRows()) {
1103  return (false);
1104  }
1105 
1106  // Fetch the subnet id.
1107  uint32_t col = 0;
1108  uint32_t subnet_id;
1109  PgSqlExchange::getColumnValue(*result_set_, next_row_, col, subnet_id);
1110  row.subnet_id_ = static_cast<SubnetID>(subnet_id);
1111  ++col;
1112 
1113  // Fetch the lease type if we were told to do so.
1114  if (fetch_type_) {
1115  uint32_t lease_type;
1116  PgSqlExchange::getColumnValue(*result_set_, next_row_ , col,
1117  lease_type);
1118  row.lease_type_ = static_cast<Lease::Type>(lease_type);
1119  ++col;
1120  } else {
1121  row.lease_type_ = Lease::TYPE_NA;
1122  }
1123 
1124  // Fetch the lease state.
1125  PgSqlExchange::getColumnValue(*result_set_, next_row_ , col,
1126  row.lease_state_);
1127  ++col;
1128 
1129  // Fetch the state count.
1130  PgSqlExchange::getColumnValue(*result_set_, next_row_, col,
1131  row.state_count_);
1132 
1133  // Protect against negative state count.a
1134  if (row.state_count_ < 0) {
1135  row.state_count_ = 0;
1136  if (!negative_count_) {
1137  negative_count_ = true;
1139  }
1140  }
1141 
1142  // Point to the next row.
1143  ++next_row_;
1144  return (true);
1145  }
1146 
1147 protected:
1148 
1151 
1154 
1156  boost::shared_ptr<PgSqlResult> result_set_;
1157 
1159  uint32_t next_row_;
1160 
1163 
1165  static bool negative_count_;
1166 };
1167 
1168 // Initialize negative state count flag to false.
1169 bool PgSqlLeaseStatsQuery::negative_count_ = false;
1170 
1171 // PgSqlLeaseContext Constructor
1172 
1173 PgSqlLeaseContext::PgSqlLeaseContext(const DatabaseConnection::ParameterMap& parameters,
1174  IOServiceAccessorPtr io_service_accessor,
1175  DbCallback db_reconnect_callback)
1176  : conn_(parameters, io_service_accessor, db_reconnect_callback) {
1177 }
1178 
1179 // PgSqlLeaseContextAlloc Constructor and Destructor
1180 
1181 PgSqlLeaseMgr::PgSqlLeaseContextAlloc::PgSqlLeaseContextAlloc(
1182  const PgSqlLeaseMgr& mgr) : ctx_(), mgr_(mgr) {
1183 
1184  if (MultiThreadingMgr::instance().getMode()) {
1185  // multi-threaded
1186  {
1187  // we need to protect the whole pool_ operation, hence extra scope {}
1188  lock_guard<mutex> lock(mgr_.pool_->mutex_);
1189  if (!mgr_.pool_->pool_.empty()) {
1190  ctx_ = mgr_.pool_->pool_.back();
1191  mgr_.pool_->pool_.pop_back();
1192  }
1193  }
1194  if (!ctx_) {
1195  ctx_ = mgr_.createContext();
1196  }
1197  } else {
1198  // single-threaded
1199  if (mgr_.pool_->pool_.empty()) {
1200  isc_throw(Unexpected, "No available PostgreSQL lease context?!");
1201  }
1202  ctx_ = mgr_.pool_->pool_.back();
1203  }
1204 }
1205 
1206 PgSqlLeaseMgr::PgSqlLeaseContextAlloc::~PgSqlLeaseContextAlloc() {
1207  if (MultiThreadingMgr::instance().getMode()) {
1208  // multi-threaded
1209  lock_guard<mutex> lock(mgr_.pool_->mutex_);
1210  mgr_.pool_->pool_.push_back(ctx_);
1211  }
1212  // If running in single-threaded mode, there's nothing to do here.
1213 }
1214 
1215 // PgSqlLeaseMgr Constructor and Destructor
1216 
1218  : parameters_(parameters), timer_name_("") {
1219 
1220  // Create unique timer name per instance.
1221  timer_name_ = "PgSqlLeaseMgr[";
1222  timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this));
1223  timer_name_ += "]DbReconnectTimer";
1224 
1225  // Validate schema version first.
1226  std::pair<uint32_t, uint32_t> code_version(PG_SCHEMA_VERSION_MAJOR,
1228  std::pair<uint32_t, uint32_t> db_version = getVersion();
1229  if (code_version != db_version) {
1231  "PostgreSQL schema version mismatch: need version: "
1232  << code_version.first << "." << code_version.second
1233  << " found version: " << db_version.first << "."
1234  << db_version.second);
1235  }
1236 
1237  // Create an initial context.
1238  pool_.reset(new PgSqlLeaseContextPool());
1239  pool_->pool_.push_back(createContext());
1240 }
1241 
1243 }
1244 
1245 bool
1248 
1249  // Invoke application layer connection lost callback.
1250  if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) {
1251  return (false);
1252  }
1253 
1254  bool reopened = false;
1255 
1256  const std::string timer_name = db_reconnect_ctl->timerName();
1257 
1258  // At least one connection was lost.
1259  try {
1260  CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
1262  LeaseMgrFactory::create(cfg_db->getLeaseDbAccessString());
1263  reopened = true;
1264  } catch (const std::exception& ex) {
1266  .arg(ex.what());
1267  }
1268 
1269  if (reopened) {
1270  // Cancel the timer.
1271  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1272  TimerMgr::instance()->unregisterTimer(timer_name);
1273  }
1274 
1275  // Invoke application layer connection recovered callback.
1276  if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) {
1277  return (false);
1278  }
1279  } else {
1280  if (!db_reconnect_ctl->checkRetries()) {
1281  // We're out of retries, log it and initiate shutdown.
1283  .arg(db_reconnect_ctl->maxRetries());
1284 
1285  // Cancel the timer.
1286  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1287  TimerMgr::instance()->unregisterTimer(timer_name);
1288  }
1289 
1290  // Invoke application layer connection failed callback.
1292  return (false);
1293  }
1294 
1296  .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
1297  .arg(db_reconnect_ctl->maxRetries())
1298  .arg(db_reconnect_ctl->retryInterval());
1299 
1300  // Start the timer.
1301  if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
1302  TimerMgr::instance()->registerTimer(timer_name,
1303  std::bind(&PgSqlLeaseMgr::dbReconnect, db_reconnect_ctl),
1304  db_reconnect_ctl->retryInterval(),
1306  }
1307  TimerMgr::instance()->setup(timer_name);
1308  }
1309 
1310  return (true);
1311 }
1312 
1313 // Create context.
1314 
1317  PgSqlLeaseContextPtr ctx(new PgSqlLeaseContext(parameters_,
1320 
1321  // Open the database.
1322  ctx->conn_.openDatabase();
1323 
1324  // Now prepare the SQL statements.
1325  uint32_t i = 0;
1326  for (; tagged_statements[i].text != NULL; ++i) {
1327  ctx->conn_.prepareStatement(tagged_statements[i]);
1328  }
1329 
1330  // Just in case somebody foo-barred things
1331  if (i != NUM_STATEMENTS) {
1332  isc_throw(DbOpenError, "Number of statements prepared: " << i
1333  << " does not match expected count:" << NUM_STATEMENTS);
1334  }
1335 
1336  // Create the exchange objects for use in exchanging data between the
1337  // program and the database.
1338  ctx->exchange4_.reset(new PgSqlLease4Exchange());
1339  ctx->exchange6_.reset(new PgSqlLease6Exchange());
1340 
1341  // Create ReconnectCtl for this connection.
1342  ctx->conn_.makeReconnectCtl(timer_name_);
1343 
1344  return (ctx);
1345 }
1346 
1347 std::string
1349  std::stringstream tmp;
1350  tmp << "PostgreSQL backend " << PG_SCHEMA_VERSION_MAJOR;
1351  tmp << "." << PG_SCHEMA_VERSION_MINOR;
1352  tmp << ", library " << PQlibVersion();
1353  return (tmp.str());
1354 }
1355 
1356 bool
1357 PgSqlLeaseMgr::addLeaseCommon(PgSqlLeaseContextPtr& ctx,
1358  StatementIndex stindex,
1359  PsqlBindArray& bind_array) {
1360  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
1361  tagged_statements[stindex].nbparams,
1362  &bind_array.values_[0],
1363  &bind_array.lengths_[0],
1364  &bind_array.formats_[0], 0));
1365 
1366  int s = PQresultStatus(r);
1367 
1368  if (s != PGRES_COMMAND_OK) {
1369  // Failure: check for the special case of duplicate entry. If this is
1370  // the case, we return false to indicate that the row was not added.
1371  // Otherwise we throw an exception.
1372  if (ctx->conn_.compareError(r, PgSqlConnection::DUPLICATE_KEY)) {
1373  return (false);
1374  }
1375  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
1376  }
1377 
1378  return (true);
1379 }
1380 
1381 bool
1384  .arg(lease->addr_.toText());
1385 
1386  // Get a context
1387  PgSqlLeaseContextAlloc get_context(*this);
1388  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1389 
1390  PsqlBindArray bind_array;
1391  ctx->exchange4_->createBindForSend(lease, bind_array);
1392  auto result = addLeaseCommon(ctx, INSERT_LEASE4, bind_array);
1393 
1394  // Update lease current expiration time (allows update between the creation
1395  // of the Lease up to the point of insertion in the database).
1396  lease->updateCurrentExpirationTime();
1397 
1398  return (result);
1399 }
1400 
1401 bool
1404  .arg(lease->addr_.toText())
1405  .arg(lease->type_);
1406 
1407  // Get a context
1408  PgSqlLeaseContextAlloc get_context(*this);
1409  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1410 
1411  PsqlBindArray bind_array;
1412  ctx->exchange6_->createBindForSend(lease, bind_array);
1413 
1414  auto result = addLeaseCommon(ctx, INSERT_LEASE6, bind_array);
1415 
1416  // Update lease current expiration time (allows update between the creation
1417  // of the Lease up to the point of insertion in the database).
1418  lease->updateCurrentExpirationTime();
1419 
1420  return (result);
1421 }
1422 
1423 template <typename Exchange, typename LeaseCollection>
1424 void
1425 PgSqlLeaseMgr::getLeaseCollection(PgSqlLeaseContextPtr& ctx,
1426  StatementIndex stindex,
1427  PsqlBindArray& bind_array,
1428  Exchange& exchange,
1429  LeaseCollection& result,
1430  bool single) const {
1431  const int n = tagged_statements[stindex].nbparams;
1432  PgSqlResult r(PQexecPrepared(ctx->conn_,
1433  tagged_statements[stindex].name, n,
1434  n > 0 ? &bind_array.values_[0] : NULL,
1435  n > 0 ? &bind_array.lengths_[0] : NULL,
1436  n > 0 ? &bind_array.formats_[0] : NULL, 0));
1437 
1438  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
1439 
1440  int rows = PQntuples(r);
1441  if (single && rows > 1) {
1442  isc_throw(MultipleRecords, "multiple records were found in the "
1443  "database where only one was expected for query "
1444  << tagged_statements[stindex].name);
1445  }
1446 
1447  for(int i = 0; i < rows; ++ i) {
1448  result.push_back(exchange->convertFromDatabase(r, i));
1449  }
1450 }
1451 
1452 void
1453 PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr& ctx,
1454  StatementIndex stindex, PsqlBindArray& bind_array,
1455  Lease4Ptr& result) const {
1456  // Create appropriate collection object and get all leases matching
1457  // the selection criteria. The "single" parameter is true to indicate
1458  // that the called method should throw an exception if multiple
1459  // matching records are found: this particular method is called when only
1460  // one or zero matches is expected.
1461  Lease4Collection collection;
1462  getLeaseCollection(ctx, stindex, bind_array, ctx->exchange4_,
1463  collection, true);
1464 
1465  // Return single record if present, else clear the lease.
1466  if (collection.empty()) {
1467  result.reset();
1468  } else {
1469  result = *collection.begin();
1470  }
1471 }
1472 
1473 void
1474 PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr& ctx,
1475  StatementIndex stindex, PsqlBindArray& bind_array,
1476  Lease6Ptr& result) const {
1477  // Create appropriate collection object and get all leases matching
1478  // the selection criteria. The "single" parameter is true to indicate
1479  // that the called method should throw an exception if multiple
1480  // matching records are found: this particular method is called when only
1481  // one or zero matches is expected.
1482  Lease6Collection collection;
1483  getLeaseCollection(ctx, stindex, bind_array, ctx->exchange6_,
1484  collection, true);
1485 
1486  // Return single record if present, else clear the lease.
1487  if (collection.empty()) {
1488  result.reset();
1489  } else {
1490  result = *collection.begin();
1491  }
1492 }
1493 
1494 Lease4Ptr
1497  .arg(addr.toText());
1498 
1499  // Set up the WHERE clause value
1500  PsqlBindArray bind_array;
1501 
1502  // LEASE ADDRESS
1503  std::string addr_str = boost::lexical_cast<std::string>(addr.toUint32());
1504  bind_array.add(addr_str);
1505 
1506  // Get the data
1507  Lease4Ptr result;
1508 
1509  // Get a context
1510  PgSqlLeaseContextAlloc get_context(*this);
1511  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1512 
1513  getLease(ctx, GET_LEASE4_ADDR, bind_array, result);
1514 
1515  return (result);
1516 }
1517 
1519 PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
1521  .arg(hwaddr.toText());
1522 
1523  // Set up the WHERE clause value
1524  PsqlBindArray bind_array;
1525 
1526  // HWADDR
1527  if (!hwaddr.hwaddr_.empty()) {
1528  bind_array.add(hwaddr.hwaddr_);
1529  } else {
1530  bind_array.add("");
1531  }
1532 
1533  // Get the data
1534  Lease4Collection result;
1535 
1536  // Get a context
1537  PgSqlLeaseContextAlloc get_context(*this);
1538  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1539 
1540  getLeaseCollection(ctx, GET_LEASE4_HWADDR, bind_array, result);
1541 
1542  return (result);
1543 }
1544 
1545 Lease4Ptr
1546 PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
1548  .arg(subnet_id)
1549  .arg(hwaddr.toText());
1550 
1551  // Set up the WHERE clause value
1552  PsqlBindArray bind_array;
1553 
1554  // HWADDR
1555  if (!hwaddr.hwaddr_.empty()) {
1556  bind_array.add(hwaddr.hwaddr_);
1557  } else {
1558  bind_array.add("");
1559  }
1560 
1561  // SUBNET_ID
1562  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1563  bind_array.add(subnet_id_str);
1564 
1565  // Get the data
1566  Lease4Ptr result;
1567 
1568  // Get a context
1569  PgSqlLeaseContextAlloc get_context(*this);
1570  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1571 
1572  getLease(ctx, GET_LEASE4_HWADDR_SUBID, bind_array, result);
1573 
1574  return (result);
1575 }
1576 
1578 PgSqlLeaseMgr::getLease4(const ClientId& clientid) const {
1580  .arg(clientid.toText());
1581 
1582  // Set up the WHERE clause value
1583  PsqlBindArray bind_array;
1584 
1585  // CLIENT_ID
1586  bind_array.add(clientid.getClientId());
1587 
1588  // Get the data
1589  Lease4Collection result;
1590 
1591  // Get a context
1592  PgSqlLeaseContextAlloc get_context(*this);
1593  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1594 
1595  getLeaseCollection(ctx, GET_LEASE4_CLIENTID, bind_array, result);
1596 
1597  return (result);
1598 }
1599 
1600 Lease4Ptr
1601 PgSqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
1603  .arg(subnet_id)
1604  .arg(clientid.toText());
1605 
1606  // Set up the WHERE clause value
1607  PsqlBindArray bind_array;
1608 
1609  // CLIENT_ID
1610  bind_array.add(clientid.getClientId());
1611 
1612  // SUBNET_ID
1613  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1614  bind_array.add(subnet_id_str);
1615 
1616  // Get the data
1617  Lease4Ptr result;
1618 
1619  // Get a context
1620  PgSqlLeaseContextAlloc get_context(*this);
1621  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1622 
1623  getLease(ctx, GET_LEASE4_CLIENTID_SUBID, bind_array, result);
1624 
1625  return (result);
1626 }
1627 
1631  .arg(subnet_id);
1632 
1633  // Set up the WHERE clause value
1634  PsqlBindArray bind_array;
1635 
1636  // SUBNET_ID
1637  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1638  bind_array.add(subnet_id_str);
1639 
1640  // ... and get the data
1641  Lease4Collection result;
1642 
1643  // Get a context
1644  PgSqlLeaseContextAlloc get_context(*this);
1645  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1646 
1647  getLeaseCollection(ctx, GET_LEASE4_SUBID, bind_array, result);
1648 
1649  return (result);
1650 }
1651 
1653 PgSqlLeaseMgr::getLeases4(const std::string& hostname) const {
1655  .arg(hostname);
1656 
1657  // Set up the WHERE clause value
1658  PsqlBindArray bind_array;
1659 
1660  // Hostname
1661  bind_array.add(hostname);
1662 
1663  // ... and get the data
1664  Lease4Collection result;
1665 
1666  // Get a context
1667  PgSqlLeaseContextAlloc get_context(*this);
1668  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1669 
1670  getLeaseCollection(ctx, GET_LEASE4_HOSTNAME, bind_array, result);
1671 
1672  return (result);
1673 }
1674 
1678 
1679  // Provide empty binding array because our query has no parameters in
1680  // WHERE clause.
1681  PsqlBindArray bind_array;
1682  Lease4Collection result;
1683 
1684  // Get a context
1685  PgSqlLeaseContextAlloc get_context(*this);
1686  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1687 
1688  getLeaseCollection(ctx, GET_LEASE4, bind_array, result);
1689 
1690  return (result);
1691 }
1692 
1694 PgSqlLeaseMgr::getLeases4(const IOAddress& lower_bound_address,
1695  const LeasePageSize& page_size) const {
1696  // Expecting IPv4 address.
1697  if (!lower_bound_address.isV4()) {
1698  isc_throw(InvalidAddressFamily, "expected IPv4 address while "
1699  "retrieving leases from the lease database, got "
1700  << lower_bound_address);
1701  }
1702 
1704  .arg(page_size.page_size_)
1705  .arg(lower_bound_address.toText());
1706 
1707  // Prepare WHERE clause
1708  PsqlBindArray bind_array;
1709 
1710  // Bind lower bound address
1711  std::string lb_address_data = boost::lexical_cast<std::string>(lower_bound_address.toUint32());
1712  bind_array.add(lb_address_data);
1713 
1714  // Bind page size value
1715  std::string page_size_data = boost::lexical_cast<std::string>(page_size.page_size_);
1716  bind_array.add(page_size_data);
1717 
1718  // Get the leases
1719  Lease4Collection result;
1720 
1721  // Get a context
1722  PgSqlLeaseContextAlloc get_context(*this);
1723  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1724 
1725  getLeaseCollection(ctx, GET_LEASE4_PAGE, bind_array, result);
1726 
1727  return (result);
1728 }
1729 
1730 Lease6Ptr
1732  const IOAddress& addr) const {
1734  .arg(addr.toText())
1735  .arg(lease_type);
1736 
1737  // Set up the WHERE clause value
1738  PsqlBindArray bind_array;
1739 
1740  // LEASE ADDRESS
1741  std::string addr_str = addr.toText();
1742  bind_array.add(addr_str);
1743 
1744  // LEASE_TYPE
1745  std::string type_str_ = boost::lexical_cast<std::string>(lease_type);
1746  bind_array.add(type_str_);
1747 
1748  // ... and get the data
1749  Lease6Ptr result;
1750 
1751  // Get a context
1752  PgSqlLeaseContextAlloc get_context(*this);
1753  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1754 
1755  getLease(ctx, GET_LEASE6_ADDR, bind_array, result);
1756 
1757  return (result);
1758 }
1759 
1762  uint32_t iaid) const {
1764  .arg(iaid)
1765  .arg(duid.toText())
1766  .arg(lease_type);
1767 
1768  // Set up the WHERE clause value
1769  PsqlBindArray bind_array;
1770 
1771  // DUID
1772  bind_array.add(duid.getDuid());
1773 
1774  // IAID
1775  std::string iaid_str = PgSqlLease6Exchange::Uiaid(iaid).dbInputString();
1776  bind_array.add(iaid_str);
1777 
1778  // LEASE_TYPE
1779  std::string lease_type_str = boost::lexical_cast<std::string>(lease_type);
1780  bind_array.add(lease_type_str);
1781 
1782  // ... and get the data
1783  Lease6Collection result;
1784 
1785  // Get a context
1786  PgSqlLeaseContextAlloc get_context(*this);
1787  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1788 
1789  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID, bind_array, result);
1790 
1791  return (result);
1792 }
1793 
1796  uint32_t iaid, SubnetID subnet_id) const {
1798  .arg(iaid)
1799  .arg(subnet_id)
1800  .arg(duid.toText())
1801  .arg(lease_type);
1802 
1803  // Set up the WHERE clause value
1804  PsqlBindArray bind_array;
1805 
1806  // LEASE_TYPE
1807  std::string lease_type_str = boost::lexical_cast<std::string>(lease_type);
1808  bind_array.add(lease_type_str);
1809 
1810  // DUID
1811  bind_array.add(duid.getDuid());
1812 
1813  // IAID
1814  std::string iaid_str = PgSqlLease6Exchange::Uiaid(iaid).dbInputString();
1815  bind_array.add(iaid_str);
1816 
1817  // SUBNET ID
1818  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1819  bind_array.add(subnet_id_str);
1820 
1821  // ... and get the data
1822  Lease6Collection result;
1823 
1824  // Get a context
1825  PgSqlLeaseContextAlloc get_context(*this);
1826  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1827 
1828  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID_SUBID, bind_array, result);
1829 
1830  return (result);
1831 }
1832 
1836  .arg(subnet_id);
1837 
1838  // Set up the WHERE clause value
1839  PsqlBindArray bind_array;
1840 
1841  // SUBNET_ID
1842  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1843  bind_array.add(subnet_id_str);
1844 
1845  // ... and get the data
1846  Lease6Collection result;
1847 
1848  // Get a context
1849  PgSqlLeaseContextAlloc get_context(*this);
1850  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1851 
1852  getLeaseCollection(ctx, GET_LEASE6_SUBID, bind_array, result);
1853 
1854  return (result);
1855 }
1856 
1858 PgSqlLeaseMgr::getLeases6(const DUID& duid) const {
1860  .arg(duid.toText());
1861 
1862  // Set up the WHERE clause value
1863  PsqlBindArray bind_array;
1864 
1865  // DUID
1866  bind_array.add(duid.getDuid());
1867  Lease6Collection result;
1868 
1869  // Get a context
1870  PgSqlLeaseContextAlloc get_context(*this);
1871  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1872 
1873  // query to fetch the data
1874  getLeaseCollection(ctx, GET_LEASE6_DUID, bind_array, result);
1875 
1876  return (result);
1877 }
1878 
1880 PgSqlLeaseMgr::getLeases6(const std::string& hostname) const {
1882  .arg(hostname);
1883 
1884  // Set up the WHERE clause value
1885  PsqlBindArray bind_array;
1886 
1887  // Hostname
1888  bind_array.add(hostname);
1889 
1890  // ... and get the data
1891  Lease6Collection result;
1892 
1893  // Get a context
1894  PgSqlLeaseContextAlloc get_context(*this);
1895  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1896 
1897  getLeaseCollection(ctx, GET_LEASE6_HOSTNAME, bind_array, result);
1898 
1899  return (result);
1900 }
1901 
1905 
1906  // Provide empty binding array because our query has no parameters in
1907  // WHERE clause.
1908  PsqlBindArray bind_array;
1909  Lease6Collection result;
1910 
1911  // Get a context
1912  PgSqlLeaseContextAlloc get_context(*this);
1913  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1914 
1915  getLeaseCollection(ctx, GET_LEASE6, bind_array, result);
1916 
1917  return (result);
1918 }
1919 
1921 PgSqlLeaseMgr::getLeases6(const IOAddress& lower_bound_address,
1922  const LeasePageSize& page_size) const {
1923  // Expecting IPv6 address.
1924  if (!lower_bound_address.isV6()) {
1925  isc_throw(InvalidAddressFamily, "expected IPv6 address while "
1926  "retrieving leases from the lease database, got "
1927  << lower_bound_address);
1928  }
1929 
1931  .arg(page_size.page_size_)
1932  .arg(lower_bound_address.toText());
1933 
1934  // Prepare WHERE clause
1935  PsqlBindArray bind_array;
1936 
1937  // In IPv6 we compare addresses represented as strings. The IPv6 zero address
1938  // is ::, so it is greater than any other address. In this special case, we
1939  // just use 0 for comparison which should be lower than any real IPv6 address.
1940  std::string lb_address_data = "0";
1941  if (!lower_bound_address.isV6Zero()) {
1942  lb_address_data = lower_bound_address.toText();
1943  }
1944 
1945  // Bind lower bound address
1946  bind_array.add(lb_address_data);
1947 
1948  // Bind page size value
1949  std::string page_size_data = boost::lexical_cast<std::string>(page_size.page_size_);
1950  bind_array.add(page_size_data);
1951 
1952  // Get the leases
1953  Lease6Collection result;
1954 
1955  // Get a context
1956  PgSqlLeaseContextAlloc get_context(*this);
1957  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1958 
1959  getLeaseCollection(ctx, GET_LEASE6_PAGE, bind_array, result);
1960 
1961  return (result);
1962 }
1963 
1964 void
1966  const size_t max_leases) const {
1968  .arg(max_leases);
1969  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE4_EXPIRE);
1970 }
1971 
1972 void
1974  const size_t max_leases) const {
1976  .arg(max_leases);
1977  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE6_EXPIRE);
1978 }
1979 
1980 template<typename LeaseCollection>
1981 void
1982 PgSqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases,
1983  const size_t max_leases,
1984  StatementIndex statement_index) const {
1985  PsqlBindArray bind_array;
1986 
1987  // Exclude reclaimed leases.
1988  std::string state_str = boost::lexical_cast<std::string>(Lease::STATE_EXPIRED_RECLAIMED);
1989  bind_array.add(state_str);
1990 
1991  // Expiration timestamp.
1992  std::string timestamp_str = PgSqlLeaseExchange::convertToDatabaseTime(time(NULL));
1993  bind_array.add(timestamp_str);
1994 
1995  // If the number of leases is 0, we will return all leases. This is
1996  // achieved by setting the limit to a very high value.
1997  uint32_t limit = max_leases > 0 ? static_cast<uint32_t>(max_leases) :
1998  std::numeric_limits<uint32_t>::max();
1999  std::string limit_str = boost::lexical_cast<std::string>(limit);
2000  bind_array.add(limit_str);
2001 
2002  // Get a context
2003  PgSqlLeaseContextAlloc get_context(*this);
2004  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2005 
2006  // Retrieve leases from the database.
2007  getLeaseCollection(ctx, statement_index, bind_array, expired_leases);
2008 }
2009 
2010 template<typename LeasePtr>
2011 void
2012 PgSqlLeaseMgr::updateLeaseCommon(PgSqlLeaseContextPtr& ctx,
2013  StatementIndex stindex,
2014  PsqlBindArray& bind_array,
2015  const LeasePtr& lease) {
2016  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2017  tagged_statements[stindex].nbparams,
2018  &bind_array.values_[0],
2019  &bind_array.lengths_[0],
2020  &bind_array.formats_[0], 0));
2021 
2022  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2023 
2024  int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
2025 
2026  // Check success case first as it is the most likely outcome.
2027  if (affected_rows == 1) {
2028  return;
2029  }
2030 
2031  // If no rows affected, lease doesn't exist.
2032  if (affected_rows == 0) {
2033  isc_throw(NoSuchLease, "unable to update lease for address " <<
2034  lease->addr_.toText() << " as it does not exist");
2035  }
2036 
2037  // Should not happen - primary key constraint should only have selected
2038  // one row.
2039  isc_throw(DbOperationError, "apparently updated more than one lease "
2040  "that had the address " << lease->addr_.toText());
2041 }
2042 
2043 void
2045  const StatementIndex stindex = UPDATE_LEASE4;
2046 
2048  .arg(lease->addr_.toText());
2049 
2050  // Get a context
2051  PgSqlLeaseContextAlloc get_context(*this);
2052  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2053 
2054  // Create the BIND array for the data being updated
2055  PsqlBindArray bind_array;
2056  ctx->exchange4_->createBindForSend(lease, bind_array);
2057 
2058  // Set up the WHERE clause and append it to the SQL_BIND array
2059  std::string addr4_str = boost::lexical_cast<std::string>(lease->addr_.toUint32());
2060  bind_array.add(addr4_str);
2061 
2062  std::string expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2063  lease->current_valid_lft_);
2064  bind_array.add(expire_str);
2065 
2066  // Drop to common update code
2067  updateLeaseCommon(ctx, stindex, bind_array, lease);
2068 
2069  // Update lease current expiration time.
2070  lease->updateCurrentExpirationTime();
2071 }
2072 
2073 void
2075  const StatementIndex stindex = UPDATE_LEASE6;
2076 
2078  .arg(lease->addr_.toText())
2079  .arg(lease->type_);
2080 
2081  // Get a context
2082  PgSqlLeaseContextAlloc get_context(*this);
2083  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2084 
2085  // Create the BIND array for the data being updated
2086  PsqlBindArray bind_array;
2087  ctx->exchange6_->createBindForSend(lease, bind_array);
2088 
2089  // Set up the WHERE clause and append it to the BIND array
2090  std::string addr_str = lease->addr_.toText();
2091  bind_array.add(addr_str);
2092 
2093  std::string expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2094  lease->current_valid_lft_);
2095  bind_array.add(expire_str);
2096 
2097  // Drop to common update code
2098  updateLeaseCommon(ctx, stindex, bind_array, lease);
2099 
2100  // Update lease current expiration time.
2101  lease->updateCurrentExpirationTime();
2102 }
2103 
2104 uint64_t
2105 PgSqlLeaseMgr::deleteLeaseCommon(StatementIndex stindex,
2106  PsqlBindArray& bind_array) {
2107  // Get a context
2108  PgSqlLeaseContextAlloc get_context(*this);
2109  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2110 
2111  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2112  tagged_statements[stindex].nbparams,
2113  &bind_array.values_[0],
2114  &bind_array.lengths_[0],
2115  &bind_array.formats_[0], 0));
2116 
2117  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2118  int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
2119 
2120  return (affected_rows);
2121 }
2122 
2123 bool
2125  const IOAddress& addr = lease->addr_;
2127  .arg(addr.toText());
2128 
2129  // Set up the WHERE clause value
2130  PsqlBindArray bind_array;
2131 
2132  std::string addr4_str = boost::lexical_cast<std::string>(addr.toUint32());
2133  bind_array.add(addr4_str);
2134 
2135  std::string expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2136  lease->current_valid_lft_);
2137  bind_array.add(expire_str);
2138 
2139  auto affected_rows = deleteLeaseCommon(DELETE_LEASE4, bind_array);
2140 
2141  // Check success case first as it is the most likely outcome.
2142  if (affected_rows == 1) {
2143  return (true);
2144  }
2145 
2146  // If no rows affected, lease doesn't exist.
2147  if (affected_rows == 0) {
2148  return (false);
2149  }
2150 
2151  // Should not happen - primary key constraint should only have selected
2152  // one row.
2153  isc_throw(DbOperationError, "apparently deleted more than one lease "
2154  "that had the address " << lease->addr_.toText());
2155 }
2156 
2157 bool
2159  const IOAddress& addr = lease->addr_;
2162  .arg(addr.toText());
2163 
2164  // Set up the WHERE clause value
2165  PsqlBindArray bind_array;
2166 
2167  std::string addr6_str = addr.toText();
2168  bind_array.add(addr6_str);
2169 
2170  std::string expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2171  lease->current_valid_lft_);
2172  bind_array.add(expire_str);
2173 
2174  auto affected_rows = deleteLeaseCommon(DELETE_LEASE6, bind_array);
2175 
2176  // Check success case first as it is the most likely outcome.
2177  if (affected_rows == 1) {
2178  return (true);
2179  }
2180 
2181  // If no rows affected, lease doesn't exist.
2182  if (affected_rows == 0) {
2183  return (false);
2184  }
2185 
2186  // Should not happen - primary key constraint should only have selected
2187  // one row.
2188  isc_throw(DbOperationError, "apparently deleted more than one lease "
2189  "that had the address " << lease->addr_.toText());
2190 }
2191 
2192 uint64_t
2195  .arg(secs);
2196  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
2197 }
2198 
2199 uint64_t
2202  .arg(secs);
2203  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
2204 }
2205 
2206 uint64_t
2207 PgSqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
2208  StatementIndex statement_index) {
2209  PsqlBindArray bind_array;
2210 
2211  // State is reclaimed.
2212  std::string state_str = boost::lexical_cast<std::string>(Lease::STATE_EXPIRED_RECLAIMED);
2213  bind_array.add(state_str);
2214 
2215  // Expiration timestamp.
2216  std::string expiration_str = PgSqlLeaseExchange::convertToDatabaseTime(time(NULL) -
2217  static_cast<time_t>(secs));
2218  bind_array.add(expiration_str);
2219 
2220  // Delete leases.
2221  return (deleteLeaseCommon(statement_index, bind_array));
2222 }
2223 
2226  // Get a context
2227  PgSqlLeaseContextAlloc get_context(*this);
2228  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2229 
2230  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2231  tagged_statements[ALL_LEASE4_STATS],
2232  false));
2233  query->start();
2234  return(query);
2235 }
2236 
2239  // Get a context
2240  PgSqlLeaseContextAlloc get_context(*this);
2241  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2242 
2243  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2244  tagged_statements[SUBNET_LEASE4_STATS],
2245  false,
2246  subnet_id));
2247  query->start();
2248  return(query);
2249 }
2250 
2253  const SubnetID& last_subnet_id) {
2254  // Get a context
2255  PgSqlLeaseContextAlloc get_context(*this);
2256  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2257 
2258  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2259  tagged_statements[SUBNET_RANGE_LEASE4_STATS],
2260  false,
2261  first_subnet_id,
2262  last_subnet_id));
2263  query->start();
2264  return(query);
2265 }
2266 
2269  // Get a context
2270  PgSqlLeaseContextAlloc get_context(*this);
2271  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2272 
2273  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2274  tagged_statements[ALL_LEASE6_STATS],
2275  true));
2276  query->start();
2277  return(query);
2278 }
2279 
2282  // Get a context
2283  PgSqlLeaseContextAlloc get_context(*this);
2284  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2285 
2286  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2287  tagged_statements[SUBNET_LEASE6_STATS],
2288  true,
2289  subnet_id));
2290  query->start();
2291  return(query);
2292 }
2293 
2296  const SubnetID& last_subnet_id) {
2297  // Get a context
2298  PgSqlLeaseContextAlloc get_context(*this);
2299  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2300 
2301  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2302  tagged_statements[SUBNET_RANGE_LEASE6_STATS],
2303  true,
2304  first_subnet_id,
2305  last_subnet_id));
2306  query->start();
2307  return(query);
2308 }
2309 
2310 size_t
2311 PgSqlLeaseMgr::wipeLeases4(const SubnetID& /*subnet_id*/) {
2312  isc_throw(NotImplemented, "wipeLeases4 is not implemented for PostgreSQL backend");
2313 }
2314 
2315 size_t
2316 PgSqlLeaseMgr::wipeLeases6(const SubnetID& /*subnet_id*/) {
2317  isc_throw(NotImplemented, "wipeLeases6 is not implemented for PostgreSQL backend");
2318 }
2319 
2320 std::string
2322  // Get a context
2323  PgSqlLeaseContextAlloc get_context(*this);
2324  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2325 
2326  std::string name = "";
2327  try {
2328  name = ctx->conn_.getParameter("name");
2329  } catch (...) {
2330  // Return an empty name
2331  }
2332  return (name);
2333 }
2334 
2335 std::string
2337  return (std::string("PostgreSQL Database"));
2338 }
2339 
2340 std::pair<uint32_t, uint32_t>
2343 
2344  return (PgSqlConnection::getVersion(parameters_));
2345 }
2346 
2347 void
2350 }
2351 
2352 void
2355 }
2356 
2357 } // namespace dhcp
2358 } // 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's stats.
RAII class creating a critical section.
const std::vector< uint8_t > & getDuid() const
Returns a const reference to the actual DUID value.
Definition: duid.cc:46
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:20
const isc::log::MessageID DHCPSRV_PGSQL_LEASE_DB_RECONNECT_FAILED
RAII wrapper for PostgreSQL Result sets.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const
Returns an IPv4 lease for specified IPv4 address.
const isc::log::MessageID DHCPSRV_PGSQL_ROLLBACK
boost::shared_ptr< LeaseStatsQuery > LeaseStatsQueryPtr
Defines a pointer to a LeaseStatsQuery.
Definition: lease_mgr.h:207
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 Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const
Returns existing IPv6 lease for a given IPv6 address.
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:122
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:79
static bool negative_count_
Received negative state count showing a problem.
static std::string convertToDatabaseTime(const time_t input_time)
Converts time_t value to a text representation in local time.
virtual std::string getName() const
Returns backend name.
const isc::log::MessageID DHCPSRV_PGSQL_GET_HOSTNAME4
#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.
const isc::log::MessageID DHCPSRV_PGSQL_LEASE_DB_RECONNECT_ATTEMPT_SCHEDULE
static void destroy()
Destroy lease manager.
virtual Lease6Collection getLeases6() const
Returns all IPv6 leases.
std::string toText() const
Dumps the contents of the array to a string.
virtual Lease4Collection getLeases4() const
Returns all IPv4 leases.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID &subnet_id)
Creates and runs the IPv6 lease stats query for a single subnet.
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...
PgSqlLeaseContextPtr createContext() const
Create a new context.
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition: lease.h:487
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:128
std::string toText(bool include_htype=true) const
Returns textual representation of a hardware address (e.g.
Definition: hwaddr.cc:51
Base class for marshalling data to and from PostgreSQL.
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.
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:26
const size_t OID_TEXT
std::vector< const char * > values_
Vector of pointers to the data values.
virtual void getExpiredLeases6(Lease6Collection &expired_leases, const size_t max_leases) const
Returns a collection of expired DHCPv6 leases.
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
not specified or undefined
Definition: dhcp4.h:55
static isc::asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service.
Definition: lease_mgr.h:758
virtual std::string getDescription() const
Returns description of the backend.
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.
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:28
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...
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:53
const uint32_t PG_SCHEMA_VERSION_MINOR
const isc::log::MessageID DHCPSRV_PGSQL_GET4
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:283
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
const isc::log::MessageID DHCPSRV_PGSQL_GET_CLIENTID
const std::vector< uint8_t > & getClientId() const
Returns reference to the client-id data.
Definition: duid.cc:117
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:114
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:23
Structure that holds a lease for IPv6 address and/or prefix.
Definition: lease.h:503
const isc::log::MessageID DHCPSRV_PGSQL_GET_PAGE6
PgSqlTaggedStatement & statement_
The query'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.
size_t size() const
Fetches the number of entries in the array.
Common PgSql Connector Pool.
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:640
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:75
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
virtual void getExpiredLeases4(Lease4Collection &expired_leases, const size_t max_leases) const
Returns a collection of expired DHCPv4 leases.
Ethernet 10Mbps.
Definition: dhcp4.h:56
Invalid address family used as input to Lease Manager.
Definition: db_exceptions.h:71
static bool invokeDbFailedCallback(const ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restore failed connectivity callback.
Defines the logger used by the top-level component of kea-dhcp-ddns.
const isc::log::MessageID DHCPSRV_PGSQL_GET6
std::function< bool(ReconnectCtlPtr db_reconnect_ctl)> DbCallback
Defines a callback prototype for propagating events upward.
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 invokeDbRecoveredCallback(const ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restored connectivity callback.
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.
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
static bool invokeDbLostCallback(const ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's lost connectivity callback.
uint32_t lease_state_
The lease_state to which the count applies.
Definition: lease_mgr.h:118
Type
Type of lease or pool.
Definition: lease.h:50
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.
static bool dbReconnect(db::ReconnectCtlPtr db_reconnect_ctl)
Attempts to reconnect the server to the lease DB backend manager.
#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:120
virtual std::pair< uint32_t, uint32_t > getVersion() const
Returns backend version.
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:61
Wraps value holding size of the page with leases.
Definition: lease_mgr.h:43
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 , but including this file is extraordinarily convoluted, so we'll use these to fill-in.
Lease::Type lease_type_
The lease_type to which the count applies.
Definition: lease_mgr.h:116
virtual void commit()
Commit Transactions.
virtual bool deleteLease(const Lease4Ptr &lease)
Deletes an IPv4 lease.
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:441
virtual size_t wipeLeases4(const SubnetID &subnet_id)
Removes specified IPv4 leases.
const isc::log::MessageID DHCPSRV_PGSQL_UPDATE_ADDR4
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
const uint32_t PG_SCHEMA_VERSION_MAJOR
Define PostgreSQL backend version: 6.2.
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:492
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' stats.
const size_t OID_TIMESTAMP
virtual LeaseStatsQueryPtr startLeaseStatsQuery6()
Creates and runs the IPv6 lease stats query.
Supports exchanging IPv6 leases with PostgreSQL.
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 isc::log::MessageID DHCPSRV_PGSQL_ADD_ADDR4
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.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.