Kea 2.0.2
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
10#include <dhcp/duid.h>
11#include <dhcp/hwaddr.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
30using namespace isc;
31using namespace isc::asiolink;
32using namespace isc::db;
33using namespace isc::dhcp;
34using namespace isc::data;
35using namespace isc::util;
36using namespace std;
37
38namespace {
39
43PgSqlTaggedStatement 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
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
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
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
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
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
367namespace isc {
368namespace dhcp {
369
376public:
377
382 fqdn_fwd_(false), fqdn_rev_(false), hostname_(""), state_str_(""),
383 user_context_("") {
384 }
385
387
388protected:
389
391
392 std::string addr_str_;
394 std::vector<uint8_t> hwaddr_;
398 time_t expire_;
399 std::string expire_str_;
400 uint32_t subnet_id_;
401 std::string subnet_id_str_;
402 time_t cltt_;
405 std::string hostname_;
406 std::string state_str_;
407 std::string user_context_;
409};
410
413private:
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
433public:
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: "
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_,
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
561 EXPIRE_COL));
562
563 getColumnValue(r, row , SUBNET_ID_COL, subnet_id_);
564
565 // Recover from overflow
567 cltt_ = expire_;
568 } else {
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
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_,
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
615private:
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
630private:
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
656 static const size_t LEASE_COLUMNS = 17;
657
658public:
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: "
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
856 EXPIRE_COL));
857
858 // Recover from overflow
860 cltt_ = expire_;
861 } else {
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_,
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_,
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
965private:
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
997public:
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
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;
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;
1117 lease_type);
1118 row.lease_type_ = static_cast<Lease::Type>(lease_type);
1119 ++col;
1120 } else {
1122 }
1123
1124 // Fetch the lease state.
1126 row.lease_state_);
1127 ++col;
1128
1129 // Fetch the state count.
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
1147protected:
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.
1170
1171// PgSqlLeaseContext Constructor
1172
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
1181PgSqlLeaseMgr::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
1206PgSqlLeaseMgr::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
1245bool
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
1347std::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
1356bool
1357PgSqlLeaseMgr::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
1381bool
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
1401bool
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
1423template <typename Exchange, typename LeaseCollection>
1424void
1425PgSqlLeaseMgr::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
1452void
1453PgSqlLeaseMgr::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
1473void
1474PgSqlLeaseMgr::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
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
1519PgSqlLeaseMgr::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
1546PgSqlLeaseMgr::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
1578PgSqlLeaseMgr::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
1601PgSqlLeaseMgr::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
1653PgSqlLeaseMgr::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
1694PgSqlLeaseMgr::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
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
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
1880PgSqlLeaseMgr::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
1921PgSqlLeaseMgr::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
1964void
1966 const size_t max_leases) const {
1968 .arg(max_leases);
1969 getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE4_EXPIRE);
1970}
1971
1972void
1974 const size_t max_leases) const {
1976 .arg(max_leases);
1977 getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE6_EXPIRE);
1978}
1979
1980template<typename LeaseCollection>
1981void
1982PgSqlLeaseMgr::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
2010template<typename LeasePtr>
2011void
2012PgSqlLeaseMgr::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
2043void
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
2073void
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
2104uint64_t
2105PgSqlLeaseMgr::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
2123bool
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
2157bool
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
2192uint64_t
2195 .arg(secs);
2196 return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
2197}
2198
2199uint64_t
2202 .arg(secs);
2203 return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
2204}
2205
2206uint64_t
2207PgSqlLeaseMgr::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
2310size_t
2312 isc_throw(NotImplemented, "wipeLeases4 is not implemented for PostgreSQL backend");
2313}
2314
2315size_t
2317 isc_throw(NotImplemented, "wipeLeases6 is not implemented for PostgreSQL backend");
2318}
2319
2320std::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
2335std::string
2337 return (std::string("PostgreSQL Database"));
2338}
2339
2340std::pair<uint32_t, uint32_t>
2343
2344 return (PgSqlConnection::getVersion(parameters_));
2345}
2346
2347void
2350}
2351
2352void
2355}
2356
2357} // namespace dhcp
2358} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when a function is not implemented.
A generic exception that is thrown when an unexpected error condition occurs.
static bool invokeDbLostCallback(const ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's lost connectivity callback.
static bool invokeDbFailedCallback(const ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restore failed connectivity callback.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
static bool invokeDbRecoveredCallback(const ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restored connectivity callback.
Exception thrown on failure to open database.
Exception thrown on failure to execute a database function.
Invalid address family used as input to Lease Manager.
Definition: db_exceptions.h:71
Multiple lease records found where one expected.
Definition: db_exceptions.h:28
Common PgSql Connector Pool.
static const char DUPLICATE_KEY[]
Define the PgSql error state for a duplicate key error.
static std::pair< uint32_t, uint32_t > getVersion(const ParameterMap &parameters)
Get the schema version.
void checkStatementError(const PgSqlResult &r, PgSqlTaggedStatement &statement)
Checks result of the r object.
Base class for marshalling data to and from PostgreSQL.
static const char * getRawColumnValue(const PgSqlResult &r, const int row, const size_t col)
Gets a pointer to the raw column value in a result set row.
static std::string convertToDatabaseTime(const time_t input_time)
Converts time_t value to a text representation in local time.
static std::string getColumnLabel(const PgSqlResult &r, const size_t col)
Fetches the name of the column in a result set.
static void convertFromBytea(const PgSqlResult &r, const int row, const size_t col, uint8_t *buffer, const size_t buffer_size, size_t &bytes_converted)
Converts a column in a row in a result set to a binary bytes.
static void getColumnValue(const PgSqlResult &r, const int row, const size_t col, std::string &value)
Fetches text column value as a string.
static time_t convertFromDatabaseTime(const std::string &db_time_val)
Converts time stamp from the database to a time_t.
std::vector< std::string > columns_
Stores text labels for columns, currently only used for logging and errors.
static isc::asiolink::IOAddress getIPv6Value(const PgSqlResult &r, const int row, const size_t col)
Converts a column in a row in a result set into IPv6 address.
RAII wrapper for PostgreSQL Result sets.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:161
Holds Client identifier or client IPv4 address.
Definition: duid.h:111
static const size_t MAX_CLIENT_ID_LEN
Maximum size of a client ID.
Definition: duid.h:128
const std::vector< uint8_t > & getClientId() const
Returns reference to the client-id data.
Definition: duid.cc:117
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:122
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:75
static const size_t MAX_DUID_LEN
maximum duid size As defined in RFC 8415, section 11.1
Definition: duid.h:31
const std::vector< uint8_t > & getDuid() const
Returns a const reference to the actual DUID value.
Definition: duid.cc:46
static void create(const std::string &dbaccess)
Create an instance of a lease manager.
static void destroy()
Destroy lease manager.
static isc::asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service.
Definition: lease_mgr.h:758
Wraps value holding size of the page with leases.
Definition: lease_mgr.h:43
const size_t page_size_
Holds page size.
Definition: lease_mgr.h:53
Base class for fulfilling a statistical lease data query.
Definition: lease_mgr.h:128
SubnetID getLastSubnetID() const
Returns the value of last subnet ID specified (or zero)
Definition: lease_mgr.h:183
SubnetID getFirstSubnetID() const
Returns the value of first subnet ID specified (or zero)
Definition: lease_mgr.h:178
SelectMode getSelectMode() const
Returns the selection criteria mode The value returned is based upon the constructor variant used and...
Definition: lease_mgr.h:190
Attempt to update lease that was not there.
Supports exchanging IPv4 leases with PostgreSQL.
Lease4Ptr convertFromDatabase(const PgSqlResult &r, int row)
Creates a Lease4 object from a given row in a result set.
void createBindForSend(const Lease4Ptr &lease, PsqlBindArray &bind_array)
Creates the bind array for sending Lease4 data to the database.
Supports exchanging IPv6 leases with PostgreSQL.
void createBindForSend(const Lease6Ptr &lease, PsqlBindArray &bind_array)
Creates the bind array for sending Lease6 data to the database.
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.
Lease6Ptr convertFromDatabase(const PgSqlResult &r, int row)
Creates a Lease6 object from a given row in a result set.
PostgreSQL Lease Context Pool.
PostgreSQL Lease Context.
PgSqlLeaseContext(const db::DatabaseConnection::ParameterMap &parameters, db::IOServiceAccessorPtr io_service_accessor, db::DbCallback db_reconnect_callback)
Constructor.
Base class for marshalling leases to and from PostgreSQL.
uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]
std::vector< uint8_t > hwaddr_
std::string addr_str_
Common Instance members used for binding and conversion.
PostgreSQL Lease Manager.
virtual std::string getName() const
Returns backend name.
virtual bool addLease(const Lease4Ptr &lease)
Adds an IPv4 lease.
virtual Lease6Collection getLeases6() const
Returns all IPv6 leases.
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.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const
Returns an IPv4 lease for specified IPv4 address.
virtual void rollback()
Rollback Transactions.
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const
Returns existing IPv6 lease for a given IPv6 address.
PgSqlLeaseContextPtr createContext() const
Create a new context.
virtual bool deleteLease(const Lease4Ptr &lease)
Deletes an IPv4 lease.
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.
static std::string getDBVersion()
Local version of getDBVersion() class method.
virtual Lease4Collection getLeases4() const
Returns all IPv4 leases.
virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t secs)
Deletes all expired-reclaimed DHCPv4 leases.
virtual void updateLease4(const Lease4Ptr &lease4)
Updates IPv4 lease.
virtual size_t wipeLeases4(const SubnetID &subnet_id)
Removes specified IPv4 leases.
virtual std::pair< uint32_t, uint32_t > getVersion() const
Returns backend version.
virtual void updateLease6(const Lease6Ptr &lease6)
Updates IPv6 lease.
virtual LeaseStatsQueryPtr startLeaseStatsQuery6()
Creates and runs the IPv6 lease stats query.
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs)
Deletes all expired-reclaimed DHCPv6 leases.
virtual std::string getDescription() const
Returns description of the backend.
StatementIndex
Statement Tags.
virtual void commit()
Commit Transactions.
PgSqlLeaseMgr(const db::DatabaseConnection::ParameterMap &parameters)
Constructor.
virtual size_t wipeLeases6(const SubnetID &subnet_id)
Removed specified IPv6 leases.
virtual void getExpiredLeases6(Lease6Collection &expired_leases, const size_t max_leases) const
Returns a collection of expired DHCPv6 leases.
virtual LeaseStatsQueryPtr startLeaseStatsQuery4()
Creates and runs the IPv4 lease stats query.
static bool dbReconnect(db::ReconnectCtlPtr db_reconnect_ctl)
Attempts to reconnect the server to the lease DB backend manager.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID &subnet_id)
Creates and runs the IPv6 lease stats query for a single subnet.
virtual ~PgSqlLeaseMgr()
Destructor (closes database)
virtual void getExpiredLeases4(Lease4Collection &expired_leases, const size_t max_leases) const
Returns a collection of expired DHCPv4 leases.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID &subnet_id)
Creates and runs the IPv4 lease stats query for a single subnet.
Base PgSql derivation of the statistical lease data query.
bool fetch_type_
Indicates if query supplies lease type.
boost::shared_ptr< PgSqlResult > result_set_
The result set returned by Postgres.
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.
PgSqlConnection & conn_
Database connection to use to execute the query.
virtual ~PgSqlLeaseStatsQuery()
Destructor.
PgSqlTaggedStatement & statement_
The query's prepared statement.
static bool negative_count_
Received negative state count showing a problem.
bool getNextRow(LeaseStatsRow &row)
Fetches the next row in the result set.
PgSqlLeaseStatsQuery(PgSqlConnection &conn, PgSqlTaggedStatement &statement, const bool fetch_type)
Constructor to query for all subnets' stats.
PgSqlLeaseStatsQuery(PgSqlConnection &conn, PgSqlTaggedStatement &statement, const bool fetch_type, const SubnetID &subnet_id)
Constructor to query for a single subnet's stats.
void start()
Creates the lease statistical data result set.
uint32_t next_row_
Index of the next row to fetch.
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition: timer_mgr.cc:449
RAII class creating a critical section.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
static const uint32_t HWADDR_SOURCE_UNKNOWN
Used when actual origin is not known, e.g.
Definition: hwaddr.h:41
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
std::function< bool(ReconnectCtlPtr db_reconnect_ctl)> DbCallback
Defines a callback prototype for propagating events upward.
const size_t OID_INT2
const uint32_t PG_SCHEMA_VERSION_MAJOR
Define PostgreSQL backend version: 6.2.
boost::shared_ptr< IOServiceAccessor > IOServiceAccessorPtr
Pointer to an instance of IOServiceAccessor.
const uint32_t PG_SCHEMA_VERSION_MINOR
const size_t OID_VARCHAR
const size_t OID_NONE
Constants for PostgreSQL data types These are defined by PostgreSQL in <catalog/pg_type....
const size_t OID_TIMESTAMP
const size_t OID_TEXT
const size_t OID_BOOL
const size_t OID_INT8
const size_t OID_BYTEA
std::function< isc::asiolink::IOServicePtr()> IOServiceAccessor
Function which returns the IOService that can be used to recover the connection.
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
const isc::log::MessageID DHCPSRV_PGSQL_GET_SUBID4
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
const isc::log::MessageID DHCPSRV_PGSQL_ADD_ADDR4
const isc::log::MessageID DHCPSRV_PGSQL_GET_SUBID_CLIENTID
const isc::log::MessageID DHCPSRV_PGSQL_GET_ADDR6
const isc::log::MessageID DHCPSRV_PGSQL_GET_DUID
const isc::log::MessageID DHCPSRV_PGSQL_GET6
const isc::log::MessageID DHCPSRV_PGSQL_GET_SUBID6
const isc::log::MessageID DHCPSRV_PGSQL_GET_PAGE4
boost::shared_ptr< CfgDbAccess > CfgDbAccessPtr
A pointer to the CfgDbAccess.
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:20
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition: lease.h:492
const isc::log::MessageID DHCPSRV_PGSQL_GET_HOSTNAME6
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:640
boost::shared_ptr< LeaseStatsQuery > LeaseStatsQueryPtr
Defines a pointer to a LeaseStatsQuery.
Definition: lease_mgr.h:207
const isc::log::MessageID DHCPSRV_PGSQL_GET_IAID_SUBID_DUID
const isc::log::MessageID DHCPSRV_PGSQL_GET_ADDR4
const isc::log::MessageID DHCPSRV_PGSQL_GET_HOSTNAME4
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
const isc::log::MessageID DHCPSRV_PGSQL_ROLLBACK
const isc::log::MessageID DHCPSRV_PGSQL_GET_HWADDR
const isc::log::MessageID DHCPSRV_PGSQL_GET_PAGE6
const isc::log::MessageID DHCPSRV_PGSQL_DELETE_EXPIRED_RECLAIMED4
const isc::log::MessageID DHCPSRV_PGSQL_UPDATE_ADDR4
const isc::log::MessageID DHCPSRV_PGSQL_GET_SUBID_HWADDR
const isc::log::MessageID DHCPSRV_PGSQL_GET_VERSION
const isc::log::MessageID DHCPSRV_PGSQL_LEASE_DB_RECONNECT_ATTEMPT_FAILED
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24
boost::shared_ptr< Lease > LeasePtr
Pointer to the lease object.
Definition: lease.h:26
const isc::log::MessageID DHCPSRV_PGSQL_GET4
const isc::log::MessageID DHCPSRV_PGSQL_ADD_ADDR6
const isc::log::MessageID DHCPSRV_PGSQL_GET_CLIENTID
const isc::log::MessageID DHCPSRV_PGSQL_GET_IAID_DUID
const isc::log::MessageID DHCPSRV_PGSQL_UPDATE_ADDR6
boost::shared_ptr< PgSqlLeaseContext > PgSqlLeaseContextPtr
Type of pointers to contexts.
const isc::log::MessageID DHCPSRV_PGSQL_LEASE_DB_RECONNECT_FAILED
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition: lease.h:487
@ HTYPE_UNDEFINED
not specified or undefined
Definition: dhcp4.h:55
@ HTYPE_ETHER
Ethernet 10Mbps.
Definition: dhcp4.h:56
const isc::log::MessageID DHCPSRV_PGSQL_NEGATIVE_LEASES_STAT
const isc::log::MessageID DHCPSRV_PGSQL_GET_EXPIRED4
const isc::log::MessageID DHCPSRV_PGSQL_GET_EXPIRED6
const isc::log::MessageID DHCPSRV_PGSQL_LEASE_DB_RECONNECT_ATTEMPT_SCHEDULE
const isc::log::MessageID DHCPSRV_PGSQL_DELETE_ADDR
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:283
const isc::log::MessageID DHCPSRV_PGSQL_COMMIT
const isc::log::MessageID DHCPSRV_PGSQL_DELETE_EXPIRED_RECLAIMED6
Definition: edns.h:19
Defines the logger used by the top-level component of kea-lfc.
Define a PostgreSQL statement.
const char * name
Short name of the query.
std::vector< int > formats_
Vector of "format" for each value.
void add(const char *value)
Adds a char array to bind array based.
size_t size() const
Fetches the number of entries in the array.
std::vector< const char * > values_
Vector of pointers to the data values.
std::string toText() const
Dumps the contents of the array to a string.
std::vector< int > lengths_
Vector of data lengths for each value.
Hardware type that represents information from DHCPv4 packet.
Definition: hwaddr.h:20
static const size_t MAX_HWADDR_LEN
Maximum size of a hardware address.
Definition: hwaddr.h:27
std::vector< uint8_t > hwaddr_
Definition: hwaddr.h:98
std::string toText(bool include_htype=true) const
Returns textual representation of a hardware address (e.g.
Definition: hwaddr.cc:51
Structure that holds a lease for IPv6 address and/or prefix.
Definition: lease.h:503
Contains a single row of lease statistical data.
Definition: lease_mgr.h:61
int64_t state_count_
state_count The count of leases in the lease state
Definition: lease_mgr.h:120
uint32_t lease_state_
The lease_state to which the count applies.
Definition: lease_mgr.h:118
SubnetID subnet_id_
The subnet ID to which this data applies.
Definition: lease_mgr.h:114
Lease::Type lease_type_
The lease_type to which the count applies.
Definition: lease_mgr.h:116
static const uint32_t INFINITY_LFT
Infinity (means static, i.e. never expire)
Definition: lease.h:38
static const uint32_t STATE_EXPIRED_RECLAIMED
Expired and reclaimed lease.
Definition: lease.h:79
Type
Type of lease or pool.
Definition: lease.h:50
@ TYPE_TA
the lease contains temporary IPv6 address
Definition: lease.h:52
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition: lease.h:53
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition: lease.h:51
Union for marshalling IAID into and out of the database IAID is defined in the RFC as 4 octets,...
std::string dbInputString()
Return a string representing the signed 32-bit value.