pgsql_exchange.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. // Copyright (C) 2016 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. #ifndef PGSQL_EXCHANGE_H
  7. #define PGSQL_EXCHANGE_H
  8. #include <dhcpsrv/pgsql_connection.h>
  9. #include <vector>
  10. namespace isc {
  11. namespace dhcp {
  12. /// @brief Structure used to bind C++ input values to dynamic SQL parameters
  13. /// The structure contains three vectors which store the input values,
  14. /// data lengths, and formats. These vectors are passed directly into the
  15. /// PostgreSQL execute call.
  16. ///
  17. /// Note that the data values are stored as pointers. These pointers need to
  18. /// be valid for the duration of the PostgreSQL statement execution. In other
  19. /// words populating them with pointers to values that go out of scope before
  20. /// statement is executed is a bad idea.
  21. struct PsqlBindArray {
  22. /// @brief Vector of pointers to the data values.
  23. std::vector<const char *> values_;
  24. /// @brief Vector of data lengths for each value.
  25. std::vector<int> lengths_;
  26. /// @brief Vector of "format" for each value. A value of 0 means the
  27. /// value is text, 1 means the value is binary.
  28. std::vector<int> formats_;
  29. /// @brief Format value for text data.
  30. static const int TEXT_FMT;
  31. /// @brief Format value for binary data.
  32. static const int BINARY_FMT;
  33. /// @brief Constant string passed to DB for boolean true values.
  34. static const char* TRUE_STR;
  35. /// @brief Constant string passed to DB for boolean false values.
  36. static const char* FALSE_STR;
  37. /// @brief Fetches the number of entries in the array.
  38. /// @return Returns size_t containing the number of entries.
  39. size_t size() const {
  40. return (values_.size());
  41. }
  42. /// @brief Indicates it the array is empty.
  43. /// @return Returns true if there are no entries in the array, false
  44. /// otherwise.
  45. bool empty() const {
  46. return (values_.empty());
  47. }
  48. /// @brief Adds a char array to bind array based
  49. ///
  50. /// Adds a TEXT_FMT value to the end of the bind array, using the given
  51. /// char* as the data source. Note that value is expected to be NULL
  52. /// terminated.
  53. ///
  54. /// @param value char array containing the null-terminated text to add.
  55. void add(const char* value);
  56. /// @brief Adds an string value to the bind array
  57. ///
  58. /// Adds a TEXT formatted value to the end of the bind array using the
  59. /// given string as the data source.
  60. ///
  61. /// @param value std::string containing the value to add.
  62. void add(const std::string& value);
  63. /// @brief Adds a binary value to the bind array.
  64. ///
  65. /// Adds a BINARY_FMT value to the end of the bind array using the
  66. /// given vector as the data source.
  67. ///
  68. /// @param data vector of binary bytes.
  69. void add(const std::vector<uint8_t>& data);
  70. /// @brief Adds a boolean value to the bind array.
  71. ///
  72. /// Converts the given boolean value to its corresponding to PostgreSQL
  73. /// string value and adds it as a TEXT_FMT value to the bind array.
  74. ///
  75. /// @param value bool value to add.
  76. void add(const bool& value);
  77. /// @brief Dumps the contents of the array to a string.
  78. /// @return std::string containing the dump
  79. std::string toText() const;
  80. };
  81. /// @brief Base class for marshalling data to and from PostgreSQL.
  82. ///
  83. /// Provides the common functionality to set up binding information between
  84. /// application objects in the program and their representation in the
  85. /// database, and for retrieving column values from rows of a result set.
  86. class PgSqlExchange {
  87. public:
  88. /// @brief Constructor
  89. PgSqlExchange(){}
  90. /// @brief Destructor
  91. virtual ~PgSqlExchange(){}
  92. /// @brief Converts time_t value to a text representation in local time.
  93. ///
  94. /// @param input_time A time_t value representing time.
  95. /// @return std::string containing stringified time.
  96. static std::string convertToDatabaseTime(const time_t input_time);
  97. /// @brief Converts lease expiration time to a text representation in
  98. /// local time.
  99. ///
  100. /// The expiration time is calculated as a sum of the cltt (client last
  101. /// transmit time) and the valid lifetime.
  102. ///
  103. /// The format of the output string is "%Y-%m-%d %H:%M:%S". Database
  104. /// table columns using this value should be typed as TIMESTAMP WITH
  105. /// TIME ZONE. For such columns PostgreSQL assumes input strings without
  106. /// timezones should be treated as in local time and are converted to UTC
  107. /// when stored. Likewise, these columns are automatically adjusted
  108. /// upon retrieval unless fetched via "extract(epoch from <column>))".
  109. ///
  110. /// Unless we start using binary input, timestamp columns must be input as
  111. /// date/time strings.
  112. ///
  113. /// @param cltt Client last transmit time
  114. /// @param valid_lifetime Valid lifetime
  115. ///
  116. /// @return std::string containing the stringified time
  117. /// @throw isc::BadValue if the sum of the calculated expiration time is
  118. /// greater than the value of @c DataSource::MAX_DB_TIME.
  119. static std::string convertToDatabaseTime(const time_t cltt,
  120. const uint32_t valid_lifetime);
  121. /// @brief Converts time stamp from the database to a time_t
  122. ///
  123. /// We're fetching timestamps as an integer string of seconds since the
  124. /// epoch. This method converts such a string int a time_t.
  125. ///
  126. /// @param db_time_val timestamp to be converted. This value
  127. /// is expected to be the number of seconds since the epoch
  128. /// expressed as base-10 integer string.
  129. /// @return Converted timestamp as time_t value.
  130. static time_t convertFromDatabaseTime(const std::string& db_time_val);
  131. /// @brief Gets a pointer to the raw column value in a result set row
  132. ///
  133. /// Given a result set, row, and column return a const char* pointer to
  134. /// the data value in the result set. The pointer is valid as long as
  135. /// the result set has not been freed. It may point to text or binary
  136. /// data depending on how query was structured. You should not attempt
  137. /// to free this pointer.
  138. ///
  139. /// @param r the result set containing the query results
  140. /// @param row the row number within the result set
  141. /// @param col the column number within the row
  142. ///
  143. /// @return a const char* pointer to the column's raw data
  144. /// @throw DbOperationError if the value cannot be fetched.
  145. const char* getRawColumnValue(const PgSqlResult& r, const int row,
  146. const size_t col) const;
  147. /// @brief Fetches boolean text ('t' or 'f') as a bool.
  148. ///
  149. /// @param r the result set containing the query results
  150. /// @param row the row number within the result set
  151. /// @param col the column number within the row
  152. /// @param[out] value parameter to receive the converted value
  153. ///
  154. /// @throw DbOperationError if the value cannot be fetched or is
  155. /// invalid.
  156. void getColumnValue(const PgSqlResult& r, const int row, const size_t col,
  157. bool &value) const;
  158. /// @brief Fetches an integer text column as a uint32_t.
  159. ///
  160. /// @param r the result set containing the query results
  161. /// @param row the row number within the result set
  162. /// @param col the column number within the row
  163. /// @param[out] value parameter to receive the converted value
  164. ///
  165. /// @throw DbOperationError if the value cannot be fetched or is
  166. /// invalid.
  167. void getColumnValue(const PgSqlResult& r, const int row, const size_t col,
  168. uint32_t &value) const;
  169. /// @brief Fetches an integer text column as a int32_t.
  170. ///
  171. /// @param r the result set containing the query results
  172. /// @param row the row number within the result set
  173. /// @param col the column number within the row
  174. /// @param[out] value parameter to receive the converted value
  175. ///
  176. /// @throw DbOperationError if the value cannot be fetched or is
  177. /// invalid.
  178. void getColumnValue(const PgSqlResult& r, const int row, const size_t col,
  179. int32_t &value) const;
  180. /// @brief Fetches an integer text column as a uint8_t.
  181. ///
  182. /// @param r the result set containing the query results
  183. /// @param row the row number within the result set
  184. /// @param col the column number within the row
  185. /// @param[out] value parameter to receive the converted value
  186. ///
  187. /// @throw DbOperationError if the value cannot be fetched or is
  188. /// invalid.
  189. void getColumnValue(const PgSqlResult& r, const int row, const size_t col,
  190. uint8_t &value) const;
  191. /// @brief Converts a column in a row in a result set to a binary bytes
  192. ///
  193. /// Method is used to convert columns stored as BYTEA into a buffer of
  194. /// binary bytes, (uint8_t). It uses PQunescapeBytea to do the conversion.
  195. ///
  196. /// @param r the result set containing the query results
  197. /// @param row the row number within the result set
  198. /// @param col the column number within the row
  199. /// @param[out] buffer pre-allocated buffer to which the converted bytes
  200. /// will be stored.
  201. /// @param buffer_size size of the output buffer
  202. /// @param[out] bytes_converted number of bytes converted
  203. /// value
  204. ///
  205. /// @throw DbOperationError if the value cannot be fetched or is
  206. /// invalid.
  207. void convertFromBytea(const PgSqlResult& r, const int row, const size_t col,
  208. uint8_t* buffer, const size_t buffer_size,
  209. size_t &bytes_converted) const;
  210. /// @brief Returns column label given a column number
  211. std::string getColumnLabel(const size_t column) const;
  212. protected:
  213. /// @brief Stores text labels for columns, currently only used for
  214. /// logging and errors.
  215. std::vector<std::string>column_labels_;
  216. };
  217. }; // end of isc::dhcp namespace
  218. }; // end of isc namespace
  219. #endif // PGSQL_EXCHANGE_H