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
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
24using namespace isc;
25using namespace isc::asiolink;
26using namespace isc::db;
27using namespace isc::dhcp;
28using namespace isc::data;
29using namespace std;
30
31namespace {
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
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
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
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
338namespace isc {
339namespace dhcp {
340
347public:
351 cltt_(0), fqdn_fwd_(false), fqdn_rev_(false), hostname_(""),
352 state_str_(""), user_context_("") {
353 }
354
356
357protected:
359
360 std::string addr_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_;
370 std::string hostname_;
371 std::string state_str_;
372 std::string user_context_;
374};
375
378private:
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
398public:
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: "
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
523 EXPIRE_COL));
524
525 getColumnValue(r, row , SUBNET_ID_COL, subnet_id_);
526
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()) {
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_,
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
571private:
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
588private:
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
614 static const size_t LEASE_COLUMNS = 17;
615
616public:
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: "
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
782 EXPIRE_COL));
783
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()) {
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,
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
881private:
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
929public:
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
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
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;
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;
1045 lease_type);
1046 row.lease_type_ = static_cast<Lease::Type>(lease_type);
1047 ++col;
1048 } else {
1050 }
1051
1052 // Fetch the lease state.
1054 row.lease_state_);
1055 ++col;
1056
1057 // Fetch the state count.
1059 row.state_count_);
1060
1061 // Point to the next row.
1062 ++next_row_;
1063 return (true);
1064 }
1065
1066protected:
1069
1072
1074 boost::shared_ptr<PgSqlResult> result_set_;
1075
1077 uint32_t next_row_;
1078
1081};
1082
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
1116std::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
1125bool
1126PgSqlLeaseMgr::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.
1141 return (false);
1142 }
1143
1144 conn_.checkStatementError(r, tagged_statements[stindex]);
1145 }
1146
1147 return (true);
1148}
1149
1150bool
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
1160bool
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
1170template <typename Exchange, typename LeaseCollection>
1171void 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
1196void
1197PgSqlLeaseMgr::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
1215void
1216PgSqlLeaseMgr::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
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
1255PgSqlLeaseMgr::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
1277PgSqlLeaseMgr::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
1304PgSqlLeaseMgr::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
1327 isc_throw(NotImplemented, "The PgSqlLeaseMgr::getLease4 function was"
1328 " called, but it is not implemented");
1329}
1330
1332PgSqlLeaseMgr::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
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
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
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
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
1593void
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
1601void
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
1609template<typename LeaseCollection>
1610void
1611PgSqlLeaseMgr::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
1635template<typename LeasePtr>
1636void
1637PgSqlLeaseMgr::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
1670void
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
1690void
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
1709uint64_t
1710PgSqlLeaseMgr::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
1724bool
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
1744uint64_t
1747 DHCPSRV_PGSQL_DELETE_EXPIRED_RECLAIMED4)
1748 .arg(secs);
1749 return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
1750}
1751
1752uint64_t
1755 DHCPSRV_PGSQL_DELETE_EXPIRED_RECLAIMED6)
1756 .arg(secs);
1757 return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
1758}
1759
1760uint64_t
1761PgSqlLeaseMgr::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
1832size_t
1834 isc_throw(NotImplemented, "wipeLeases4 is not implemented for PgSQL backend");
1835}
1836
1837size_t
1839 isc_throw(NotImplemented, "wipeLeases6 is not implemented for PgSQL backend");
1840}
1841
1842string
1844 string name = "";
1845 try {
1846 name = conn_.getParameter("name");
1847 } catch (...) {
1848 // Return an empty name
1849 }
1850 return (name);
1851}
1852
1853string
1855 return (string("PostgreSQL Database"));
1856}
1857
1858pair<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
1884void
1886 conn_.commit();
1887}
1888
1889void
1891 conn_.rollback();
1892}
1893
1894}; // end of isc::dhcp namespace
1895}; // end of isc namespace
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.
static ElementPtr fromJSON(const std::string &in, bool preproc=false)
These functions will parse the given string (JSON) representation of a compound element.
Definition: data.cc:750
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
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:64
Multiple lease records found where one expected.
Definition: db_exceptions.h:28
Common PgSql Connector Pool.
void rollback()
Rollback Transactions.
bool compareError(const PgSqlResult &r, const char *error_state)
Checks a result set's SQL state against an error state.
void prepareStatement(const PgSqlTaggedStatement &statement)
Prepare Single Statement.
static const char DUPLICATE_KEY[]
Define the PgSql error state for a duplicate key error.
void commit()
Commit Transactions.
void openDatabase()
Open Database.
void checkStatementError(const PgSqlResult &r, PgSqlTaggedStatement &statement) const
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.
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:116
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:121
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:74
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:44
Abstract Lease Manager.
Definition: lease_mgr.h:222
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.
PgSqlLease4Exchange()
Default constructor.
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.
Base class for marshalling leases to and from PostgreSQL.
std::string addr_str_
Common Instance members used for binding and conversion.
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.
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::string getName() const
Returns name of the database.
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.
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.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID &subnet_id)
Creates and runs the IPv6 lease stats query for a single subnet.
virtual std::pair< uint32_t, uint32_t > getVersion() const
Returns backend version.
virtual ~PgSqlLeaseMgr()
Destructor (closes database)
virtual bool deleteLease(const isc::asiolink::IOAddress &addr)
Deletes a lease.
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.
virtual std::string getDescription() const
Returns description of the backend.
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.
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.
#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
int version()
returns Kea hooks version.
#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:23
const size_t OID_INT2
const uint32_t PG_SCHEMA_VERSION_MAJOR
Define PostgreSQL backend version: 5.0.
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
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:21
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition: lease.h:463
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:604
boost::shared_ptr< LeaseStatsQuery > LeaseStatsQueryPtr
Defines a pointer to a LeaseStatsQuery.
Definition: lease_mgr.h:207
TaggedStatementArray tagged_statements
Prepared MySQL statements used by the backend to insert and retrieve hosts from the database.
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
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:29
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition: lease.h:455
@ HTYPE_UNDEFINED
not specified or undefined
Definition: dhcp4.h:55
@ HTYPE_ETHER
Ethernet 10Mbps.
Definition: dhcp4.h:56
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:248
Defines the logger used by the top-level component of kea-dhcp-ddns.
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::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 IPv4 address.
Definition: lease.h:256
Structure that holds a lease for IPv6 address and/or prefix.
Definition: lease.h:471
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 STATE_EXPIRED_RECLAIMED
Expired and reclaimed lease.
Definition: lease.h:67
Type
Type of lease or pool.
Definition: lease.h:38
@ TYPE_TA
the lease contains temporary IPv6 address
Definition: lease.h:40
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition: lease.h:41
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition: lease.h:39