mysql_lease_mgr.cc 86 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053
  1. // Copyright (C) 2012-2015 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. #include <config.h>
  7. #include <asiolink/io_address.h>
  8. #include <dhcp/duid.h>
  9. #include <dhcp/hwaddr.h>
  10. #include <dhcpsrv/dhcpsrv_log.h>
  11. #include <dhcpsrv/mysql_lease_mgr.h>
  12. #include <dhcpsrv/mysql_connection.h>
  13. #include <boost/static_assert.hpp>
  14. #include <mysqld_error.h>
  15. #include <iostream>
  16. #include <iomanip>
  17. #include <limits.h>
  18. #include <sstream>
  19. #include <string>
  20. #include <time.h>
  21. using namespace isc;
  22. using namespace isc::dhcp;
  23. using namespace std;
  24. /// @file
  25. ///
  26. /// This file holds the implementation of the Lease Manager using MySQL. The
  27. /// implementation uses MySQL's C API, as it comes as standard with the MySQL
  28. /// client libraries.
  29. ///
  30. /// In general, each of the database access methods corresponds to one SQL
  31. /// statement. To avoid the overhead of parsing a statement every time it is
  32. /// used, when the database is opened "prepared statements" are created -
  33. /// essentially doing the SQL parsing up front. Every time a method is used
  34. /// to access data, the corresponding prepared statement is referenced. Each
  35. /// prepared statement contains a set of placeholders for data, each
  36. /// placeholder being for:
  37. ///
  38. /// - data being added to the database (as in adding or updating a lease)
  39. /// - data being retrieved from the database (as in getting lease information)
  40. /// - selection criteria used to determine which records to update/retrieve.
  41. ///
  42. /// All such data is associated with the prepared statment using an array of
  43. /// MYSQL_BIND structures. Each element in the array corresponds to one
  44. /// parameter in the prepared statement - the first element in the array is
  45. /// associated with the first parameter, the second element with the second
  46. /// parameter etc.
  47. ///
  48. /// Within this file, the setting up of the MYSQL_BIND arrays for data being
  49. /// passed to and retrieved from the database is handled in the
  50. /// isc::dhcp::MySqlLease4Exchange and isc::dhcp::MySqlLease6Exchange classes.
  51. /// The classes also hold intermediate variables required for exchanging some
  52. /// of the data.
  53. ///
  54. /// With these exchange objects in place, many of the methods follow similar
  55. /// logic:
  56. /// - Set up the MYSQL_BIND array for data being transferred to/from the
  57. /// database. For data being transferred to the database, some of the
  58. /// data is extracted from the lease to intermediate variables, whilst
  59. /// in other cases the MYSQL_BIND arrays point to the data in the lease.
  60. /// - Set up the MYSQL_BIND array for the data selection parameters.
  61. /// - Bind these arrays to the prepared statement.
  62. /// - Execute the statement.
  63. /// - If there is output, copy the data from the bound variables to the output
  64. /// lease object.
  65. namespace {
  66. /// @brief Maximum length of the hostname stored in DNS.
  67. ///
  68. /// This length is restricted by the length of the domain-name carried
  69. /// in the Client FQDN %Option (see RFC4702 and RFC4704).
  70. const size_t HOSTNAME_MAX_LEN = 255;
  71. /// @brief Maximum size of an IPv6 address represented as a text string.
  72. ///
  73. /// This is 32 hexadecimal characters written in 8 groups of four, plus seven
  74. /// colon separators.
  75. const size_t ADDRESS6_TEXT_MAX_LEN = 39;
  76. TaggedStatement tagged_statements[] = {
  77. {MySqlLeaseMgr::DELETE_LEASE4,
  78. "DELETE FROM lease4 WHERE address = ?"},
  79. {MySqlLeaseMgr::DELETE_LEASE4_STATE_EXPIRED,
  80. "DELETE FROM lease4 "
  81. "WHERE state = ? AND expire < ?"},
  82. {MySqlLeaseMgr::DELETE_LEASE6,
  83. "DELETE FROM lease6 WHERE address = ?"},
  84. {MySqlLeaseMgr::DELETE_LEASE6_STATE_EXPIRED,
  85. "DELETE FROM lease6 "
  86. "WHERE state = ? AND expire < ?"},
  87. {MySqlLeaseMgr::GET_LEASE4_ADDR,
  88. "SELECT address, hwaddr, client_id, "
  89. "valid_lifetime, expire, subnet_id, "
  90. "fqdn_fwd, fqdn_rev, hostname, "
  91. "state "
  92. "FROM lease4 "
  93. "WHERE address = ?"},
  94. {MySqlLeaseMgr::GET_LEASE4_CLIENTID,
  95. "SELECT address, hwaddr, client_id, "
  96. "valid_lifetime, expire, subnet_id, "
  97. "fqdn_fwd, fqdn_rev, hostname, "
  98. "state "
  99. "FROM lease4 "
  100. "WHERE client_id = ?"},
  101. {MySqlLeaseMgr::GET_LEASE4_CLIENTID_SUBID,
  102. "SELECT address, hwaddr, client_id, "
  103. "valid_lifetime, expire, subnet_id, "
  104. "fqdn_fwd, fqdn_rev, hostname, "
  105. "state "
  106. "FROM lease4 "
  107. "WHERE client_id = ? AND subnet_id = ?"},
  108. {MySqlLeaseMgr::GET_LEASE4_HWADDR,
  109. "SELECT address, hwaddr, client_id, "
  110. "valid_lifetime, expire, subnet_id, "
  111. "fqdn_fwd, fqdn_rev, hostname, "
  112. "state "
  113. "FROM lease4 "
  114. "WHERE hwaddr = ?"},
  115. {MySqlLeaseMgr::GET_LEASE4_HWADDR_SUBID,
  116. "SELECT address, hwaddr, client_id, "
  117. "valid_lifetime, expire, subnet_id, "
  118. "fqdn_fwd, fqdn_rev, hostname, "
  119. "state "
  120. "FROM lease4 "
  121. "WHERE hwaddr = ? AND subnet_id = ?"},
  122. {MySqlLeaseMgr::GET_LEASE4_EXPIRE,
  123. "SELECT address, hwaddr, client_id, "
  124. "valid_lifetime, expire, subnet_id, "
  125. "fqdn_fwd, fqdn_rev, hostname, "
  126. "state "
  127. "FROM lease4 "
  128. "WHERE state != ? AND expire < ? "
  129. "ORDER BY expire ASC "
  130. "LIMIT ?"},
  131. {MySqlLeaseMgr::GET_LEASE6_ADDR,
  132. "SELECT address, duid, valid_lifetime, "
  133. "expire, subnet_id, pref_lifetime, "
  134. "lease_type, iaid, prefix_len, "
  135. "fqdn_fwd, fqdn_rev, hostname, "
  136. "hwaddr, hwtype, hwaddr_source, "
  137. "state "
  138. "FROM lease6 "
  139. "WHERE address = ? AND lease_type = ?"},
  140. {MySqlLeaseMgr::GET_LEASE6_DUID_IAID,
  141. "SELECT address, duid, valid_lifetime, "
  142. "expire, subnet_id, pref_lifetime, "
  143. "lease_type, iaid, prefix_len, "
  144. "fqdn_fwd, fqdn_rev, hostname, "
  145. "hwaddr, hwtype, hwaddr_source, "
  146. "state "
  147. "FROM lease6 "
  148. "WHERE duid = ? AND iaid = ? AND lease_type = ?"},
  149. {MySqlLeaseMgr::GET_LEASE6_DUID_IAID_SUBID,
  150. "SELECT address, duid, valid_lifetime, "
  151. "expire, subnet_id, pref_lifetime, "
  152. "lease_type, iaid, prefix_len, "
  153. "fqdn_fwd, fqdn_rev, hostname, "
  154. "hwaddr, hwtype, hwaddr_source, "
  155. "state "
  156. "FROM lease6 "
  157. "WHERE duid = ? AND iaid = ? AND subnet_id = ? "
  158. "AND lease_type = ?"},
  159. {MySqlLeaseMgr::GET_LEASE6_EXPIRE,
  160. "SELECT address, duid, valid_lifetime, "
  161. "expire, subnet_id, pref_lifetime, "
  162. "lease_type, iaid, prefix_len, "
  163. "fqdn_fwd, fqdn_rev, hostname, "
  164. "hwaddr, hwtype, hwaddr_source, "
  165. "state "
  166. "FROM lease6 "
  167. "WHERE state != ? AND expire < ? "
  168. "ORDER BY expire ASC "
  169. "LIMIT ?"},
  170. {MySqlLeaseMgr::GET_VERSION,
  171. "SELECT version, minor FROM schema_version"},
  172. {MySqlLeaseMgr::INSERT_LEASE4,
  173. "INSERT INTO lease4(address, hwaddr, client_id, "
  174. "valid_lifetime, expire, subnet_id, "
  175. "fqdn_fwd, fqdn_rev, hostname, state) "
  176. "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
  177. {MySqlLeaseMgr::INSERT_LEASE6,
  178. "INSERT INTO lease6(address, duid, valid_lifetime, "
  179. "expire, subnet_id, pref_lifetime, "
  180. "lease_type, iaid, prefix_len, "
  181. "fqdn_fwd, fqdn_rev, hostname, "
  182. "hwaddr, hwtype, hwaddr_source, "
  183. "state) "
  184. "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
  185. {MySqlLeaseMgr::UPDATE_LEASE4,
  186. "UPDATE lease4 SET address = ?, hwaddr = ?, "
  187. "client_id = ?, valid_lifetime = ?, expire = ?, "
  188. "subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, "
  189. "hostname = ?, state = ? "
  190. "WHERE address = ?"},
  191. {MySqlLeaseMgr::UPDATE_LEASE6,
  192. "UPDATE lease6 SET address = ?, duid = ?, "
  193. "valid_lifetime = ?, expire = ?, subnet_id = ?, "
  194. "pref_lifetime = ?, lease_type = ?, iaid = ?, "
  195. "prefix_len = ?, fqdn_fwd = ?, fqdn_rev = ?, "
  196. "hostname = ?, hwaddr = ?, hwtype = ?, hwaddr_source = ?, "
  197. "state = ? "
  198. "WHERE address = ?"},
  199. // End of list sentinel
  200. {MySqlLeaseMgr::NUM_STATEMENTS, NULL}
  201. };
  202. };
  203. namespace isc {
  204. namespace dhcp {
  205. /// @brief Common MySQL and Lease Data Methods
  206. ///
  207. /// The MySqlLease4Exchange and MySqlLease6Exchange classes provide the
  208. /// functionaility to set up binding information between variables in the
  209. /// program and data extracted from the database. This class is the common
  210. /// base to both of them, containing some common methods.
  211. class MySqlLeaseExchange {
  212. public:
  213. /// @brief Set error indicators
  214. ///
  215. /// Sets the error indicator for each of the MYSQL_BIND elements. It points
  216. /// the "error" field within an element of the input array to the
  217. /// corresponding element of the passed error array.
  218. ///
  219. /// @param bind Array of BIND elements
  220. /// @param error Array of error elements. If there is an error in getting
  221. /// data associated with one of the "bind" elements, the
  222. /// corresponding element in the error array is set to MLM_TRUE.
  223. /// @param count Size of each of the arrays.
  224. static void setErrorIndicators(MYSQL_BIND* bind, my_bool* error,
  225. size_t count) {
  226. for (size_t i = 0; i < count; ++i) {
  227. error[i] = MLM_FALSE;
  228. bind[i].error = reinterpret_cast<char*>(&error[i]);
  229. }
  230. }
  231. /// @brief Return columns in error
  232. ///
  233. /// If an error is returned from a fetch (in particular, a truncated
  234. /// status), this method can be called to get the names of the fields in
  235. /// error. It returns a string comprising the names of the fields
  236. /// separated by commas. In the case of there being no error indicators
  237. /// set, it returns the string "(None)".
  238. ///
  239. /// @param error Array of error elements. An element is set to MLM_TRUE
  240. /// if the corresponding column in the database is the source of
  241. /// the error.
  242. /// @param names Array of column names, the same size as the error array.
  243. /// @param count Size of each of the arrays.
  244. static std::string getColumnsInError(my_bool* error, std::string* names,
  245. size_t count) {
  246. std::string result = "";
  247. // Accumulate list of column names
  248. for (size_t i = 0; i < count; ++i) {
  249. if (error[i] == MLM_TRUE) {
  250. if (!result.empty()) {
  251. result += ", ";
  252. }
  253. result += names[i];
  254. }
  255. }
  256. if (result.empty()) {
  257. result = "(None)";
  258. }
  259. return (result);
  260. }
  261. };
  262. /// @brief Exchange MySQL and Lease4 Data
  263. ///
  264. /// On any MySQL operation, arrays of MYSQL_BIND structures must be built to
  265. /// describe the parameters in the prepared statements. Where information is
  266. /// inserted or retrieved - INSERT, UPDATE, SELECT - a large amount of that
  267. /// structure is identical. This class handles the creation of that array.
  268. ///
  269. /// Owing to the MySQL API, the process requires some intermediate variables
  270. /// to hold things like data length etc. This object holds those variables.
  271. ///
  272. /// @note There are no unit tests for this class. It is tested indirectly
  273. /// in all MySqlLeaseMgr::xxx4() calls where it is used.
  274. class MySqlLease4Exchange : public MySqlLeaseExchange {
  275. /// @brief Set number of database columns for this lease structure
  276. static const size_t LEASE_COLUMNS = 10;
  277. public:
  278. /// @brief Constructor
  279. ///
  280. /// The initialization of the variables here is only to satisfy cppcheck -
  281. /// all variables are initialized/set in the methods before they are used.
  282. MySqlLease4Exchange() : addr4_(0), hwaddr_length_(0), client_id_length_(0),
  283. client_id_null_(MLM_FALSE),
  284. subnet_id_(0), valid_lifetime_(0),
  285. fqdn_fwd_(false), fqdn_rev_(false), hostname_length_(0),
  286. state_(0) {
  287. memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
  288. memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
  289. memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
  290. std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
  291. // Set the column names (for error messages)
  292. columns_[0] = "address";
  293. columns_[1] = "hwaddr";
  294. columns_[2] = "client_id";
  295. columns_[3] = "valid_lifetime";
  296. columns_[4] = "expire";
  297. columns_[5] = "subnet_id";
  298. columns_[6] = "fqdn_fwd";
  299. columns_[7] = "fqdn_rev";
  300. columns_[8] = "hostname";
  301. columns_[9] = "state";
  302. BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
  303. }
  304. /// @brief Create MYSQL_BIND objects for Lease4 Pointer
  305. ///
  306. /// Fills in the MYSQL_BIND array for sending data in the Lease4 object to
  307. /// the database.
  308. ///
  309. /// @param lease Lease object to be added to the database. None of the
  310. /// fields in the lease are modified - the lease data is only read.
  311. ///
  312. /// @return Vector of MySQL BIND objects representing the data to be added.
  313. std::vector<MYSQL_BIND> createBindForSend(const Lease4Ptr& lease) {
  314. // Store lease object to ensure it remains valid.
  315. lease_ = lease;
  316. // Initialize prior to constructing the array of MYSQL_BIND structures.
  317. // It sets all fields, including is_null, to zero, so we need to set
  318. // is_null only if it should be true. This gives up minor performance
  319. // benefit while being safe approach. For improved readability, the
  320. // code that explicitly sets is_null is there, but is commented out.
  321. memset(bind_, 0, sizeof(bind_));
  322. // Set up the structures for the various components of the lease4
  323. // structure.
  324. try {
  325. // Address: uint32_t
  326. // The address in the Lease structure is an IOAddress object. Convert
  327. // this to an integer for storage.
  328. addr4_ = static_cast<uint32_t>(lease_->addr_);
  329. bind_[0].buffer_type = MYSQL_TYPE_LONG;
  330. bind_[0].buffer = reinterpret_cast<char*>(&addr4_);
  331. bind_[0].is_unsigned = MLM_TRUE;
  332. // bind_[0].is_null = &MLM_FALSE; // commented out for performance
  333. // reasons, see memset() above
  334. // hwaddr: varbinary(128)
  335. // For speed, we avoid copying the data into temporary storage and
  336. // instead extract it from the lease structure directly.
  337. hwaddr_length_ = lease_->hwaddr_->hwaddr_.size();
  338. bind_[1].buffer_type = MYSQL_TYPE_BLOB;
  339. bind_[1].buffer = reinterpret_cast<char*>(&(lease_->hwaddr_->hwaddr_[0]));
  340. bind_[1].buffer_length = hwaddr_length_;
  341. bind_[1].length = &hwaddr_length_;
  342. // bind_[1].is_null = &MLM_FALSE; // commented out for performance
  343. // reasons, see memset() above
  344. // client_id: varbinary(128)
  345. if (lease_->client_id_) {
  346. client_id_ = lease_->client_id_->getClientId();
  347. client_id_length_ = client_id_.size();
  348. bind_[2].buffer_type = MYSQL_TYPE_BLOB;
  349. bind_[2].buffer = reinterpret_cast<char*>(&client_id_[0]);
  350. bind_[2].buffer_length = client_id_length_;
  351. bind_[2].length = &client_id_length_;
  352. // bind_[2].is_null = &MLM_FALSE; // commented out for performance
  353. // reasons, see memset() above
  354. } else {
  355. bind_[2].buffer_type = MYSQL_TYPE_NULL;
  356. // According to http://dev.mysql.com/doc/refman/5.5/en/
  357. // c-api-prepared-statement-data-structures.html, the other
  358. // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
  359. // but let's set them to some sane values in case earlier versions
  360. // didn't have that assumption.
  361. client_id_null_ = MLM_TRUE;
  362. bind_[2].buffer = NULL;
  363. bind_[2].is_null = &client_id_null_;
  364. }
  365. // valid lifetime: unsigned int
  366. bind_[3].buffer_type = MYSQL_TYPE_LONG;
  367. bind_[3].buffer = reinterpret_cast<char*>(&lease_->valid_lft_);
  368. bind_[3].is_unsigned = MLM_TRUE;
  369. // bind_[3].is_null = &MLM_FALSE; // commented out for performance
  370. // reasons, see memset() above
  371. // expire: timestamp
  372. // The lease structure holds the client last transmission time (cltt_)
  373. // For convenience for external tools, this is converted to lease
  374. // expiry time (expire). The relationship is given by:
  375. //
  376. // expire = cltt_ + valid_lft_
  377. MySqlConnection::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_,
  378. expire_);
  379. bind_[4].buffer_type = MYSQL_TYPE_TIMESTAMP;
  380. bind_[4].buffer = reinterpret_cast<char*>(&expire_);
  381. bind_[4].buffer_length = sizeof(expire_);
  382. // bind_[4].is_null = &MLM_FALSE; // commented out for performance
  383. // reasons, see memset() above
  384. // subnet_id: unsigned int
  385. // Can use lease_->subnet_id_ directly as it is of type uint32_t.
  386. bind_[5].buffer_type = MYSQL_TYPE_LONG;
  387. bind_[5].buffer = reinterpret_cast<char*>(&lease_->subnet_id_);
  388. bind_[5].is_unsigned = MLM_TRUE;
  389. // bind_[5].is_null = &MLM_FALSE; // commented out for performance
  390. // reasons, see memset() above
  391. // fqdn_fwd: boolean
  392. bind_[6].buffer_type = MYSQL_TYPE_TINY;
  393. bind_[6].buffer = reinterpret_cast<char*>(&lease_->fqdn_fwd_);
  394. bind_[6].is_unsigned = MLM_TRUE;
  395. // bind_[6].is_null = &MLM_FALSE; // commented out for performance
  396. // reasons, see memset() above
  397. // fqdn_rev: boolean
  398. bind_[7].buffer_type = MYSQL_TYPE_TINY;
  399. bind_[7].buffer = reinterpret_cast<char*>(&lease_->fqdn_rev_);
  400. bind_[7].is_unsigned = MLM_TRUE;
  401. // bind_[7].is_null = &MLM_FALSE; // commented out for performance
  402. // reasons, see memset() above
  403. // hostname: varchar(255)
  404. bind_[8].buffer_type = MYSQL_TYPE_VARCHAR;
  405. bind_[8].buffer = const_cast<char*>(lease_->hostname_.c_str());
  406. bind_[8].buffer_length = lease_->hostname_.length();
  407. // bind_[8].is_null = &MLM_FALSE; // commented out for performance
  408. // reasons, see memset() above
  409. // state: uint32_t.
  410. bind_[9].buffer_type = MYSQL_TYPE_LONG;
  411. bind_[9].buffer = reinterpret_cast<char*>(&lease_->state_);
  412. bind_[9].is_unsigned = MLM_TRUE;
  413. // bind_[9].is_null = &MLM_FALSE; // commented out for performance
  414. // reasons, see memset() above
  415. // Add the error flags
  416. setErrorIndicators(bind_, error_, LEASE_COLUMNS);
  417. // .. and check that we have the numbers correct at compile time.
  418. BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
  419. } catch (const std::exception& ex) {
  420. isc_throw(DbOperationError,
  421. "Could not create bind array from Lease4: "
  422. << lease_->addr_.toText() << ", reason: " << ex.what());
  423. }
  424. // Add the data to the vector. Note the end element is one after the
  425. // end of the array.
  426. return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
  427. }
  428. /// @brief Create BIND array to receive data
  429. ///
  430. /// Creates a MYSQL_BIND array to receive Lease4 data from the database.
  431. /// After data is successfully received, getLeaseData() can be used to copy
  432. /// it to a Lease6 object.
  433. ///
  434. std::vector<MYSQL_BIND> createBindForReceive() {
  435. // Initialize MYSQL_BIND array.
  436. // It sets all fields, including is_null, to zero, so we need to set
  437. // is_null only if it should be true. This gives up minor performance
  438. // benefit while being safe approach. For improved readability, the
  439. // code that explicitly sets is_null is there, but is commented out.
  440. memset(bind_, 0, sizeof(bind_));
  441. // address: uint32_t
  442. bind_[0].buffer_type = MYSQL_TYPE_LONG;
  443. bind_[0].buffer = reinterpret_cast<char*>(&addr4_);
  444. bind_[0].is_unsigned = MLM_TRUE;
  445. // bind_[0].is_null = &MLM_FALSE; // commented out for performance
  446. // reasons, see memset() above
  447. // hwaddr: varbinary(20)
  448. hwaddr_length_ = sizeof(hwaddr_buffer_);
  449. bind_[1].buffer_type = MYSQL_TYPE_BLOB;
  450. bind_[1].buffer = reinterpret_cast<char*>(hwaddr_buffer_);
  451. bind_[1].buffer_length = hwaddr_length_;
  452. bind_[1].length = &hwaddr_length_;
  453. // bind_[1].is_null = &MLM_FALSE; // commented out for performance
  454. // reasons, see memset() above
  455. // client_id: varbinary(128)
  456. client_id_length_ = sizeof(client_id_buffer_);
  457. bind_[2].buffer_type = MYSQL_TYPE_BLOB;
  458. bind_[2].buffer = reinterpret_cast<char*>(client_id_buffer_);
  459. bind_[2].buffer_length = client_id_length_;
  460. bind_[2].length = &client_id_length_;
  461. bind_[2].is_null = &client_id_null_;
  462. // bind_[2].is_null = &MLM_FALSE; // commented out for performance
  463. // reasons, see memset() above
  464. // lease_time: unsigned int
  465. bind_[3].buffer_type = MYSQL_TYPE_LONG;
  466. bind_[3].buffer = reinterpret_cast<char*>(&valid_lifetime_);
  467. bind_[3].is_unsigned = MLM_TRUE;
  468. // bind_[3].is_null = &MLM_FALSE; // commented out for performance
  469. // reasons, see memset() above
  470. // expire: timestamp
  471. bind_[4].buffer_type = MYSQL_TYPE_TIMESTAMP;
  472. bind_[4].buffer = reinterpret_cast<char*>(&expire_);
  473. bind_[4].buffer_length = sizeof(expire_);
  474. // bind_[4].is_null = &MLM_FALSE; // commented out for performance
  475. // reasons, see memset() above
  476. // subnet_id: unsigned int
  477. bind_[5].buffer_type = MYSQL_TYPE_LONG;
  478. bind_[5].buffer = reinterpret_cast<char*>(&subnet_id_);
  479. bind_[5].is_unsigned = MLM_TRUE;
  480. // bind_[5].is_null = &MLM_FALSE; // commented out for performance
  481. // reasons, see memset() above
  482. // fqdn_fwd: boolean
  483. bind_[6].buffer_type = MYSQL_TYPE_TINY;
  484. bind_[6].buffer = reinterpret_cast<char*>(&fqdn_fwd_);
  485. bind_[6].is_unsigned = MLM_TRUE;
  486. // bind_[6].is_null = &MLM_FALSE; // commented out for performance
  487. // reasons, see memset() above
  488. // fqdn_rev: boolean
  489. bind_[7].buffer_type = MYSQL_TYPE_TINY;
  490. bind_[7].buffer = reinterpret_cast<char*>(&fqdn_rev_);
  491. bind_[7].is_unsigned = MLM_TRUE;
  492. // bind_[7].is_null = &MLM_FALSE; // commented out for performance
  493. // reasons, see memset() above
  494. // hostname: varchar(255)
  495. hostname_length_ = sizeof(hostname_buffer_);
  496. bind_[8].buffer_type = MYSQL_TYPE_STRING;
  497. bind_[8].buffer = reinterpret_cast<char*>(hostname_buffer_);
  498. bind_[8].buffer_length = hostname_length_;
  499. bind_[8].length = &hostname_length_;
  500. // bind_[8].is_null = &MLM_FALSE; // commented out for performance
  501. // reasons, see memset() above
  502. // state: uint32_t
  503. bind_[9].buffer_type = MYSQL_TYPE_LONG;
  504. bind_[9].buffer = reinterpret_cast<char*>(&state_);
  505. bind_[9].is_unsigned = MLM_TRUE;
  506. // bind_[9].is_null = &MLM_FALSE; // commented out for performance
  507. // reasons, see memset() above
  508. // Add the error flags
  509. setErrorIndicators(bind_, error_, LEASE_COLUMNS);
  510. // .. and check that we have the numbers correct at compile time.
  511. BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
  512. // Add the data to the vector. Note the end element is one after the
  513. // end of the array.
  514. return(std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
  515. }
  516. /// @brief Copy Received Data into Lease4 Object
  517. ///
  518. /// Called after the MYSQL_BIND array created by createBindForReceive()
  519. /// has been used, this copies data from the internal member variables
  520. /// into a Lease4 object.
  521. ///
  522. /// @return Lease4Ptr Pointer to a Lease6 object holding the relevant
  523. /// data.
  524. Lease4Ptr getLeaseData() {
  525. // Convert times received from the database to times for the lease
  526. // structure
  527. time_t cltt = 0;
  528. MySqlConnection::convertFromDatabaseTime(expire_, valid_lifetime_, cltt);
  529. if (client_id_null_==MLM_TRUE) {
  530. // There's no client-id, so we pass client-id_length_ set to 0
  531. client_id_length_ = 0;
  532. }
  533. // Hostname is passed to Lease4 as a string object. We have to create
  534. // it from the buffer holding hostname and the buffer length.
  535. std::string hostname(hostname_buffer_,
  536. hostname_buffer_ + hostname_length_);
  537. // Recreate the hardware address.
  538. HWAddrPtr hwaddr(new HWAddr(hwaddr_buffer_, hwaddr_length_, HTYPE_ETHER));
  539. // note that T1 and T2 are not stored
  540. Lease4Ptr lease(new Lease4(addr4_, hwaddr,
  541. client_id_buffer_, client_id_length_,
  542. valid_lifetime_, 0, 0, cltt, subnet_id_,
  543. fqdn_fwd_, fqdn_rev_, hostname));
  544. lease->state_ = state_;
  545. return (lease);
  546. }
  547. /// @brief Return columns in error
  548. ///
  549. /// If an error is returned from a fetch (in particular, a truncated
  550. /// status), this method can be called to get the names of the fields in
  551. /// error. It returns a string comprising the names of the fields
  552. /// separated by commas. In the case of there being no error indicators
  553. /// set, it returns the string "(None)".
  554. ///
  555. /// @return Comma-separated list of columns in error, or the string
  556. /// "(None)".
  557. std::string getErrorColumns() {
  558. return (getColumnsInError(error_, columns_, LEASE_COLUMNS));
  559. }
  560. private:
  561. // Note: All array lengths are equal to the corresponding variable in the
  562. // schema.
  563. // Note: Arrays are declared fixed length for speed of creation
  564. uint32_t addr4_; ///< IPv4 address
  565. MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array
  566. std::string columns_[LEASE_COLUMNS];///< Column names
  567. my_bool error_[LEASE_COLUMNS]; ///< Error array
  568. std::vector<uint8_t> hwaddr_; ///< Hardware address
  569. uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
  570. ///< Hardware address buffer
  571. unsigned long hwaddr_length_; ///< Hardware address length
  572. std::vector<uint8_t> client_id_; ///< Client identification
  573. uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
  574. ///< Client ID buffer
  575. unsigned long client_id_length_; ///< Client ID address length
  576. my_bool client_id_null_; ///< Is Client ID null?
  577. MYSQL_TIME expire_; ///< Lease expiry time
  578. Lease4Ptr lease_; ///< Pointer to lease object
  579. uint32_t subnet_id_; ///< Subnet identification
  580. uint32_t valid_lifetime_; ///< Lease time
  581. my_bool fqdn_fwd_; ///< Has forward DNS update been
  582. ///< performed
  583. my_bool fqdn_rev_; ///< Has reverse DNS update been
  584. ///< performed
  585. char hostname_buffer_[HOSTNAME_MAX_LEN];
  586. ///< Client hostname
  587. unsigned long hostname_length_; ///< Client hostname length
  588. uint32_t state_; ///< Lease state
  589. };
  590. /// @brief Exchange MySQL and Lease6 Data
  591. ///
  592. /// On any MySQL operation, arrays of MYSQL_BIND structures must be built to
  593. /// describe the parameters in the prepared statements. Where information is
  594. /// inserted or retrieved - INSERT, UPDATE, SELECT - a large amount of that
  595. /// structure is identical. This class handles the creation of that array.
  596. ///
  597. /// Owing to the MySQL API, the process requires some intermediate variables
  598. /// to hold things like data length etc. This object holds those variables.
  599. ///
  600. /// @note There are no unit tests for this class. It is tested indirectly
  601. /// in all MySqlLeaseMgr::xxx6() calls where it is used.
  602. class MySqlLease6Exchange : public MySqlLeaseExchange {
  603. /// @brief Set number of database columns for this lease structure
  604. static const size_t LEASE_COLUMNS = 16;
  605. public:
  606. /// @brief Constructor
  607. ///
  608. /// The initialization of the variables here is nonly to satisfy cppcheck -
  609. /// all variables are initialized/set in the methods before they are used.
  610. MySqlLease6Exchange() : addr6_length_(0), duid_length_(0),
  611. iaid_(0), lease_type_(0), prefixlen_(0),
  612. pref_lifetime_(0), subnet_id_(0), valid_lifetime_(0),
  613. fqdn_fwd_(false), fqdn_rev_(false),
  614. hostname_length_(0), hwaddr_length_(0),
  615. hwaddr_null_(MLM_FALSE), hwtype_(0), hwaddr_source_(0),
  616. state_(0) {
  617. memset(addr6_buffer_, 0, sizeof(addr6_buffer_));
  618. memset(duid_buffer_, 0, sizeof(duid_buffer_));
  619. memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
  620. memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
  621. std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
  622. // Set the column names (for error messages)
  623. columns_[0] = "address";
  624. columns_[1] = "duid";
  625. columns_[2] = "valid_lifetime";
  626. columns_[3] = "expire";
  627. columns_[4] = "subnet_id";
  628. columns_[5] = "pref_lifetime";
  629. columns_[6] = "lease_type";
  630. columns_[7] = "iaid";
  631. columns_[8] = "prefix_len";
  632. columns_[9] = "fqdn_fwd";
  633. columns_[10] = "fqdn_rev";
  634. columns_[11] = "hostname";
  635. columns_[12] = "hwaddr";
  636. columns_[13] = "hwtype";
  637. columns_[14] = "hwaddr_source";
  638. columns_[15] = "state";
  639. BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
  640. }
  641. /// @brief Create MYSQL_BIND objects for Lease6 Pointer
  642. ///
  643. /// Fills in the MYSQL_BIND array for sending data in the Lease4 object to
  644. /// the database.
  645. ///
  646. /// @param lease Lease object to be added to the database.
  647. ///
  648. /// @return Vector of MySQL BIND objects representing the data to be added.
  649. std::vector<MYSQL_BIND> createBindForSend(const Lease6Ptr& lease) {
  650. // Store lease object to ensure it remains valid.
  651. lease_ = lease;
  652. // Ensure bind_ array clear for constructing the MYSQL_BIND structures
  653. // for this lease.
  654. // It sets all fields, including is_null, to zero, so we need to set
  655. // is_null only if it should be true. This gives up minor performance
  656. // benefit while being safe approach. For improved readability, the
  657. // code that explicitly sets is_null is there, but is commented out.
  658. memset(bind_, 0, sizeof(bind_));
  659. try {
  660. // address: varchar(39)
  661. addr6_ = lease_->addr_.toText();
  662. addr6_length_ = addr6_.size();
  663. // In the following statement, the string is being read. However, the
  664. // MySQL C interface does not use "const", so the "buffer" element
  665. // is declared as "char*" instead of "const char*". To resolve this,
  666. // the "const" is discarded. (Note that the address of addr6_.c_str()
  667. // is guaranteed to be valid until the next non-const operation on
  668. // addr6_.)
  669. //
  670. // The const_cast could be avoided by copying the string to a writeable
  671. // buffer and storing the address of that in the "buffer" element.
  672. // However, this introduces a copy operation (with additional overhead)
  673. // purely to get round the structures introduced by design of the
  674. // MySQL interface (which uses the area pointed to by "buffer" as input
  675. // when specifying query parameters and as output when retrieving data).
  676. // For that reason, "const_cast" has been used.
  677. bind_[0].buffer_type = MYSQL_TYPE_STRING;
  678. bind_[0].buffer = const_cast<char*>(addr6_.c_str());
  679. bind_[0].buffer_length = addr6_length_;
  680. bind_[0].length = &addr6_length_;
  681. // bind_[0].is_null = &MLM_FALSE; // commented out for performance
  682. // reasons, see memset() above
  683. // duid: varchar(128)
  684. if (!lease_->duid_) {
  685. isc_throw(DbOperationError, "lease6 for address " << addr6_
  686. << " is missing mandatory client-id.");
  687. }
  688. duid_ = lease_->duid_->getDuid();
  689. duid_length_ = duid_.size();
  690. bind_[1].buffer_type = MYSQL_TYPE_BLOB;
  691. bind_[1].buffer = reinterpret_cast<char*>(&(duid_[0]));
  692. bind_[1].buffer_length = duid_length_;
  693. bind_[1].length = &duid_length_;
  694. // bind_[1].is_null = &MLM_FALSE; // commented out for performance
  695. // reasons, see memset() above
  696. // valid lifetime: unsigned int
  697. bind_[2].buffer_type = MYSQL_TYPE_LONG;
  698. bind_[2].buffer = reinterpret_cast<char*>(&lease_->valid_lft_);
  699. bind_[2].is_unsigned = MLM_TRUE;
  700. // bind_[2].is_null = &MLM_FALSE; // commented out for performance
  701. // reasons, see memset() above
  702. // expire: timestamp
  703. // The lease structure holds the client last transmission time (cltt_)
  704. // For convenience for external tools, this is converted to lease
  705. /// expiry time (expire). The relationship is given by:
  706. //
  707. // expire = cltt_ + valid_lft_
  708. //
  709. MySqlConnection::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_,
  710. expire_);
  711. bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
  712. bind_[3].buffer = reinterpret_cast<char*>(&expire_);
  713. bind_[3].buffer_length = sizeof(expire_);
  714. // bind_[3].is_null = &MLM_FALSE; // commented out for performance
  715. // reasons, see memset() above
  716. // subnet_id: unsigned int
  717. // Can use lease_->subnet_id_ directly as it is of type uint32_t.
  718. bind_[4].buffer_type = MYSQL_TYPE_LONG;
  719. bind_[4].buffer = reinterpret_cast<char*>(&lease_->subnet_id_);
  720. bind_[4].is_unsigned = MLM_TRUE;
  721. // bind_[4].is_null = &MLM_FALSE; // commented out for performance
  722. // reasons, see memset() above
  723. // pref_lifetime: unsigned int
  724. // Can use lease_->preferred_lft_ directly as it is of type uint32_t.
  725. bind_[5].buffer_type = MYSQL_TYPE_LONG;
  726. bind_[5].buffer = reinterpret_cast<char*>(&lease_->preferred_lft_);
  727. bind_[5].is_unsigned = MLM_TRUE;
  728. // bind_[5].is_null = &MLM_FALSE; // commented out for performance
  729. // reasons, see memset() above
  730. // lease_type: tinyint
  731. // Must convert to uint8_t as lease_->type_ is a LeaseType variable.
  732. lease_type_ = lease_->type_;
  733. bind_[6].buffer_type = MYSQL_TYPE_TINY;
  734. bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
  735. bind_[6].is_unsigned = MLM_TRUE;
  736. // bind_[6].is_null = &MLM_FALSE; // commented out for performance
  737. // reasons, see memset() above
  738. // iaid: unsigned int
  739. // Can use lease_->iaid_ directly as it is of type uint32_t.
  740. bind_[7].buffer_type = MYSQL_TYPE_LONG;
  741. bind_[7].buffer = reinterpret_cast<char*>(&lease_->iaid_);
  742. bind_[7].is_unsigned = MLM_TRUE;
  743. // bind_[7].is_null = &MLM_FALSE; // commented out for performance
  744. // reasons, see memset() above
  745. // prefix_len: unsigned tinyint
  746. // Can use lease_->prefixlen_ directly as it is uint32_t.
  747. bind_[8].buffer_type = MYSQL_TYPE_TINY;
  748. bind_[8].buffer = reinterpret_cast<char*>(&lease_->prefixlen_);
  749. bind_[8].is_unsigned = MLM_TRUE;
  750. // bind_[8].is_null = &MLM_FALSE; // commented out for performance
  751. // reasons, see memset() above
  752. // fqdn_fwd: boolean
  753. bind_[9].buffer_type = MYSQL_TYPE_TINY;
  754. bind_[9].buffer = reinterpret_cast<char*>(&lease_->fqdn_fwd_);
  755. bind_[9].is_unsigned = MLM_TRUE;
  756. // bind_[7].is_null = &MLM_FALSE; // commented out for performance
  757. // reasons, see memset() above
  758. // fqdn_rev: boolean
  759. bind_[10].buffer_type = MYSQL_TYPE_TINY;
  760. bind_[10].buffer = reinterpret_cast<char*>(&lease_->fqdn_rev_);
  761. bind_[10].is_unsigned = MLM_TRUE;
  762. // bind_[10].is_null = &MLM_FALSE; // commented out for performance
  763. // reasons, see memset() above
  764. // hostname: varchar(255)
  765. bind_[11].buffer_type = MYSQL_TYPE_VARCHAR;
  766. bind_[11].buffer = const_cast<char*>(lease_->hostname_.c_str());
  767. bind_[11].buffer_length = lease_->hostname_.length();
  768. // bind_[11].is_null = &MLM_FALSE; // commented out for performance
  769. // reasons, see memset() above
  770. // hwaddr: varbinary(20) - hardware/MAC address
  771. HWAddrPtr hwaddr = lease_->hwaddr_;
  772. if (hwaddr) {
  773. hwaddr_ = hwaddr->hwaddr_;
  774. hwaddr_length_ = hwaddr->hwaddr_.size();
  775. bind_[12].buffer_type = MYSQL_TYPE_BLOB;
  776. bind_[12].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
  777. bind_[12].buffer_length = hwaddr_length_;
  778. bind_[12].length = &hwaddr_length_;
  779. } else {
  780. bind_[12].buffer_type = MYSQL_TYPE_NULL;
  781. // According to http://dev.mysql.com/doc/refman/5.5/en/
  782. // c-api-prepared-statement-data-structures.html, the other
  783. // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
  784. // but let's set them to some sane values in case earlier versions
  785. // didn't have that assumption.
  786. hwaddr_null_ = MLM_TRUE;
  787. bind_[12].buffer = NULL;
  788. bind_[12].is_null = &hwaddr_null_;
  789. }
  790. // hwtype
  791. if (hwaddr) {
  792. hwtype_ = lease->hwaddr_->htype_;
  793. bind_[13].buffer_type = MYSQL_TYPE_SHORT;
  794. bind_[13].buffer = reinterpret_cast<char*>(&hwtype_);
  795. bind_[13].is_unsigned = MLM_TRUE;
  796. } else {
  797. hwtype_ = 0;
  798. bind_[13].buffer_type = MYSQL_TYPE_NULL;
  799. // According to http://dev.mysql.com/doc/refman/5.5/en/
  800. // c-api-prepared-statement-data-structures.html, the other
  801. // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
  802. // but let's set them to some sane values in case earlier versions
  803. // didn't have that assumption.
  804. hwaddr_null_ = MLM_TRUE;
  805. bind_[13].buffer = NULL;
  806. bind_[13].is_null = &hwaddr_null_;
  807. }
  808. /// Hardware source
  809. if (hwaddr) {
  810. hwaddr_source_ = lease->hwaddr_->source_;
  811. bind_[14].buffer_type = MYSQL_TYPE_LONG;
  812. bind_[14].buffer = reinterpret_cast<char*>(&hwaddr_source_);
  813. bind_[14].is_unsigned = MLM_TRUE;
  814. } else {
  815. hwaddr_source_ = 0;
  816. bind_[14].buffer_type = MYSQL_TYPE_NULL;
  817. // According to http://dev.mysql.com/doc/refman/5.5/en/
  818. // c-api-prepared-statement-data-structures.html, the other
  819. // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
  820. // but let's set them to some sane values in case earlier versions
  821. // didn't have that assumption.
  822. hwaddr_null_ = MLM_TRUE;
  823. bind_[14].buffer = NULL;
  824. bind_[14].is_null = &hwaddr_null_;
  825. }
  826. // state: uint32_t
  827. bind_[15].buffer_type = MYSQL_TYPE_LONG;
  828. bind_[15].buffer = reinterpret_cast<char*>(&lease_->state_);
  829. bind_[15].is_unsigned = MLM_TRUE;
  830. // bind_[15].is_null = &MLM_FALSE; // commented out for performance
  831. // reasons, see memset() above
  832. // Add the error flags
  833. setErrorIndicators(bind_, error_, LEASE_COLUMNS);
  834. // .. and check that we have the numbers correct at compile time.
  835. BOOST_STATIC_ASSERT(14 < LEASE_COLUMNS);
  836. } catch (const std::exception& ex) {
  837. isc_throw(DbOperationError,
  838. "Could not create bind array from Lease6: "
  839. << lease_->addr_.toText() << ", reason: " << ex.what());
  840. }
  841. // Add the data to the vector. Note the end element is one after the
  842. // end of the array.
  843. return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
  844. }
  845. /// @brief Create BIND array to receive data
  846. ///
  847. /// Creates a MYSQL_BIND array to receive Lease6 data from the database.
  848. /// After data is successfully received, getLeaseData() is used to copy
  849. /// it to a Lease6 object.
  850. ///
  851. /// @return Vector of MySQL BIND objects passed to the MySQL data retrieval
  852. /// functions.
  853. std::vector<MYSQL_BIND> createBindForReceive() {
  854. // Initialize MYSQL_BIND array.
  855. // It sets all fields, including is_null, to zero, so we need to set
  856. // is_null only if it should be true. This gives up minor performance
  857. // benefit while being safe approach. For improved readability, the
  858. // code that explicitly sets is_null is there, but is commented out.
  859. memset(bind_, 0, sizeof(bind_));
  860. // address: varchar(39)
  861. // A Lease6_ address has a maximum of 39 characters. The array is
  862. // one byte longer than this to guarantee that we can always null
  863. // terminate it whatever is returned.
  864. addr6_length_ = sizeof(addr6_buffer_) - 1;
  865. bind_[0].buffer_type = MYSQL_TYPE_STRING;
  866. bind_[0].buffer = addr6_buffer_;
  867. bind_[0].buffer_length = addr6_length_;
  868. bind_[0].length = &addr6_length_;
  869. // bind_[0].is_null = &MLM_FALSE; // commented out for performance
  870. // reasons, see memset() above
  871. // client_id: varbinary(128)
  872. duid_length_ = sizeof(duid_buffer_);
  873. bind_[1].buffer_type = MYSQL_TYPE_BLOB;
  874. bind_[1].buffer = reinterpret_cast<char*>(duid_buffer_);
  875. bind_[1].buffer_length = duid_length_;
  876. bind_[1].length = &duid_length_;
  877. // bind_[1].is_null = &MLM_FALSE; // commented out for performance
  878. // reasons, see memset() above
  879. // lease_time: unsigned int
  880. bind_[2].buffer_type = MYSQL_TYPE_LONG;
  881. bind_[2].buffer = reinterpret_cast<char*>(&valid_lifetime_);
  882. bind_[2].is_unsigned = MLM_TRUE;
  883. // bind_[2].is_null = &MLM_FALSE; // commented out for performance
  884. // reasons, see memset() above
  885. // expire: timestamp
  886. bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
  887. bind_[3].buffer = reinterpret_cast<char*>(&expire_);
  888. bind_[3].buffer_length = sizeof(expire_);
  889. // bind_[3].is_null = &MLM_FALSE; // commented out for performance
  890. // reasons, see memset() above
  891. // subnet_id: unsigned int
  892. bind_[4].buffer_type = MYSQL_TYPE_LONG;
  893. bind_[4].buffer = reinterpret_cast<char*>(&subnet_id_);
  894. bind_[4].is_unsigned = MLM_TRUE;
  895. // bind_[4].is_null = &MLM_FALSE; // commented out for performance
  896. // reasons, see memset() above
  897. // pref_lifetime: unsigned int
  898. bind_[5].buffer_type = MYSQL_TYPE_LONG;
  899. bind_[5].buffer = reinterpret_cast<char*>(&pref_lifetime_);
  900. bind_[5].is_unsigned = MLM_TRUE;
  901. // bind_[5].is_null = &MLM_FALSE; // commented out for performance
  902. // reasons, see memset() above
  903. // lease_type: tinyint
  904. bind_[6].buffer_type = MYSQL_TYPE_TINY;
  905. bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
  906. bind_[6].is_unsigned = MLM_TRUE;
  907. // bind_[6].is_null = &MLM_FALSE; // commented out for performance
  908. // reasons, see memset() above
  909. // iaid: unsigned int
  910. bind_[7].buffer_type = MYSQL_TYPE_LONG;
  911. bind_[7].buffer = reinterpret_cast<char*>(&iaid_);
  912. bind_[7].is_unsigned = MLM_TRUE;
  913. // bind_[7].is_null = &MLM_FALSE; // commented out for performance
  914. // reasons, see memset() above
  915. // prefix_len: unsigned tinyint
  916. bind_[8].buffer_type = MYSQL_TYPE_TINY;
  917. bind_[8].buffer = reinterpret_cast<char*>(&prefixlen_);
  918. bind_[8].is_unsigned = MLM_TRUE;
  919. // bind_[8].is_null = &MLM_FALSE; // commented out for performance
  920. // reasons, see memset() above
  921. // fqdn_fwd: boolean
  922. bind_[9].buffer_type = MYSQL_TYPE_TINY;
  923. bind_[9].buffer = reinterpret_cast<char*>(&fqdn_fwd_);
  924. bind_[9].is_unsigned = MLM_TRUE;
  925. // bind_[9].is_null = &MLM_FALSE; // commented out for performance
  926. // reasons, see memset() above
  927. // fqdn_rev: boolean
  928. bind_[10].buffer_type = MYSQL_TYPE_TINY;
  929. bind_[10].buffer = reinterpret_cast<char*>(&fqdn_rev_);
  930. bind_[10].is_unsigned = MLM_TRUE;
  931. // bind_[10].is_null = &MLM_FALSE; // commented out for performance
  932. // reasons, see memset() above
  933. // hostname: varchar(255)
  934. hostname_length_ = sizeof(hostname_buffer_);
  935. bind_[11].buffer_type = MYSQL_TYPE_STRING;
  936. bind_[11].buffer = reinterpret_cast<char*>(hostname_buffer_);
  937. bind_[11].buffer_length = hostname_length_;
  938. bind_[11].length = &hostname_length_;
  939. // bind_[11].is_null = &MLM_FALSE; // commented out for performance
  940. // reasons, see memset() above
  941. // hardware address
  942. // hwaddr: varbinary(20)
  943. hwaddr_null_ = MLM_FALSE;
  944. hwaddr_length_ = sizeof(hwaddr_buffer_);
  945. bind_[12].buffer_type = MYSQL_TYPE_BLOB;
  946. bind_[12].buffer = reinterpret_cast<char*>(hwaddr_buffer_);
  947. bind_[12].buffer_length = hwaddr_length_;
  948. bind_[12].length = &hwaddr_length_;
  949. bind_[12].is_null = &hwaddr_null_;
  950. // hardware type: unsigned short int (16 bits)
  951. bind_[13].buffer_type = MYSQL_TYPE_SHORT;
  952. bind_[13].buffer = reinterpret_cast<char*>(&hwtype_);
  953. bind_[13].is_unsigned = MLM_TRUE;
  954. // hardware source: unsigned int (32 bits)
  955. bind_[14].buffer_type = MYSQL_TYPE_LONG;
  956. bind_[14].buffer = reinterpret_cast<char*>(&hwaddr_source_);
  957. bind_[14].is_unsigned = MLM_TRUE;
  958. // state: uint32_t
  959. bind_[15].buffer_type = MYSQL_TYPE_LONG;
  960. bind_[15].buffer = reinterpret_cast<char*>(&state_);
  961. bind_[15].is_unsigned = MLM_TRUE;
  962. // bind_[15].is_null = &MLM_FALSE; // commented out for performance
  963. // reasons, see memset() above
  964. // Add the error flags
  965. setErrorIndicators(bind_, error_, LEASE_COLUMNS);
  966. // .. and check that we have the numbers correct at compile time.
  967. BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
  968. // Add the data to the vector. Note the end element is one after the
  969. // end of the array.
  970. return(std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
  971. }
  972. /// @brief Copy Received Data into Lease6 Object
  973. ///
  974. /// Called after the MYSQL_BIND array created by createBindForReceive()
  975. /// has been used, this copies data from the internal member variables
  976. /// into a Lease6 object.
  977. ///
  978. /// @return Lease6Ptr Pointer to a Lease6 object holding the relevant
  979. /// data.
  980. ///
  981. /// @throw isc::BadValue Unable to convert Lease Type value in database
  982. Lease6Ptr getLeaseData() {
  983. // The address buffer is declared larger than the buffer size passed
  984. // to the access function so that we can always append a null byte.
  985. // Create the IOAddress object corresponding to the received data.
  986. addr6_buffer_[addr6_length_] = '\0';
  987. std::string address = addr6_buffer_;
  988. isc::asiolink::IOAddress addr(address);
  989. // Set the lease type in a variable of the appropriate data type, which
  990. // has been initialized with an arbitrary (but valid) value.
  991. Lease::Type type = Lease::TYPE_NA;
  992. switch (lease_type_) {
  993. case Lease::TYPE_NA:
  994. type = Lease::TYPE_NA;
  995. break;
  996. case Lease::TYPE_TA:
  997. type = Lease::TYPE_TA;
  998. break;
  999. case Lease::TYPE_PD:
  1000. type = Lease::TYPE_PD;
  1001. break;
  1002. default:
  1003. isc_throw(BadValue, "invalid lease type returned (" <<
  1004. static_cast<int>(lease_type_) << ") for lease with "
  1005. << "address " << address << ". Only 0, 1, or 2 are "
  1006. << "allowed.");
  1007. }
  1008. // Set up DUID,
  1009. DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_));
  1010. // Hostname is passed to Lease6 as a string object, so we have to
  1011. // create it from the hostname buffer and length.
  1012. std::string hostname(hostname_buffer_,
  1013. hostname_buffer_ + hostname_length_);
  1014. /// Set hardware address if it was set
  1015. HWAddrPtr hwaddr;
  1016. if (hwaddr_null_ == MLM_FALSE) {
  1017. hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_, hwtype_));
  1018. hwaddr->source_ = hwaddr_source_;
  1019. }
  1020. // Create the lease and set the cltt (after converting from the
  1021. // expire time retrieved from the database).
  1022. Lease6Ptr result(new Lease6(type, addr, duid_ptr, iaid_,
  1023. pref_lifetime_, valid_lifetime_, 0, 0,
  1024. subnet_id_, fqdn_fwd_, fqdn_rev_,
  1025. hostname, hwaddr, prefixlen_));
  1026. time_t cltt = 0;
  1027. MySqlConnection::convertFromDatabaseTime(expire_, valid_lifetime_, cltt);
  1028. result->cltt_ = cltt;
  1029. // Set state.
  1030. result->state_ = state_;
  1031. return (result);
  1032. }
  1033. /// @brief Return columns in error
  1034. ///
  1035. /// If an error is returned from a fetch (in particular, a truncated
  1036. /// status), this method can be called to get the names of the fields in
  1037. /// error. It returns a string comprising the names of the fields
  1038. /// separated by commas. In the case of there being no error indicators
  1039. /// set, it returns the string "(None)".
  1040. ///
  1041. /// @return Comma-separated list of columns in error, or the string
  1042. /// "(None)".
  1043. std::string getErrorColumns() {
  1044. return (getColumnsInError(error_, columns_, LEASE_COLUMNS));
  1045. }
  1046. private:
  1047. // Note: All array lengths are equal to the corresponding variable in the
  1048. // schema.
  1049. // Note: arrays are declared fixed length for speed of creation
  1050. std::string addr6_; ///< String form of address
  1051. char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Character
  1052. ///< array form of V6 address
  1053. unsigned long addr6_length_; ///< Length of the address
  1054. MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array
  1055. std::string columns_[LEASE_COLUMNS];///< Column names
  1056. std::vector<uint8_t> duid_; ///< Client identification
  1057. uint8_t duid_buffer_[DUID::MAX_DUID_LEN]; ///< Buffer form of DUID
  1058. unsigned long duid_length_; ///< Length of the DUID
  1059. my_bool error_[LEASE_COLUMNS]; ///< Error indicators
  1060. MYSQL_TIME expire_; ///< Lease expiry time
  1061. uint32_t iaid_; ///< Identity association ID
  1062. Lease6Ptr lease_; ///< Pointer to lease object
  1063. uint8_t lease_type_; ///< Lease type
  1064. uint8_t prefixlen_; ///< Prefix length
  1065. uint32_t pref_lifetime_; ///< Preferred lifetime
  1066. uint32_t subnet_id_; ///< Subnet identification
  1067. uint32_t valid_lifetime_; ///< Lease time
  1068. my_bool fqdn_fwd_; ///< Has forward DNS update been
  1069. ///< performed
  1070. my_bool fqdn_rev_; ///< Has reverse DNS update been
  1071. ///< performed
  1072. char hostname_buffer_[HOSTNAME_MAX_LEN];
  1073. ///< Client hostname
  1074. unsigned long hostname_length_; ///< Client hostname length
  1075. uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
  1076. ///< Buffer for Hardware address
  1077. std::vector<uint8_t> hwaddr_; ///< Hardware address (optional)
  1078. unsigned long hwaddr_length_; ///< Aux. variable denoting hwaddr_ size()
  1079. my_bool hwaddr_null_; ///< Used when HWAddr is null
  1080. uint16_t hwtype_; ///< Hardware type
  1081. uint32_t hwaddr_source_; ///< Source of the hardware address
  1082. uint32_t state_; ///< Lease state.
  1083. };
  1084. // MySqlLeaseMgr Constructor and Destructor
  1085. MySqlLeaseMgr::MySqlLeaseMgr(const MySqlConnection::ParameterMap& parameters)
  1086. : conn_(parameters) {
  1087. // Open the database.
  1088. conn_.openDatabase();
  1089. // Enable autocommit. To avoid a flush to disk on every commit, the global
  1090. // parameter innodb_flush_log_at_trx_commit should be set to 2. This will
  1091. // cause the changes to be written to the log, but flushed to disk in the
  1092. // background every second. Setting the parameter to that value will speed
  1093. // up the system, but at the risk of losing data if the system crashes.
  1094. my_bool result = mysql_autocommit(conn_.mysql_, 1);
  1095. if (result != 0) {
  1096. isc_throw(DbOperationError, mysql_error(conn_.mysql_));
  1097. }
  1098. // Prepare all statements likely to be used.
  1099. conn_.prepareStatements(tagged_statements, MySqlLeaseMgr::NUM_STATEMENTS);
  1100. // Create the exchange objects for use in exchanging data between the
  1101. // program and the database.
  1102. exchange4_.reset(new MySqlLease4Exchange());
  1103. exchange6_.reset(new MySqlLease6Exchange());
  1104. }
  1105. MySqlLeaseMgr::~MySqlLeaseMgr() {
  1106. // There is no need to close the database in this destructor: it is
  1107. // closed in the destructor of the mysql_ member variable.
  1108. }
  1109. std::string
  1110. MySqlLeaseMgr::getDBVersion() {
  1111. std::stringstream tmp;
  1112. tmp << "MySQL backend " << MYSQL_SCHEMA_VERSION_MAJOR;
  1113. tmp << "." << MYSQL_SCHEMA_VERSION_MINOR;
  1114. tmp << ", library " << mysql_get_client_info();
  1115. return (tmp.str());
  1116. }
  1117. // Add leases to the database. The two public methods accept a lease object
  1118. // (either V4 of V6), bind the contents to the appropriate prepared
  1119. // statement, then call common code to execute the statement.
  1120. bool
  1121. MySqlLeaseMgr::addLeaseCommon(StatementIndex stindex,
  1122. std::vector<MYSQL_BIND>& bind) {
  1123. // Bind the parameters to the statement
  1124. int status = mysql_stmt_bind_param(conn_.statements_[stindex], &bind[0]);
  1125. checkError(status, stindex, "unable to bind parameters");
  1126. // Execute the statement
  1127. status = mysql_stmt_execute(conn_.statements_[stindex]);
  1128. if (status != 0) {
  1129. // Failure: check for the special case of duplicate entry. If this is
  1130. // the case, we return false to indicate that the row was not added.
  1131. // Otherwise we throw an exception.
  1132. if (mysql_errno(conn_.mysql_) == ER_DUP_ENTRY) {
  1133. return (false);
  1134. }
  1135. checkError(status, stindex, "unable to execute");
  1136. }
  1137. // Insert succeeded
  1138. return (true);
  1139. }
  1140. bool
  1141. MySqlLeaseMgr::addLease(const Lease4Ptr& lease) {
  1142. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1143. DHCPSRV_MYSQL_ADD_ADDR4).arg(lease->addr_.toText());
  1144. // Create the MYSQL_BIND array for the lease
  1145. std::vector<MYSQL_BIND> bind = exchange4_->createBindForSend(lease);
  1146. // ... and drop to common code.
  1147. return (addLeaseCommon(INSERT_LEASE4, bind));
  1148. }
  1149. bool
  1150. MySqlLeaseMgr::addLease(const Lease6Ptr& lease) {
  1151. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1152. DHCPSRV_MYSQL_ADD_ADDR6).arg(lease->addr_.toText())
  1153. .arg(lease->type_);
  1154. // Create the MYSQL_BIND array for the lease
  1155. std::vector<MYSQL_BIND> bind = exchange6_->createBindForSend(lease);
  1156. // ... and drop to common code.
  1157. return (addLeaseCommon(INSERT_LEASE6, bind));
  1158. }
  1159. // Extraction of leases from the database.
  1160. //
  1161. // All getLease() methods ultimately call getLeaseCollection(). This
  1162. // binds the input parameters passed to it with the appropriate prepared
  1163. // statement and executes the statement. It then gets the results from the
  1164. // database. getlease() methods that expect a single result back call it
  1165. // with the "single" parameter set true: this causes an exception to be
  1166. // generated if multiple records can be retrieved from the result set. (Such
  1167. // an occurrence either indicates corruption in the database, or that an
  1168. // assumption that a query can only return a single record is incorrect.)
  1169. // Methods that require a collection of records have "single" set to the
  1170. // default value of false. The logic is the same for both Lease4 and Lease6
  1171. // objects, so the code is templated.
  1172. //
  1173. // Methods that require a collection of objects access this method through
  1174. // two interface methods (also called getLeaseCollection()). These are
  1175. // short enough as to be defined in the header file: all they do is to supply
  1176. // the appropriate MySqlLeaseXExchange object depending on the type of the
  1177. // LeaseCollection objects passed to them.
  1178. //
  1179. // Methods that require a single object to be returned access the method
  1180. // through two interface methods (called getLease()). As well as supplying
  1181. // the appropriate exchange object, they convert between lease collection
  1182. // holding zero or one leases into an appropriate Lease object.
  1183. template <typename Exchange, typename LeaseCollection>
  1184. void MySqlLeaseMgr::getLeaseCollection(StatementIndex stindex,
  1185. MYSQL_BIND* bind,
  1186. Exchange& exchange,
  1187. LeaseCollection& result,
  1188. bool single) const {
  1189. // Bind the selection parameters to the statement
  1190. int status = mysql_stmt_bind_param(conn_.statements_[stindex], bind);
  1191. checkError(status, stindex, "unable to bind WHERE clause parameter");
  1192. // Set up the MYSQL_BIND array for the data being returned and bind it to
  1193. // the statement.
  1194. std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
  1195. status = mysql_stmt_bind_result(conn_.statements_[stindex], &outbind[0]);
  1196. checkError(status, stindex, "unable to bind SELECT clause parameters");
  1197. // Execute the statement
  1198. status = mysql_stmt_execute(conn_.statements_[stindex]);
  1199. checkError(status, stindex, "unable to execute");
  1200. // Ensure that all the lease information is retrieved in one go to avoid
  1201. // overhead of going back and forth between client and server.
  1202. status = mysql_stmt_store_result(conn_.statements_[stindex]);
  1203. checkError(status, stindex, "unable to set up for storing all results");
  1204. // Set up the fetch "release" object to release resources associated
  1205. // with the call to mysql_stmt_fetch when this method exits, then
  1206. // retrieve the data.
  1207. MySqlFreeResult fetch_release(conn_.statements_[stindex]);
  1208. int count = 0;
  1209. while ((status = mysql_stmt_fetch(conn_.statements_[stindex])) == 0) {
  1210. try {
  1211. result.push_back(exchange->getLeaseData());
  1212. } catch (const isc::BadValue& ex) {
  1213. // Rethrow the exception with a bit more data.
  1214. isc_throw(BadValue, ex.what() << ". Statement is <" <<
  1215. conn_.text_statements_[stindex] << ">");
  1216. }
  1217. if (single && (++count > 1)) {
  1218. isc_throw(MultipleRecords, "multiple records were found in the "
  1219. "database where only one was expected for query "
  1220. << conn_.text_statements_[stindex]);
  1221. }
  1222. }
  1223. // How did the fetch end?
  1224. if (status == 1) {
  1225. // Error - unable to fetch results
  1226. checkError(status, stindex, "unable to fetch results");
  1227. } else if (status == MYSQL_DATA_TRUNCATED) {
  1228. // Data truncated - throw an exception indicating what was at fault
  1229. isc_throw(DataTruncated, conn_.text_statements_[stindex]
  1230. << " returned truncated data: columns affected are "
  1231. << exchange->getErrorColumns());
  1232. }
  1233. }
  1234. void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* bind,
  1235. Lease4Ptr& result) const {
  1236. // Create appropriate collection object and get all leases matching
  1237. // the selection criteria. The "single" paraeter is true to indicate
  1238. // that the called method should throw an exception if multiple
  1239. // matching records are found: this particular method is called when only
  1240. // one or zero matches is expected.
  1241. Lease4Collection collection;
  1242. getLeaseCollection(stindex, bind, exchange4_, collection, true);
  1243. // Return single record if present, else clear the lease.
  1244. if (collection.empty()) {
  1245. result.reset();
  1246. } else {
  1247. result = *collection.begin();
  1248. }
  1249. }
  1250. void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* bind,
  1251. Lease6Ptr& result) const {
  1252. // Create appropriate collection object and get all leases matching
  1253. // the selection criteria. The "single" paraeter is true to indicate
  1254. // that the called method should throw an exception if multiple
  1255. // matching records are found: this particular method is called when only
  1256. // one or zero matches is expected.
  1257. Lease6Collection collection;
  1258. getLeaseCollection(stindex, bind, exchange6_, collection, true);
  1259. // Return single record if present, else clear the lease.
  1260. if (collection.empty()) {
  1261. result.reset();
  1262. } else {
  1263. result = *collection.begin();
  1264. }
  1265. }
  1266. // Basic lease access methods. Obtain leases from the database using various
  1267. // criteria.
  1268. Lease4Ptr
  1269. MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
  1270. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1271. DHCPSRV_MYSQL_GET_ADDR4).arg(addr.toText());
  1272. // Set up the WHERE clause value
  1273. MYSQL_BIND inbind[1];
  1274. memset(inbind, 0, sizeof(inbind));
  1275. uint32_t addr4 = static_cast<uint32_t>(addr);
  1276. inbind[0].buffer_type = MYSQL_TYPE_LONG;
  1277. inbind[0].buffer = reinterpret_cast<char*>(&addr4);
  1278. inbind[0].is_unsigned = MLM_TRUE;
  1279. // Get the data
  1280. Lease4Ptr result;
  1281. getLease(GET_LEASE4_ADDR, inbind, result);
  1282. return (result);
  1283. }
  1284. Lease4Collection
  1285. MySqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
  1286. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1287. DHCPSRV_MYSQL_GET_HWADDR).arg(hwaddr.toText());
  1288. // Set up the WHERE clause value
  1289. MYSQL_BIND inbind[1];
  1290. memset(inbind, 0, sizeof(inbind));
  1291. // As "buffer" is "char*" - even though the data is being read - we need
  1292. // to cast away the "const"ness as well as reinterpreting the data as
  1293. // a "char*". (We could avoid the "const_cast" by copying the data to a
  1294. // local variable, but as the data is only being read, this introduces
  1295. // an unnecessary copy).
  1296. unsigned long hwaddr_length = hwaddr.hwaddr_.size();
  1297. uint8_t* data = const_cast<uint8_t*>(&hwaddr.hwaddr_[0]);
  1298. inbind[0].buffer_type = MYSQL_TYPE_BLOB;
  1299. inbind[0].buffer = reinterpret_cast<char*>(data);
  1300. inbind[0].buffer_length = hwaddr_length;
  1301. inbind[0].length = &hwaddr_length;
  1302. // Get the data
  1303. Lease4Collection result;
  1304. getLeaseCollection(GET_LEASE4_HWADDR, inbind, result);
  1305. return (result);
  1306. }
  1307. Lease4Ptr
  1308. MySqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
  1309. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1310. DHCPSRV_MYSQL_GET_SUBID_HWADDR)
  1311. .arg(subnet_id).arg(hwaddr.toText());
  1312. // Set up the WHERE clause value
  1313. MYSQL_BIND inbind[2];
  1314. memset(inbind, 0, sizeof(inbind));
  1315. // As "buffer" is "char*" - even though the data is being read - we need
  1316. // to cast away the "const"ness as well as reinterpreting the data as
  1317. // a "char*". (We could avoid the "const_cast" by copying the data to a
  1318. // local variable, but as the data is only being read, this introduces
  1319. // an unnecessary copy).
  1320. unsigned long hwaddr_length = hwaddr.hwaddr_.size();
  1321. uint8_t* data = const_cast<uint8_t*>(&hwaddr.hwaddr_[0]);
  1322. inbind[0].buffer_type = MYSQL_TYPE_BLOB;
  1323. inbind[0].buffer = reinterpret_cast<char*>(data);
  1324. inbind[0].buffer_length = hwaddr_length;
  1325. inbind[0].length = &hwaddr_length;
  1326. inbind[1].buffer_type = MYSQL_TYPE_LONG;
  1327. inbind[1].buffer = reinterpret_cast<char*>(&subnet_id);
  1328. inbind[1].is_unsigned = MLM_TRUE;
  1329. // Get the data
  1330. Lease4Ptr result;
  1331. getLease(GET_LEASE4_HWADDR_SUBID, inbind, result);
  1332. return (result);
  1333. }
  1334. Lease4Collection
  1335. MySqlLeaseMgr::getLease4(const ClientId& clientid) const {
  1336. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1337. DHCPSRV_MYSQL_GET_CLIENTID).arg(clientid.toText());
  1338. // Set up the WHERE clause value
  1339. MYSQL_BIND inbind[1];
  1340. memset(inbind, 0, sizeof(inbind));
  1341. std::vector<uint8_t> client_data = clientid.getClientId();
  1342. unsigned long client_data_length = client_data.size();
  1343. inbind[0].buffer_type = MYSQL_TYPE_BLOB;
  1344. inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
  1345. inbind[0].buffer_length = client_data_length;
  1346. inbind[0].length = &client_data_length;
  1347. // Get the data
  1348. Lease4Collection result;
  1349. getLeaseCollection(GET_LEASE4_CLIENTID, inbind, result);
  1350. return (result);
  1351. }
  1352. Lease4Ptr
  1353. MySqlLeaseMgr::getLease4(const ClientId&, const HWAddr&, SubnetID) const {
  1354. /// This function is currently not implemented because allocation engine
  1355. /// searches for the lease using HW address or client identifier.
  1356. /// It never uses both parameters in the same time. We need to
  1357. /// consider if this function is needed at all.
  1358. isc_throw(NotImplemented, "The MySqlLeaseMgr::getLease4 function was"
  1359. " called, but it is not implemented");
  1360. }
  1361. Lease4Ptr
  1362. MySqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
  1363. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1364. DHCPSRV_MYSQL_GET_SUBID_CLIENTID)
  1365. .arg(subnet_id).arg(clientid.toText());
  1366. // Set up the WHERE clause value
  1367. MYSQL_BIND inbind[2];
  1368. memset(inbind, 0, sizeof(inbind));
  1369. std::vector<uint8_t> client_data = clientid.getClientId();
  1370. unsigned long client_data_length = client_data.size();
  1371. inbind[0].buffer_type = MYSQL_TYPE_BLOB;
  1372. inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
  1373. inbind[0].buffer_length = client_data_length;
  1374. inbind[0].length = &client_data_length;
  1375. inbind[1].buffer_type = MYSQL_TYPE_LONG;
  1376. inbind[1].buffer = reinterpret_cast<char*>(&subnet_id);
  1377. inbind[1].is_unsigned = MLM_TRUE;
  1378. // Get the data
  1379. Lease4Ptr result;
  1380. getLease(GET_LEASE4_CLIENTID_SUBID, inbind, result);
  1381. return (result);
  1382. }
  1383. Lease6Ptr
  1384. MySqlLeaseMgr::getLease6(Lease::Type lease_type,
  1385. const isc::asiolink::IOAddress& addr) const {
  1386. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1387. DHCPSRV_MYSQL_GET_ADDR6).arg(addr.toText())
  1388. .arg(lease_type);
  1389. // Set up the WHERE clause value
  1390. MYSQL_BIND inbind[2];
  1391. memset(inbind, 0, sizeof(inbind));
  1392. std::string addr6 = addr.toText();
  1393. unsigned long addr6_length = addr6.size();
  1394. // See the earlier description of the use of "const_cast" when accessing
  1395. // the address for an explanation of the reason.
  1396. inbind[0].buffer_type = MYSQL_TYPE_STRING;
  1397. inbind[0].buffer = const_cast<char*>(addr6.c_str());
  1398. inbind[0].buffer_length = addr6_length;
  1399. inbind[0].length = &addr6_length;
  1400. // LEASE_TYPE
  1401. inbind[1].buffer_type = MYSQL_TYPE_TINY;
  1402. inbind[1].buffer = reinterpret_cast<char*>(&lease_type);
  1403. inbind[1].is_unsigned = MLM_TRUE;
  1404. Lease6Ptr result;
  1405. getLease(GET_LEASE6_ADDR, inbind, result);
  1406. return (result);
  1407. }
  1408. Lease6Collection
  1409. MySqlLeaseMgr::getLeases6(Lease::Type lease_type,
  1410. const DUID& duid, uint32_t iaid) const {
  1411. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1412. DHCPSRV_MYSQL_GET_IAID_DUID).arg(iaid).arg(duid.toText())
  1413. .arg(lease_type);
  1414. // Set up the WHERE clause value
  1415. MYSQL_BIND inbind[3];
  1416. memset(inbind, 0, sizeof(inbind));
  1417. // In the following statement, the DUID is being read. However, the
  1418. // MySQL C interface does not use "const", so the "buffer" element
  1419. // is declared as "char*" instead of "const char*". To resolve this,
  1420. // the "const" is discarded before the uint8_t* is cast to char*.
  1421. //
  1422. // Note that the const_cast could be avoided by copying the DUID to
  1423. // a writeable buffer and storing the address of that in the "buffer"
  1424. // element. However, this introduces a copy operation (with additional
  1425. // overhead) purely to get round the structures introduced by design of
  1426. // the MySQL interface (which uses the area pointed to by "buffer" as
  1427. // input when specifying query parameters and as output when retrieving
  1428. // data). For that reason, "const_cast" has been used.
  1429. const vector<uint8_t>& duid_vector = duid.getDuid();
  1430. unsigned long duid_length = duid_vector.size();
  1431. inbind[0].buffer_type = MYSQL_TYPE_BLOB;
  1432. inbind[0].buffer = reinterpret_cast<char*>(
  1433. const_cast<uint8_t*>(&duid_vector[0]));
  1434. inbind[0].buffer_length = duid_length;
  1435. inbind[0].length = &duid_length;
  1436. // IAID
  1437. inbind[1].buffer_type = MYSQL_TYPE_LONG;
  1438. inbind[1].buffer = reinterpret_cast<char*>(&iaid);
  1439. inbind[1].is_unsigned = MLM_TRUE;
  1440. // LEASE_TYPE
  1441. inbind[2].buffer_type = MYSQL_TYPE_TINY;
  1442. inbind[2].buffer = reinterpret_cast<char*>(&lease_type);
  1443. inbind[2].is_unsigned = MLM_TRUE;
  1444. // ... and get the data
  1445. Lease6Collection result;
  1446. getLeaseCollection(GET_LEASE6_DUID_IAID, inbind, result);
  1447. return (result);
  1448. }
  1449. Lease6Collection
  1450. MySqlLeaseMgr::getLeases6(Lease::Type lease_type,
  1451. const DUID& duid, uint32_t iaid,
  1452. SubnetID subnet_id) const {
  1453. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1454. DHCPSRV_MYSQL_GET_IAID_SUBID_DUID)
  1455. .arg(iaid).arg(subnet_id).arg(duid.toText())
  1456. .arg(lease_type);
  1457. // Set up the WHERE clause value
  1458. MYSQL_BIND inbind[4];
  1459. memset(inbind, 0, sizeof(inbind));
  1460. // See the earlier description of the use of "const_cast" when accessing
  1461. // the DUID for an explanation of the reason.
  1462. const vector<uint8_t>& duid_vector = duid.getDuid();
  1463. unsigned long duid_length = duid_vector.size();
  1464. inbind[0].buffer_type = MYSQL_TYPE_BLOB;
  1465. inbind[0].buffer = reinterpret_cast<char*>(
  1466. const_cast<uint8_t*>(&duid_vector[0]));
  1467. inbind[0].buffer_length = duid_length;
  1468. inbind[0].length = &duid_length;
  1469. // IAID
  1470. inbind[1].buffer_type = MYSQL_TYPE_LONG;
  1471. inbind[1].buffer = reinterpret_cast<char*>(&iaid);
  1472. inbind[1].is_unsigned = MLM_TRUE;
  1473. // Subnet ID
  1474. inbind[2].buffer_type = MYSQL_TYPE_LONG;
  1475. inbind[2].buffer = reinterpret_cast<char*>(&subnet_id);
  1476. inbind[2].is_unsigned = MLM_TRUE;
  1477. // LEASE_TYPE
  1478. inbind[3].buffer_type = MYSQL_TYPE_TINY;
  1479. inbind[3].buffer = reinterpret_cast<char*>(&lease_type);
  1480. inbind[3].is_unsigned = MLM_TRUE;
  1481. // ... and get the data
  1482. Lease6Collection result;
  1483. getLeaseCollection(GET_LEASE6_DUID_IAID_SUBID, inbind, result);
  1484. return (result);
  1485. }
  1486. void
  1487. MySqlLeaseMgr::getExpiredLeases6(Lease6Collection& expired_leases,
  1488. const size_t max_leases) const {
  1489. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_GET_EXPIRED6)
  1490. .arg(max_leases);
  1491. getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE6_EXPIRE);
  1492. }
  1493. void
  1494. MySqlLeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
  1495. const size_t max_leases) const {
  1496. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_GET_EXPIRED4)
  1497. .arg(max_leases);
  1498. getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE4_EXPIRE);
  1499. }
  1500. template<typename LeaseCollection>
  1501. void
  1502. MySqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases,
  1503. const size_t max_leases,
  1504. StatementIndex statement_index) const {
  1505. // Set up the WHERE clause value
  1506. MYSQL_BIND inbind[3];
  1507. memset(inbind, 0, sizeof(inbind));
  1508. // Exclude reclaimed leases.
  1509. uint32_t state = static_cast<uint32_t>(Lease::STATE_EXPIRED_RECLAIMED);
  1510. inbind[0].buffer_type = MYSQL_TYPE_LONG;
  1511. inbind[0].buffer = reinterpret_cast<char*>(&state);
  1512. inbind[0].is_unsigned = MLM_TRUE;
  1513. // Expiration timestamp.
  1514. MYSQL_TIME expire_time;
  1515. conn_.convertToDatabaseTime(time(NULL), expire_time);
  1516. inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
  1517. inbind[1].buffer = reinterpret_cast<char*>(&expire_time);
  1518. inbind[1].buffer_length = sizeof(expire_time);
  1519. // If the number of leases is 0, we will return all leases. This is
  1520. // achieved by setting the limit to a very high value.
  1521. uint32_t limit = max_leases > 0 ? static_cast<uint32_t>(max_leases) :
  1522. std::numeric_limits<uint32_t>::max();
  1523. inbind[2].buffer_type = MYSQL_TYPE_LONG;
  1524. inbind[2].buffer = reinterpret_cast<char*>(&limit);
  1525. inbind[2].is_unsigned = MLM_TRUE;
  1526. // Get the data
  1527. getLeaseCollection(statement_index, inbind, expired_leases);
  1528. }
  1529. // Update lease methods. These comprise common code that handles the actual
  1530. // update, and type-specific methods that set up the parameters for the prepared
  1531. // statement depending on the type of lease.
  1532. template <typename LeasePtr>
  1533. void
  1534. MySqlLeaseMgr::updateLeaseCommon(StatementIndex stindex, MYSQL_BIND* bind,
  1535. const LeasePtr& lease) {
  1536. // Bind the parameters to the statement
  1537. int status = mysql_stmt_bind_param(conn_.statements_[stindex], bind);
  1538. checkError(status, stindex, "unable to bind parameters");
  1539. // Execute
  1540. status = mysql_stmt_execute(conn_.statements_[stindex]);
  1541. checkError(status, stindex, "unable to execute");
  1542. // See how many rows were affected. The statement should only update a
  1543. // single row.
  1544. int affected_rows = mysql_stmt_affected_rows(conn_.statements_[stindex]);
  1545. if (affected_rows == 0) {
  1546. isc_throw(NoSuchLease, "unable to update lease for address " <<
  1547. lease->addr_ << " as it does not exist");
  1548. } else if (affected_rows > 1) {
  1549. // Should not happen - primary key constraint should only have selected
  1550. // one row.
  1551. isc_throw(DbOperationError, "apparently updated more than one lease "
  1552. "that had the address " << lease->addr_);
  1553. }
  1554. }
  1555. void
  1556. MySqlLeaseMgr::updateLease4(const Lease4Ptr& lease) {
  1557. const StatementIndex stindex = UPDATE_LEASE4;
  1558. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1559. DHCPSRV_MYSQL_UPDATE_ADDR4).arg(lease->addr_.toText());
  1560. // Create the MYSQL_BIND array for the data being updated
  1561. std::vector<MYSQL_BIND> bind = exchange4_->createBindForSend(lease);
  1562. // Set up the WHERE clause and append it to the MYSQL_BIND array
  1563. MYSQL_BIND where;
  1564. memset(&where, 0, sizeof(where));
  1565. uint32_t addr4 = static_cast<uint32_t>(lease->addr_);
  1566. where.buffer_type = MYSQL_TYPE_LONG;
  1567. where.buffer = reinterpret_cast<char*>(&addr4);
  1568. where.is_unsigned = MLM_TRUE;
  1569. bind.push_back(where);
  1570. // Drop to common update code
  1571. updateLeaseCommon(stindex, &bind[0], lease);
  1572. }
  1573. void
  1574. MySqlLeaseMgr::updateLease6(const Lease6Ptr& lease) {
  1575. const StatementIndex stindex = UPDATE_LEASE6;
  1576. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1577. DHCPSRV_MYSQL_UPDATE_ADDR6).arg(lease->addr_.toText())
  1578. .arg(lease->type_);
  1579. // Create the MYSQL_BIND array for the data being updated
  1580. std::vector<MYSQL_BIND> bind = exchange6_->createBindForSend(lease);
  1581. // Set up the WHERE clause value
  1582. MYSQL_BIND where;
  1583. memset(&where, 0, sizeof(where));
  1584. std::string addr6 = lease->addr_.toText();
  1585. unsigned long addr6_length = addr6.size();
  1586. // See the earlier description of the use of "const_cast" when accessing
  1587. // the address for an explanation of the reason.
  1588. where.buffer_type = MYSQL_TYPE_STRING;
  1589. where.buffer = const_cast<char*>(addr6.c_str());
  1590. where.buffer_length = addr6_length;
  1591. where.length = &addr6_length;
  1592. bind.push_back(where);
  1593. // Drop to common update code
  1594. updateLeaseCommon(stindex, &bind[0], lease);
  1595. }
  1596. // Delete lease methods. Similar to other groups of methods, these comprise
  1597. // a per-type method that sets up the relevant MYSQL_BIND array (in this
  1598. // case, a single method for both V4 and V6 addresses) and a common method that
  1599. // handles the common processing.
  1600. uint64_t
  1601. MySqlLeaseMgr::deleteLeaseCommon(StatementIndex stindex, MYSQL_BIND* bind) {
  1602. // Bind the input parameters to the statement
  1603. int status = mysql_stmt_bind_param(conn_.statements_[stindex], bind);
  1604. checkError(status, stindex, "unable to bind WHERE clause parameter");
  1605. // Execute
  1606. status = mysql_stmt_execute(conn_.statements_[stindex]);
  1607. checkError(status, stindex, "unable to execute");
  1608. // See how many rows were affected. Note that the statement may delete
  1609. // multiple rows.
  1610. return (static_cast<uint64_t>(mysql_stmt_affected_rows(conn_.statements_[stindex])));
  1611. }
  1612. bool
  1613. MySqlLeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) {
  1614. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1615. DHCPSRV_MYSQL_DELETE_ADDR).arg(addr.toText());
  1616. // Set up the WHERE clause value
  1617. MYSQL_BIND inbind[1];
  1618. memset(inbind, 0, sizeof(inbind));
  1619. if (addr.isV4()) {
  1620. uint32_t addr4 = static_cast<uint32_t>(addr);
  1621. inbind[0].buffer_type = MYSQL_TYPE_LONG;
  1622. inbind[0].buffer = reinterpret_cast<char*>(&addr4);
  1623. inbind[0].is_unsigned = MLM_TRUE;
  1624. return (deleteLeaseCommon(DELETE_LEASE4, inbind) > 0);
  1625. } else {
  1626. std::string addr6 = addr.toText();
  1627. unsigned long addr6_length = addr6.size();
  1628. // See the earlier description of the use of "const_cast" when accessing
  1629. // the address for an explanation of the reason.
  1630. inbind[0].buffer_type = MYSQL_TYPE_STRING;
  1631. inbind[0].buffer = const_cast<char*>(addr6.c_str());
  1632. inbind[0].buffer_length = addr6_length;
  1633. inbind[0].length = &addr6_length;
  1634. return (deleteLeaseCommon(DELETE_LEASE6, inbind) > 0);
  1635. }
  1636. }
  1637. uint64_t
  1638. MySqlLeaseMgr::deleteExpiredReclaimedLeases4(const uint32_t secs) {
  1639. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1640. DHCPSRV_MYSQL_DELETE_EXPIRED_RECLAIMED4)
  1641. .arg(secs);
  1642. return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
  1643. }
  1644. uint64_t
  1645. MySqlLeaseMgr::deleteExpiredReclaimedLeases6(const uint32_t secs) {
  1646. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1647. DHCPSRV_MYSQL_DELETE_EXPIRED_RECLAIMED6)
  1648. .arg(secs);
  1649. return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
  1650. }
  1651. uint64_t
  1652. MySqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
  1653. StatementIndex statement_index) {
  1654. // Set up the WHERE clause value
  1655. MYSQL_BIND inbind[2];
  1656. memset(inbind, 0, sizeof(inbind));
  1657. // State is reclaimed.
  1658. uint32_t state = static_cast<uint32_t>(Lease::STATE_EXPIRED_RECLAIMED);
  1659. inbind[0].buffer_type = MYSQL_TYPE_LONG;
  1660. inbind[0].buffer = reinterpret_cast<char*>(&state);
  1661. inbind[0].is_unsigned = MLM_TRUE;
  1662. // Expiration timestamp.
  1663. MYSQL_TIME expire_time;
  1664. conn_.convertToDatabaseTime(time(NULL) - static_cast<time_t>(secs), expire_time);
  1665. inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
  1666. inbind[1].buffer = reinterpret_cast<char*>(&expire_time);
  1667. inbind[1].buffer_length = sizeof(expire_time);
  1668. // Get the number of deleted leases and log it.
  1669. uint64_t deleted_leases = deleteLeaseCommon(statement_index, inbind);
  1670. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1671. DHCPSRV_MYSQL_DELETED_EXPIRED_RECLAIMED)
  1672. .arg(deleted_leases);
  1673. return (deleted_leases);
  1674. }
  1675. // Miscellaneous database methods.
  1676. std::string
  1677. MySqlLeaseMgr::getName() const {
  1678. std::string name = "";
  1679. try {
  1680. name = conn_.getParameter("name");
  1681. } catch (...) {
  1682. // Return an empty name
  1683. }
  1684. return (name);
  1685. }
  1686. std::string
  1687. MySqlLeaseMgr::getDescription() const {
  1688. return (std::string("MySQL Database"));
  1689. }
  1690. std::pair<uint32_t, uint32_t>
  1691. MySqlLeaseMgr::getVersion() const {
  1692. const StatementIndex stindex = GET_VERSION;
  1693. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1694. DHCPSRV_MYSQL_GET_VERSION);
  1695. uint32_t major; // Major version number
  1696. uint32_t minor; // Minor version number
  1697. // Execute the prepared statement
  1698. int status = mysql_stmt_execute(conn_.statements_[stindex]);
  1699. if (status != 0) {
  1700. isc_throw(DbOperationError, "unable to execute <"
  1701. << conn_.text_statements_[stindex] << "> - reason: " <<
  1702. mysql_error(conn_.mysql_));
  1703. }
  1704. // Bind the output of the statement to the appropriate variables.
  1705. MYSQL_BIND bind[2];
  1706. memset(bind, 0, sizeof(bind));
  1707. bind[0].buffer_type = MYSQL_TYPE_LONG;
  1708. bind[0].is_unsigned = 1;
  1709. bind[0].buffer = &major;
  1710. bind[0].buffer_length = sizeof(major);
  1711. bind[1].buffer_type = MYSQL_TYPE_LONG;
  1712. bind[1].is_unsigned = 1;
  1713. bind[1].buffer = &minor;
  1714. bind[1].buffer_length = sizeof(minor);
  1715. status = mysql_stmt_bind_result(conn_.statements_[stindex], bind);
  1716. if (status != 0) {
  1717. isc_throw(DbOperationError, "unable to bind result set: " <<
  1718. mysql_error(conn_.mysql_));
  1719. }
  1720. // Fetch the data and set up the "release" object to release associated
  1721. // resources when this method exits then retrieve the data.
  1722. MySqlFreeResult fetch_release(conn_.statements_[stindex]);
  1723. status = mysql_stmt_fetch(conn_.statements_[stindex]);
  1724. if (status != 0) {
  1725. isc_throw(DbOperationError, "unable to obtain result set: " <<
  1726. mysql_error(conn_.mysql_));
  1727. }
  1728. return (std::make_pair(major, minor));
  1729. }
  1730. void
  1731. MySqlLeaseMgr::commit() {
  1732. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_COMMIT);
  1733. if (mysql_commit(conn_.mysql_) != 0) {
  1734. isc_throw(DbOperationError, "commit failed: " << mysql_error(conn_.mysql_));
  1735. }
  1736. }
  1737. void
  1738. MySqlLeaseMgr::rollback() {
  1739. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_ROLLBACK);
  1740. if (mysql_rollback(conn_.mysql_) != 0) {
  1741. isc_throw(DbOperationError, "rollback failed: " << mysql_error(conn_.mysql_));
  1742. }
  1743. }
  1744. void
  1745. MySqlLeaseMgr::checkError(int status, StatementIndex index,
  1746. const char* what) const {
  1747. conn_.checkError(status, index, what);
  1748. }
  1749. }; // end of isc::dhcp namespace
  1750. }; // end of isc namespace