Kea  1.5.0
pgsql_lease_mgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2018 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/dhcpsrv_log.h>
15 
16 #include <boost/static_assert.hpp>
17 
18 #include <iomanip>
19 #include <limits>
20 #include <sstream>
21 #include <string>
22 #include <time.h>
23 
24 using namespace isc;
25 using namespace isc::asiolink;
26 using namespace isc::db;
27 using namespace isc::dhcp;
28 using namespace isc::data;
29 using namespace std;
30 
31 namespace {
32 
37  // DELETE_LEASE4
38  { 1, { OID_INT8 },
39  "delete_lease4",
40  "DELETE FROM lease4 WHERE address = $1"},
41 
42  // DELETE_LEASE4_STATE_EXPIRED
43  { 2, { OID_INT8, OID_TIMESTAMP },
44  "delete_lease4_state_expired",
45  "DELETE FROM lease4 "
46  "WHERE state = $1 AND expire < $2"},
47 
48  // DELETE_LEASE6
49  { 1, { OID_VARCHAR },
50  "delete_lease6",
51  "DELETE FROM lease6 WHERE address = $1"},
52 
53  // DELETE_LEASE6_STATE_EXPIRED
54  { 2, { OID_INT8, OID_TIMESTAMP },
55  "delete_lease6_state_expired",
56  "DELETE FROM lease6 "
57  "WHERE state = $1 AND expire < $2"},
58 
59  // GET_LEASE4
60  { 0, { OID_NONE },
61  "get_lease4",
62  "SELECT address, hwaddr, client_id, "
63  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
64  "fqdn_fwd, fqdn_rev, hostname, "
65  "state, user_context "
66  "FROM lease4"},
67 
68  // GET_LEASE4_ADDR
69  { 1, { OID_INT8 },
70  "get_lease4_addr",
71  "SELECT address, hwaddr, client_id, "
72  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
73  "fqdn_fwd, fqdn_rev, hostname, "
74  "state, user_context "
75  "FROM lease4 "
76  "WHERE address = $1"},
77 
78  // GET_LEASE4_CLIENTID
79  { 1, { OID_BYTEA },
80  "get_lease4_clientid",
81  "SELECT address, hwaddr, client_id, "
82  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
83  "fqdn_fwd, fqdn_rev, hostname, "
84  "state, user_context "
85  "FROM lease4 "
86  "WHERE client_id = $1"},
87 
88  // GET_LEASE4_CLIENTID_SUBID
89  { 2, { OID_BYTEA, OID_INT8 },
90  "get_lease4_clientid_subid",
91  "SELECT address, hwaddr, client_id, "
92  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
93  "fqdn_fwd, fqdn_rev, hostname, "
94  "state, user_context "
95  "FROM lease4 "
96  "WHERE client_id = $1 AND subnet_id = $2"},
97 
98  // GET_LEASE4_HWADDR
99  { 1, { OID_BYTEA },
100  "get_lease4_hwaddr",
101  "SELECT address, hwaddr, client_id, "
102  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
103  "fqdn_fwd, fqdn_rev, hostname, "
104  "state, user_context "
105  "FROM lease4 "
106  "WHERE hwaddr = $1"},
107 
108  // GET_LEASE4_HWADDR_SUBID
109  { 2, { OID_BYTEA, OID_INT8 },
110  "get_lease4_hwaddr_subid",
111  "SELECT address, hwaddr, client_id, "
112  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
113  "fqdn_fwd, fqdn_rev, hostname, "
114  "state, user_context "
115  "FROM lease4 "
116  "WHERE hwaddr = $1 AND subnet_id = $2"},
117 
118  // GET_LEASE4_PAGE
119  { 2, { OID_INT8, OID_INT8 },
120  "get_lease4_page",
121  "SELECT address, hwaddr, client_id, "
122  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
123  "fqdn_fwd, fqdn_rev, hostname, "
124  "state, user_context "
125  "FROM lease4 "
126  "WHERE address > $1 "
127  "ORDER BY address "
128  "LIMIT $2"},
129 
130  // GET_LEASE4_SUBID
131  { 1, { OID_INT8 },
132  "get_lease4_subid",
133  "SELECT address, hwaddr, client_id, "
134  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
135  "fqdn_fwd, fqdn_rev, hostname, "
136  "state, user_context "
137  "FROM lease4 "
138  "WHERE subnet_id = $1"},
139 
140  // GET_LEASE4_EXPIRE
141  { 3, { OID_INT8, OID_TIMESTAMP, OID_INT8 },
142  "get_lease4_expire",
143  "SELECT address, hwaddr, client_id, "
144  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
145  "fqdn_fwd, fqdn_rev, hostname, "
146  "state, user_context "
147  "FROM lease4 "
148  "WHERE state != $1 AND expire < $2 "
149  "ORDER BY expire "
150  "LIMIT $3"},
151 
152  // GET_LEASE6
153  { 0, { OID_NONE },
154  "get_lease6",
155  "SELECT address, duid, valid_lifetime, "
156  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
157  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
158  "hwaddr, hwtype, hwaddr_source, "
159  "state, user_context "
160  "FROM lease6"},
161 
162  // GET_LEASE6_ADDR
163  { 2, { OID_VARCHAR, OID_INT2 },
164  "get_lease6_addr",
165  "SELECT address, duid, valid_lifetime, "
166  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
167  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
168  "hwaddr, hwtype, hwaddr_source, "
169  "state, user_context "
170  "FROM lease6 "
171  "WHERE address = $1 AND lease_type = $2"},
172 
173  // GET_LEASE6_DUID_IAID
174  { 3, { OID_BYTEA, OID_INT8, OID_INT2 },
175  "get_lease6_duid_iaid",
176  "SELECT address, duid, valid_lifetime, "
177  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
178  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
179  "hwaddr, hwtype, hwaddr_source, "
180  "state, user_context "
181  "FROM lease6 "
182  "WHERE duid = $1 AND iaid = $2 AND lease_type = $3"},
183 
184  // GET_LEASE6_DUID_IAID_SUBID
185  { 4, { OID_INT2, OID_BYTEA, OID_INT8, OID_INT8 },
186  "get_lease6_duid_iaid_subid",
187  "SELECT address, duid, valid_lifetime, "
188  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
189  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
190  "hwaddr, hwtype, hwaddr_source, "
191  "state, user_context "
192  "FROM lease6 "
193  "WHERE lease_type = $1 "
194  "AND duid = $2 AND iaid = $3 AND subnet_id = $4"},
195 
196  // GET_LEASE6_PAGE
197  { 2, { OID_VARCHAR, OID_INT8 },
198  "get_lease6_page",
199  "SELECT address, duid, valid_lifetime, "
200  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
201  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
202  "hwaddr, hwtype, hwaddr_source, "
203  "state, user_context "
204  "FROM lease6 "
205  "WHERE address > $1 "
206  "ORDER BY address "
207  "LIMIT $2"},
208 
209  // GET_LEASE6_SUBID
210  { 1, { OID_INT8 },
211  "get_lease6_subid",
212  "SELECT address, duid, valid_lifetime, "
213  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
214  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
215  "hwaddr, hwtype, hwaddr_source, "
216  "state, user_context "
217  "FROM lease6 "
218  "WHERE subnet_id = $1"},
219 
220  // GET_LEASE6_DUID
221  { 1, { OID_BYTEA },
222  "get_lease6_duid",
223  "SELECT address, duid, valid_lifetime, "
224  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
225  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
226  "hwaddr, hwtype, hwaddr_source, "
227  "state, user_context "
228  "FROM lease6 "
229  "WHERE duid = $1"},
230 
231  // GET_LEASE6_EXPIRE
232  { 3, { OID_INT8, OID_TIMESTAMP, OID_INT8 },
233  "get_lease6_expire",
234  "SELECT address, duid, valid_lifetime, "
235  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
236  "lease_type, iaid, prefix_len, "
237  "fqdn_fwd, fqdn_rev, hostname, "
238  "hwaddr, hwtype, hwaddr_source, "
239  "state, user_context "
240  "FROM lease6 "
241  "WHERE state != $1 AND expire < $2 "
242  "ORDER BY expire "
243  "LIMIT $3"},
244 
245  // INSERT_LEASE4
248  "insert_lease4",
249  "INSERT INTO lease4(address, hwaddr, client_id, "
250  "valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, "
251  "state, user_context) "
252  "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)"},
253 
254  // INSERT_LEASE6
258  "insert_lease6",
259  "INSERT INTO lease6(address, duid, valid_lifetime, "
260  "expire, subnet_id, pref_lifetime, "
261  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
262  "hwaddr, hwtype, hwaddr_source, "
263  "state, user_context) "
264  "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)"},
265 
266  // UPDATE_LEASE4
269  "update_lease4",
270  "UPDATE lease4 SET address = $1, hwaddr = $2, "
271  "client_id = $3, valid_lifetime = $4, expire = $5, "
272  "subnet_id = $6, fqdn_fwd = $7, fqdn_rev = $8, hostname = $9, "
273  "state = $10, user_context = $11 "
274  "WHERE address = $12"},
275 
276  // UPDATE_LEASE6
281  "update_lease6",
282  "UPDATE lease6 SET address = $1, duid = $2, "
283  "valid_lifetime = $3, expire = $4, subnet_id = $5, "
284  "pref_lifetime = $6, lease_type = $7, iaid = $8, "
285  "prefix_len = $9, fqdn_fwd = $10, fqdn_rev = $11, hostname = $12, "
286  "hwaddr = $13, hwtype = $14, hwaddr_source = $15, "
287  "state = $16, user_context = $17 "
288  "WHERE address = $18"},
289  // ALL_LEASE4_STATS
290  { 0, { OID_NONE },
291  "all_lease4_stats",
292  "SELECT subnet_id, state, leases as state_count"
293  " FROM lease4_stat ORDER BY subnet_id, state"},
294 
295  // SUBNET_LEASE4_STATS
296  { 1, { OID_INT8 },
297  "subnet_lease4_stats",
298  "SELECT subnet_id, state, leases as state_count"
299  " FROM lease4_stat "
300  " WHERE subnet_id = $1 "
301  " ORDER BY state"},
302 
303  // SUBNET_RANGE_LEASE4_STATS
304  { 2, { OID_INT8, OID_INT8 },
305  "subnet_range_lease4_stats",
306  "SELECT subnet_id, state, leases as state_count"
307  " FROM lease4_stat "
308  " WHERE subnet_id >= $1 and subnet_id <= $2 "
309  " ORDER BY subnet_id, state"},
310 
311  // ALL_LEASE6_STATS,
312  { 0, { OID_NONE },
313  "all_lease6_stats",
314  "SELECT subnet_id, lease_type, state, leases as state_count"
315  " FROM lease6_stat ORDER BY subnet_id, lease_type, state" },
316 
317  // SUBNET_LEASE6_STATS
318  { 1, { OID_INT8 },
319  "subnet_lease6_stats",
320  "SELECT subnet_id, lease_type, state, leases as state_count"
321  " FROM lease6_stat "
322  " WHERE subnet_id = $1 "
323  " ORDER BY lease_type, state" },
324 
325  // SUBNET_RANGE_LEASE6_STATS
326  { 2, { OID_INT8, OID_INT8 },
327  "subnet_range_lease6_stats",
328  "SELECT subnet_id, lease_type, state, leases as state_count"
329  " FROM lease6_stat "
330  " WHERE subnet_id >= $1 and subnet_id <= $2 "
331  " ORDER BY subnet_id, lease_type, state" },
332  // End of list sentinel
333  { 0, { 0 }, NULL, NULL}
334 };
335 
336 } // namespace
337 
338 namespace isc {
339 namespace dhcp {
340 
347 public:
349  : addr_str_(""), valid_lifetime_(0), valid_lifetime_str_(""),
350  expire_(0), expire_str_(""), subnet_id_(0), subnet_id_str_(""),
351  cltt_(0), fqdn_fwd_(false), fqdn_rev_(false), hostname_(""),
352  state_str_(""), user_context_("") {
353  }
354 
356 
357 protected:
359 
360  std::string addr_str_;
361  uint32_t valid_lifetime_;
362  std::string valid_lifetime_str_;
363  time_t expire_;
364  std::string expire_str_;
365  uint32_t subnet_id_;
366  std::string subnet_id_str_;
367  time_t cltt_;
368  bool fqdn_fwd_;
369  bool fqdn_rev_;
370  std::string hostname_;
371  std::string state_str_;
372  std::string user_context_;
374 };
375 
378 private:
379 
384  static const size_t ADDRESS_COL = 0;
385  static const size_t HWADDR_COL = 1;
386  static const size_t CLIENT_ID_COL = 2;
387  static const size_t VALID_LIFETIME_COL = 3;
388  static const size_t EXPIRE_COL = 4;
389  static const size_t SUBNET_ID_COL = 5;
390  static const size_t FQDN_FWD_COL = 6;
391  static const size_t FQDN_REV_COL = 7;
392  static const size_t HOSTNAME_COL = 8;
393  static const size_t STATE_COL = 9;
394  static const size_t USER_CONTEXT_COL = 10;
396  static const size_t LEASE_COLUMNS = 11;
397 
398 public:
399 
402  : lease_(), addr4_(0), hwaddr_length_(0), hwaddr_(hwaddr_length_),
403  client_id_length_(0) {
404 
405  BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
406 
407  memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
408  memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
409 
410  // Set the column names (for error messages)
411  columns_.push_back("address");
412  columns_.push_back("hwaddr");
413  columns_.push_back("client_id");
414  columns_.push_back("valid_lifetime");
415  columns_.push_back("expire");
416  columns_.push_back("subnet_id");
417  columns_.push_back("fqdn_fwd");
418  columns_.push_back("fqdn_rev");
419  columns_.push_back("hostname");
420  columns_.push_back("state");
421  columns_.push_back("user_context");
422  }
423 
436  void createBindForSend(const Lease4Ptr& lease, PsqlBindArray& bind_array) {
437  if (!lease) {
438  isc_throw(BadValue, "createBindForSend:: Lease4 object is NULL");
439  }
440 
441  // Store lease object to ensure it remains valid.
442  lease_ = lease;
443 
444  try {
445  addr_str_ = boost::lexical_cast<std::string>
446  (lease->addr_.toUint32());
447  bind_array.add(addr_str_);
448 
449  if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) {
450  // PostgreSql does not provide MAX on variable length types
451  // so we have to enforce it ourselves.
452  if (lease->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
453  isc_throw(DbOperationError, "Hardware address length : "
454  << lease_->hwaddr_->hwaddr_.size()
455  << " exceeds maximum allowed of: "
456  << HWAddr::MAX_HWADDR_LEN);
457  }
458  bind_array.add(lease->hwaddr_->hwaddr_);
459  } else {
460  bind_array.add("");
461  }
462 
463  if (lease->client_id_) {
464  bind_array.add(lease->client_id_->getClientId());
465  } else {
466  bind_array.add("");
467  }
468 
469  valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
470  bind_array.add(valid_lifetime_str_);
471 
472  expire_str_ = convertToDatabaseTime(lease->cltt_, lease_->valid_lft_);
473  bind_array.add(expire_str_);
474 
475  subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
476  bind_array.add(subnet_id_str_);
477 
478  bind_array.add(lease->fqdn_fwd_);
479 
480  bind_array.add(lease->fqdn_rev_);
481 
482  bind_array.add(lease->hostname_);
483 
484  state_str_ = boost::lexical_cast<std::string>(lease->state_);
485  bind_array.add(state_str_);
486 
487  ConstElementPtr ctx = lease->getContext();
488  if (ctx) {
489  user_context_ = ctx->str();
490  } else {
491  user_context_ = "";
492  }
493  bind_array.add(user_context_);
494 
495  } catch (const std::exception& ex) {
497  "Could not create bind array from Lease4: "
498  << lease_->addr_.toText() << ", reason: " << ex.what());
499  }
500  }
501 
511  try {
512  getColumnValue(r, row, ADDRESS_COL, addr4_);
513 
514  convertFromBytea(r, row, HWADDR_COL, hwaddr_buffer_,
515  sizeof(hwaddr_buffer_), hwaddr_length_);
516 
517  convertFromBytea(r, row, CLIENT_ID_COL, client_id_buffer_,
518  sizeof(client_id_buffer_), client_id_length_);
519 
520  getColumnValue(r, row, VALID_LIFETIME_COL, valid_lifetime_);
521 
522  expire_ = convertFromDatabaseTime(getRawColumnValue(r, row,
523  EXPIRE_COL));
524 
525  getColumnValue(r, row , SUBNET_ID_COL, subnet_id_);
526 
527  cltt_ = expire_ - valid_lifetime_;
528 
529  getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
530 
531  getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
532 
533  hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
534 
535  uint32_t state;
536  getColumnValue(r, row , STATE_COL, state);
537 
538  HWAddrPtr hwaddr(new HWAddr(hwaddr_buffer_, hwaddr_length_,
539  HTYPE_ETHER));
540 
541  user_context_ = getRawColumnValue(r, row, USER_CONTEXT_COL);
542  ConstElementPtr ctx;
543  if (!user_context_.empty()) {
544  ctx = Element::fromJSON(user_context_);
545  if (!ctx || (ctx->getType() != Element::map)) {
546  isc_throw(BadValue, "user context '" << user_context_
547  << "' is not a JSON map");
548  }
549  }
550 
551  Lease4Ptr result(new Lease4(addr4_, hwaddr,
552  client_id_buffer_, client_id_length_,
553  valid_lifetime_, 0, 0, cltt_,
554  subnet_id_, fqdn_fwd_, fqdn_rev_,
555  hostname_));
556 
557  result->state_ = state;
558 
559  if (ctx) {
560  result->setContext(ctx);
561  }
562 
563  return (result);
564  } catch (const std::exception& ex) {
566  "Could not convert data to Lease4, reason: "
567  << ex.what());
568  }
569  }
570 
571 private:
575  Lease4Ptr lease_;
576 
578  uint32_t addr4_;
579  size_t hwaddr_length_;
580  std::vector<uint8_t> hwaddr_;
581  uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
582  size_t client_id_length_;
583  uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
584 };
585 
588 private:
589 
594 
595  static const int ADDRESS_COL = 0;
596  static const int DUID_COL = 1;
597  static const int VALID_LIFETIME_COL = 2;
598  static const int EXPIRE_COL = 3;
599  static const int SUBNET_ID_COL = 4;
600  static const int PREF_LIFETIME_COL = 5;
601  static const int LEASE_TYPE_COL = 6;
602  static const int IAID_COL = 7;
603  static const int PREFIX_LEN_COL = 8;
604  static const int FQDN_FWD_COL = 9;
605  static const int FQDN_REV_COL = 10;
606  static const int HOSTNAME_COL = 11;
607  static const int HWADDR_COL = 12;
608  static const int HWTYPE_COL = 13;
609  static const int HWADDR_SOURCE_COL = 14;
610  static const int STATE_COL = 15;
611  static const size_t USER_CONTEXT_COL = 16;
613  static const size_t LEASE_COLUMNS = 17;
615 
616 public:
618  : lease_(), duid_length_(0), duid_(), iaid_u_(0), iaid_str_(""),
619  lease_type_(Lease6::TYPE_NA), lease_type_str_(""), prefix_len_(0),
620  prefix_len_str_(""), pref_lifetime_(0), preferred_lifetime_str_("") {
621 
622  BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
623 
624  memset(duid_buffer_, 0, sizeof(duid_buffer_));
625 
626  // Set the column names (for error messages)
627  columns_.push_back("address");
628  columns_.push_back("duid");
629  columns_.push_back("valid_lifetime");
630  columns_.push_back("expire");
631  columns_.push_back("subnet_id");
632  columns_.push_back("pref_lifetime");
633  columns_.push_back("lease_type");
634  columns_.push_back("iaid");
635  columns_.push_back("prefix_len");
636  columns_.push_back("fqdn_fwd");
637  columns_.push_back("fqdn_rev");
638  columns_.push_back("hostname");
639  columns_.push_back("hwaddr");
640  columns_.push_back("hwtype");
641  columns_.push_back("hwaddr_source");
642  columns_.push_back("state");
643  columns_.push_back("user_context");
644  }
645 
658  void createBindForSend(const Lease6Ptr& lease, PsqlBindArray& bind_array) {
659  if (!lease) {
660  isc_throw(BadValue, "createBindForSend:: Lease6 object is NULL");
661  }
662 
663  // Store lease object to ensure it remains valid.
664  lease_ = lease;
665  try {
666  addr_str_ = lease_->addr_.toText();
667  bind_array.add(addr_str_);
668 
669  if (lease_->duid_) {
670  bind_array.add(lease_->duid_->getDuid());
671  } else {
672  isc_throw (BadValue, "IPv6 Lease cannot have a null DUID");
673  }
674 
675  valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
676  bind_array.add(valid_lifetime_str_);
677 
678  expire_str_ = convertToDatabaseTime(lease->cltt_, lease_->valid_lft_);
679  bind_array.add(expire_str_);
680 
681  subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
682  bind_array.add(subnet_id_str_);
683 
684  preferred_lifetime_str_ = boost::lexical_cast<std::string>(lease_->preferred_lft_);
685  bind_array.add(preferred_lifetime_str_);
686 
687  lease_type_str_ = boost::lexical_cast<std::string>(lease_->type_);
688  bind_array.add(lease_type_str_);
689 
690  // The iaid is stored as an INT in lease6 table, so we must
691  // lexically cast from an integer version to avoid out of range
692  // exception failure upon insert.
693  iaid_u_.uval_ = lease_->iaid_;
694  iaid_str_ = boost::lexical_cast<std::string>(iaid_u_.ival_);
695  bind_array.add(iaid_str_);
696 
697  prefix_len_str_ = boost::lexical_cast<std::string>
698  (static_cast<unsigned int>(lease_->prefixlen_));
699  bind_array.add(prefix_len_str_);
700 
701  bind_array.add(lease->fqdn_fwd_);
702 
703  bind_array.add(lease->fqdn_rev_);
704 
705  bind_array.add(lease->hostname_);
706 
707  if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) {
708  // PostgreSql does not provide MAX on variable length types
709  // so we have to enforce it ourselves.
710  if (lease->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
711  isc_throw(DbOperationError, "Hardware address length : "
712  << lease_->hwaddr_->hwaddr_.size()
713  << " exceeds maximum allowed of: "
714  << HWAddr::MAX_HWADDR_LEN);
715  }
716  bind_array.add(lease->hwaddr_->hwaddr_);
717  } else {
718  bind_array.add("");
719  }
720 
721  if (lease->hwaddr_) {
722  hwtype_str_ = boost::lexical_cast<std::string>
723  (static_cast<unsigned int>(lease_->hwaddr_->htype_));
724  hwaddr_source_str_ = boost::lexical_cast<std::string>
725  (static_cast<unsigned int>(lease_->hwaddr_->source_));
726  } else {
727  hwtype_str_ = boost::lexical_cast<std::string>
728  (static_cast<unsigned int>(HTYPE_UNDEFINED));
729  hwaddr_source_str_ = boost::lexical_cast<std::string>
730  (static_cast<unsigned int>(HWAddr::HWADDR_SOURCE_UNKNOWN));
731  }
732 
733  bind_array.add(hwtype_str_);
734 
735  bind_array.add(hwaddr_source_str_);
736 
737  state_str_ = boost::lexical_cast<std::string>(lease->state_);
738  bind_array.add(state_str_);
739 
740  ConstElementPtr ctx = lease->getContext();
741  if (ctx) {
742  user_context_ = ctx->str();
743  } else {
744  user_context_ = "";
745  }
746  bind_array.add(user_context_);
747 
748  } catch (const std::exception& ex) {
750  "Could not create bind array from Lease6: "
751  << lease_->addr_.toText() << ", reason: " << ex.what());
752  }
753  }
754 
764  try {
765 
773 
774  isc::asiolink::IOAddress addr(getIPv6Value(r, row, ADDRESS_COL));
775 
776  convertFromBytea(r, row, DUID_COL, duid_buffer_, sizeof(duid_buffer_), duid_length_);
777  DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_));
778 
779  getColumnValue(r, row, VALID_LIFETIME_COL, valid_lifetime_);
780 
781  expire_ = convertFromDatabaseTime(getRawColumnValue(r, row,
782  EXPIRE_COL));
783 
784  cltt_ = expire_ - valid_lifetime_;
785 
786  getColumnValue(r, row , SUBNET_ID_COL, subnet_id_);
787 
788  getColumnValue(r, row , PREF_LIFETIME_COL, pref_lifetime_);
789 
790  getLeaseTypeColumnValue(r, row, LEASE_TYPE_COL, lease_type_);
791 
792  getColumnValue(r, row , IAID_COL, iaid_u_.ival_);
793 
794  getColumnValue(r, row , PREFIX_LEN_COL, prefix_len_);
795 
796  getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
797 
798  getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
799 
800  hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
801 
802  convertFromBytea(r, row, HWADDR_COL, hwaddr_buffer_,
803  sizeof(hwaddr_buffer_), hwaddr_length_);
804 
805  getColumnValue(r, row , HWTYPE_COL, hwtype_);
806 
807  getColumnValue(r, row , HWADDR_SOURCE_COL, hwaddr_source_);
808 
809  HWAddrPtr hwaddr;
810 
811  if (hwaddr_length_) {
812  hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_,
813  hwtype_));
814 
815  hwaddr->source_ = hwaddr_source_;
816  }
817 
818  uint32_t state;
819  getColumnValue(r, row , STATE_COL, state);
820 
821  user_context_ = getRawColumnValue(r, row, USER_CONTEXT_COL);
822  ConstElementPtr ctx;
823  if (!user_context_.empty()) {
824  ctx = Element::fromJSON(user_context_);
825  if (!ctx || (ctx->getType() != Element::map)) {
826  isc_throw(BadValue, "user context '" << user_context_
827  << "' is not a JSON map");
828  }
829  }
830 
831  Lease6Ptr result(new Lease6(lease_type_, addr, duid_ptr,
832  iaid_u_.uval_, pref_lifetime_,
833  valid_lifetime_, 0, 0,
834  subnet_id_, fqdn_fwd_, fqdn_rev_,
835  hostname_, hwaddr, prefix_len_));
836  result->cltt_ = cltt_;
837 
838  result->state_ = state;
839 
840  if (ctx) {
841  result->setContext(ctx);
842  }
843 
844  return (result);
845  } catch (const std::exception& ex) {
847  "Could not convert data to Lease6, reason: "
848  << ex.what());
849  }
850  }
851 
864  void getLeaseTypeColumnValue(const PgSqlResult& r, const int row,
865  const size_t col, Lease6::Type& value) const {
866  uint32_t raw_value = 0;
867  getColumnValue(r, row , col, raw_value);
868  switch (raw_value) {
869  case Lease6::TYPE_NA:
870  case Lease6::TYPE_TA:
871  case Lease6::TYPE_PD:
872  value = static_cast<Lease6::Type>(raw_value);
873  break;
874 
875  default:
876  isc_throw(DbOperationError, "Invalid lease type: " << raw_value
877  << " for: " << getColumnLabel(r, col) << " row:" << row);
878  }
879  }
880 
881 private:
885  Lease6Ptr lease_;
886 
888 
889  size_t duid_length_;
890  vector<uint8_t> duid_;
891  uint8_t duid_buffer_[DUID::MAX_DUID_LEN];
892 
899  union Uiaid {
900  Uiaid(uint32_t val) : uval_(val){};
901  Uiaid(int32_t val) : ival_(val){};
902  uint32_t uval_;
903  int32_t ival_;
904  } iaid_u_;
905 
906  std::string iaid_str_;
907  Lease6::Type lease_type_;
908  std::string lease_type_str_;
909  uint8_t prefix_len_;
910  std::string prefix_len_str_;
911  uint32_t pref_lifetime_;
912  std::string preferred_lifetime_str_;
913  size_t hwaddr_length_;
914  vector<uint8_t> hwaddr_;
915  uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
916  uint32_t hwtype_;
917  std::string hwtype_str_;
918  uint32_t hwaddr_source_;
919  std::string hwaddr_source_str_;
921 };
922 
929 public:
939  const bool fetch_type)
940  : conn_(conn), statement_(statement), result_set_(), next_row_(0),
941  fetch_type_(fetch_type) {
942  }
943 
953  const bool fetch_type, const SubnetID& subnet_id)
954  : LeaseStatsQuery(subnet_id), conn_(conn), statement_(statement), result_set_(),
955  next_row_(0), fetch_type_(fetch_type) {
956  }
957 
969  const bool fetch_type, const SubnetID& first_subnet_id,
970  const SubnetID& last_subnet_id)
971  : LeaseStatsQuery(first_subnet_id, last_subnet_id), conn_(conn), statement_(statement),
972  result_set_(), next_row_(0), fetch_type_(fetch_type) {
973  }
974 
976  virtual ~PgSqlLeaseStatsQuery() {};
977 
987  void start() {
988 
989  if (getSelectMode() == ALL_SUBNETS) {
990  // Run the query with no where clause parameters.
991  result_set_.reset(new PgSqlResult(PQexecPrepared(conn_, statement_.name,
992  0, 0, 0, 0, 0)));
993  } else {
994  // Set up the WHERE clause values
995  PsqlBindArray parms;
996 
997  // Add first_subnet_id used by both single and range.
998  std::string subnet_id_str = boost::lexical_cast<std::string>(getFirstSubnetID());
999  parms.add(subnet_id_str);
1000 
1001  // Add last_subnet_id for range.
1002  if (getSelectMode() == SUBNET_RANGE) {
1003  // Add last_subnet_id used by range.
1004  string subnet_id_str = boost::lexical_cast<std::string>(getLastSubnetID());
1005  parms.add(subnet_id_str);
1006  }
1007 
1008  // Run the query with where clause parameters.
1009  result_set_.reset(new PgSqlResult(PQexecPrepared(conn_, statement_.name,
1010  parms.size(), &parms.values_[0],
1011  &parms.lengths_[0], &parms.formats_[0], 0)));
1012  }
1013 
1014  conn_.checkStatementError(*result_set_, statement_);
1015  }
1016 
1029  // If we're past the end, punt.
1030  if (next_row_ >= result_set_->getRows()) {
1031  return (false);
1032  }
1033 
1034  // Fetch the subnet id.
1035  uint32_t col = 0;
1036  uint32_t subnet_id;
1037  PgSqlExchange::getColumnValue(*result_set_, next_row_, col, subnet_id);
1038  row.subnet_id_ = static_cast<SubnetID>(subnet_id);
1039  ++col;
1040 
1041  // Fetch the lease type if we were told to do so.
1042  if (fetch_type_) {
1043  uint32_t lease_type;
1044  PgSqlExchange::getColumnValue(*result_set_, next_row_ , col,
1045  lease_type);
1046  row.lease_type_ = static_cast<Lease::Type>(lease_type);
1047  ++col;
1048  } else {
1049  row.lease_type_ = Lease::TYPE_NA;
1050  }
1051 
1052  // Fetch the lease state.
1053  PgSqlExchange::getColumnValue(*result_set_, next_row_ , col,
1054  row.lease_state_);
1055  ++col;
1056 
1057  // Fetch the state count.
1058  PgSqlExchange::getColumnValue(*result_set_, next_row_, col,
1059  row.state_count_);
1060 
1061  // Point to the next row.
1062  ++next_row_;
1063  return (true);
1064  }
1065 
1066 protected:
1069 
1072 
1074  boost::shared_ptr<PgSqlResult> result_set_;
1075 
1077  uint32_t next_row_;
1078 
1081 };
1082 
1083 PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
1084  : LeaseMgr(), exchange4_(new PgSqlLease4Exchange()),
1085  exchange6_(new PgSqlLease6Exchange()), conn_(parameters) {
1086  conn_.openDatabase();
1087 
1088  // Validate schema version first.
1089  std::pair<uint32_t, uint32_t> code_version(PG_SCHEMA_VERSION_MAJOR,
1091  std::pair<uint32_t, uint32_t> db_version = getVersion();
1092  if (code_version != db_version) {
1094  "PostgreSQL schema version mismatch: need version: "
1095  << code_version.first << "." << code_version.second
1096  << " found version: " << db_version.first << "."
1097  << db_version.second);
1098  }
1099 
1100  // Now prepare the SQL statements.
1101  int i = 0;
1102  for( ; tagged_statements[i].text != NULL ; ++i) {
1104  }
1105 
1106  // Just in case somebody foo-barred things
1107  if (i != NUM_STATEMENTS) {
1108  isc_throw(DbOpenError, "Number of statements prepared: " << i
1109  << " does not match expected count:" << NUM_STATEMENTS);
1110  }
1111 }
1112 
1114 }
1115 
1116 std::string
1118  std::stringstream tmp;
1119  tmp << "PostgreSQL backend " << PG_SCHEMA_VERSION_MAJOR;
1120  tmp << "." << PG_SCHEMA_VERSION_MINOR;
1121  tmp << ", library " << PQlibVersion();
1122  return (tmp.str());
1123 }
1124 
1125 bool
1126 PgSqlLeaseMgr::addLeaseCommon(StatementIndex stindex,
1127  PsqlBindArray& bind_array) {
1128  PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name,
1129  tagged_statements[stindex].nbparams,
1130  &bind_array.values_[0],
1131  &bind_array.lengths_[0],
1132  &bind_array.formats_[0], 0));
1133 
1134  int s = PQresultStatus(r);
1135 
1136  if (s != PGRES_COMMAND_OK) {
1137  // Failure: check for the special case of duplicate entry. If this is
1138  // the case, we return false to indicate that the row was not added.
1139  // Otherwise we throw an exception.
1140  if (conn_.compareError(r, PgSqlConnection::DUPLICATE_KEY)) {
1141  return (false);
1142  }
1143 
1144  conn_.checkStatementError(r, tagged_statements[stindex]);
1145  }
1146 
1147  return (true);
1148 }
1149 
1150 bool
1153  DHCPSRV_PGSQL_ADD_ADDR4).arg(lease->addr_.toText());
1154 
1155  PsqlBindArray bind_array;
1156  exchange4_->createBindForSend(lease, bind_array);
1157  return (addLeaseCommon(INSERT_LEASE4, bind_array));
1158 }
1159 
1160 bool
1163  DHCPSRV_PGSQL_ADD_ADDR6).arg(lease->addr_.toText());
1164  PsqlBindArray bind_array;
1165  exchange6_->createBindForSend(lease, bind_array);
1166 
1167  return (addLeaseCommon(INSERT_LEASE6, bind_array));
1168 }
1169 
1170 template <typename Exchange, typename LeaseCollection>
1171 void PgSqlLeaseMgr::getLeaseCollection(StatementIndex stindex,
1172  PsqlBindArray& bind_array,
1173  Exchange& exchange,
1174  LeaseCollection& result,
1175  bool single) const {
1176  const int n = tagged_statements[stindex].nbparams;
1177  PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name, n,
1178  n > 0 ? &bind_array.values_[0] : NULL,
1179  n > 0 ? &bind_array.lengths_[0] : NULL,
1180  n > 0 ? &bind_array.formats_[0] : NULL, 0));
1181 
1182  conn_.checkStatementError(r, tagged_statements[stindex]);
1183 
1184  int rows = PQntuples(r);
1185  if (single && rows > 1) {
1186  isc_throw(MultipleRecords, "multiple records were found in the "
1187  "database where only one was expected for query "
1188  << tagged_statements[stindex].name);
1189  }
1190 
1191  for(int i = 0; i < rows; ++ i) {
1192  result.push_back(exchange->convertFromDatabase(r, i));
1193  }
1194 }
1195 
1196 void
1197 PgSqlLeaseMgr::getLease(StatementIndex stindex, PsqlBindArray& bind_array,
1198  Lease4Ptr& result) const {
1199  // Create appropriate collection object and get all leases matching
1200  // the selection criteria. The "single" parameter is true to indicate
1201  // that the called method should throw an exception if multiple
1202  // matching records are found: this particular method is called when only
1203  // one or zero matches is expected.
1204  Lease4Collection collection;
1205  getLeaseCollection(stindex, bind_array, exchange4_, collection, true);
1206 
1207  // Return single record if present, else clear the lease.
1208  if (collection.empty()) {
1209  result.reset();
1210  } else {
1211  result = *collection.begin();
1212  }
1213 }
1214 
1215 void
1216 PgSqlLeaseMgr::getLease(StatementIndex stindex, PsqlBindArray& bind_array,
1217  Lease6Ptr& result) const {
1218  // Create appropriate collection object and get all leases matching
1219  // the selection criteria. The "single" parameter is true to indicate
1220  // that the called method should throw an exception if multiple
1221  // matching records are found: this particular method is called when only
1222  // one or zero matches is expected.
1223  Lease6Collection collection;
1224  getLeaseCollection(stindex, bind_array, exchange6_, collection, true);
1225 
1226  // Return single record if present, else clear the lease.
1227  if (collection.empty()) {
1228  result.reset();
1229  } else {
1230  result = *collection.begin();
1231  }
1232 }
1233 
1234 Lease4Ptr
1237  DHCPSRV_PGSQL_GET_ADDR4).arg(addr.toText());
1238 
1239  // Set up the WHERE clause value
1240  PsqlBindArray bind_array;
1241 
1242  // LEASE ADDRESS
1243  std::string addr_str = boost::lexical_cast<std::string>
1244  (addr.toUint32());
1245  bind_array.add(addr_str);
1246 
1247  // Get the data
1248  Lease4Ptr result;
1249  getLease(GET_LEASE4_ADDR, bind_array, result);
1250 
1251  return (result);
1252 }
1253 
1255 PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
1257  DHCPSRV_PGSQL_GET_HWADDR).arg(hwaddr.toText());
1258 
1259  // Set up the WHERE clause value
1260  PsqlBindArray bind_array;
1261 
1262  // HWADDR
1263  if (!hwaddr.hwaddr_.empty()) {
1264  bind_array.add(hwaddr.hwaddr_);
1265  } else {
1266  bind_array.add("");
1267  }
1268 
1269  // Get the data
1270  Lease4Collection result;
1271  getLeaseCollection(GET_LEASE4_HWADDR, bind_array, result);
1272 
1273  return (result);
1274 }
1275 
1276 Lease4Ptr
1277 PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
1279  DHCPSRV_PGSQL_GET_SUBID_HWADDR)
1280  .arg(subnet_id).arg(hwaddr.toText());
1281 
1282  // Set up the WHERE clause value
1283  PsqlBindArray bind_array;
1284 
1285  // HWADDR
1286  if (!hwaddr.hwaddr_.empty()) {
1287  bind_array.add(hwaddr.hwaddr_);
1288  } else {
1289  bind_array.add("");
1290  }
1291 
1292  // SUBNET_ID
1293  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1294  bind_array.add(subnet_id_str);
1295 
1296  // Get the data
1297  Lease4Ptr result;
1298  getLease(GET_LEASE4_HWADDR_SUBID, bind_array, result);
1299 
1300  return (result);
1301 }
1302 
1304 PgSqlLeaseMgr::getLease4(const ClientId& clientid) const {
1306  DHCPSRV_PGSQL_GET_CLIENTID).arg(clientid.toText());
1307 
1308  // Set up the WHERE clause value
1309  PsqlBindArray bind_array;
1310 
1311  // CLIENT_ID
1312  bind_array.add(clientid.getClientId());
1313 
1314  // Get the data
1315  Lease4Collection result;
1316  getLeaseCollection(GET_LEASE4_CLIENTID, bind_array, result);
1317 
1318  return (result);
1319 }
1320 
1321 Lease4Ptr
1327  isc_throw(NotImplemented, "The PgSqlLeaseMgr::getLease4 function was"
1328  " called, but it is not implemented");
1329 }
1330 
1331 Lease4Ptr
1332 PgSqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
1334  DHCPSRV_PGSQL_GET_SUBID_CLIENTID)
1335  .arg(subnet_id).arg(clientid.toText());
1336 
1337  // Set up the WHERE clause value
1338  PsqlBindArray bind_array;
1339 
1340  // CLIENT_ID
1341  bind_array.add(clientid.getClientId());
1342 
1343  // SUBNET_ID
1344  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1345  bind_array.add(subnet_id_str);
1346 
1347  // Get the data
1348  Lease4Ptr result;
1349  getLease(GET_LEASE4_CLIENTID_SUBID, bind_array, result);
1350 
1351  return (result);
1352 }
1353 
1356  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET_SUBID4)
1357  .arg(subnet_id);
1358 
1359  // Set up the WHERE clause value
1360  PsqlBindArray bind_array;
1361 
1362  // SUBNET_ID
1363  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1364  bind_array.add(subnet_id_str);
1365 
1366  // ... and get the data
1367  Lease4Collection result;
1368  getLeaseCollection(GET_LEASE4_SUBID, bind_array, result);
1369 
1370  return (result);
1371 }
1372 
1375  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET4);
1376 
1377  // Provide empty binding array because our query has no parameters in
1378  // WHERE clause.
1379  PsqlBindArray bind_array;
1380  Lease4Collection result;
1381  getLeaseCollection(GET_LEASE4, bind_array, result);
1382 
1383  return (result);
1384 }
1385 
1388  const LeasePageSize& page_size) const {
1389  // Expecting IPv4 address.
1390  if (!lower_bound_address.isV4()) {
1391  isc_throw(InvalidAddressFamily, "expected IPv4 address while "
1392  "retrieving leases from the lease database, got "
1393  << lower_bound_address);
1394  }
1395 
1396  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET_PAGE4)
1397  .arg(page_size.page_size_)
1398  .arg(lower_bound_address.toText());
1399 
1400  // Prepare WHERE clause
1401  PsqlBindArray bind_array;
1402 
1403  // Bind lower bound address
1404  std::string lb_address_data = boost::lexical_cast<std::string>
1405  (lower_bound_address.toUint32());
1406  bind_array.add(lb_address_data);
1407 
1408  // Bind page size value
1409  std::string page_size_data = boost::lexical_cast<std::string>(page_size.page_size_);
1410  bind_array.add(page_size_data);
1411 
1412  // Get the leases
1413  Lease4Collection result;
1414  getLeaseCollection(GET_LEASE4_PAGE, bind_array, result);
1415 
1416  return (result);
1417 }
1418 
1419 Lease6Ptr
1421  const isc::asiolink::IOAddress& addr) const {
1422  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET_ADDR6)
1423  .arg(addr.toText()).arg(lease_type);
1424 
1425  // Set up the WHERE clause value
1426  PsqlBindArray bind_array;
1427 
1428  // LEASE ADDRESS
1429  std::string addr_str = addr.toText();
1430  bind_array.add(addr_str);
1431 
1432  // LEASE_TYPE
1433  std::string type_str_ = boost::lexical_cast<std::string>(lease_type);
1434  bind_array.add(type_str_);
1435 
1436  // ... and get the data
1437  Lease6Ptr result;
1438  getLease(GET_LEASE6_ADDR, bind_array, result);
1439 
1440  return (result);
1441 }
1442 
1445  uint32_t iaid) const {
1447  DHCPSRV_PGSQL_GET_IAID_DUID)
1448  .arg(iaid).arg(duid.toText()).arg(lease_type);
1449 
1450  // Set up the WHERE clause value
1451  PsqlBindArray bind_array;
1452 
1453  // DUID
1454  bind_array.add(duid.getDuid());
1455 
1456  // IAID
1457  std::string iaid_str = boost::lexical_cast<std::string>(iaid);
1458  bind_array.add(iaid_str);
1459 
1460  // LEASE_TYPE
1461  std::string lease_type_str = boost::lexical_cast<std::string>(lease_type);
1462  bind_array.add(lease_type_str);
1463 
1464  // ... and get the data
1465  Lease6Collection result;
1466  getLeaseCollection(GET_LEASE6_DUID_IAID, bind_array, result);
1467 
1468  return (result);
1469 }
1470 
1473  uint32_t iaid, SubnetID subnet_id) const {
1475  DHCPSRV_PGSQL_GET_IAID_SUBID_DUID)
1476  .arg(iaid).arg(subnet_id).arg(duid.toText()).arg(lease_type);
1477 
1478  // Set up the WHERE clause value
1479  PsqlBindArray bind_array;
1480 
1481  // LEASE_TYPE
1482  std::string lease_type_str = boost::lexical_cast<std::string>(lease_type);
1483  bind_array.add(lease_type_str);
1484 
1485  // DUID
1486  bind_array.add(duid.getDuid());
1487 
1488  // IAID
1489  std::string iaid_str = boost::lexical_cast<std::string>(iaid);
1490  bind_array.add(iaid_str);
1491 
1492  // SUBNET ID
1493  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1494  bind_array.add(subnet_id_str);
1495 
1496  // ... and get the data
1497  Lease6Collection result;
1498  getLeaseCollection(GET_LEASE6_DUID_IAID_SUBID, bind_array, result);
1499 
1500  return (result);
1501 }
1502 
1505  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET_SUBID6)
1506  .arg(subnet_id);
1507 
1508  // Set up the WHERE clause value
1509  PsqlBindArray bind_array;
1510 
1511  // SUBNET_ID
1512  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
1513  bind_array.add(subnet_id_str);
1514 
1515  // ... and get the data
1516  Lease6Collection result;
1517  getLeaseCollection(GET_LEASE6_SUBID, bind_array, result);
1518 
1519  return (result);
1520 }
1521 
1523 PgSqlLeaseMgr::getLeases6(const DUID& duid) const {
1525  DHCPSRV_PGSQL_GET_DUID)
1526  .arg(duid.toText());
1527 
1528  // Set up the WHERE clause value
1529  PsqlBindArray bind_array;
1530 
1531  // DUID
1532  bind_array.add(duid.getDuid());
1533  Lease6Collection result;
1534 
1535  // query to fetch the data
1536  getLeaseCollection(GET_LEASE6_DUID, bind_array, result);
1537 
1538  return (result);
1539 }
1540 
1543  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET6);
1544 
1545  // Provide empty binding array because our query has no parameters in
1546  // WHERE clause.
1547  PsqlBindArray bind_array;
1548  Lease6Collection result;
1549  getLeaseCollection(GET_LEASE6, bind_array, result);
1550 
1551  return (result);
1552 }
1553 
1556  const LeasePageSize& page_size) const {
1557  // Expecting IPv6 address.
1558  if (!lower_bound_address.isV6()) {
1559  isc_throw(InvalidAddressFamily, "expected IPv6 address while "
1560  "retrieving leases from the lease database, got "
1561  << lower_bound_address);
1562  }
1563 
1564  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET_PAGE6)
1565  .arg(page_size.page_size_)
1566  .arg(lower_bound_address.toText());
1567 
1568  // Prepare WHERE clause
1569  PsqlBindArray bind_array;
1570 
1571  // In IPv6 we compare addresses represented as strings. The IPv6 zero address
1572  // is ::, so it is greater than any other address. In this special case, we
1573  // just use 0 for comparison which should be lower than any real IPv6 address.
1574  std::string lb_address_data = "0";
1575  if (!lower_bound_address.isV6Zero()) {
1576  lb_address_data = lower_bound_address.toText();
1577  }
1578 
1579  // Bind lower bound address
1580  bind_array.add(lb_address_data);
1581 
1582  // Bind page size value
1583  std::string page_size_data = boost::lexical_cast<std::string>(page_size.page_size_);
1584  bind_array.add(page_size_data);
1585 
1586  // Get the leases
1587  Lease6Collection result;
1588  getLeaseCollection(GET_LEASE6_PAGE, bind_array, result);
1589 
1590  return (result);
1591 }
1592 
1593 void
1595  const size_t max_leases) const {
1596  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET_EXPIRED4)
1597  .arg(max_leases);
1598  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE4_EXPIRE);
1599 }
1600 
1601 void
1603  const size_t max_leases) const {
1604  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET_EXPIRED6)
1605  .arg(max_leases);
1606  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE6_EXPIRE);
1607 }
1608 
1609 template<typename LeaseCollection>
1610 void
1611 PgSqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases,
1612  const size_t max_leases,
1613  StatementIndex statement_index) const {
1614  PsqlBindArray bind_array;
1615 
1616  // Exclude reclaimed leases.
1617  std::string state_str = boost::lexical_cast<std::string>(Lease::STATE_EXPIRED_RECLAIMED);
1618  bind_array.add(state_str);
1619 
1620  // Expiration timestamp.
1621  std::string timestamp_str = PgSqlLeaseExchange::convertToDatabaseTime(time(NULL));
1622  bind_array.add(timestamp_str);
1623 
1624  // If the number of leases is 0, we will return all leases. This is
1625  // achieved by setting the limit to a very high value.
1626  uint32_t limit = max_leases > 0 ? static_cast<uint32_t>(max_leases) :
1627  std::numeric_limits<uint32_t>::max();
1628  std::string limit_str = boost::lexical_cast<std::string>(limit);
1629  bind_array.add(limit_str);
1630 
1631  // Retrieve leases from the database.
1632  getLeaseCollection(statement_index, bind_array, expired_leases);
1633 }
1634 
1635 template<typename LeasePtr>
1636 void
1637 PgSqlLeaseMgr::updateLeaseCommon(StatementIndex stindex,
1638  PsqlBindArray& bind_array,
1639  const LeasePtr& lease) {
1641  DHCPSRV_PGSQL_ADD_ADDR4).arg(tagged_statements[stindex].name);
1642 
1643  PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name,
1644  tagged_statements[stindex].nbparams,
1645  &bind_array.values_[0],
1646  &bind_array.lengths_[0],
1647  &bind_array.formats_[0], 0));
1648 
1649  conn_.checkStatementError(r, tagged_statements[stindex]);
1650 
1651  int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
1652 
1653  // Check success case first as it is the most likely outcome.
1654  if (affected_rows == 1) {
1655  return;
1656  }
1657 
1658  // If no rows affected, lease doesn't exist.
1659  if (affected_rows == 0) {
1660  isc_throw(NoSuchLease, "unable to update lease for address " <<
1661  lease->addr_.toText() << " as it does not exist");
1662  }
1663 
1664  // Should not happen - primary key constraint should only have selected
1665  // one row.
1666  isc_throw(DbOperationError, "apparently updated more than one lease "
1667  "that had the address " << lease->addr_.toText());
1668 }
1669 
1670 void
1672  const StatementIndex stindex = UPDATE_LEASE4;
1673 
1675  DHCPSRV_PGSQL_UPDATE_ADDR4).arg(lease->addr_.toText());
1676 
1677  // Create the BIND array for the data being updated
1678  PsqlBindArray bind_array;
1679  exchange4_->createBindForSend(lease, bind_array);
1680 
1681  // Set up the WHERE clause and append it to the SQL_BIND array
1682  std::string addr4_ = boost::lexical_cast<std::string>
1683  (lease->addr_.toUint32());
1684  bind_array.add(addr4_);
1685 
1686  // Drop to common update code
1687  updateLeaseCommon(stindex, bind_array, lease);
1688 }
1689 
1690 void
1692  const StatementIndex stindex = UPDATE_LEASE6;
1693 
1695  DHCPSRV_PGSQL_UPDATE_ADDR6).arg(lease->addr_.toText());
1696 
1697  // Create the BIND array for the data being updated
1698  PsqlBindArray bind_array;
1699  exchange6_->createBindForSend(lease, bind_array);
1700 
1701  // Set up the WHERE clause and append it to the BIND array
1702  std::string addr_str = lease->addr_.toText();
1703  bind_array.add(addr_str);
1704 
1705  // Drop to common update code
1706  updateLeaseCommon(stindex, bind_array, lease);
1707 }
1708 
1709 uint64_t
1710 PgSqlLeaseMgr::deleteLeaseCommon(StatementIndex stindex,
1711  PsqlBindArray& bind_array) {
1712  PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name,
1713  tagged_statements[stindex].nbparams,
1714  &bind_array.values_[0],
1715  &bind_array.lengths_[0],
1716  &bind_array.formats_[0], 0));
1717 
1718  conn_.checkStatementError(r, tagged_statements[stindex]);
1719  int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
1720 
1721  return (affected_rows);
1722 }
1723 
1724 bool
1727  DHCPSRV_PGSQL_DELETE_ADDR).arg(addr.toText());
1728 
1729  // Set up the WHERE clause value
1730  PsqlBindArray bind_array;
1731 
1732  if (addr.isV4()) {
1733  std::string addr4_str = boost::lexical_cast<std::string>
1734  (addr.toUint32());
1735  bind_array.add(addr4_str);
1736  return (deleteLeaseCommon(DELETE_LEASE4, bind_array) > 0);
1737  }
1738 
1739  std::string addr6_str = addr.toText();
1740  bind_array.add(addr6_str);
1741  return (deleteLeaseCommon(DELETE_LEASE6, bind_array) > 0);
1742 }
1743 
1744 uint64_t
1747  DHCPSRV_PGSQL_DELETE_EXPIRED_RECLAIMED4)
1748  .arg(secs);
1749  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
1750 }
1751 
1752 uint64_t
1755  DHCPSRV_PGSQL_DELETE_EXPIRED_RECLAIMED6)
1756  .arg(secs);
1757  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
1758 }
1759 
1760 uint64_t
1761 PgSqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
1762  StatementIndex statement_index) {
1763  PsqlBindArray bind_array;
1764 
1765  // State is reclaimed.
1766  std::string state_str = boost::lexical_cast<std::string>(Lease::STATE_EXPIRED_RECLAIMED);
1767  bind_array.add(state_str);
1768 
1769  // Expiration timestamp.
1770  std::string expiration_str =
1771  PgSqlLeaseExchange::convertToDatabaseTime(time(NULL) - static_cast<time_t>(secs));
1772  bind_array.add(expiration_str);
1773 
1774  // Delete leases.
1775  return (deleteLeaseCommon(statement_index, bind_array));
1776 }
1777 
1780  LeaseStatsQueryPtr query(
1782  query->start();
1783  return(query);
1784 }
1785 
1788  LeaseStatsQueryPtr query(
1790  false, subnet_id));
1791  query->start();
1792  return(query);
1793 }
1794 
1797  const SubnetID& last_subnet_id) {
1798  LeaseStatsQueryPtr query(
1800  false, first_subnet_id, last_subnet_id));
1801  query->start();
1802  return(query);
1803 }
1804 
1807  LeaseStatsQueryPtr query(
1809  query->start();
1810  return(query);
1811 }
1812 
1815  LeaseStatsQueryPtr query(
1817  true, subnet_id));
1818  query->start();
1819  return(query);
1820 }
1821 
1824  const SubnetID& last_subnet_id) {
1825  LeaseStatsQueryPtr query(
1827  true, first_subnet_id, last_subnet_id));
1828  query->start();
1829  return(query);
1830 }
1831 
1832 size_t
1833 PgSqlLeaseMgr::wipeLeases4(const SubnetID& /*subnet_id*/) {
1834  isc_throw(NotImplemented, "wipeLeases4 is not implemented for PgSQL backend");
1835 }
1836 
1837 size_t
1838 PgSqlLeaseMgr::wipeLeases6(const SubnetID& /*subnet_id*/) {
1839  isc_throw(NotImplemented, "wipeLeases6 is not implemented for PgSQL backend");
1840 }
1841 
1842 string
1844  string name = "";
1845  try {
1846  name = conn_.getParameter("name");
1847  } catch (...) {
1848  // Return an empty name
1849  }
1850  return (name);
1851 }
1852 
1853 string
1855  return (string("PostgreSQL Database"));
1856 }
1857 
1858 pair<uint32_t, uint32_t>
1861  DHCPSRV_PGSQL_GET_VERSION);
1862 
1863  const char* version_sql = "SELECT version, minor FROM schema_version;";
1864  PgSqlResult r(PQexec(conn_, version_sql));
1865  if(PQresultStatus(r) != PGRES_TUPLES_OK) {
1866  isc_throw(DbOperationError, "unable to execute PostgreSQL statement <"
1867  << version_sql << ", reason: " << PQerrorMessage(conn_));
1868  }
1869 
1870  istringstream tmp;
1871  uint32_t version;
1872  tmp.str(PQgetvalue(r, 0, 0));
1873  tmp >> version;
1874  tmp.str("");
1875  tmp.clear();
1876 
1877  uint32_t minor;
1878  tmp.str(PQgetvalue(r, 0, 1));
1879  tmp >> minor;
1880 
1881  return (make_pair(version, minor));
1882 }
1883 
1884 void
1886  conn_.commit();
1887 }
1888 
1889 void
1891  conn_.rollback();
1892 }
1893 
1894 }; // end of isc::dhcp namespace
1895 }; // end of isc namespace
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.
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:20
RAII wrapper for PostgreSQL Result sets.
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
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:67
const std::vector< uint8_t > & getClientId() const
Returns reference to the client-id data.
Definition: duid.cc:116
Structure that holds a lease for IPv4 address.
Definition: lease.h:256
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 name of the database.
Abstract Lease Manager.
Definition: lease_mgr.h:222
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.
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.
uint32_t next_row_
Index of the next row to fetch.
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.
std::vector< int > lengths_
Vector of data lengths for each value.
Attempt to update lease that was not there.
bool compareError(const PgSqlResult &r, const char *error_state)
Checks a result set's SQL state against an error state.
virtual std::pair< uint32_t, uint32_t > getVersion() const
Returns backend version.
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition: lease.h:455
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs)
Deletes all expired-reclaimed DHCPv6 leases.
std::vector< uint8_t > hwaddr_
Definition: hwaddr.h:98
Base class for fulfilling a statistical lease data query.
Definition: lease_mgr.h:128
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.
PgSqlLease4Exchange()
Default constructor.
void createBindForSend(const Lease4Ptr &lease, PsqlBindArray &bind_array)
Creates the bind array for sending Lease4 data to the database.
boost::shared_ptr< Lease > LeasePtr
Pointer to the lease object.
Definition: lease.h:26
const size_t OID_TEXT
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
std::vector< const char * > values_
Vector of pointers to the data values.
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
Exception thrown on failure to open database.
not specified or undefined
Definition: dhcp4.h:55
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.
void commit()
Commit Transactions.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID &subnet_id)
Creates and runs the IPv4 lease stats query for a single subnet.
TaggedStatementArray tagged_statements
Prepared MySQL statements used by the backend to insert and retrieve hosts from the database.
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.
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 add(const char *value)
Adds a char array to bind array based.
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
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:245
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
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.
void rollback()
Rollback Transactions.
virtual void updateLease6(const Lease6Ptr &lease6)
Updates IPv6 lease.
virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t secs)
Deletes all expired-reclaimed DHCPv4 leases.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
Structure that holds a lease for IPv6 address and/or prefix.
Definition: lease.h:471
PgSqlTaggedStatement & statement_
The query's prepared statement.
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
virtual size_t wipeLeases6(const SubnetID &subnet_id)
Removed specified IPv6 leases.
virtual LeaseStatsQueryPtr startLeaseStatsQuery4()
Creates and runs the IPv4 lease stats query.
virtual void rollback()
Rollback Transactions.
std::string addr_str_
Common Instance members used for binding and conversion.
Common PgSql Connector Pool.
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:604
virtual std::string getDescription() const
Returns description of the backend.
const std::vector< uint8_t > & getDuid() const
Returns a const reference to the actual DUID value.
Definition: duid.cc:44
Ethernet 10Mbps.
Definition: dhcp4.h:56
void prepareStatement(const PgSqlTaggedStatement &statement)
Prepare Single Statement.
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:64
Defines the logger used by the top-level component of kea-dhcp-ddns.
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.
size_t size() const
Fetches the number of entries in the array.
void checkStatementError(const PgSqlResult &r, PgSqlTaggedStatement &statement) const
Checks result of the r object.
const size_t OID_BYTEA
PgSqlConnection & conn_
Database connection to use to execute the query.
virtual Lease6Collection getLeases6() const
Returns all IPv6 leases.
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:38
virtual bool deleteLease(const isc::asiolink::IOAddress &addr)
Deletes a lease.
Holds Client identifier or client IPv4 address.
Definition: duid.h:111
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
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
void openDatabase()
Open Database.
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
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:74
Wraps value holding size of the page with leases.
Definition: lease_mgr.h:43
const size_t OID_NONE
Constants for PostgreSQL data types These are defined by PostgreSQL in <catalog/pg_type....
Lease::Type lease_type_
The lease_type to which the count applies.
Definition: lease_mgr.h:116
virtual void commit()
Commit Transactions.
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.
int version()
returns Kea hooks version.
virtual size_t wipeLeases4(const SubnetID &subnet_id)
Removes specified IPv4 leases.
const uint32_t PG_SCHEMA_VERSION_MAJOR
Define PostgreSQL backend version: 5.0.
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:460
virtual Lease4Collection getLeases4() const
Returns all IPv4 leases.
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.
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:121
Exception thrown on failure to execute a database function.
Supports exchanging IPv4 leases with PostgreSQL.
std::string toText(bool include_htype=true) const
Returns textual representation of a hardware address (e.g.
Definition: hwaddr.cc:51
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.