Kea  2.5.3
pgsql_lease_mgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2023 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/cfg_db_access.h>
13 #include <dhcpsrv/cfgmgr.h>
14 #include <dhcpsrv/dhcpsrv_log.h>
18 #include <dhcpsrv/timer_mgr.h>
20 
21 #include <boost/make_shared.hpp>
22 #include <boost/static_assert.hpp>
23 
24 #include <iomanip>
25 #include <limits>
26 #include <sstream>
27 #include <string>
28 #include <time.h>
29 
30 using namespace isc;
31 using namespace isc::asiolink;
32 using namespace isc::db;
33 using namespace isc::dhcp;
34 using namespace isc::data;
35 using namespace isc::util;
36 using namespace std;
37 
38 namespace {
39 
43 PgSqlTaggedStatement tagged_statements[] = {
44  // DELETE_LEASE4
45  { 2, { OID_INT8, OID_TIMESTAMP },
46  "delete_lease4",
47  "DELETE FROM lease4 WHERE address = $1 AND expire = $2" },
48 
49  // DELETE_LEASE4_STATE_EXPIRED
50  { 2, { OID_INT8, OID_TIMESTAMP },
51  "delete_lease4_state_expired",
52  "DELETE FROM lease4 "
53  "WHERE state = $1 AND expire < $2" },
54 
55  // DELETE_LEASE6
56  { 2, { OID_VARCHAR, OID_TIMESTAMP },
57  "delete_lease6",
58  "DELETE FROM lease6 WHERE address = cast($1 as inet) 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, relay_id, remote_id, pool_id "
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, relay_id, remote_id, pool_id "
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, relay_id, remote_id, pool_id "
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, relay_id, remote_id, pool_id "
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, relay_id, remote_id, pool_id "
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, relay_id, remote_id, pool_id "
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, relay_id, remote_id, pool_id "
132  "FROM lease4 "
133  "WHERE address > $1 "
134  "ORDER BY address "
135  "LIMIT $2" },
136 
137  // GET_LEASE4_UCTX_PAGE
138  { 2, { OID_INT8, OID_INT8 },
139  "get_lease4_uctx_page",
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, relay_id, remote_id, pool_id "
144  "FROM lease4 "
145  "WHERE address > $1 AND user_context IS NOT NULL "
146  "ORDER BY address "
147  "LIMIT $2" },
148 
149  // GET_LEASE4_SUBID
150  { 1, { OID_INT8 },
151  "get_lease4_subid",
152  "SELECT address, hwaddr, client_id, "
153  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
154  "fqdn_fwd, fqdn_rev, hostname, "
155  "state, user_context, relay_id, remote_id, pool_id "
156  "FROM lease4 "
157  "WHERE subnet_id = $1" },
158 
159  // GET_LEASE4_HOSTNAME
160  { 1, { OID_VARCHAR },
161  "get_lease4_hostname",
162  "SELECT address, hwaddr, client_id, "
163  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
164  "fqdn_fwd, fqdn_rev, hostname, "
165  "state, user_context, relay_id, remote_id, pool_id "
166  "FROM lease4 "
167  "WHERE lower(hostname) = $1" },
168 
169  // GET_LEASE4_EXPIRE
170  { 3, { OID_INT8, OID_TIMESTAMP, OID_INT8 },
171  "get_lease4_expire",
172  "SELECT address, hwaddr, client_id, "
173  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
174  "fqdn_fwd, fqdn_rev, hostname, "
175  "state, user_context, relay_id, remote_id, pool_id "
176  "FROM lease4 "
177  "WHERE state != $1 AND valid_lifetime != 4294967295 AND expire < $2 "
178  "ORDER BY expire "
179  "LIMIT $3" },
180 
181  // GET_LEASE4_RELAYID
182  { 3, { OID_BYTEA, OID_INT8, OID_INT8 },
183  "get_lease4_relayid",
184  "SELECT address, hwaddr, client_id, "
185  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
186  "fqdn_fwd, fqdn_rev, hostname, "
187  "state, user_context, relay_id, remote_id, pool_id "
188  "FROM lease4 "
189  "WHERE relay_id = $1 and address > $2 "
190  "ORDER BY address "
191  "LIMIT $3" },
192 
193  // GET_LEASE4_RELAYID_QST
194  { 4, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8 },
195  "get_lease4_relayid_qst",
196  "SELECT address, hwaddr, client_id, "
197  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
198  "fqdn_fwd, fqdn_rev, hostname, "
199  "state, user_context, relay_id, remote_id, pool_id "
200  "FROM lease4 "
201  "WHERE relay_id = $1 and address > $2 "
202  "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
203  "THEN 0 ELSE valid_lifetime END) >= $3 "
204  "ORDER BY address "
205  "LIMIT $4" },
206 
207  // GET_LEASE4_RELAYID_QSET
209  "get_lease4_relayid_qset",
210  "SELECT address, hwaddr, client_id, "
211  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
212  "fqdn_fwd, fqdn_rev, hostname, "
213  "state, user_context, relay_id, remote_id, pool_id "
214  "FROM lease4 "
215  "WHERE relay_id = $1 and address > $2 "
216  "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
217  "THEN 0 ELSE valid_lifetime END) >= $3 "
218  "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
219  "THEN 0 ELSE valid_lifetime END) <= $4 "
220  "ORDER BY address "
221  "LIMIT $5" },
222 
223  // GET_LEASE4_RELAYID_QET
224  { 4, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8 },
225  "get_lease4_relayid_qet",
226  "SELECT address, hwaddr, client_id, "
227  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
228  "fqdn_fwd, fqdn_rev, hostname, "
229  "state, user_context, relay_id, remote_id, pool_id "
230  "FROM lease4 "
231  "WHERE relay_id = $1 and address > $2 "
232  "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
233  "THEN 0 ELSE valid_lifetime END) <= $3 "
234  "ORDER BY address "
235  "LIMIT $4" },
236 
237  // GET_LEASE4_REMOTEID
238  { 3, { OID_BYTEA, OID_INT8, OID_INT8 },
239  "get_lease4_remoteid",
240  "SELECT address, hwaddr, client_id, "
241  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
242  "fqdn_fwd, fqdn_rev, hostname, "
243  "state, user_context, relay_id, remote_id, pool_id "
244  "FROM lease4 "
245  "WHERE remote_id = $1 and address > $2 "
246  "ORDER BY address "
247  "LIMIT $3" },
248 
249  // GET_LEASE4_REMOTEID_QST
250  { 4, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8 },
251  "get_lease4_remoteid_qst",
252  "SELECT address, hwaddr, client_id, "
253  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
254  "fqdn_fwd, fqdn_rev, hostname, "
255  "state, user_context, relay_id, remote_id, pool_id "
256  "FROM lease4 "
257  "WHERE remote_id = $1 and address > $2 "
258  "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
259  "THEN 0 ELSE valid_lifetime END) >= $3 "
260  "ORDER BY address "
261  "LIMIT $4" },
262 
263  // GET_LEASE4_REMOTEID_QSET
265  "get_lease4_remoteid_qset",
266  "SELECT address, hwaddr, client_id, "
267  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
268  "fqdn_fwd, fqdn_rev, hostname, "
269  "state, user_context, relay_id, remote_id, pool_id "
270  "FROM lease4 "
271  "WHERE remote_id = $1 and address > $2 "
272  "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
273  "THEN 0 ELSE valid_lifetime END) >= $3 "
274  "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
275  "THEN 0 ELSE valid_lifetime END) <= $4 "
276  "ORDER BY address "
277  "LIMIT $5" },
278 
279  // GET_LEASE4_REMOTEID_QET
280  { 4, { OID_BYTEA, OID_INT8, OID_INT8, OID_INT8 },
281  "get_lease4_remoteid_qet",
282  "SELECT address, hwaddr, client_id, "
283  "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
284  "fqdn_fwd, fqdn_rev, hostname, "
285  "state, user_context, relay_id, remote_id, pool_id "
286  "FROM lease4 "
287  "WHERE remote_id = $1 and address > $2 "
288  "and EXTRACT(EPOCH FROM expire) - (CASE valid_lifetime WHEN 4294967295 "
289  "THEN 0 ELSE valid_lifetime END) <= $3 "
290  "ORDER BY address "
291  "LIMIT $4" },
292 
293  // GET_LEASE6
294  { 0, { OID_NONE },
295  "get_lease6",
296  "SELECT host(address), duid, valid_lifetime, "
297  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
298  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
299  "hwaddr, hwtype, hwaddr_source, "
300  "state, user_context, pool_id "
301  "FROM lease6 "
302  "ORDER BY address "},
303 
304  // GET_LEASE6_ADDR
305  { 2, { OID_VARCHAR, OID_INT2 },
306  "get_lease6_addr",
307  "SELECT host(address), duid, valid_lifetime, "
308  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
309  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
310  "hwaddr, hwtype, hwaddr_source, "
311  "state, user_context, pool_id "
312  "FROM lease6 "
313  "WHERE address = cast($1 as inet) AND lease_type = $2"},
314 
315  // GET_LEASE6_DUID_IAID
316  { 3, { OID_BYTEA, OID_INT8, OID_INT2 },
317  "get_lease6_duid_iaid",
318  "SELECT host(address), duid, valid_lifetime, "
319  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
320  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
321  "hwaddr, hwtype, hwaddr_source, "
322  "state, user_context, pool_id "
323  "FROM lease6 "
324  "WHERE duid = $1 AND iaid = $2 AND lease_type = $3" },
325 
326  // GET_LEASE6_DUID_IAID_SUBID
327  { 4, { OID_INT2, OID_BYTEA, OID_INT8, OID_INT8 },
328  "get_lease6_duid_iaid_subid",
329  "SELECT host(address), duid, valid_lifetime, "
330  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
331  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
332  "hwaddr, hwtype, hwaddr_source, "
333  "state, user_context, pool_id "
334  "FROM lease6 "
335  "WHERE lease_type = $1 "
336  "AND duid = $2 AND iaid = $3 AND subnet_id = $4" },
337 
338  // GET_LEASE6_PAGE
339  { 2, { OID_VARCHAR, OID_INT8 },
340  "get_lease6_page",
341  "SELECT host(address), duid, valid_lifetime, "
342  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
343  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
344  "hwaddr, hwtype, hwaddr_source, "
345  "state, user_context, pool_id "
346  "FROM lease6 "
347  "WHERE address > cast($1 as inet) "
348  "ORDER BY address "
349  "LIMIT $2"},
350 
351  // GET_LEASE6_UCTX_PAGE
352  { 2, { OID_VARCHAR, OID_INT8 },
353  "get_lease6_uctx_page",
354  "SELECT host(address), duid, valid_lifetime, "
355  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
356  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
357  "hwaddr, hwtype, hwaddr_source, "
358  "state, user_context, pool_id "
359  "FROM lease6 "
360  "WHERE address > cast($1 as inet) AND user_context IS NOT NULL "
361  "ORDER BY address "
362  "LIMIT $2" },
363 
364  // GET_LEASE6_SUBID
365  { 1, { OID_INT8 },
366  "get_lease6_subid",
367  "SELECT host(address), duid, valid_lifetime, "
368  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
369  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
370  "hwaddr, hwtype, hwaddr_source, "
371  "state, user_context, pool_id "
372  "FROM lease6 "
373  "WHERE subnet_id = $1" },
374 
375  // GET_LEASE6_DUID
376  { 1, { OID_BYTEA },
377  "get_lease6_duid",
378  "SELECT host(address), duid, valid_lifetime, "
379  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
380  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
381  "hwaddr, hwtype, hwaddr_source, "
382  "state, user_context, pool_id "
383  "FROM lease6 "
384  "WHERE duid = $1" },
385 
386  // GET_LEASE6_HOSTNAME
387  { 1, { OID_VARCHAR },
388  "get_lease6_hostname",
389  "SELECT host(address), duid, valid_lifetime, "
390  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
391  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
392  "hwaddr, hwtype, hwaddr_source, "
393  "state, user_context, pool_id "
394  "FROM lease6 "
395  "WHERE lower(hostname) = $1" },
396 
397  // GET_LEASE6_EXPIRE
398  { 3, { OID_INT8, OID_TIMESTAMP, OID_INT8 },
399  "get_lease6_expire",
400  "SELECT host(address), duid, valid_lifetime, "
401  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
402  "lease_type, iaid, prefix_len, "
403  "fqdn_fwd, fqdn_rev, hostname, "
404  "hwaddr, hwtype, hwaddr_source, "
405  "state, user_context, pool_id "
406  "FROM lease6 "
407  "WHERE state != $1 AND valid_lifetime != 4294967295 AND expire < $2 "
408  "ORDER BY expire "
409  "LIMIT $3" },
410 
411  // GET_LEASE6_LINK
412  { 3, { OID_VARCHAR, OID_VARCHAR, OID_INT8 },
413  "get_lease6_link",
414  "SELECT host(address), duid, valid_lifetime, "
415  "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
416  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
417  "hwaddr, hwtype, hwaddr_source, "
418  "state, user_context, pool_id "
419  "FROM lease6 "
420  "WHERE address BETWEEN cast($1 as inet) and cast($2 as inet) "
421  "ORDER BY address "
422  "LIMIT $3" },
423 
424  // INSERT_LEASE4
427  OID_BYTEA, OID_INT8 },
428  "insert_lease4",
429  "INSERT INTO lease4(address, hwaddr, client_id, "
430  "valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, "
431  "state, user_context, relay_id, remote_id, pool_id) "
432  "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)" },
433 
434  // INSERT_LEASE6
438  OID_INT8},
439  "insert_lease6",
440  "INSERT INTO lease6(address, duid, valid_lifetime, "
441  "expire, subnet_id, pref_lifetime, "
442  "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
443  "hwaddr, hwtype, hwaddr_source, "
444  "state, user_context, pool_id) "
445  "VALUES (cast($1 as inet), $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)" },
446 
447  // UPDATE_LEASE4
451  "update_lease4",
452  "UPDATE lease4 SET address = $1, hwaddr = $2, "
453  "client_id = $3, valid_lifetime = $4, expire = $5, "
454  "subnet_id = $6, fqdn_fwd = $7, fqdn_rev = $8, hostname = $9, "
455  "state = $10, user_context = $11, relay_id = $12, remote_id = $13, pool_id = $14 "
456  "WHERE address = $15 AND expire = $16" },
457 
458  // UPDATE_LEASE6
463  "update_lease6",
464  "UPDATE lease6 SET address = cast($1 as inet), duid = $2, "
465  "valid_lifetime = $3, expire = $4, subnet_id = $5, "
466  "pref_lifetime = $6, lease_type = $7, iaid = $8, "
467  "prefix_len = $9, fqdn_fwd = $10, fqdn_rev = $11, hostname = $12, "
468  "hwaddr = $13, hwtype = $14, hwaddr_source = $15, "
469  "state = $16, user_context = $17, pool_id = $18 "
470  "WHERE address = cast($19 as inet) AND expire = $20" },
471 
472  // ALL_LEASE4_STATS
473  { 0, { OID_NONE },
474  "all_lease4_stats",
475  "SELECT subnet_id, state, leases as state_count"
476  " FROM lease4_stat ORDER BY subnet_id, state" },
477 
478  // SUBNET_LEASE4_STATS
479  { 1, { OID_INT8 },
480  "subnet_lease4_stats",
481  "SELECT subnet_id, state, leases as state_count"
482  " FROM lease4_stat "
483  " WHERE subnet_id = $1 "
484  " ORDER BY state" },
485 
486  // SUBNET_RANGE_LEASE4_STATS
487  { 2, { OID_INT8, OID_INT8 },
488  "subnet_range_lease4_stats",
489  "SELECT subnet_id, state, leases as state_count"
490  " FROM lease4_stat "
491  " WHERE subnet_id >= $1 and subnet_id <= $2 "
492  " ORDER BY subnet_id, state" },
493 
494  // ALL_POOL_LEASE4_STATS
495  { 0, { OID_NONE },
496  "all_pool_lease4_stats",
497  "SELECT subnet_id, pool_id, state, leases as state_count"
498  " FROM lease4_pool_stat ORDER BY subnet_id, pool_id, state" },
499 
500  // ALL_LEASE6_STATS,
501  { 0, { OID_NONE },
502  "all_lease6_stats",
503  "SELECT subnet_id, lease_type, state, leases as state_count"
504  " FROM lease6_stat ORDER BY subnet_id, lease_type, state" },
505 
506  // SUBNET_LEASE6_STATS
507  { 1, { OID_INT8 },
508  "subnet_lease6_stats",
509  "SELECT subnet_id, lease_type, state, leases as state_count"
510  " FROM lease6_stat "
511  " WHERE subnet_id = $1 "
512  " ORDER BY lease_type, state" },
513 
514  // SUBNET_RANGE_LEASE6_STATS
515  { 2, { OID_INT8, OID_INT8 },
516  "subnet_range_lease6_stats",
517  "SELECT subnet_id, lease_type, state, leases as state_count"
518  " FROM lease6_stat "
519  " WHERE subnet_id >= $1 and subnet_id <= $2 "
520  " ORDER BY subnet_id, lease_type, state" },
521 
522  // ALL_POOL_LEASE6_STATS,
523  { 0, { OID_NONE },
524  "all_pool_lease6_stats",
525  "SELECT subnet_id, pool_id, lease_type, state, leases as state_count"
526  " FROM lease6_pool_stat ORDER BY subnet_id, pool_id, lease_type, state" },
527 
528  // CHECK_LEASE4_LIMITS
529  { 1, { OID_TEXT },
530  "check_lease4_limits",
531  "SELECT checkLease4Limits($1)" },
532 
533  // CHECK_LEASE6_LIMITS
534  { 1, { OID_TEXT },
535  "check_lease6_limits",
536  "SELECT checkLease6Limits($1)" },
537 
538  // IS_JSON_SUPPORTED
539  { 0, { OID_NONE },
540  "is_json_supported",
541  "SELECT isJsonSupported()" },
542 
543  // GET_LEASE4_COUNT_BY_CLASS
544  { 1, { OID_VARCHAR },
545  "get_lease4_count_by_class",
546  "SELECT leases "
547  "FROM lease4_stat_by_client_class "
548  "WHERE client_class = $1" },
549 
550  // GET_LEASE6_COUNT_BY_CLASS
551  { 2, { OID_VARCHAR, OID_INT2 },
552  "get_lease6_count_by_class",
553  "SELECT leases "
554  "FROM lease6_stat_by_client_class "
555  "WHERE client_class = $1 AND lease_type = $2" },
556 
557  // WIPE_RELAY_ID6
558  { 0, { OID_NONE },
559  "wipe_relay_id6",
560  "DELETE FROM lease6_relay_id" },
561 
562  // WIPE_REMOTE_ID6
563  { 0, { OID_NONE },
564  "wipe_remote_id6",
565  "DELETE FROM lease6_remote_id" },
566 
567  // DELETE_RELAY_ID6
568  { 1, { OID_VARCHAR },
569  "delete_relay_id6",
570  "DELETE FROM lease6_relay_id WHERE lease_addr = cast($1 as inet)" },
571 
572  // DELETE_REMOTE_ID6
573  { 1, { OID_VARCHAR },
574  "delete_remote_id6",
575  "DELETE FROM lease6_remote_id WHERE lease_addr = cast($1 as inet)" },
576 
577  // ADD_RELAY_ID6
578  { 2, { OID_BYTEA, OID_VARCHAR },
579  "add_relay_id6",
580  "INSERT INTO lease6_relay_id(relay_id, lease_addr) "
581  "VALUES ($1, cast($2 as inet))" },
582 
583  // ADD_REMOTE_ID6
584  { 2, { OID_BYTEA, OID_VARCHAR },
585  "add_remote_id6",
586  "INSERT INTO lease6_remote_id(remote_id, lease_addr) "
587  "VALUES ($1, cast($2 as inet))" },
588 
589  // GET_RELAY_ID6
590  { 3, { OID_BYTEA, OID_VARCHAR, OID_INT8 },
591  "get_relay_id6",
592  "SELECT DISTINCT ON(l.address) "
593  "host(l.address), l.duid, l.valid_lifetime, "
594  "extract(epoch from l.expire)::bigint, l.subnet_id, l.pref_lifetime, "
595  "l.lease_type, l.iaid, l.prefix_len, l.fqdn_fwd, l.fqdn_rev, "
596  "l.hostname, l.hwaddr, l.hwtype, l.hwaddr_source, "
597  "l.state, l.user_context, l.pool_id "
598  "FROM lease6 AS l "
599  "INNER JOIN lease6_relay_id AS r "
600  " ON l.address = r.lease_addr "
601  " WHERE r.relay_id = $1 AND r.lease_addr > cast($2 as inet) "
602  "ORDER BY l.address "
603  "LIMIT $3" },
604 
605  // GET_REMOTE_ID6
606  { 3, { OID_BYTEA, OID_VARCHAR, OID_INT8 },
607  "get_remote_id6",
608  "SELECT DISTINCT ON(l.address) "
609  "host(l.address), l.duid, l.valid_lifetime, "
610  "extract(epoch from l.expire)::bigint, l.subnet_id, l.pref_lifetime, "
611  "l.lease_type, l.iaid, l.prefix_len, l.fqdn_fwd, l.fqdn_rev, "
612  "l.hostname, l.hwaddr, l.hwtype, l.hwaddr_source, "
613  "l.state, l.user_context, l.pool_id "
614  "FROM lease6 AS l "
615  "INNER JOIN lease6_remote_id AS r "
616  " ON l.address = r.lease_addr "
617  " WHERE r.remote_id = $1 AND r.lease_addr > cast($2 as inet) "
618  "ORDER BY l.address "
619  "LIMIT $3" },
620 
621  // GET_RELAY_ID6_LINK
623  "get_relay_id6_link",
624  "SELECT DISTINCT ON(l.address) "
625  "host(l.address), l.duid, l.valid_lifetime, "
626  "extract(epoch from l.expire)::bigint, l.subnet_id, l.pref_lifetime, "
627  "l.lease_type, l.iaid, l.prefix_len, l.fqdn_fwd, l.fqdn_rev, "
628  "l.hostname, l.hwaddr, l.hwtype, l.hwaddr_source, "
629  "l.state, l.user_context, l.pool_id "
630  "FROM lease6 AS l "
631  "INNER JOIN lease6_relay_id AS r "
632  " ON l.address = r.lease_addr "
633  " WHERE r.relay_id = $1 AND r.lease_addr "
634  "BETWEEN cast($2 as inet) and cast($3 as inet) "
635  "ORDER BY l.address "
636  "LIMIT $4" },
637 
638  // GET_REMOTE_ID6_LINK
640  "get_remote_id6_link",
641  "SELECT DISTINCT ON(l.address) "
642  "host(l.address), l.duid, l.valid_lifetime, "
643  "extract(epoch from l.expire)::bigint, l.subnet_id, l.pref_lifetime, "
644  "l.lease_type, l.iaid, l.prefix_len, l.fqdn_fwd, l.fqdn_rev, "
645  "l.hostname, l.hwaddr, l.hwtype, l.hwaddr_source, "
646  "l.state, l.user_context, l.pool_id "
647  "FROM lease6 AS l "
648  "INNER JOIN lease6_remote_id AS r "
649  " ON l.address = r.lease_addr "
650  " WHERE r.remote_id = $1 AND r.lease_addr "
651  "BETWEEN cast($2 as inet) and cast($3 as inet) "
652  "ORDER BY l.address "
653  "LIMIT $4" },
654 
655  // COUNT_RELAY_ID6
656  { 0, { OID_NONE },
657  "count_relay_id6",
658  "SELECT COUNT(*) FROM lease6_relay_id" },
659 
660  // COUNT_REMOTE_ID6
661  { 0, { OID_NONE },
662  "count_remote_id6",
663  "SELECT COUNT(*) FROM lease6_remote_id" },
664 
665  // End of list sentinel
666  { 0, { 0 }, 0, 0 }
667 };
668 
669 } // namespace
670 
671 namespace isc {
672 namespace dhcp {
673 
680 public:
681 
683  : addr_str_(""), hwaddr_length_(0), hwaddr_(hwaddr_length_),
684  valid_lifetime_(0), valid_lifetime_str_(""), expire_(0),
685  expire_str_(""), subnet_id_(0), subnet_id_str_(""), pool_id_(0),
686  pool_id_str_(""), cltt_(0), fqdn_fwd_(false), fqdn_rev_(false),
687  hostname_(""), state_str_(""), user_context_(""), addr_bin_(16) {
688  }
689 
690  virtual ~PgSqlLeaseExchange() {}
691 
692 protected:
693 
695 
696  std::string addr_str_;
698  std::vector<uint8_t> hwaddr_;
699  uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
700  uint32_t valid_lifetime_;
701  std::string valid_lifetime_str_;
702  time_t expire_;
703  std::string expire_str_;
704  uint32_t subnet_id_;
705  std::string subnet_id_str_;
706  uint32_t pool_id_;
707  std::string pool_id_str_;
708  time_t cltt_;
709  bool fqdn_fwd_;
710  bool fqdn_rev_;
711  std::string hostname_;
712  std::string state_str_;
713  std::string user_context_;
714  std::vector<uint8_t> addr_bin_;
716 };
717 
720 private:
721 
726 
727  static const size_t ADDRESS_COL = 0;
728  static const size_t HWADDR_COL = 1;
729  static const size_t CLIENT_ID_COL = 2;
730  static const size_t VALID_LIFETIME_COL = 3;
731  static const size_t EXPIRE_COL = 4;
732  static const size_t SUBNET_ID_COL = 5;
733  static const size_t FQDN_FWD_COL = 6;
734  static const size_t FQDN_REV_COL = 7;
735  static const size_t HOSTNAME_COL = 8;
736  static const size_t STATE_COL = 9;
737  static const size_t USER_CONTEXT_COL = 10;
738  static const size_t RELAY_ID_COL = 11;
739  static const size_t REMOTE_ID_COL = 12;
740  static const size_t POOL_ID_COL = 13;
742  static const size_t LEASE_COLUMNS = 14;
744 
745 public:
746 
749  : lease_(), addr4_(0), client_id_length_(0),
750  relay_id_length_(0), remote_id_length_(0) {
751 
752  BOOST_STATIC_ASSERT(13 < LEASE_COLUMNS);
753 
754  memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
755  memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
756  memset(relay_id_buffer_, 0, sizeof(relay_id_buffer_));
757  memset(remote_id_buffer_, 0, sizeof(remote_id_buffer_));
758 
759  // Set the column names (for error messages)
760  columns_.push_back("address");
761  columns_.push_back("hwaddr");
762  columns_.push_back("client_id");
763  columns_.push_back("valid_lifetime");
764  columns_.push_back("expire");
765  columns_.push_back("subnet_id");
766  columns_.push_back("fqdn_fwd");
767  columns_.push_back("fqdn_rev");
768  columns_.push_back("hostname");
769  columns_.push_back("state");
770  columns_.push_back("user_context");
771  columns_.push_back("relay_id");
772  columns_.push_back("remote_id");
773  columns_.push_back("pool_id");
774  }
775 
788  void createBindForSend(const Lease4Ptr& lease, PsqlBindArray& bind_array) {
789  if (!lease) {
790  isc_throw(BadValue, "createBindForSend:: Lease4 object is NULL");
791  }
792 
793  // Store lease object to ensure it remains valid.
794  lease_ = lease;
795 
796  try {
797  addr_str_ = boost::lexical_cast<std::string>(lease->addr_.toUint32());
798  bind_array.add(addr_str_);
799 
800  if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) {
801  // PostgreSql does not provide MAX on variable length types
802  // so we have to enforce it ourselves.
803  if (lease->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
804  isc_throw(DbOperationError, "Hardware address length : "
805  << lease_->hwaddr_->hwaddr_.size()
806  << " exceeds maximum allowed of: "
807  << HWAddr::MAX_HWADDR_LEN);
808  }
809  bind_array.add(lease->hwaddr_->hwaddr_);
810  } else {
811  bind_array.add("");
812  }
813 
814  if (lease->client_id_) {
815  bind_array.add(lease->client_id_->getClientId());
816  } else {
817  bind_array.add("");
818  }
819 
820  valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
821  bind_array.add(valid_lifetime_str_);
822 
823  // The lease structure holds the client last transmission time (cltt_)
824  // For convenience for external tools, this is converted to lease
825  // expiry time (expire). The relationship is given by:
826  // expire = cltt_ + valid_lft_
827  // Avoid overflow with infinite valid lifetime by using
828  // expire = cltt_ when valid_lft_ = 0xffffffff
829  if (lease_->valid_lft_ == Lease::INFINITY_LFT) {
830  expire_str_ = convertToDatabaseTime(lease->cltt_, 0);
831  } else {
832  expire_str_ = convertToDatabaseTime(lease->cltt_,
833  lease_->valid_lft_);
834  }
835  bind_array.add(expire_str_);
836 
837  subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
838  bind_array.add(subnet_id_str_);
839 
840  bind_array.add(lease->fqdn_fwd_);
841 
842  bind_array.add(lease->fqdn_rev_);
843 
844  bind_array.add(lease->hostname_);
845 
846  state_str_ = boost::lexical_cast<std::string>(lease->state_);
847  bind_array.add(state_str_);
848 
849  ConstElementPtr ctx = lease->getContext();
850  if (ctx) {
851  user_context_ = ctx->str();
852  } else {
853  user_context_ = "";
854  }
855  bind_array.add(user_context_);
856 
857  if (!lease->relay_id_.empty()) {
858  bind_array.add(lease->relay_id_);
859  } else {
860  bind_array.addNull();
861  }
862 
863  if (!lease->remote_id_.empty()) {
864  bind_array.add(lease->remote_id_);
865  } else {
866  bind_array.addNull();
867  }
868 
869  pool_id_str_ = boost::lexical_cast<std::string>(lease->pool_id_);
870  bind_array.add(pool_id_str_);
871  } catch (const std::exception& ex) {
873  "Could not create bind array from Lease4: "
874  << lease_->addr_.toText() << ", reason: " << ex.what());
875  }
876  }
877 
887  try {
888  getColumnValue(r, row, ADDRESS_COL, addr4_);
889 
890  convertFromBytea(r, row, HWADDR_COL, hwaddr_buffer_,
891  sizeof(hwaddr_buffer_), hwaddr_length_);
892 
893  convertFromBytea(r, row, CLIENT_ID_COL, client_id_buffer_,
894  sizeof(client_id_buffer_), client_id_length_);
895 
896  getColumnValue(r, row, VALID_LIFETIME_COL, valid_lifetime_);
897 
898  expire_ = convertFromDatabaseTime(getRawColumnValue(r, row,
899  EXPIRE_COL));
900 
901  getColumnValue(r, row, SUBNET_ID_COL, subnet_id_);
902 
903  // Recover from overflow (see createBindForSend)
904  if (valid_lifetime_ == Lease::INFINITY_LFT) {
905  cltt_ = expire_;
906  } else {
907  cltt_ = expire_ - valid_lifetime_;
908  }
909 
910  getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
911 
912  getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
913 
914  hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
915 
916  uint32_t state;
917  getColumnValue(r, row, STATE_COL, state);
918 
919  HWAddrPtr hwaddr(new HWAddr(hwaddr_buffer_, hwaddr_length_,
920  HTYPE_ETHER));
921 
922  user_context_ = getRawColumnValue(r, row, USER_CONTEXT_COL);
923  ConstElementPtr ctx;
924  if (!user_context_.empty()) {
925  ctx = Element::fromJSON(user_context_);
926  if (!ctx || (ctx->getType() != Element::map)) {
927  isc_throw(BadValue, "user context '" << user_context_
928  << "' is not a JSON map");
929  }
930  }
931 
932  convertFromBytea(r, row, RELAY_ID_COL, relay_id_buffer_,
933  sizeof(relay_id_buffer_), relay_id_length_);
934 
935  convertFromBytea(r, row, REMOTE_ID_COL, remote_id_buffer_,
936  sizeof(remote_id_buffer_), remote_id_length_);
937 
938  getColumnValue(r, row, POOL_ID_COL, pool_id_);
939 
940  Lease4Ptr result(boost::make_shared<Lease4>(addr4_, hwaddr,
941  client_id_buffer_,
942  client_id_length_,
943  valid_lifetime_, cltt_,
944  subnet_id_, fqdn_fwd_,
945  fqdn_rev_, hostname_));
946 
947  result->state_ = state;
948 
949  if (ctx) {
950  result->setContext(ctx);
951  }
952 
953  if (relay_id_length_) {
954  result->relay_id_.assign(relay_id_buffer_,
955  relay_id_buffer_ + relay_id_length_);
956  }
957 
958  if (remote_id_length_) {
959  result->remote_id_.assign(remote_id_buffer_,
960  remote_id_buffer_ + remote_id_length_);
961  }
962 
963  result->pool_id_ = pool_id_;
964 
965  return (result);
966  } catch (const std::exception& ex) {
968  "Could not convert data to Lease4, reason: "
969  << ex.what());
970  }
971  }
972 
973 private:
974 
978  Lease4Ptr lease_;
979 
981  uint32_t addr4_;
982  size_t client_id_length_;
983  uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
984  size_t relay_id_length_;
985  uint8_t relay_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
986  size_t remote_id_length_;
987  uint8_t remote_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
988 };
989 
992 private:
993 
998 
999  static const size_t ADDRESS_COL = 0;
1000  static const size_t DUID_COL = 1;
1001  static const size_t VALID_LIFETIME_COL = 2;
1002  static const size_t EXPIRE_COL = 3;
1003  static const size_t SUBNET_ID_COL = 4;
1004  static const size_t PREF_LIFETIME_COL = 5;
1005  static const size_t LEASE_TYPE_COL = 6;
1006  static const size_t IAID_COL = 7;
1007  static const size_t PREFIX_LEN_COL = 8;
1008  static const size_t FQDN_FWD_COL = 9;
1009  static const size_t FQDN_REV_COL = 10;
1010  static const size_t HOSTNAME_COL = 11;
1011  static const size_t HWADDR_COL = 12;
1012  static const size_t HWTYPE_COL = 13;
1013  static const size_t HWADDR_SOURCE_COL = 14;
1014  static const size_t STATE_COL = 15;
1015  static const size_t USER_CONTEXT_COL = 16;
1016  static const size_t POOL_ID_COL = 17;
1018  static const size_t LEASE_COLUMNS = 18;
1020 
1021 public:
1022 
1029  union Uiaid {
1032  Uiaid(uint32_t val) : uval_(val) {};
1033 
1036  Uiaid(int32_t val) : ival_(val) {};
1037 
1039  std::string dbInputString() {
1040  return (boost::lexical_cast<std::string>(ival_));
1041  };
1042 
1043  uint32_t uval_;
1044  int32_t ival_;
1045  };
1046 
1048  : lease_(), duid_length_(0), duid_(duid_length_), iaid_u_(0),
1049  iaid_str_(""), lease_type_(Lease6::TYPE_NA), lease_type_str_(""),
1050  prefix_len_(0), prefix_len_str_(""), pref_lifetime_(0),
1051  preferred_lifetime_str_(""), hwtype_(0), hwtype_str_(""),
1052  hwaddr_source_(0), hwaddr_source_str_("") {
1053 
1054  BOOST_STATIC_ASSERT(17 < LEASE_COLUMNS);
1055 
1056  memset(duid_buffer_, 0, sizeof(duid_buffer_));
1057 
1058  // Set the column names (for error messages)
1059  columns_.push_back("address");
1060  columns_.push_back("duid");
1061  columns_.push_back("valid_lifetime");
1062  columns_.push_back("expire");
1063  columns_.push_back("subnet_id");
1064  columns_.push_back("pref_lifetime");
1065  columns_.push_back("lease_type");
1066  columns_.push_back("iaid");
1067  columns_.push_back("prefix_len");
1068  columns_.push_back("fqdn_fwd");
1069  columns_.push_back("fqdn_rev");
1070  columns_.push_back("hostname");
1071  columns_.push_back("hwaddr");
1072  columns_.push_back("hwtype");
1073  columns_.push_back("hwaddr_source");
1074  columns_.push_back("state");
1075  columns_.push_back("user_context");
1076  columns_.push_back("pool_id");
1077  }
1078 
1091  void createBindForSend(const Lease6Ptr& lease, PsqlBindArray& bind_array) {
1092  if (!lease) {
1093  isc_throw(BadValue, "createBindForSend:: Lease6 object is NULL");
1094  }
1095 
1096  // Store lease object to ensure it remains valid.
1097  lease_ = lease;
1098  try {
1099  addr_str_ = lease_->addr_.toText();
1100  bind_array.add(addr_str_);
1101 
1102  if (lease_->duid_) {
1103  bind_array.add(lease_->duid_->getDuid());
1104  } else {
1105  isc_throw (BadValue, "IPv6 Lease cannot have a null DUID");
1106  }
1107 
1108  valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
1109  bind_array.add(valid_lifetime_str_);
1110 
1111  // The lease structure holds the client last transmission time (cltt_)
1112  // For convenience for external tools, this is converted to lease
1113  // expiry time (expire). The relationship is given by:
1114  // expire = cltt_ + valid_lft_
1115  // Avoid overflow with infinite valid lifetime by using
1116  // expire = cltt_ when valid_lft_ = 0xffffffff
1117  if (lease_->valid_lft_ == Lease::INFINITY_LFT) {
1118  expire_str_ = convertToDatabaseTime(lease->cltt_, 0);
1119  } else {
1120  expire_str_ = convertToDatabaseTime(lease->cltt_,
1121  lease_->valid_lft_);
1122  }
1123  bind_array.add(expire_str_);
1124 
1125  subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
1126  bind_array.add(subnet_id_str_);
1127 
1128  preferred_lifetime_str_ = boost::lexical_cast<std::string>(lease_->preferred_lft_);
1129  bind_array.add(preferred_lifetime_str_);
1130 
1131  lease_type_str_ = boost::lexical_cast<std::string>(lease_->type_);
1132  bind_array.add(lease_type_str_);
1133 
1134  // The iaid is stored as an INT in lease6 table, so we must
1135  // lexically cast from an integer version to avoid out of range
1136  // exception failure upon insert.
1137  iaid_u_.uval_ = lease_->iaid_;
1138  iaid_str_ = iaid_u_.dbInputString();
1139  bind_array.add(iaid_str_);
1140 
1141  prefix_len_str_ = boost::lexical_cast<std::string>
1142  (static_cast<unsigned int>(lease_->prefixlen_));
1143  bind_array.add(prefix_len_str_);
1144 
1145  bind_array.add(lease->fqdn_fwd_);
1146 
1147  bind_array.add(lease->fqdn_rev_);
1148 
1149  bind_array.add(lease->hostname_);
1150 
1151  if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) {
1152  // PostgreSql does not provide MAX on variable length types
1153  // so we have to enforce it ourselves.
1154  if (lease->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
1155  isc_throw(DbOperationError, "Hardware address length : "
1156  << lease_->hwaddr_->hwaddr_.size()
1157  << " exceeds maximum allowed of: "
1158  << HWAddr::MAX_HWADDR_LEN);
1159  }
1160  bind_array.add(lease->hwaddr_->hwaddr_);
1161  } else {
1162  bind_array.add("");
1163  }
1164 
1165  if (lease->hwaddr_) {
1166  hwtype_str_ = boost::lexical_cast<std::string>
1167  (static_cast<unsigned int>(lease_->hwaddr_->htype_));
1168  hwaddr_source_str_ = boost::lexical_cast<std::string>
1169  (static_cast<unsigned int>(lease_->hwaddr_->source_));
1170  } else {
1171  hwtype_str_ = boost::lexical_cast<std::string>
1172  (static_cast<unsigned int>(HTYPE_UNDEFINED));
1173  hwaddr_source_str_ = boost::lexical_cast<std::string>
1174  (static_cast<unsigned int>(HWAddr::HWADDR_SOURCE_UNKNOWN));
1175  }
1176 
1177  bind_array.add(hwtype_str_);
1178 
1179  bind_array.add(hwaddr_source_str_);
1180 
1181  state_str_ = boost::lexical_cast<std::string>(lease->state_);
1182  bind_array.add(state_str_);
1183 
1184  ConstElementPtr ctx = lease->getContext();
1185  if (ctx) {
1186  user_context_ = ctx->str();
1187  } else {
1188  user_context_ = "";
1189  }
1190  bind_array.add(user_context_);
1191 
1192  pool_id_str_ = boost::lexical_cast<std::string>(lease->pool_id_);
1193  bind_array.add(pool_id_str_);
1194  } catch (const std::exception& ex) {
1196  "Could not create bind array from Lease6: "
1197  << lease_->addr_.toText() << ", reason: " << ex.what());
1198  }
1199  }
1200 
1210  try {
1211 
1219 
1220  IOAddress addr(getIPv6Value(r, row, ADDRESS_COL));
1221 
1222  convertFromBytea(r, row, DUID_COL, duid_buffer_, sizeof(duid_buffer_), duid_length_);
1223  DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_));
1224 
1225  getColumnValue(r, row, VALID_LIFETIME_COL, valid_lifetime_);
1226 
1227  expire_ = convertFromDatabaseTime(getRawColumnValue(r, row,
1228  EXPIRE_COL));
1229 
1230  // Recover from overflow (see createBindForSend)
1231  if (valid_lifetime_ == Lease::INFINITY_LFT) {
1232  cltt_ = expire_;
1233  } else {
1234  cltt_ = expire_ - valid_lifetime_;
1235  }
1236 
1237  getColumnValue(r, row, SUBNET_ID_COL, subnet_id_);
1238 
1239  getColumnValue(r, row, PREF_LIFETIME_COL, pref_lifetime_);
1240 
1241  getLeaseTypeColumnValue(r, row, LEASE_TYPE_COL, lease_type_);
1242 
1243  getColumnValue(r, row, IAID_COL, iaid_u_.ival_);
1244 
1245  getColumnValue(r, row, PREFIX_LEN_COL, prefix_len_);
1246 
1247  getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
1248 
1249  getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
1250 
1251  hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
1252 
1253  convertFromBytea(r, row, HWADDR_COL, hwaddr_buffer_,
1254  sizeof(hwaddr_buffer_), hwaddr_length_);
1255 
1256  getColumnValue(r, row, HWTYPE_COL, hwtype_);
1257 
1258  getColumnValue(r, row, HWADDR_SOURCE_COL, hwaddr_source_);
1259 
1260  HWAddrPtr hwaddr;
1261 
1262  if (hwaddr_length_) {
1263  hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_,
1264  hwtype_));
1265 
1266  hwaddr->source_ = hwaddr_source_;
1267  }
1268 
1269  uint32_t state;
1270  getColumnValue(r, row, STATE_COL, state);
1271 
1272  user_context_ = getRawColumnValue(r, row, USER_CONTEXT_COL);
1273  ConstElementPtr ctx;
1274  if (!user_context_.empty()) {
1275  ctx = Element::fromJSON(user_context_);
1276  if (!ctx || (ctx->getType() != Element::map)) {
1277  isc_throw(BadValue, "user context '" << user_context_
1278  << "' is not a JSON map");
1279  }
1280  }
1281 
1282  getColumnValue(r, row, POOL_ID_COL, pool_id_);
1283 
1284  if (lease_type_ != Lease::TYPE_PD) {
1285  prefix_len_ = 128;
1286  }
1287 
1288  Lease6Ptr result(boost::make_shared<Lease6>(lease_type_, addr,
1289  duid_ptr,
1290  iaid_u_.uval_,
1291  pref_lifetime_,
1292  valid_lifetime_,
1293  subnet_id_, fqdn_fwd_,
1294  fqdn_rev_, hostname_,
1295  hwaddr, prefix_len_));
1296  // Update cltt_ and current_cltt_ explicitly.
1297  result->cltt_ = cltt_;
1298  result->current_cltt_ = cltt_;
1299 
1300  result->state_ = state;
1301 
1302  if (ctx) {
1303  result->setContext(ctx);
1304  }
1305 
1306  result->pool_id_ = pool_id_;
1307 
1308  return (result);
1309  } catch (const std::exception& ex) {
1311  "Could not convert data to Lease6, reason: "
1312  << ex.what());
1313  }
1314  }
1315 
1328  void getLeaseTypeColumnValue(const PgSqlResult& r, const int row,
1329  const size_t col, Lease6::Type& value) const {
1330  uint32_t raw_value = 0;
1331  getColumnValue(r, row, col, raw_value);
1332  switch (raw_value) {
1333  case Lease6::TYPE_NA:
1334  case Lease6::TYPE_TA:
1335  case Lease6::TYPE_PD:
1336  value = static_cast<Lease6::Type>(raw_value);
1337  break;
1338 
1339  default:
1340  isc_throw(DbOperationError, "Invalid lease type: " << raw_value
1341  << " for: " << getColumnLabel(r, col) << " row:" << row);
1342  }
1343  }
1344 
1345 private:
1349  Lease6Ptr lease_;
1350 
1352 
1353  size_t duid_length_;
1354  std::vector<uint8_t> duid_;
1355  uint8_t duid_buffer_[DUID::MAX_DUID_LEN];
1356  union Uiaid iaid_u_;
1357  std::string iaid_str_;
1358  Lease6::Type lease_type_;
1359  std::string lease_type_str_;
1360  uint8_t prefix_len_;
1361  std::string prefix_len_str_;
1362  uint32_t pref_lifetime_;
1363  std::string preferred_lifetime_str_;
1364  uint32_t hwtype_;
1365  std::string hwtype_str_;
1366  uint32_t hwaddr_source_;
1367  std::string hwaddr_source_str_;
1369 };
1370 
1377 public:
1378 
1389  const bool fetch_type, const bool fetch_pool = false)
1390  : conn_(conn), statement_(statement), result_set_(), next_row_(0),
1391  fetch_type_(fetch_type), fetch_pool_(fetch_pool) {
1392  }
1393 
1403  const bool fetch_type, const SubnetID& subnet_id)
1404  : LeaseStatsQuery(subnet_id), conn_(conn), statement_(statement), result_set_(),
1405  next_row_(0), fetch_type_(fetch_type), fetch_pool_(false) {
1406  }
1407 
1419  const bool fetch_type, const SubnetID& first_subnet_id,
1420  const SubnetID& last_subnet_id)
1421  : LeaseStatsQuery(first_subnet_id, last_subnet_id), conn_(conn), statement_(statement),
1422  result_set_(), next_row_(0), fetch_type_(fetch_type), fetch_pool_(false) {
1423  }
1424 
1427 
1437  void start() {
1438 
1439  if (getSelectMode() == ALL_SUBNETS || getSelectMode() == ALL_SUBNET_POOLS) {
1440  // Run the query with no where clause parameters.
1441  result_set_.reset(new PgSqlResult(PQexecPrepared(conn_, statement_.name,
1442  0, 0, 0, 0, 0)));
1443  } else {
1444  // Set up the WHERE clause values
1445  PsqlBindArray parms;
1446 
1447  // Add first_subnet_id used by both single and range.
1448  parms.addTempString(boost::lexical_cast<std::string>(getFirstSubnetID()));
1449 
1450  // Add last_subnet_id for range.
1451  if (getSelectMode() == SUBNET_RANGE) {
1452  // Add last_subnet_id used by range.
1453  parms.addTempString(boost::lexical_cast<std::string>(getLastSubnetID()));
1454  }
1455 
1456  // Run the query with where clause parameters.
1457  result_set_.reset(new PgSqlResult(PQexecPrepared(conn_, statement_.name,
1458  parms.size(), &parms.values_[0],
1459  &parms.lengths_[0], &parms.formats_[0], 0)));
1460  }
1461 
1462  conn_.checkStatementError(*result_set_, statement_);
1463  }
1464 
1480  // If we're past the end, punt.
1481  if (next_row_ >= result_set_->getRows()) {
1482  return (false);
1483  }
1484 
1485  // Fetch the subnet id.
1486  uint32_t col = 0;
1487  uint32_t subnet_id;
1488  PgSqlExchange::getColumnValue(*result_set_, next_row_, col, subnet_id);
1489  row.subnet_id_ = static_cast<SubnetID>(subnet_id);
1490  ++col;
1491 
1492  // Fetch the pool id if we were told to do so.
1493  if (fetch_pool_) {
1494  PgSqlExchange::getColumnValue(*result_set_, next_row_, col,
1495  row.pool_id_);
1496  ++col;
1497  }
1498 
1499  // Fetch the lease type if we were told to do so.
1500  if (fetch_type_) {
1501  uint32_t lease_type;
1502  PgSqlExchange::getColumnValue(*result_set_, next_row_, col,
1503  lease_type);
1504  row.lease_type_ = static_cast<Lease::Type>(lease_type);
1505  ++col;
1506  } else {
1507  row.lease_type_ = Lease::TYPE_NA;
1508  }
1509 
1510  // Fetch the lease state.
1511  PgSqlExchange::getColumnValue(*result_set_, next_row_, col,
1512  row.lease_state_);
1513  ++col;
1514 
1515  // Fetch the state count.
1516  PgSqlExchange::getColumnValue(*result_set_, next_row_, col,
1517  row.state_count_);
1518 
1519  // Protect against negative state count.a
1520  if (row.state_count_ < 0) {
1521  row.state_count_ = 0;
1522  if (!negative_count_) {
1523  negative_count_ = true;
1525  }
1526  }
1527 
1528  // Point to the next row.
1529  ++next_row_;
1530  return (true);
1531  }
1532 
1533 protected:
1534 
1537 
1540 
1542  boost::shared_ptr<PgSqlResult> result_set_;
1543 
1545  uint32_t next_row_;
1546 
1549 
1552 
1554  static bool negative_count_;
1555 };
1556 
1557 // Initialize negative state count flag to false.
1558 bool PgSqlLeaseStatsQuery::negative_count_ = false;
1559 
1560 // PgSqlLeaseContext Constructor
1561 
1562 PgSqlLeaseContext::PgSqlLeaseContext(const DatabaseConnection::ParameterMap& parameters,
1563  IOServiceAccessorPtr io_service_accessor,
1564  DbCallback db_reconnect_callback)
1565  : conn_(parameters, io_service_accessor, db_reconnect_callback) {
1566 }
1567 
1568 // PgSqlLeaseContextAlloc Constructor and Destructor
1569 
1570 PgSqlLeaseMgr::PgSqlLeaseContextAlloc::PgSqlLeaseContextAlloc(
1571  const PgSqlLeaseMgr& mgr) : ctx_(), mgr_(mgr) {
1572 
1573  if (MultiThreadingMgr::instance().getMode()) {
1574  // multi-threaded
1575  {
1576  // we need to protect the whole pool_ operation, hence extra scope {}
1577  lock_guard<mutex> lock(mgr_.pool_->mutex_);
1578  if (!mgr_.pool_->pool_.empty()) {
1579  ctx_ = mgr_.pool_->pool_.back();
1580  mgr_.pool_->pool_.pop_back();
1581  }
1582  }
1583  if (!ctx_) {
1584  ctx_ = mgr_.createContext();
1585  }
1586  } else {
1587  // single-threaded
1588  if (mgr_.pool_->pool_.empty()) {
1589  isc_throw(Unexpected, "No available PostgreSQL lease context?!");
1590  }
1591  ctx_ = mgr_.pool_->pool_.back();
1592  }
1593 }
1594 
1595 PgSqlLeaseMgr::PgSqlLeaseContextAlloc::~PgSqlLeaseContextAlloc() {
1596  if (MultiThreadingMgr::instance().getMode()) {
1597  // multi-threaded
1598  lock_guard<mutex> lock(mgr_.pool_->mutex_);
1599  mgr_.pool_->pool_.push_back(ctx_);
1600  }
1601  // If running in single-threaded mode, there's nothing to do here.
1602 }
1603 
1604 // PgSqlLeaseTrackingContextAlloc Constructor and Destructor
1605 
1606 PgSqlLeaseMgr::PgSqlLeaseTrackingContextAlloc::PgSqlLeaseTrackingContextAlloc(
1607  PgSqlLeaseMgr& mgr, const LeasePtr& lease) : ctx_(), mgr_(mgr), lease_(lease) {
1608 
1609  if (MultiThreadingMgr::instance().getMode()) {
1610  // multi-threaded
1611  {
1612  // we need to protect the whole pool_ operation, hence extra scope {}
1613  lock_guard<mutex> lock(mgr_.pool_->mutex_);
1614  if (mgr_.hasCallbacks() && !mgr_.tryLock(lease)) {
1615  isc_throw(DbOperationError, "unable to lock the lease " << lease->addr_);
1616  }
1617  if (!mgr_.pool_->pool_.empty()) {
1618  ctx_ = mgr_.pool_->pool_.back();
1619  mgr_.pool_->pool_.pop_back();
1620  }
1621  }
1622  if (!ctx_) {
1623  ctx_ = mgr_.createContext();
1624  }
1625  } else {
1626  // single-threaded
1627  if (mgr_.pool_->pool_.empty()) {
1628  isc_throw(Unexpected, "No available PostgreSQL lease context?!");
1629  }
1630  ctx_ = mgr_.pool_->pool_.back();
1631  }
1632 }
1633 
1634 PgSqlLeaseMgr::PgSqlLeaseTrackingContextAlloc::~PgSqlLeaseTrackingContextAlloc() {
1635  if (MultiThreadingMgr::instance().getMode()) {
1636  // multi-threaded
1637  lock_guard<mutex> lock(mgr_.pool_->mutex_);
1638  if (mgr_.hasCallbacks()) {
1639  mgr_.unlock(lease_);
1640  }
1641  mgr_.pool_->pool_.push_back(ctx_);
1642  }
1643  // If running in single-threaded mode, there's nothing to do here.
1644 }
1645 
1646 // PgSqlLeaseMgr Constructor and Destructor
1647 
1649  : TrackingLeaseMgr(), parameters_(parameters), timer_name_("") {
1650 
1651  // Check if the extended info tables are enabled.
1652  setExtendedInfoTablesEnabled(parameters);
1653 
1654  // Create unique timer name per instance.
1655  timer_name_ = "PgSqlLeaseMgr[";
1656  timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this));
1657  timer_name_ += "]DbReconnectTimer";
1658 
1659  // Check TLS support.
1660  size_t tls(0);
1661  tls += parameters.count("trust-anchor");
1662  tls += parameters.count("cert-file");
1663  tls += parameters.count("key-file");
1664  tls += parameters.count("cipher-list");
1665 #ifdef HAVE_PGSQL_SSL
1666  if ((tls > 0) && !PgSqlConnection::warned_about_tls) {
1669  .arg(DatabaseConnection::redactedAccessString(parameters_));
1670  PQinitSSL(1);
1671  }
1672 #else
1673  if (tls > 0) {
1675  .arg(DatabaseConnection::redactedAccessString(parameters_));
1676  isc_throw(DbOpenError, "Attempt to configure TLS for PostgreSQL "
1677  << "backend (built with this feature disabled)");
1678  }
1679 #endif
1680 
1681  // Validate schema version first.
1682  std::pair<uint32_t, uint32_t> code_version(PGSQL_SCHEMA_VERSION_MAJOR,
1684  std::pair<uint32_t, uint32_t> db_version = getVersion();
1685  if (code_version != db_version) {
1687  "PostgreSQL schema version mismatch: need version: "
1688  << code_version.first << "." << code_version.second
1689  << " found version: " << db_version.first << "."
1690  << db_version.second);
1691  }
1692 
1693  // Create an initial context.
1694  pool_.reset(new PgSqlLeaseContextPool());
1695  pool_->pool_.push_back(createContext());
1696 }
1697 
1699 }
1700 
1701 bool
1704 
1705  // Invoke application layer connection lost callback.
1706  if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) {
1707  return (false);
1708  }
1709 
1710  bool reopened = false;
1711 
1712  const std::string timer_name = db_reconnect_ctl->timerName();
1713 
1714  // At least one connection was lost.
1715  try {
1716  CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
1717  LeaseMgrFactory::recreate(cfg_db->getLeaseDbAccessString());
1718  reopened = true;
1719  } catch (const std::exception& ex) {
1721  .arg(ex.what());
1722  }
1723 
1724  if (reopened) {
1725  // Cancel the timer.
1726  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1727  TimerMgr::instance()->unregisterTimer(timer_name);
1728  }
1729 
1730  // Invoke application layer connection recovered callback.
1731  if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) {
1732  return (false);
1733  }
1734  } else {
1735  if (!db_reconnect_ctl->checkRetries()) {
1736  // We're out of retries, log it and initiate shutdown.
1738  .arg(db_reconnect_ctl->maxRetries());
1739 
1740  // Cancel the timer.
1741  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1742  TimerMgr::instance()->unregisterTimer(timer_name);
1743  }
1744 
1745  // Invoke application layer connection failed callback.
1747  return (false);
1748  }
1749 
1751  .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
1752  .arg(db_reconnect_ctl->maxRetries())
1753  .arg(db_reconnect_ctl->retryInterval());
1754 
1755  // Start the timer.
1756  if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
1757  TimerMgr::instance()->registerTimer(timer_name,
1758  std::bind(&PgSqlLeaseMgr::dbReconnect, db_reconnect_ctl),
1759  db_reconnect_ctl->retryInterval(),
1761  }
1762  TimerMgr::instance()->setup(timer_name);
1763  }
1764 
1765  return (true);
1766 }
1767 
1768 // Create context.
1769 
1772  PgSqlLeaseContextPtr ctx(new PgSqlLeaseContext(parameters_,
1775 
1776  // Open the database.
1777  ctx->conn_.openDatabase();
1778 
1779  // Now prepare the SQL statements.
1780  uint32_t i = 0;
1781  for (; tagged_statements[i].text != NULL; ++i) {
1782  ctx->conn_.prepareStatement(tagged_statements[i]);
1783  }
1784 
1785  // Just in case somebody foo-barred things
1786  if (i != NUM_STATEMENTS) {
1787  isc_throw(DbOpenError, "Number of statements prepared: " << i
1788  << " does not match expected count:" << NUM_STATEMENTS);
1789  }
1790 
1791  // Create the exchange objects for use in exchanging data between the
1792  // program and the database.
1793  ctx->exchange4_.reset(new PgSqlLease4Exchange());
1794  ctx->exchange6_.reset(new PgSqlLease6Exchange());
1795 
1796  // Create ReconnectCtl for this connection.
1797  ctx->conn_.makeReconnectCtl(timer_name_);
1798 
1799  return (ctx);
1800 }
1801 
1802 std::string
1804  std::stringstream tmp;
1805  tmp << "PostgreSQL backend " << PGSQL_SCHEMA_VERSION_MAJOR;
1806  tmp << "." << PGSQL_SCHEMA_VERSION_MINOR;
1807  tmp << ", library " << PQlibVersion();
1808  return (tmp.str());
1809 }
1810 
1811 bool
1812 PgSqlLeaseMgr::addLeaseCommon(PgSqlLeaseContextPtr& ctx,
1813  StatementIndex stindex,
1814  PsqlBindArray& bind_array) {
1815  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
1816  tagged_statements[stindex].nbparams,
1817  &bind_array.values_[0],
1818  &bind_array.lengths_[0],
1819  &bind_array.formats_[0], 0));
1820 
1821  int s = PQresultStatus(r);
1822 
1823  if (s != PGRES_COMMAND_OK) {
1824  // Failure: check for the special case of duplicate entry. If this is
1825  // the case, we return false to indicate that the row was not added.
1826  // Otherwise we throw an exception.
1827  if (ctx->conn_.compareError(r, PgSqlConnection::DUPLICATE_KEY)) {
1828  return (false);
1829  }
1830  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
1831  }
1832 
1833  return (true);
1834 }
1835 
1836 bool
1839  .arg(lease->addr_.toText());
1840 
1841  // Get a context
1842  PgSqlLeaseTrackingContextAlloc get_context(*this, lease);
1843  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1844 
1845  PsqlBindArray bind_array;
1846  ctx->exchange4_->createBindForSend(lease, bind_array);
1847  auto result = addLeaseCommon(ctx, INSERT_LEASE4, bind_array);
1848 
1849  // Update lease current expiration time (allows update between the creation
1850  // of the Lease up to the point of insertion in the database).
1851  lease->updateCurrentExpirationTime();
1852 
1853  // Run installed callbacks.
1854  if (hasCallbacks()) {
1855  trackAddLease(lease, false);
1856  }
1857 
1858  return (result);
1859 }
1860 
1861 bool
1864  .arg(lease->addr_.toText())
1865  .arg(lease->type_);
1866 
1867  lease->extended_info_action_ = Lease6::ACTION_IGNORE;
1868 
1869  // Get a context
1870  PgSqlLeaseTrackingContextAlloc get_context(*this, lease);
1871  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1872 
1873  PsqlBindArray bind_array;
1874  ctx->exchange6_->createBindForSend(lease, bind_array);
1875 
1876  auto result = addLeaseCommon(ctx, INSERT_LEASE6, bind_array);
1877 
1878  // Update lease current expiration time (allows update between the creation
1879  // of the Lease up to the point of insertion in the database).
1880  lease->updateCurrentExpirationTime();
1881 
1883  static_cast<void>(addExtendedInfo6(lease));
1884  }
1885 
1886  // Run installed callbacks.
1887  if (hasCallbacks()) {
1888  trackAddLease(lease, false);
1889  }
1890 
1891  return (result);
1892 }
1893 
1894 template <typename Exchange, typename LeaseCollection>
1895 void
1896 PgSqlLeaseMgr::getLeaseCollection(PgSqlLeaseContextPtr& ctx,
1897  StatementIndex stindex,
1898  PsqlBindArray& bind_array,
1899  Exchange& exchange,
1900  LeaseCollection& result,
1901  bool single) const {
1902  const int n = tagged_statements[stindex].nbparams;
1903  PgSqlResult r(PQexecPrepared(ctx->conn_,
1904  tagged_statements[stindex].name, n,
1905  n > 0 ? &bind_array.values_[0] : NULL,
1906  n > 0 ? &bind_array.lengths_[0] : NULL,
1907  n > 0 ? &bind_array.formats_[0] : NULL, 0));
1908 
1909  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
1910 
1911  int rows = PQntuples(r);
1912  if (single && rows > 1) {
1913  isc_throw(MultipleRecords, "multiple records were found in the "
1914  "database where only one was expected for query "
1915  << tagged_statements[stindex].name);
1916  }
1917 
1918  for(int i = 0; i < rows; ++i) {
1919  result.push_back(exchange->convertFromDatabase(r, i));
1920  }
1921 }
1922 
1923 void
1924 PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr& ctx,
1925  StatementIndex stindex, PsqlBindArray& bind_array,
1926  Lease4Ptr& result) const {
1927  // Create appropriate collection object and get all leases matching
1928  // the selection criteria. The "single" parameter is true to indicate
1929  // that the called method should throw an exception if multiple
1930  // matching records are found: this particular method is called when only
1931  // one or zero matches is expected.
1932  Lease4Collection collection;
1933  getLeaseCollection(ctx, stindex, bind_array, ctx->exchange4_,
1934  collection, true);
1935 
1936  // Return single record if present, else clear the lease.
1937  if (collection.empty()) {
1938  result.reset();
1939  } else {
1940  result = *collection.begin();
1941  }
1942 }
1943 
1944 void
1945 PgSqlLeaseMgr::getLease(PgSqlLeaseContextPtr& ctx,
1946  StatementIndex stindex, PsqlBindArray& bind_array,
1947  Lease6Ptr& result) const {
1948  // Create appropriate collection object and get all leases matching
1949  // the selection criteria. The "single" parameter is true to indicate
1950  // that the called method should throw an exception if multiple
1951  // matching records are found: this particular method is called when only
1952  // one or zero matches is expected.
1953  Lease6Collection collection;
1954  getLeaseCollection(ctx, stindex, bind_array, ctx->exchange6_,
1955  collection, true);
1956 
1957  // Return single record if present, else clear the lease.
1958  if (collection.empty()) {
1959  result.reset();
1960  } else {
1961  result = *collection.begin();
1962  }
1963 }
1964 
1965 Lease4Ptr
1968  .arg(addr.toText());
1969 
1970  // Set up the WHERE clause value
1971  PsqlBindArray bind_array;
1972 
1973  // LEASE ADDRESS
1974  std::string addr_str = boost::lexical_cast<std::string>(addr.toUint32());
1975  bind_array.add(addr_str);
1976 
1977  // Get the data
1978  Lease4Ptr result;
1979 
1980  // Get a context
1981  PgSqlLeaseContextAlloc get_context(*this);
1982  PgSqlLeaseContextPtr ctx = get_context.ctx_;
1983 
1984  getLease(ctx, GET_LEASE4_ADDR, bind_array, result);
1985 
1986  return (result);
1987 }
1988 
1990 PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
1992  .arg(hwaddr.toText());
1993 
1994  // Set up the WHERE clause value
1995  PsqlBindArray bind_array;
1996 
1997  // HWADDR
1998  if (!hwaddr.hwaddr_.empty()) {
1999  bind_array.add(hwaddr.hwaddr_);
2000  } else {
2001  bind_array.add("");
2002  }
2003 
2004  // Get the data
2005  Lease4Collection result;
2006 
2007  // Get a context
2008  PgSqlLeaseContextAlloc get_context(*this);
2009  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2010 
2011  getLeaseCollection(ctx, GET_LEASE4_HWADDR, bind_array, result);
2012 
2013  return (result);
2014 }
2015 
2016 Lease4Ptr
2017 PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
2019  .arg(subnet_id)
2020  .arg(hwaddr.toText());
2021 
2022  // Set up the WHERE clause value
2023  PsqlBindArray bind_array;
2024 
2025  // HWADDR
2026  if (!hwaddr.hwaddr_.empty()) {
2027  bind_array.add(hwaddr.hwaddr_);
2028  } else {
2029  bind_array.add("");
2030  }
2031 
2032  // SUBNET_ID
2033  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
2034  bind_array.add(subnet_id_str);
2035 
2036  // Get the data
2037  Lease4Ptr result;
2038 
2039  // Get a context
2040  PgSqlLeaseContextAlloc get_context(*this);
2041  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2042 
2043  getLease(ctx, GET_LEASE4_HWADDR_SUBID, bind_array, result);
2044 
2045  return (result);
2046 }
2047 
2049 PgSqlLeaseMgr::getLease4(const ClientId& clientid) const {
2051  .arg(clientid.toText());
2052 
2053  // Set up the WHERE clause value
2054  PsqlBindArray bind_array;
2055 
2056  // CLIENT_ID
2057  bind_array.add(clientid.getClientId());
2058 
2059  // Get the data
2060  Lease4Collection result;
2061 
2062  // Get a context
2063  PgSqlLeaseContextAlloc get_context(*this);
2064  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2065 
2066  getLeaseCollection(ctx, GET_LEASE4_CLIENTID, bind_array, result);
2067 
2068  return (result);
2069 }
2070 
2071 Lease4Ptr
2072 PgSqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
2074  .arg(subnet_id)
2075  .arg(clientid.toText());
2076 
2077  // Set up the WHERE clause value
2078  PsqlBindArray bind_array;
2079 
2080  // CLIENT_ID
2081  bind_array.add(clientid.getClientId());
2082 
2083  // SUBNET_ID
2084  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
2085  bind_array.add(subnet_id_str);
2086 
2087  // Get the data
2088  Lease4Ptr result;
2089 
2090  // Get a context
2091  PgSqlLeaseContextAlloc get_context(*this);
2092  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2093 
2094  getLease(ctx, GET_LEASE4_CLIENTID_SUBID, bind_array, result);
2095 
2096  return (result);
2097 }
2098 
2102  .arg(subnet_id);
2103 
2104  // Set up the WHERE clause value
2105  PsqlBindArray bind_array;
2106 
2107  // SUBNET_ID
2108  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
2109  bind_array.add(subnet_id_str);
2110 
2111  // ... and get the data
2112  Lease4Collection result;
2113 
2114  // Get a context
2115  PgSqlLeaseContextAlloc get_context(*this);
2116  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2117 
2118  getLeaseCollection(ctx, GET_LEASE4_SUBID, bind_array, result);
2119 
2120  return (result);
2121 }
2122 
2124 PgSqlLeaseMgr::getLeases4(const std::string& hostname) const {
2126  .arg(hostname);
2127 
2128  // Set up the WHERE clause value
2129  PsqlBindArray bind_array;
2130 
2131  // Hostname
2132  bind_array.add(hostname);
2133 
2134  // ... and get the data
2135  Lease4Collection result;
2136 
2137  // Get a context
2138  PgSqlLeaseContextAlloc get_context(*this);
2139  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2140 
2141  getLeaseCollection(ctx, GET_LEASE4_HOSTNAME, bind_array, result);
2142 
2143  return (result);
2144 }
2145 
2149 
2150  // Provide empty binding array because our query has no parameters in
2151  // WHERE clause.
2152  PsqlBindArray bind_array;
2153  Lease4Collection result;
2154 
2155  // Get a context
2156  PgSqlLeaseContextAlloc get_context(*this);
2157  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2158 
2159  getLeaseCollection(ctx, GET_LEASE4, bind_array, result);
2160 
2161  return (result);
2162 }
2163 
2165 PgSqlLeaseMgr::getLeases4(const IOAddress& lower_bound_address,
2166  const LeasePageSize& page_size) const {
2167  // Expecting IPv4 address.
2168  if (!lower_bound_address.isV4()) {
2169  isc_throw(InvalidAddressFamily, "expected IPv4 address while "
2170  "retrieving leases from the lease database, got "
2171  << lower_bound_address);
2172  }
2173 
2175  .arg(page_size.page_size_)
2176  .arg(lower_bound_address.toText());
2177 
2178  // Prepare WHERE clause
2179  PsqlBindArray bind_array;
2180 
2181  // Bind lower bound address
2182  std::string lb_address_data = boost::lexical_cast<std::string>(lower_bound_address.toUint32());
2183  bind_array.add(lb_address_data);
2184 
2185  // Bind page size value
2186  std::string page_size_data = boost::lexical_cast<std::string>(page_size.page_size_);
2187  bind_array.add(page_size_data);
2188 
2189  // Get the leases
2190  Lease4Collection result;
2191 
2192  // Get a context
2193  PgSqlLeaseContextAlloc get_context(*this);
2194  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2195 
2196  getLeaseCollection(ctx, GET_LEASE4_PAGE, bind_array, result);
2197 
2198  return (result);
2199 }
2200 
2201 Lease6Ptr
2203  const IOAddress& addr) const {
2205  .arg(addr.toText())
2206  .arg(lease_type);
2207 
2208  // Set up the WHERE clause value
2209  PsqlBindArray bind_array;
2210 
2211  // LEASE ADDRESS
2212  std::string addr_str = addr.toText();
2213  bind_array.add(addr_str);
2214 
2215  // LEASE_TYPE
2216  std::string type_str_ = boost::lexical_cast<std::string>(lease_type);
2217  bind_array.add(type_str_);
2218 
2219  // ... and get the data
2220  Lease6Ptr result;
2221 
2222  // Get a context
2223  PgSqlLeaseContextAlloc get_context(*this);
2224  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2225 
2226  getLease(ctx, GET_LEASE6_ADDR, bind_array, result);
2227 
2228  return (result);
2229 }
2230 
2233  uint32_t iaid) const {
2235  .arg(iaid)
2236  .arg(duid.toText())
2237  .arg(lease_type);
2238 
2239  // Set up the WHERE clause value
2240  PsqlBindArray bind_array;
2241 
2242  // DUID
2243  bind_array.add(duid.getDuid());
2244 
2245  // IAID
2246  std::string iaid_str = PgSqlLease6Exchange::Uiaid(iaid).dbInputString();
2247  bind_array.add(iaid_str);
2248 
2249  // LEASE_TYPE
2250  std::string lease_type_str = boost::lexical_cast<std::string>(lease_type);
2251  bind_array.add(lease_type_str);
2252 
2253  // ... and get the data
2254  Lease6Collection result;
2255 
2256  // Get a context
2257  PgSqlLeaseContextAlloc get_context(*this);
2258  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2259 
2260  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID, bind_array, result);
2261 
2262  return (result);
2263 }
2264 
2267  uint32_t iaid, SubnetID subnet_id) const {
2269  .arg(iaid)
2270  .arg(subnet_id)
2271  .arg(duid.toText())
2272  .arg(lease_type);
2273 
2274  // Set up the WHERE clause value
2275  PsqlBindArray bind_array;
2276 
2277  // LEASE_TYPE
2278  std::string lease_type_str = boost::lexical_cast<std::string>(lease_type);
2279  bind_array.add(lease_type_str);
2280 
2281  // DUID
2282  bind_array.add(duid.getDuid());
2283 
2284  // IAID
2285  std::string iaid_str = PgSqlLease6Exchange::Uiaid(iaid).dbInputString();
2286  bind_array.add(iaid_str);
2287 
2288  // SUBNET ID
2289  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
2290  bind_array.add(subnet_id_str);
2291 
2292  // ... and get the data
2293  Lease6Collection result;
2294 
2295  // Get a context
2296  PgSqlLeaseContextAlloc get_context(*this);
2297  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2298 
2299  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID_SUBID, bind_array, result);
2300 
2301  return (result);
2302 }
2303 
2307  .arg(subnet_id);
2308 
2309  // Set up the WHERE clause value
2310  PsqlBindArray bind_array;
2311 
2312  // SUBNET_ID
2313  std::string subnet_id_str = boost::lexical_cast<std::string>(subnet_id);
2314  bind_array.add(subnet_id_str);
2315 
2316  // ... and get the data
2317  Lease6Collection result;
2318 
2319  // Get a context
2320  PgSqlLeaseContextAlloc get_context(*this);
2321  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2322 
2323  getLeaseCollection(ctx, GET_LEASE6_SUBID, bind_array, result);
2324 
2325  return (result);
2326 }
2327 
2329 PgSqlLeaseMgr::getLeases6(const DUID& duid) const {
2331  .arg(duid.toText());
2332 
2333  // Set up the WHERE clause value
2334  PsqlBindArray bind_array;
2335 
2336  // DUID
2337  bind_array.add(duid.getDuid());
2338  Lease6Collection result;
2339 
2340  // Get a context
2341  PgSqlLeaseContextAlloc get_context(*this);
2342  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2343 
2344  // query to fetch the data
2345  getLeaseCollection(ctx, GET_LEASE6_DUID, bind_array, result);
2346 
2347  return (result);
2348 }
2349 
2351 PgSqlLeaseMgr::getLeases6(const std::string& hostname) const {
2353  .arg(hostname);
2354 
2355  // Set up the WHERE clause value
2356  PsqlBindArray bind_array;
2357 
2358  // Hostname
2359  bind_array.add(hostname);
2360 
2361  // ... and get the data
2362  Lease6Collection result;
2363 
2364  // Get a context
2365  PgSqlLeaseContextAlloc get_context(*this);
2366  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2367 
2368  getLeaseCollection(ctx, GET_LEASE6_HOSTNAME, bind_array, result);
2369 
2370  return (result);
2371 }
2372 
2376 
2377  // Provide empty binding array because our query has no parameters in
2378  // WHERE clause.
2379  PsqlBindArray bind_array;
2380  Lease6Collection result;
2381 
2382  // Get a context
2383  PgSqlLeaseContextAlloc get_context(*this);
2384  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2385 
2386  getLeaseCollection(ctx, GET_LEASE6, bind_array, result);
2387 
2388  return (result);
2389 }
2390 
2392 PgSqlLeaseMgr::getLeases6(const IOAddress& lower_bound_address,
2393  const LeasePageSize& page_size) const {
2394  // Expecting IPv6 address.
2395  if (!lower_bound_address.isV6()) {
2396  isc_throw(InvalidAddressFamily, "expected IPv6 address while "
2397  "retrieving leases from the lease database, got "
2398  << lower_bound_address);
2399  }
2400 
2402  .arg(page_size.page_size_)
2403  .arg(lower_bound_address.toText());
2404 
2405  // Prepare WHERE clause
2406  PsqlBindArray bind_array;
2407 
2408  // Bind lower bound address
2409  std::string lb_address_data = lower_bound_address.toText();
2410  bind_array.add(lb_address_data);
2411 
2412  // Bind page size value
2413  std::string page_size_data =
2414  boost::lexical_cast<std::string>(page_size.page_size_);
2415  bind_array.add(page_size_data);
2416 
2417  // Get the leases
2418  Lease6Collection result;
2419 
2420  // Get a context
2421  PgSqlLeaseContextAlloc get_context(*this);
2422  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2423 
2424  getLeaseCollection(ctx, GET_LEASE6_PAGE, bind_array, result);
2425 
2426  return (result);
2427 }
2428 
2429 void
2431  const size_t max_leases) const {
2433  .arg(max_leases);
2434  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE4_EXPIRE);
2435 }
2436 
2437 void
2439  const size_t max_leases) const {
2441  .arg(max_leases);
2442  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE6_EXPIRE);
2443 }
2444 
2445 template<typename LeaseCollection>
2446 void
2447 PgSqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases,
2448  const size_t max_leases,
2449  StatementIndex statement_index) const {
2450  PsqlBindArray bind_array;
2451 
2452  // Exclude reclaimed leases.
2453  std::string state_str = boost::lexical_cast<std::string>(Lease::STATE_EXPIRED_RECLAIMED);
2454  bind_array.add(state_str);
2455 
2456  // Expiration timestamp.
2457  std::string timestamp_str = PgSqlLeaseExchange::convertToDatabaseTime(time(0));
2458  bind_array.add(timestamp_str);
2459 
2460  // If the number of leases is 0, we will return all leases. This is
2461  // achieved by setting the limit to a very high value.
2462  uint32_t limit = max_leases > 0 ? static_cast<uint32_t>(max_leases) :
2463  std::numeric_limits<uint32_t>::max();
2464  std::string limit_str = boost::lexical_cast<std::string>(limit);
2465  bind_array.add(limit_str);
2466 
2467  // Get a context
2468  PgSqlLeaseContextAlloc get_context(*this);
2469  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2470 
2471  // Retrieve leases from the database.
2472  getLeaseCollection(ctx, statement_index, bind_array, expired_leases);
2473 }
2474 
2475 template<typename LeasePtr>
2476 void
2477 PgSqlLeaseMgr::updateLeaseCommon(PgSqlLeaseContextPtr& ctx,
2478  StatementIndex stindex,
2479  PsqlBindArray& bind_array,
2480  const LeasePtr& lease) {
2481  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2482  tagged_statements[stindex].nbparams,
2483  &bind_array.values_[0],
2484  &bind_array.lengths_[0],
2485  &bind_array.formats_[0], 0));
2486 
2487  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2488 
2489  int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
2490 
2491  // Check success case first as it is the most likely outcome.
2492  if (affected_rows == 1) {
2493  return;
2494  }
2495 
2496  // If no rows affected, lease doesn't exist.
2497  if (affected_rows == 0) {
2498  isc_throw(NoSuchLease, "unable to update lease for address " <<
2499  lease->addr_.toText() << " as it does not exist");
2500  }
2501 
2502  // Should not happen - primary key constraint should only have selected
2503  // one row.
2504  isc_throw(DbOperationError, "apparently updated more than one lease "
2505  "that had the address " << lease->addr_.toText());
2506 }
2507 
2508 void
2510  const StatementIndex stindex = UPDATE_LEASE4;
2511 
2513  .arg(lease->addr_.toText());
2514 
2515  // Get a context
2516  PgSqlLeaseTrackingContextAlloc get_context(*this, lease);
2517  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2518 
2519  // Create the BIND array for the data being updated
2520  PsqlBindArray bind_array;
2521  ctx->exchange4_->createBindForSend(lease, bind_array);
2522 
2523  // Set up the WHERE clause and append it to the SQL_BIND array
2524  std::string addr4_str = boost::lexical_cast<std::string>(lease->addr_.toUint32());
2525  bind_array.add(addr4_str);
2526 
2527  std::string expire_str;
2528  // Avoid overflow (see createBindForSend)
2529  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2530  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2531  } else {
2532  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2533  lease->current_valid_lft_);
2534  }
2535  bind_array.add(expire_str);
2536 
2537  // Drop to common update code
2538  updateLeaseCommon(ctx, stindex, bind_array, lease);
2539 
2540  // Update lease current expiration time.
2541  lease->updateCurrentExpirationTime();
2542 
2543  // Run installed callbacks.
2544  if (hasCallbacks()) {
2545  trackUpdateLease(lease, false);
2546  }
2547 }
2548 
2549 void
2551  const StatementIndex stindex = UPDATE_LEASE6;
2552 
2554  .arg(lease->addr_.toText())
2555  .arg(lease->type_);
2556 
2557  // Get the recorded action and reset it.
2558  Lease6::ExtendedInfoAction recorded_action = lease->extended_info_action_;
2559  lease->extended_info_action_ = Lease6::ACTION_IGNORE;
2560 
2561  // Get a context
2562  PgSqlLeaseTrackingContextAlloc get_context(*this, lease);
2563  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2564 
2565  // Create the BIND array for the data being updated
2566  PsqlBindArray bind_array;
2567  ctx->exchange6_->createBindForSend(lease, bind_array);
2568 
2569  // Set up the WHERE clause and append it to the BIND array
2570  std::string addr_str = lease->addr_.toText();
2571  bind_array.add(addr_str);
2572 
2573  std::string expire_str;
2574  // Avoid overflow (see createBindForSend)
2575  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2576  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2577  } else {
2578  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2579  lease->current_valid_lft_);
2580  }
2581  bind_array.add(expire_str);
2582 
2583  // Drop to common update code
2584  updateLeaseCommon(ctx, stindex, bind_array, lease);
2585 
2586  // Update lease current expiration time.
2587  lease->updateCurrentExpirationTime();
2588 
2589  // Update extended info tables.
2591  switch (recorded_action) {
2592  case Lease6::ACTION_IGNORE:
2593  break;
2594 
2595  case Lease6::ACTION_DELETE:
2596  deleteExtendedInfo6(lease->addr_);
2597  break;
2598 
2599  case Lease6::ACTION_UPDATE:
2600  deleteExtendedInfo6(lease->addr_);
2601  static_cast<void>(addExtendedInfo6(lease));
2602  break;
2603  }
2604  }
2605 
2606  // Run installed callbacks.
2607  if (hasCallbacks()) {
2608  trackUpdateLease(lease, false);
2609  }
2610 }
2611 
2612 uint64_t
2613 PgSqlLeaseMgr::deleteLeaseCommon(PgSqlLeaseContextPtr& ctx,
2614  StatementIndex stindex,
2615  PsqlBindArray& bind_array) {
2616  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2617  tagged_statements[stindex].nbparams,
2618  &bind_array.values_[0],
2619  &bind_array.lengths_[0],
2620  &bind_array.formats_[0], 0));
2621 
2622  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2623  int affected_rows = boost::lexical_cast<int>(PQcmdTuples(r));
2624 
2625  return (affected_rows);
2626 }
2627 
2628 bool
2630  const IOAddress& addr = lease->addr_;
2632  .arg(addr.toText());
2633 
2634  // Set up the WHERE clause value
2635  PsqlBindArray bind_array;
2636 
2637  std::string addr4_str = boost::lexical_cast<std::string>(addr.toUint32());
2638  bind_array.add(addr4_str);
2639 
2640  std::string expire_str;
2641  // Avoid overflow (see createBindForSend)
2642  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2643  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2644  } else {
2645  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2646  lease->current_valid_lft_);
2647  }
2648  bind_array.add(expire_str);
2649 
2650  // Get a context
2651  PgSqlLeaseTrackingContextAlloc get_context(*this, lease);
2652  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2653 
2654  auto affected_rows = deleteLeaseCommon(ctx, DELETE_LEASE4, bind_array);
2655 
2656  // Check success case first as it is the most likely outcome.
2657  if (affected_rows == 1) {
2658  if (hasCallbacks()) {
2659  trackDeleteLease(lease, false);
2660  }
2661  return (true);
2662  }
2663 
2664  // If no rows affected, lease doesn't exist.
2665  if (affected_rows == 0) {
2666  return (false);
2667  }
2668 
2669  // Should not happen - primary key constraint should only have selected
2670  // one row.
2671  isc_throw(DbOperationError, "apparently deleted more than one lease "
2672  "that had the address " << lease->addr_.toText());
2673 }
2674 
2675 bool
2677  const IOAddress& addr = lease->addr_;
2680  .arg(addr.toText());
2681 
2682  lease->extended_info_action_ = Lease6::ACTION_IGNORE;
2683 
2684  // Set up the WHERE clause value
2685  PsqlBindArray bind_array;
2686 
2687  std::string addr6_str = addr.toText();
2688  bind_array.add(addr6_str);
2689 
2690  std::string expire_str;
2691  // Avoid overflow (see createBindForSend)
2692  if (lease->current_valid_lft_ == Lease::INFINITY_LFT) {
2693  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_, 0);
2694  } else {
2695  expire_str = PgSqlLeaseExchange::convertToDatabaseTime(lease->current_cltt_,
2696  lease->current_valid_lft_);
2697  }
2698  bind_array.add(expire_str);
2699 
2700  // Get a context
2701  PgSqlLeaseTrackingContextAlloc get_context(*this, lease);
2702  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2703 
2704  auto affected_rows = deleteLeaseCommon(ctx, DELETE_LEASE6, bind_array);
2705 
2706  // Check success case first as it is the most likely outcome.
2707  if (affected_rows == 1) {
2708  // Delete references from extended info tables.
2709  // Performed by the delete cascade.
2710 
2711  // Run installed callbacks.
2712  if (hasCallbacks()) {
2713  trackDeleteLease(lease, false);
2714  }
2715  return (true);
2716  }
2717 
2718  // If no rows affected, lease doesn't exist.
2719  if (affected_rows == 0) {
2720  return (false);
2721  }
2722 
2723  // Should not happen - primary key constraint should only have selected
2724  // one row.
2725  isc_throw(DbOperationError, "apparently deleted more than one lease "
2726  "that had the address " << lease->addr_.toText());
2727 }
2728 
2729 uint64_t
2732  .arg(secs);
2733  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
2734 }
2735 
2736 uint64_t
2739  .arg(secs);
2740  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
2741 }
2742 
2743 uint64_t
2744 PgSqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
2745  StatementIndex statement_index) {
2746  PsqlBindArray bind_array;
2747 
2748  // State is reclaimed.
2749  std::string state_str = boost::lexical_cast<std::string>(Lease::STATE_EXPIRED_RECLAIMED);
2750  bind_array.add(state_str);
2751 
2752  // Expiration timestamp.
2753  std::string expiration_str = PgSqlLeaseExchange::convertToDatabaseTime(time(0) -
2754  static_cast<time_t>(secs));
2755  bind_array.add(expiration_str);
2756 
2757  // Get a context
2758  PgSqlLeaseContextAlloc get_context(*this);
2759  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2760 
2761  // Delete leases.
2762  return (deleteLeaseCommon(ctx, statement_index, bind_array));
2763 }
2764 
2765 string
2766 PgSqlLeaseMgr::checkLimits(ConstElementPtr const& user_context, StatementIndex const stindex) const {
2767  // No user context means no limits means allocation allowed means empty string.
2768  if (!user_context) {
2769  return string();
2770  }
2771 
2772  // Get a context.
2773  PgSqlLeaseContextAlloc get_context(*this);
2774  PgSqlLeaseContextPtr ctx(get_context.ctx_);
2775 
2776  // Create bindings.
2777  PsqlBindArray bind_array;
2778  std::string const user_context_str(user_context->str());
2779  bind_array.add(user_context_str);
2780 
2781  // Execute the select.
2782  PgSqlResult r(PQexecPrepared(ctx->conn_,
2783  tagged_statements[stindex].name,
2784  tagged_statements[stindex].nbparams,
2785  &bind_array.values_[0],
2786  &bind_array.lengths_[0],
2787  &bind_array.formats_[0], 0));
2788  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2789 
2790  std::string limits;
2791  PgSqlExchange::getColumnValue(r, 0, 0, limits);
2792  return limits;
2793 }
2794 
2795 string
2796 PgSqlLeaseMgr::checkLimits4(ConstElementPtr const& user_context) const {
2797  return checkLimits(user_context, CHECK_LEASE4_LIMITS);
2798 }
2799 
2800 string
2801 PgSqlLeaseMgr::checkLimits6(ConstElementPtr const& user_context) const {
2802  return checkLimits(user_context, CHECK_LEASE6_LIMITS);
2803 }
2804 
2805 bool
2807  // Get a context.
2808  PgSqlLeaseContextAlloc get_context(*this);
2809  PgSqlLeaseContextPtr ctx(get_context.ctx_);
2810 
2811  // Execute the select.
2812  StatementIndex const stindex(IS_JSON_SUPPORTED);
2813  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2814  0, 0, 0, 0, 0));
2815  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2816 
2817  bool json_supported;
2818  PgSqlExchange::getColumnValue(r, 0, 0, json_supported);
2819  return json_supported;
2820 }
2821 
2822 size_t
2824  const Lease::Type& ltype /* = Lease::TYPE_V4*/) const {
2825  // Get a context.
2826  PgSqlLeaseContextAlloc get_context(*this);
2827  PgSqlLeaseContextPtr ctx(get_context.ctx_);
2828 
2829  // Create bindings.
2830  PsqlBindArray bind_array;
2831  bind_array.add(client_class);
2832  if (ltype != Lease::TYPE_V4) {
2833  bind_array.add(ltype);
2834  }
2835 
2836  // Execute the select.
2837  StatementIndex const stindex(ltype == Lease::TYPE_V4 ? GET_LEASE4_COUNT_BY_CLASS :
2839  PgSqlResult r(PQexecPrepared(ctx->conn_,
2840  tagged_statements[stindex].name,
2841  tagged_statements[stindex].nbparams,
2842  &bind_array.values_[0],
2843  &bind_array.lengths_[0],
2844  &bind_array.formats_[0], 0));
2845  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2846 
2847  int rows = PQntuples(r);
2848  if (rows == 0) {
2849  // No entries means 0 leases.
2850  return 0;
2851  }
2852 
2853  size_t count;
2854  PgSqlExchange::getColumnValue(r, 0, 0, count);
2855  return count;
2856 }
2857 
2858 void
2860  isc_throw(NotImplemented, "PgSqlLeaseMgr::recountClassLeases4() not implemented");
2861 }
2862 
2863 void
2865  isc_throw(NotImplemented, "PgSqlLeaseMgr::recountClassLeases6() not implemented");
2866 }
2867 
2868 void
2870  isc_throw(NotImplemented, "PgSqlLeaseMgr::clearClassLeaseCounts() not implemented");
2871 }
2872 
2873 void
2874 PgSqlLeaseMgr::writeLeases4(const std::string&) {
2875  isc_throw(NotImplemented, "PgSqlLeaseMgr::writeLeases4() not implemented");
2876 }
2877 
2878 void
2879 PgSqlLeaseMgr::writeLeases6(const std::string&) {
2880  isc_throw(NotImplemented, "PgSqlLeaseMgr::writeLeases6() not implemented");
2881 }
2882 
2885  // Get a context
2886  PgSqlLeaseContextAlloc get_context(*this);
2887  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2888 
2889  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2890  tagged_statements[ALL_LEASE4_STATS],
2891  false));
2892  query->start();
2893  return(query);
2894 }
2895 
2898  // Get a context
2899  PgSqlLeaseContextAlloc get_context(*this);
2900  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2901 
2902  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2903  tagged_statements[ALL_POOL_LEASE4_STATS],
2904  false, true));
2905  query->start();
2906  return(query);
2907 }
2908 
2911  // Get a context
2912  PgSqlLeaseContextAlloc get_context(*this);
2913  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2914 
2915  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2916  tagged_statements[SUBNET_LEASE4_STATS],
2917  false,
2918  subnet_id));
2919  query->start();
2920  return(query);
2921 }
2922 
2925  const SubnetID& last_subnet_id) {
2926  // Get a context
2927  PgSqlLeaseContextAlloc get_context(*this);
2928  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2929 
2930  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2931  tagged_statements[SUBNET_RANGE_LEASE4_STATS],
2932  false,
2933  first_subnet_id,
2934  last_subnet_id));
2935  query->start();
2936  return(query);
2937 }
2938 
2941  // Get a context
2942  PgSqlLeaseContextAlloc get_context(*this);
2943  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2944 
2945  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2946  tagged_statements[ALL_LEASE6_STATS],
2947  true));
2948  query->start();
2949  return(query);
2950 }
2951 
2954  // Get a context
2955  PgSqlLeaseContextAlloc get_context(*this);
2956  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2957 
2958  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2959  tagged_statements[ALL_POOL_LEASE6_STATS],
2960  true, true));
2961  query->start();
2962  return(query);
2963 }
2964 
2967  // Get a context
2968  PgSqlLeaseContextAlloc get_context(*this);
2969  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2970 
2971  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2972  tagged_statements[SUBNET_LEASE6_STATS],
2973  true,
2974  subnet_id));
2975  query->start();
2976  return(query);
2977 }
2978 
2981  const SubnetID& last_subnet_id) {
2982  // Get a context
2983  PgSqlLeaseContextAlloc get_context(*this);
2984  PgSqlLeaseContextPtr ctx = get_context.ctx_;
2985 
2986  LeaseStatsQueryPtr query(new PgSqlLeaseStatsQuery(ctx->conn_,
2987  tagged_statements[SUBNET_RANGE_LEASE6_STATS],
2988  true,
2989  first_subnet_id,
2990  last_subnet_id));
2991  query->start();
2992  return(query);
2993 }
2994 
2995 size_t
2996 PgSqlLeaseMgr::wipeLeases4(const SubnetID& /*subnet_id*/) {
2997  isc_throw(NotImplemented, "wipeLeases4 is not implemented for PostgreSQL backend");
2998 }
2999 
3000 size_t
3001 PgSqlLeaseMgr::wipeLeases6(const SubnetID& /*subnet_id*/) {
3002  isc_throw(NotImplemented, "wipeLeases6 is not implemented for PostgreSQL backend");
3003 }
3004 
3005 std::string
3007  // Get a context
3008  PgSqlLeaseContextAlloc get_context(*this);
3009  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3010 
3011  std::string name = "";
3012  try {
3013  name = ctx->conn_.getParameter("name");
3014  } catch (...) {
3015  // Return an empty name
3016  }
3017  return (name);
3018 }
3019 
3020 std::string
3022  return (std::string("PostgreSQL Database"));
3023 }
3024 
3025 std::pair<uint32_t, uint32_t>
3028 
3029  return (PgSqlConnection::getVersion(parameters_));
3030 }
3031 
3032 void
3035 }
3036 
3037 void
3040 }
3041 
3042 void
3044  deleteRelayId6(addr);
3045  deleteRemoteId6(addr);
3046 }
3047 
3048 void
3049 PgSqlLeaseMgr::deleteRelayId6(const IOAddress& addr) {
3050  // Set up the WHERE clause value.
3051  PsqlBindArray bind_array;
3052 
3053  std::string addr_data = addr.toText();
3054  bind_array.add(addr_data);
3055 
3056  // Get a context.
3057  PgSqlLeaseContextAlloc get_context(*this);
3058  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3059 
3060  // Delete from lease6_relay_id table.
3061  StatementIndex stindex = DELETE_RELAY_ID6;
3062 
3063  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
3064  tagged_statements[stindex].nbparams,
3065  &bind_array.values_[0],
3066  &bind_array.lengths_[0],
3067  &bind_array.formats_[0], 0));
3068 
3069  int s = PQresultStatus(r);
3070 
3071  if (s != PGRES_COMMAND_OK) {
3072  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
3073  }
3074 }
3075 
3076 void
3077 PgSqlLeaseMgr::deleteRemoteId6(const IOAddress& addr) {
3078  // Set up the WHERE clause value.
3079  PsqlBindArray bind_array;
3080 
3081  std::string addr_data = addr.toText();
3082  bind_array.add(addr_data);
3083 
3084  // Get a context.
3085  PgSqlLeaseContextAlloc get_context(*this);
3086  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3087 
3088  // Delete from lease6_remote_id table.
3090 
3091  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
3092  tagged_statements[stindex].nbparams,
3093  &bind_array.values_[0],
3094  &bind_array.lengths_[0],
3095  &bind_array.formats_[0], 0));
3096 
3097  int s = PQresultStatus(r);
3098 
3099  if (s != PGRES_COMMAND_OK) {
3100  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
3101  }
3102 }
3103 
3104 void
3106  const vector<uint8_t>& relay_id) {
3107  // Set up the WHERE clause value.
3108  PsqlBindArray bind_array;
3109 
3110  // Bind the relay id.
3111  if (relay_id.empty()) {
3112  isc_throw(BadValue, "empty relay id");
3113  }
3114  bind_array.add(relay_id);
3115 
3116  // Bind the lease address.
3117  std::string lease_addr_data = lease_addr.toText();
3118  bind_array.add(lease_addr_data);
3119 
3120  // Get a context.
3121  PgSqlLeaseContextAlloc get_context(*this);
3122  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3123 
3124  // Add to lease6_remote_id table.
3125  StatementIndex stindex = ADD_RELAY_ID6;
3126 
3127  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
3128  tagged_statements[stindex].nbparams,
3129  &bind_array.values_[0],
3130  &bind_array.lengths_[0],
3131  &bind_array.formats_[0], 0));
3132 
3133  int s = PQresultStatus(r);
3134 
3135  if (s != PGRES_COMMAND_OK) {
3136  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
3137  }
3138 }
3139 
3140 void
3142  const vector<uint8_t>& remote_id) {
3143  // Set up the WHERE clause value.
3144  PsqlBindArray bind_array;
3145 
3146  // Bind the remote id.
3147  if (remote_id.empty()) {
3148  isc_throw(BadValue, "empty remote id");
3149  }
3150  bind_array.add(remote_id);
3151 
3152  // Bind the lease address.
3153  std::string lease_addr_data = lease_addr.toText();
3154  bind_array.add(lease_addr_data);
3155 
3156  // Get a context.
3157  PgSqlLeaseContextAlloc get_context(*this);
3158  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3159 
3160  // Add to lease6_remote_id table.
3161  StatementIndex stindex = ADD_REMOTE_ID6;
3162 
3163  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
3164  tagged_statements[stindex].nbparams,
3165  &bind_array.values_[0],
3166  &bind_array.lengths_[0],
3167  &bind_array.formats_[0], 0));
3168 
3169  int s = PQresultStatus(r);
3170 
3171  if (s != PGRES_COMMAND_OK) {
3172  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
3173  }
3174 }
3175 
3176 namespace {
3177 
3178 std::string
3179 idToText(const OptionBuffer& id) {
3180  std::stringstream tmp;
3181  tmp << std::hex;
3182  bool delim = false;
3183  for (std::vector<uint8_t>::const_iterator it = id.begin();
3184  it != id.end(); ++it) {
3185  if (delim) {
3186  tmp << ":";
3187  }
3188  tmp << std::setw(2) << std::setfill('0')
3189  << static_cast<unsigned int>(*it);
3190  delim = true;
3191  }
3192  return (tmp.str());
3193 }
3194 
3195 } // anonymous namespace
3196 
3199  const IOAddress& lower_bound_address,
3200  const LeasePageSize& page_size,
3201  const time_t& qry_start_time /* = 0 */,
3202  const time_t& qry_end_time /* = 0 */) {
3203  // Expecting IPv4 address.
3204  if (!lower_bound_address.isV4()) {
3205  isc_throw(InvalidAddressFamily, "expected IPv4 address while "
3206  "retrieving leases from the lease database, got "
3207  << lower_bound_address);
3208  }
3209 
3210  // Catch 2038 bug with 32 bit time_t.
3211  if ((qry_start_time < 0) || (qry_end_time < 0)) {
3212  isc_throw(BadValue, "negative time value");
3213  }
3214 
3215  bool have_qst = (qry_start_time > 0);
3216  bool have_qet = (qry_end_time > 0);
3217 
3218  // Start time must be before end time.
3219  if (have_qst && have_qet && (qry_start_time > qry_end_time)) {
3220  isc_throw(BadValue, "start time must be before end time");
3221  }
3222 
3225  .arg(page_size.page_size_)
3226  .arg(lower_bound_address.toText())
3227  .arg(idToText(relay_id))
3228  .arg(qry_start_time)
3229  .arg(qry_end_time);
3230 
3231  // Prepare WHERE clause
3232  PsqlBindArray bind_array;
3233 
3234  // Bind relay id
3235  if (!relay_id.empty()) {
3236  bind_array.add(relay_id);
3237  } else {
3238  bind_array.add("");
3239  }
3240 
3241  // Bind lower bound address
3242  std::string lb_address_data =
3243  boost::lexical_cast<std::string>(lower_bound_address.toUint32());
3244  bind_array.add(lb_address_data);
3245 
3246  // Bind query start time.
3247  std::string start_time_str;
3248  if (have_qst) {
3249  start_time_str = boost::lexical_cast<std::string>(qry_start_time);
3250  bind_array.add(start_time_str);
3251  }
3252 
3253  // Bind query end time.
3254  std::string end_time_str;
3255  if (have_qet) {
3256  end_time_str = boost::lexical_cast<std::string>(qry_end_time);
3257  bind_array.add(end_time_str);
3258  }
3259 
3260  // Bind page size value
3261  std::string page_size_data =
3262  boost::lexical_cast<std::string>(page_size.page_size_);
3263  bind_array.add(page_size_data);
3264 
3266  if (have_qst && !have_qet) {
3267  stindex = GET_LEASE4_RELAYID_QST;
3268  } else if (have_qst && have_qet) {
3269  stindex = GET_LEASE4_RELAYID_QSET;
3270  } else if (!have_qst && have_qet) {
3271  stindex = GET_LEASE4_RELAYID_QET;
3272  }
3273 
3274  // Get the leases
3275  Lease4Collection result;
3276 
3277  // Get a context
3278  PgSqlLeaseContextAlloc get_context(*this);
3279  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3280 
3281  getLeaseCollection(ctx, stindex, bind_array, result);
3282 
3283  return (result);
3284 }
3285 
3288  const IOAddress& lower_bound_address,
3289  const LeasePageSize& page_size,
3290  const time_t& qry_start_time /* = 0 */,
3291  const time_t& qry_end_time /* = 0 */) {
3292  // Expecting IPv4 address.
3293  if (!lower_bound_address.isV4()) {
3294  isc_throw(InvalidAddressFamily, "expected IPv4 address while "
3295  "retrieving leases from the lease database, got "
3296  << lower_bound_address);
3297  }
3298 
3299  // Catch 2038 bug with 32 bit time_t.
3300  if ((qry_start_time < 0) || (qry_end_time < 0)) {
3301  isc_throw(BadValue, "negative time value");
3302  }
3303 
3304  bool have_qst = (qry_start_time > 0);
3305  bool have_qet = (qry_end_time > 0);
3306 
3307  // Start time must be before end time.
3308  if (have_qst && have_qet && (qry_start_time > qry_end_time)) {
3309  isc_throw(BadValue, "start time must be before end time");
3310  }
3311 
3314  .arg(page_size.page_size_)
3315  .arg(lower_bound_address.toText())
3316  .arg(idToText(remote_id))
3317  .arg(qry_start_time)
3318  .arg(qry_end_time);
3319 
3320  // Prepare WHERE clause
3321  PsqlBindArray bind_array;
3322 
3323  // Bind remote id
3324  if (!remote_id.empty()) {
3325  bind_array.add(remote_id);
3326  } else {
3327  bind_array.add("");
3328  }
3329 
3330  // Bind lower bound address
3331  std::string lb_address_data =
3332  boost::lexical_cast<std::string>(lower_bound_address.toUint32());
3333  bind_array.add(lb_address_data);
3334 
3335  // Bind query start time.
3336  std::string start_time_str;
3337  if (have_qst) {
3338  start_time_str = boost::lexical_cast<std::string>(qry_start_time);
3339  bind_array.add(start_time_str);
3340  }
3341 
3342  // Bind query end time.
3343  std::string end_time_str;
3344  if (have_qet) {
3345  end_time_str = boost::lexical_cast<std::string>(qry_end_time);
3346  bind_array.add(end_time_str);
3347  }
3348 
3349  // Bind page size value
3350  std::string page_size_data =
3351  boost::lexical_cast<std::string>(page_size.page_size_);
3352  bind_array.add(page_size_data);
3353 
3355  if (have_qst && !have_qet) {
3356  stindex = GET_LEASE4_REMOTEID_QST;
3357  } else if (have_qst && have_qet) {
3358  stindex = GET_LEASE4_REMOTEID_QSET;
3359  } else if (!have_qst && have_qet) {
3360  stindex = GET_LEASE4_REMOTEID_QET;
3361  }
3362 
3363  // Get the leases
3364  Lease4Collection result;
3365 
3366  // Get a context
3367  PgSqlLeaseContextAlloc get_context(*this);
3368  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3369 
3370  getLeaseCollection(ctx, stindex, bind_array, result);
3371 
3372  return (result);
3373 }
3374 
3375 size_t
3377  auto check = CfgMgr::instance().getCurrentCfg()->
3378  getConsistency()->getExtendedInfoSanityCheck();
3379 
3380  size_t pages = 0;
3381  size_t updated = 0;
3382  IOAddress start_addr = IOAddress::IPV4_ZERO_ADDRESS();
3383  for (;;) {
3386  .arg(pages)
3387  .arg(start_addr.toText())
3388  .arg(updated);
3389 
3390  // Prepare WHERE clause.
3391  PsqlBindArray bind_array;
3392 
3393  // Bind start address.
3394  uint32_t start_addr_data = start_addr.toUint32();
3395  bind_array.add(start_addr_data);
3396 
3397  // Bind page size value.
3398  std::string page_size_data =
3399  boost::lexical_cast<std::string>(page_size.page_size_);
3400  bind_array.add(page_size_data);
3401 
3402  Lease4Collection leases;
3403 
3404  // Get a context.
3405  {
3406  PgSqlLeaseContextAlloc get_context(*this);
3407  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3408 
3409  getLeaseCollection(ctx, GET_LEASE4_UCTX_PAGE, bind_array, leases);
3410  }
3411 
3412  if (leases.empty()) {
3413  // Done.
3414  break;
3415  }
3416 
3417  ++pages;
3418  start_addr = leases.back()->addr_;
3419  for (auto lease : leases) {
3420  ConstElementPtr previous_user_context = lease->getContext();
3421  vector<uint8_t> previous_relay_id = lease->relay_id_;
3422  vector<uint8_t> previous_remote_id = lease->remote_id_;
3423  if (!previous_user_context &&
3424  previous_relay_id.empty() &&
3425  previous_remote_id.empty()) {
3426  continue;
3427  }
3428  bool modified = upgradeLease4ExtendedInfo(lease, check);
3429  try {
3430  lease->relay_id_.clear();
3431  lease->remote_id_.clear();
3432  extractLease4ExtendedInfo(lease, false);
3433  if (modified ||
3434  (previous_relay_id != lease->relay_id_) ||
3435  (previous_remote_id != lease->remote_id_)) {
3436  updateLease4(lease);
3437  ++updated;
3438  }
3439  } catch (const NoSuchLease&) {
3440  // The lease was modified in parallel:
3441  // as its extended info was processed just ignore.
3442  continue;
3443  } catch (const std::exception& ex) {
3444  // Something when wrong, for instance extract failed.
3447  .arg(lease->addr_.toText())
3448  .arg(ex.what());
3449  }
3450  }
3451  }
3452 
3454  .arg(pages)
3455  .arg(updated);
3456 
3457  return (updated);
3458 }
3459 
3462  const IOAddress& link_addr,
3463  uint8_t link_len,
3464  const IOAddress& lower_bound_address,
3465  const LeasePageSize& page_size) {
3468  .arg(page_size.page_size_)
3469  .arg(lower_bound_address.toText())
3470  .arg(relay_id.toText())
3471  .arg(link_addr.toText())
3472  .arg(static_cast<unsigned>(link_len));
3473 
3474  // Expecting IPv6 valid prefix and address.
3475  if (!link_addr.isV6()) {
3476  isc_throw(InvalidAddressFamily, "expected IPv6 link address while "
3477  "retrieving leases from the lease database, got "
3478  << link_addr);
3479  }
3480  if (link_len > 128) {
3481  isc_throw(OutOfRange, "invalid IPv6 prefix length "
3482  << static_cast<unsigned>(link_len));
3483  }
3484  if (!lower_bound_address.isV6()) {
3485  isc_throw(InvalidAddressFamily, "expected IPv6 start address while "
3486  "retrieving leases from the lease database, got "
3487  << lower_bound_address);
3488  }
3489 
3490  std::vector<uint8_t> relay_id_data = relay_id.getDuid();
3491  if (relay_id_data.size() == 0) {
3492  isc_throw(BadValue, "empty relay id");
3493  }
3494 
3495  Lease6Collection result;
3496 
3497  if (!link_len) {
3498  // Set up the WHERE clause value.
3499  PsqlBindArray bind_array;
3500 
3501  // Bind the relay id.
3502  bind_array.add(relay_id_data);
3503 
3504  // Bind the lower bound address.
3505  std::string lb_addr_data = lower_bound_address.toText();
3506  bind_array.add(lb_addr_data);
3507 
3508  // Bind page size value.
3509  std::string page_size_data =
3510  boost::lexical_cast<std::string>(page_size.page_size_);
3511  bind_array.add(page_size_data);
3512 
3513  // Get a context.
3514  PgSqlLeaseContextAlloc get_context(*this);
3515  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3516 
3517  getLeaseCollection(ctx, GET_RELAY_ID6, bind_array, result);
3518  } else {
3519  const IOAddress& first_addr = firstAddrInPrefix(link_addr, link_len);
3520  const IOAddress& last_addr = lastAddrInPrefix(link_addr, link_len);
3521  IOAddress start_addr = lower_bound_address;
3522  if (lower_bound_address < first_addr) {
3523  start_addr = first_addr;
3524  } else if (last_addr <= lower_bound_address) {
3525  // Range was already done.
3526  return (result);
3527  } else {
3528  // The lower bound address is from the last call so skip it.
3529  start_addr = IOAddress::increase(lower_bound_address);
3530  }
3531 
3532  // Set up the WHERE clause value.
3533  PsqlBindArray bind_array;
3534 
3535  // Bind the relay id.
3536  bind_array.add(relay_id_data);
3537 
3538  // Bind the start address.
3539  std::string start_addr_data = start_addr.toText();
3540  bind_array.add(start_addr_data);
3541 
3542  // Bind the last address.
3543  std::string last_addr_data = last_addr.toText();
3544  bind_array.add(last_addr_data);
3545 
3546  // Bind page size value.
3547  std::string page_size_data =
3548  boost::lexical_cast<std::string>(page_size.page_size_);
3549  bind_array.add(page_size_data);
3550 
3551  // Get a context.
3552  PgSqlLeaseContextAlloc get_context(*this);
3553  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3554 
3555  getLeaseCollection(ctx, GET_RELAY_ID6_LINK, bind_array, result);
3556  }
3557 
3558  return (result);
3559 }
3560 
3563  const IOAddress& link_addr,
3564  uint8_t link_len,
3565  const IOAddress& lower_bound_address,
3566  const LeasePageSize& page_size) {
3569  .arg(page_size.page_size_)
3570  .arg(lower_bound_address.toText())
3571  .arg(idToText(remote_id))
3572  .arg(link_addr.toText())
3573  .arg(static_cast<unsigned>(link_len));
3574 
3575  // Expecting IPv6 valid prefix and address.
3576  if (!link_addr.isV6()) {
3577  isc_throw(InvalidAddressFamily, "expected IPv6 link address while "
3578  "retrieving leases from the lease database, got "
3579  << link_addr);
3580  }
3581  if (link_len > 128) {
3582  isc_throw(OutOfRange, "invalid IPv6 prefix length "
3583  << static_cast<unsigned>(link_len));
3584  }
3585  if (!lower_bound_address.isV6()) {
3586  isc_throw(InvalidAddressFamily, "expected IPv6 start address while "
3587  "retrieving leases from the lease database, got "
3588  << lower_bound_address);
3589  }
3590 
3591  if (remote_id.size() == 0) {
3592  isc_throw(BadValue, "empty remote id");
3593  }
3594 
3595  Lease6Collection result;
3596 
3597  if (!link_len) {
3598  // Set up the WHERE clause value.
3599  PsqlBindArray bind_array;
3600 
3601  // Bind the remote id.
3602  bind_array.add(remote_id);
3603 
3604  // Bind the lower bound address.
3605  std::string lb_addr_data = lower_bound_address.toText();
3606  bind_array.add(lb_addr_data);
3607 
3608  // Bind page size value.
3609  std::string page_size_data =
3610  boost::lexical_cast<std::string>(page_size.page_size_);
3611  bind_array.add(page_size_data);
3612 
3613  // Get a context.
3614  PgSqlLeaseContextAlloc get_context(*this);
3615  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3616 
3617  getLeaseCollection(ctx, GET_REMOTE_ID6, bind_array, result);
3618  } else {
3619  const IOAddress& first_addr = firstAddrInPrefix(link_addr, link_len);
3620  const IOAddress& last_addr = lastAddrInPrefix(link_addr, link_len);
3621  IOAddress start_addr = lower_bound_address;
3622  if (lower_bound_address < first_addr) {
3623  start_addr = first_addr;
3624  } else if (last_addr <= lower_bound_address) {
3625  // Range was already done.
3626  return (result);
3627  } else {
3628  // The lower bound address is from the last call so skip it.
3629  start_addr = IOAddress::increase(lower_bound_address);
3630  }
3631 
3632  // Set up the WHERE clause value.
3633  PsqlBindArray bind_array;
3634 
3635  // Bind the remote id.
3636  bind_array.add(remote_id);
3637 
3638  // Bind the start address.
3639  std::string start_addr_data = start_addr.toText();
3640  bind_array.add(start_addr_data);
3641 
3642  // Bind the last address.
3643  std::string last_addr_data = last_addr.toText();
3644  bind_array.add(last_addr_data);
3645 
3646  // Bind page size value.
3647  std::string page_size_data =
3648  boost::lexical_cast<std::string>(page_size.page_size_);
3649  bind_array.add(page_size_data);
3650 
3651  // Get a context.
3652  PgSqlLeaseContextAlloc get_context(*this);
3653  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3654 
3655  getLeaseCollection(ctx, GET_REMOTE_ID6_LINK, bind_array, result);
3656  }
3657 
3658  return (result);
3659 }
3660 
3663  uint8_t link_len,
3664  const IOAddress& lower_bound_address,
3665  const LeasePageSize& page_size) {
3668  .arg(page_size.page_size_)
3669  .arg(lower_bound_address.toText())
3670  .arg(link_addr.toText())
3671  .arg(static_cast<unsigned>(link_len));
3672 
3673  // Expecting IPv6 valid prefix and address.
3674  if (!link_addr.isV6()) {
3675  isc_throw(InvalidAddressFamily, "expected IPv6 link address while "
3676  "retrieving leases from the lease database, got "
3677  << link_addr);
3678  }
3679 
3680  if ((link_len == 0) || (link_len > 128)) {
3681  isc_throw(OutOfRange, "invalid IPv6 prefix length "
3682  << static_cast<unsigned>(link_len));
3683  }
3684 
3685  if (!lower_bound_address.isV6()) {
3686  isc_throw(InvalidAddressFamily, "expected IPv6 start address while "
3687  "retrieving leases from the lease database, got "
3688  << lower_bound_address);
3689  }
3690 
3691  Lease6Collection result;
3692  const IOAddress& first_addr = firstAddrInPrefix(link_addr, link_len);
3693  const IOAddress& last_addr = lastAddrInPrefix(link_addr, link_len);
3694  IOAddress start_addr = lower_bound_address;
3695  if (lower_bound_address < first_addr) {
3696  start_addr = first_addr;
3697  } else if (last_addr <= lower_bound_address) {
3698  // Range was already done.
3699  return (result);
3700  } else {
3701  // The lower bound address is from the last call so skip it.
3702  start_addr = IOAddress::increase(lower_bound_address);
3703  }
3704 
3705  // Prepare WHERE clause
3706  PsqlBindArray bind_array;
3707 
3708  // Bind start address
3709  std::string start_addr_str = start_addr.toText();
3710  bind_array.add(start_addr_str);
3711 
3712  // Bind last address
3713  std::string last_addr_str = last_addr.toText();
3714  bind_array.add(last_addr_str);
3715 
3716  // Bind page size value
3717  std::string page_size_data =
3718  boost::lexical_cast<std::string>(page_size.page_size_);
3719  bind_array.add(page_size_data);
3720 
3721  // Get a context
3722  PgSqlLeaseContextAlloc get_context(*this);
3723  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3724 
3725  // Get the leases
3726  getLeaseCollection(ctx, GET_LEASE6_LINK, bind_array, result);
3727 
3728  return (result);
3729 }
3730 
3731 size_t
3733  auto check = CfgMgr::instance().getCurrentCfg()->
3734  getConsistency()->getExtendedInfoSanityCheck();
3735 
3736  // First step is to wipe tables if enabled.
3739  }
3740 
3741  size_t pages = 0;
3742  size_t updated = 0;
3743  IOAddress start_addr = IOAddress::IPV6_ZERO_ADDRESS();
3744  for (;;) {
3747  .arg(pages)
3748  .arg(start_addr.toText())
3749  .arg(updated);
3750 
3751  // Prepare WHERE clause.
3752  PsqlBindArray bind_array;
3753 
3754  // Bind start address.
3755  std::string start_addr_str = start_addr.toText();
3756  bind_array.add(start_addr_str);
3757 
3758  // Bind page size value.
3759  std::string page_size_data =
3760  boost::lexical_cast<std::string>(page_size.page_size_);
3761  bind_array.add(page_size_data);
3762 
3763  Lease6Collection leases;
3764 
3765  // Get a context.
3766  {
3767  PgSqlLeaseContextAlloc get_context(*this);
3768  PgSqlLeaseContextPtr ctx = get_context.ctx_;
3769 
3770  getLeaseCollection(ctx, GET_LEASE6_UCTX_PAGE, bind_array, leases);
3771  }
3772 
3773  if (leases.empty()) {
3774  // Done.
3775  break;
3776  }
3777 
3778  ++pages;
3779  start_addr = leases.back()->addr_;
3780  for (auto lease : leases) {
3781  try {
3782  bool modified = upgradeLease6ExtendedInfo(lease, check);
3783  if (modified) {
3784  updateLease6(lease);
3785  }
3786  bool added = (getExtendedInfoTablesEnabled() &&
3787  addExtendedInfo6(lease));
3788  if (modified || added) {
3789  ++updated;
3790  }
3791  } catch (const NoSuchLease&) {
3792  // The lease was modified in parallel:
3793  // as its extended info was processed just ignore.
3794  continue;
3795  } catch (const std::exception& ex) {
3796  // Something when wrong, for instance extract failed.
3799  .arg(lease->addr_.toText())
3800  .arg(ex.what());
3801  }
3802  }
3803  }
3804 
3806  .arg(pages)
3807  .arg(updated);
3808 
3809  return (updated);
3810 }
3811 
3812 void
3814  // Get a context.
3815  PgSqlLeaseContextAlloc get_context(*this);
3816  PgSqlLeaseContextPtr ctx(get_context.ctx_);
3817 
3818  // Execute WIPE_RELAY_ID6.
3819  StatementIndex const stindex1 = WIPE_RELAY_ID6;
3820  PgSqlResult r1(PQexecPrepared(ctx->conn_, tagged_statements[stindex1].name,
3821  0, 0, 0, 0, 0));
3822  ctx->conn_.checkStatementError(r1, tagged_statements[stindex1]);
3823 
3824  // Execute WIPE_REMOTE_ID6.
3825  StatementIndex const stindex2 = WIPE_REMOTE_ID6;
3826  PgSqlResult r2(PQexecPrepared(ctx->conn_, tagged_statements[stindex2].name,
3827  0, 0, 0, 0, 0));
3828  ctx->conn_.checkStatementError(r2, tagged_statements[stindex2]);
3829 }
3830 
3831 size_t
3833  // Get a context.
3834  PgSqlLeaseContextAlloc get_context(*this);
3835  PgSqlLeaseContextPtr ctx(get_context.ctx_);
3836 
3837  // Execute COUNT_RELAY_ID6.
3838  StatementIndex stindex = COUNT_RELAY_ID6;
3839  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
3840  0, 0, 0, 0, 0));
3841  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
3842  uint64_t count;
3843  PgSqlExchange::getColumnValue(r, 0, 0, count);
3844  return (static_cast<size_t>(count));
3845 }
3846 
3847 size_t
3849  // Get a context.
3850  PgSqlLeaseContextAlloc get_context(*this);
3851  PgSqlLeaseContextPtr ctx(get_context.ctx_);
3852 
3853  // Execute COUNT_REMOTE_ID6.
3854  StatementIndex stindex = COUNT_REMOTE_ID6;
3855  PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
3856  0, 0, 0, 0, 0));
3857  ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
3858  uint64_t count;
3859  PgSqlExchange::getColumnValue(r, 0, 0, count);
3860  return (static_cast<size_t>(count));
3861 }
3862 
3863 } // namespace dhcp
3864 } // 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 if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
static bool invokeDbLostCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's lost connectivity callback.
static std::string redactedAccessString(const ParameterMap &parameters)
Redact database access string.
static bool invokeDbFailedCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restore failed connectivity callback.
static bool invokeDbRecoveredCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restored connectivity callback.
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:59
Multiple lease records found where one expected.
Definition: db_exceptions.h:16
Common PgSql Connector Pool.
static bool warned_about_tls
Emit the TLS support warning only once.
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.
Base class for marshalling data to and from PostgreSQL.
static std::string convertToDatabaseTime(const time_t input_time)
Converts UTC time_t value to a text representation in local time.
static void getColumnValue(const PgSqlResult &r, const int row, const size_t col, std::string &value)
Fetches text column value as a string.
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:218
const std::vector< uint8_t > & getClientId() const
Returns reference to the client-id data.
Definition: duid.cc:70
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:138
const std::vector< uint8_t > & getDuid() const
Returns a const reference to the actual DUID value.
Definition: duid.cc:34
std::string toText() const
Returns textual representation of the identifier (e.g.
Definition: duid.h:84
static void recreate(const std::string &dbaccess, bool preserve_callbacks=true)
Recreate an instance of a lease manager with optionally preserving registered callbacks.
void setExtendedInfoTablesEnabled(const bool enabled)
Modifies the setting whether the lease6 extended info tables are enabled.
Definition: lease_mgr.h:1039
static bool upgradeLease6ExtendedInfo(const Lease6Ptr &lease, CfgConsistency::ExtendedInfoSanity check=CfgConsistency::EXTENDED_INFO_CHECK_FIX)
Upgrade a V6 lease user context to the new extended info entry.
Definition: lease_mgr.cc:771
bool getExtendedInfoTablesEnabled() const
Returns the setting indicating if lease6 extended info tables are enabled.
Definition: lease_mgr.h:1031
static isc::asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service.
Definition: lease_mgr.h:842
static void extractLease4ExtendedInfo(const Lease4Ptr &lease, bool ignore_errors=true)
Extract relay and remote identifiers from the extended info.
Definition: lease_mgr.cc:1123
static bool upgradeLease4ExtendedInfo(const Lease4Ptr &lease, CfgConsistency::ExtendedInfoSanity check=CfgConsistency::EXTENDED_INFO_CHECK_FIX)
The following queries are used to fulfill Bulk Lease Query queries.
Definition: lease_mgr.cc:539
virtual bool addExtendedInfo6(const Lease6Ptr &lease)
Extract extended info from a lease6 and add it into tables.
Definition: lease_mgr.cc:1209
Wraps value holding size of the page with leases.
Definition: lease_mgr.h:46
const size_t page_size_
Holds page size.
Definition: lease_mgr.h:56
Base class for fulfilling a statistical lease data query.
Definition: lease_mgr.h:149
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.
Base class for marshalling leases to and from PostgreSQL.
std::vector< uint8_t > addr_bin_
std::vector< uint8_t > hwaddr_
std::string addr_str_
Common Instance members used for binding and conversion.
PostgreSQL Lease Manager.
virtual Lease6Collection getLeases6ByRelayId(const DUID &relay_id, const asiolink::IOAddress &link_addr, uint8_t link_len, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size) override
Returns existing IPv6 leases with a given relay-id.
virtual void recountClassLeases6() override
Recount the leases per class for V6 leases.
virtual LeaseStatsQueryPtr startLeaseStatsQuery4() override
Creates and runs the IPv4 lease stats query.
virtual size_t wipeLeases4(const SubnetID &subnet_id) override
Removes specified IPv4 leases.
PgSqlLeaseContextPtr createContext() const
Create a new context.
virtual Lease4Collection getLeases4() const override
Returns all IPv4 leases.
virtual LeaseStatsQueryPtr startLeaseStatsQuery6() override
Creates and runs the IPv6 lease stats query.
virtual Lease4Collection getLeases4ByRemoteId(const OptionBuffer &remote_id, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size, const time_t &qry_start_time=0, const time_t &qry_end_time=0) override
Returns existing IPv4 leases with a given remote-id.
virtual LeaseStatsQueryPtr startPoolLeaseStatsQuery4() override
Creates and runs the IPv4 lease stats query for all subnets and pools.
virtual std::string checkLimits6(isc::data::ConstElementPtr const &user_context) const override
Checks if the IPv6 lease limits set in the given user context are exceeded.
virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t secs) override
Deletes all expired-reclaimed DHCPv4 leases.
virtual Lease6Collection getLeases6ByRemoteId(const OptionBuffer &remote_id, const asiolink::IOAddress &link_addr, uint8_t link_len, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size) override
Returns existing IPv6 leases with a given remote-id.
static std::string getDBVersion()
Local version of getDBVersion() class method.
virtual std::string checkLimits4(isc::data::ConstElementPtr const &user_context) const override
Checks if the IPv4 lease limits set in the given user context are exceeded.
virtual size_t byRemoteId6size() const override
Return the by-remote-id table size.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID &subnet_id) override
Creates and runs the IPv4 lease stats query for a single subnet.
virtual void addRelayId6(const isc::asiolink::IOAddress &lease_addr, const std::vector< uint8_t > &relay_id) override
Add lease6 extended info into by-relay-id table.
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs) override
Deletes all expired-reclaimed DHCPv6 leases.
virtual void deleteExtendedInfo6(const isc::asiolink::IOAddress &addr) override
Extended information / Bulk Lease Query shared interface.
virtual void recountClassLeases4() override
Recount the leases per class for V4 leases.
virtual size_t upgradeExtendedInfo4(const LeasePageSize &page_size) override
Upgrade extended info (v4).
virtual size_t wipeLeases6(const SubnetID &subnet_id) override
Removed specified IPv6 leases.
virtual void getExpiredLeases4(Lease4Collection &expired_leases, const size_t max_leases) const override
Returns a collection of expired DHCPv4 leases.
virtual void updateLease6(const Lease6Ptr &lease6) override
Updates IPv6 lease.
virtual std::pair< uint32_t, uint32_t > getVersion() const override
Returns backend version.
virtual std::string getDescription() const override
Returns description of the backend.
virtual void wipeExtendedInfoTables6() override
Wipe extended info table (v6).
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery6(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id) override
Creates and runs the IPv6 lease stats query for a single subnet.
virtual size_t upgradeExtendedInfo6(const LeasePageSize &page_size) override
Upgrade extended info (v6).
virtual size_t byRelayId6size() const override
Return the by-relay-id table size.
virtual Lease4Collection getLeases4ByRelayId(const OptionBuffer &relay_id, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size, const time_t &qry_start_time=0, const time_t &qry_end_time=0) override
The following queries are used to fulfill Bulk Lease Query queries.
virtual void commit() override
Commit Transactions.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID &subnet_id) override
Creates and runs the IPv6 lease stats query for a single subnet.
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const override
Returns existing IPv6 lease for a given IPv6 address.
virtual Lease6Collection getLeases6() const override
Returns all IPv6 leases.
virtual void addRemoteId6(const isc::asiolink::IOAddress &lease_addr, const std::vector< uint8_t > &remote_id) override
Add lease6 extended info into by-remote-id table.
StatementIndex
Statement Tags.
virtual void rollback() override
Rollback Transactions.
virtual void updateLease4(const Lease4Ptr &lease4) override
Updates IPv4 lease.
virtual LeaseStatsQueryPtr startPoolLeaseStatsQuery6() override
Creates and runs the IPv6 lease stats query for all subnets and pools.
virtual void writeLeases6(const std::string &) override
Write V6 leases to a file.
virtual void getExpiredLeases6(Lease6Collection &expired_leases, const size_t max_leases) const override
Returns a collection of expired DHCPv6 leases.
virtual std::string getName() const override
Returns backend name.
PgSqlLeaseMgr(const db::DatabaseConnection::ParameterMap &parameters)
Constructor.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const override
Returns an IPv4 lease for specified IPv4 address.
virtual void clearClassLeaseCounts() override
Clears the class-lease count map.
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery4(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id) override
Creates and runs the IPv4 lease stats query for a single subnet.
static bool dbReconnect(util::ReconnectCtlPtr db_reconnect_ctl)
Attempts to reconnect the server to the lease DB backend manager.
virtual ~PgSqlLeaseMgr()
Destructor (closes database)
virtual bool isJsonSupported() const override
Checks if JSON support is enabled in the database.
virtual size_t getClassLeaseCount(const ClientClass &client_class, const Lease::Type &ltype=Lease::TYPE_V4) const override
Returns the class lease count for a given class and lease type.
virtual Lease6Collection getLeases6ByLink(const asiolink::IOAddress &link_addr, uint8_t link_len, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size) override
Returns existing IPv6 leases with on a given link.
virtual bool addLease(const Lease4Ptr &lease) override
Adds an IPv4 lease.
virtual void writeLeases4(const std::string &) override
Write V4 leases to a file.
virtual bool deleteLease(const Lease4Ptr &lease) override
Deletes an IPv4 lease.
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.
bool fetch_pool_
Indicates if query requires pool data.
PgSqlLeaseStatsQuery(PgSqlConnection &conn, PgSqlTaggedStatement &statement, const bool fetch_type, const bool fetch_pool=false)
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
Introduces callbacks into the LeaseMgr.
void trackUpdateLease(const LeasePtr &lease, bool mt_safe)
Invokes the callbacks when a lease is updated.
void trackAddLease(const LeasePtr &lease, bool mt_safe)
Invokes the callbacks when a new lease is added.
void trackDeleteLease(const LeasePtr &lease, bool mt_safe)
Invokes the callbacks when a lease is deleted.
bool hasCallbacks() const
Checks if any callbacks have been registered.
RAII class creating a critical section.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#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:29
const size_t OID_INT2
boost::shared_ptr< IOServiceAccessor > IOServiceAccessorPtr
Pointer to an instance of IOServiceAccessor.
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 uint32_t PGSQL_SCHEMA_VERSION_MINOR
const size_t OID_INT8
const size_t OID_BYTEA
std::function< bool(util::ReconnectCtlPtr db_reconnect_ctl)> DbCallback
Defines a callback prototype for propagating events upward.
std::function< isc::asiolink::IOServicePtr()> IOServiceAccessor
Function which returns the IOService that can be used to recover the connection.
const uint32_t PGSQL_SCHEMA_VERSION_MAJOR
Define the PostgreSQL backend version.
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
std::string ClientClass
Defines a single class name.
Definition: classify.h:42
const isc::log::MessageID DHCPSRV_PGSQL_GET_REMOTEID6
const isc::log::MessageID DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO6_PAGE
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:131
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition: lease.h:502
const isc::log::MessageID DHCPSRV_PGSQL_GET_HOSTNAME6
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:670
boost::shared_ptr< LeaseStatsQuery > LeaseStatsQueryPtr
Defines a pointer to a LeaseStatsQuery.
Definition: lease_mgr.h:233
const isc::log::MessageID DHCPSRV_PGSQL_GET_IAID_SUBID_DUID
const isc::log::MessageID DHCPSRV_PGSQL_GET_ADDR4
const isc::log::MessageID DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO6
const isc::log::MessageID DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO6_ERROR
const isc::log::MessageID DHCPSRV_PGSQL_GET_HOSTNAME4
const isc::log::MessageID DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4
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_NO_TLS_SUPPORT
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_GET_REMOTEID4
const isc::log::MessageID DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_PAGE
const isc::log::MessageID DHCPSRV_PGSQL_LEASE_DB_RECONNECT_ATTEMPT_FAILED
const isc::log::MessageID DHCPSRV_PGSQL_TLS_SUPPORT
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:25
boost::shared_ptr< Lease > LeasePtr
Pointer to the lease object.
Definition: lease.h:22
const isc::log::MessageID DHCPSRV_PGSQL_GET_LINKADDR6
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_RELAYID6
const isc::log::MessageID DHCPSRV_PGSQL_GET_IAID_DUID
const isc::log::MessageID DHCPSRV_PGSQL_UPDATE_ADDR6
const isc::log::MessageID DHCPSRV_PGSQL_GET_RELAYID4
boost::shared_ptr< PgSqlLeaseContext > PgSqlLeaseContextPtr
Type of pointers to contexts.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
const isc::log::MessageID DHCPSRV_PGSQL_LEASE_DB_RECONNECT_FAILED
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition: lease.h:497
const isc::log::MessageID DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_ERROR
@ 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:289
const isc::log::MessageID DHCPSRV_PGSQL_COMMIT
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition: dhcpsrv_log.h:26
const isc::log::MessageID DHCPSRV_PGSQL_DELETE_EXPIRED_RECLAIMED6
Definition: edns.h:19
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
Defines the logger used by the top-level component of kea-lfc.
Define a PostgreSQL statement.
void addTempString(const std::string &str)
Binds the given string to the bind array.
std::vector< const char * > values_
Vector of pointers to the data values.
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.
void addNull(const int format=PsqlBindArray::TEXT_FMT)
Adds a NULL value to the bind array.
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
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:513
ExtendedInfoAction
Action on extended info tables.
Definition: lease.h:550
@ ACTION_UPDATE
update extended info tables.
Definition: lease.h:553
@ ACTION_DELETE
delete reference to the lease
Definition: lease.h:552
@ ACTION_IGNORE
ignore extended info,
Definition: lease.h:551
Contains a single row of lease statistical data.
Definition: lease_mgr.h:64
uint32_t pool_id_
The pool ID to which this data applies.
Definition: lease_mgr.h:132
int64_t state_count_
state_count The count of leases in the lease state
Definition: lease_mgr.h:141
uint32_t lease_state_
The lease_state to which the count applies.
Definition: lease_mgr.h:138
SubnetID subnet_id_
The subnet ID to which this data applies.
Definition: lease_mgr.h:129
Lease::Type lease_type_
The lease_type to which the count applies.
Definition: lease_mgr.h:135
static const uint32_t INFINITY_LFT
Infinity (means static, i.e. never expire)
Definition: lease.h:34
static const uint32_t STATE_EXPIRED_RECLAIMED
Expired and reclaimed lease.
Definition: lease.h:75
Type
Type of lease or pool.
Definition: lease.h:46
@ TYPE_V4
IPv4 lease.
Definition: lease.h:50
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.