Mercurial > code
changeset 184:4c746050969a
Add support for request (PostgreSQL done)
Task: #199
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 11 Nov 2013 18:05:47 +0100 |
parents | 73146c7c763f |
children | 523156bb3af5 |
files | C++/Driver.cpp C++/Driver.h C++/DriverPostgres.cpp C++/DriverPostgres.h |
diffstat | 4 files changed, 298 insertions(+), 17 deletions(-) [+] |
line wrap: on
line diff
--- a/C++/Driver.cpp Tue Oct 29 21:33:00 2013 +0100 +++ b/C++/Driver.cpp Mon Nov 11 18:05:47 2013 +0100 @@ -107,6 +107,82 @@ } /* -------------------------------------------------------- + * Request class + * -------------------------------------------------------- */ + +Request::Request(const std::string &command) + : m_pos(0) + , m_params(0) + , m_command(command) +{ + int i = -1; + + while ((i = command.find('#', i + 1)) != std::string::npos) + ++ m_params; +} + +Request::~Request() +{ +} + +void Request::assertCorrect() +{ + if (m_params <= 0) + throw std::runtime_error("no more arguments to set"); +} + +void Request::setValue(const std::string &value) +{ + assertCorrect(); + + m_pos = m_command.find('#', m_pos); + m_command.replace(m_pos, 1, value); + m_pos += value.length(); + m_params --; +} + +template <> +void Request::bind(bool value) +{ + setValue(bindBoolean(value)); +} + +template <> +void Request::bind(Date value) +{ + setValue(bindDate(value)); +} + +template <> +void Request::bind(double value) +{ + setValue(bindDouble(value)); +} + +template <> +void Request::bind(int value) +{ + setValue(bindInt(value)); +} + +template <> +void Request::bind(std::string value) +{ + setValue(bindString(value)); +} + +template <> +void Request::bind(const char *value) +{ + setValue(bindString(value)); +} + +Request::operator std::string() +{ + return m_command; +} + +/* -------------------------------------------------------- * Driver class * -------------------------------------------------------- */ @@ -122,3 +198,8 @@ { return m_error; } + +Query::Ptr Driver::query(Request::Ptr request) +{ + return query(static_cast<std::string>(*request)); +}
--- a/C++/Driver.h Tue Oct 29 21:33:00 2013 +0100 +++ b/C++/Driver.h Mon Nov 11 18:05:47 2013 +0100 @@ -20,9 +20,9 @@ #define _DRIVER_H_ #include <iostream> -#include <map> #include <memory> #include <string> +#include <unordered_map> #include "Date.h" @@ -71,7 +71,6 @@ }; private: - /** * Check if the request is valid and throws an exception * on error. @@ -191,6 +190,97 @@ }; /** + * @class Request + * @brief A secure helper for creating requests + * + * This helps creating class with SQL injection security and such. + */ +class Request { +public: + friend class Driver; + + using Ptr = std::shared_ptr<Request>; + +private: + size_t m_pos; + int m_params; + std::string m_command; + + void assertCorrect(); + + void setValue(const std::string &value); + +protected: + /** + * Bind a boolean. + * + * @param value the boolean + * @return the string to use + */ + virtual std::string bindBoolean(bool value) = 0; + + /** + * Bind a date. + * + * @param value the date + * @return the string to use + */ + virtual std::string bindDate(Date value) = 0; + + /** + * Bind a double. + * + * @param value the double + * @return the string to use + */ + virtual std::string bindDouble(double value) = 0; + + /** + * Bind an integer. + * + * @param value the integer + * @return the string to use + */ + virtual std::string bindInt(int value) = 0; + + /** + * Bind a string. + * + * @param value the string + * @return the string to use + */ + virtual std::string bindString(std::string value) = 0; + + /** + * Default constructor with SQL command. + * + * @param command the SQL command + */ + Request(const std::string &command); + +public: + /** + * Default destructor. + */ + virtual ~Request(); + + /** + * Bind a value. + * + * @param value the value + */ + template <typename T> + void bind(T value); + + /** + * Convert the request to string. + * + * @return the request as a string + */ + operator std::string(); +}; + +/** * @class Driver * @brief A generic SQL driver * @@ -210,8 +300,8 @@ Driver(); public: - typedef std::map<std::string, std::string> Params; - typedef std::shared_ptr<Driver> Ptr; + using Params = std::unordered_map<std::string, std::string>; + using Ptr = std::shared_ptr<Driver>; /** * Create a new Driver object, some queries need to do additional @@ -240,6 +330,15 @@ const std::string &getError() const; /** + * Wrapper for std::string variant. + * + * @param request the request to use + * @return a result + * @throw Query::Exception on failure + */ + Query::Ptr query(Request::Ptr request); + + /** * Create a synchronous connection, it waits and block until * the connection is made up to a specified timeout max. * @@ -248,6 +347,15 @@ virtual bool connect(const Params ¶ms) = 0; /** + * Prepare a request with the specified SQL command. + * + * @param command the SQL command to parse and bind + * @return a request to use with query + * @see query + */ + virtual Request::Ptr prepare(const std::string &command) = 0; + + /** * Execute a query. * * @param query the SQL command
--- a/C++/DriverPostgres.cpp Tue Oct 29 21:33:00 2013 +0100 +++ b/C++/DriverPostgres.cpp Mon Nov 11 18:05:47 2013 +0100 @@ -37,8 +37,7 @@ int idx = PQfnumber(m_result.get(), column.c_str()); long timestamp = static_cast<long>(time(0)); - try - { + try { std::ostringstream oss; std::string value, req; @@ -55,8 +54,7 @@ Query::Ptr result = m_driver->query(req); timestamp = result->get<double>(0, "RESULT"); - } - catch (...) { } + } catch (...) { } return Date(static_cast<time_t>(timestamp)); } @@ -173,6 +171,58 @@ } /* -------------------------------------------------------- + * Request PostgreSQL + * -------------------------------------------------------- */ + +RequestPostgres::RequestPostgres(const std::string &command) + : Request(command) +{ +} + +std::string RequestPostgres::bindBoolean(bool value) +{ + return (value) ? "'t'" : "'f'"; +} + +std::string RequestPostgres::bindDate(Date value) +{ + std::ostringstream oss; + + oss << "to_timestamp("; + oss << value.getTimestamp(); + oss << ")"; + + return oss.str(); +} + +std::string RequestPostgres::bindDouble(double value) +{ + return std::to_string(value); +} + +std::string RequestPostgres::bindInt(int value) +{ + return std::to_string(value); +} + +std::string RequestPostgres::bindString(std::string value) +{ + std::ostringstream oss; + + oss << "'"; + for (auto c : value) { + if (c == '\'') + oss << "\\'"; + else + oss << c; + } + + oss << "'"; + + return oss.str(); +} + +/* -------------------------------------------------------- * Driver PostgreSQL * -------------------------------------------------------- */ @@ -221,6 +271,11 @@ return true; } +Request::Ptr DriverPostgres::prepare(const std::string &command) +{ + return std::make_shared<RequestPostgres>(command); +} + Query::Ptr DriverPostgres::query(const std::string &cmd) { PGresult *info;
--- a/C++/DriverPostgres.h Tue Oct 29 21:33:00 2013 +0100 +++ b/C++/DriverPostgres.h Mon Nov 11 18:05:47 2013 +0100 @@ -24,9 +24,6 @@ #define _DRIVER_PG_H_ #include <cerrno> -#include <map> -#include <memory> -#include <string> #include <libpq-fe.h> @@ -36,8 +33,7 @@ * @class QueryPostgres * @brief Query implementation for PostgreSQL. */ -class QueryPostgres : public Query -{ +class QueryPostgres : public Query { public: struct PQQueryDeleter { @@ -117,16 +113,52 @@ }; /** + * @class RequestPostgres + * @brief Request implementation for PostgreSQL. + */ +class RequestPostgres : public Request { +protected: + /** + * @copydoc Request::bindBoolean + */ + virtual std::string bindBoolean(bool value); + + /** + * @copydoc Request::bindDate + */ + virtual std::string bindDate(Date value); + + /** + * @copydoc Request::bindDouble + */ + virtual std::string bindDouble(double value); + + /** + * @copydoc Request::bindInt + */ + virtual std::string bindInt(int value); + + /** + * @copydoc Request::bindString + */ + virtual std::string bindString(std::string value); + +public: + /** + * @copydoc Request::Request + */ + RequestPostgres(const std::string &command); +}; + +/** * @class DriverPostgres * @brief Driver implementation for PostgreSQL. */ -class DriverPostgres : public Driver -{ +class DriverPostgres : public Driver { public: friend class Driver; - struct PGDeleter - { + struct PGDeleter { void operator()(PGconn *conn) { PQfinish(conn); @@ -165,6 +197,11 @@ virtual bool connect(const Params ¶ms); /** + * @copydoc Driver::prepare + */ + virtual Request::Ptr prepare(const std::string &command); + + /** * @copydoc Driver::query */ virtual Query::Ptr query(const std::string &command);