changeset 214:6c49e5e3ecc8

Driver: now data is shared internally
author David Demelier <markand@malikania.fr>
date Tue, 25 Mar 2014 20:42:11 +0100
parents 1829c4266bee
children 5bb5712d400f
files C++/Driver.cpp C++/Driver.h C++/DriverPostgres.cpp C++/DriverPostgres.h
diffstat 4 files changed, 641 insertions(+), 555 deletions(-) [+]
line wrap: on
line diff
--- a/C++/Driver.cpp	Mon Mar 24 13:54:28 2014 +0100
+++ b/C++/Driver.cpp	Tue Mar 25 20:42:11 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * Driver.cpp -- generic SQL driver access
  *
- * Copyright (c) 2013, David Demelier <markand@malikania.fr>
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -16,31 +16,20 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <map>
-#include <string>
 #include <sstream>
 
 #include "Driver.h"
 
 /* ---------------------------------------------------------
- * Query::Error class
- * --------------------------------------------------------- */
+ * DriverQuery class
+ * ---------------------------------------------------------*/
 
-Query::Error::Error(const std::string &error)
-	: m_error(error)
+DriverQuery::DriverQuery(Ptr impl)
+	: m_impl(impl)
 {
 }
 
-const char *Query::Error::Error::what() const throw()
-{
-	return m_error.c_str();
-}
-
-/* ---------------------------------------------------------
- * Query class
- * ---------------------------------------------------------*/
-
-void Query::assertRequest(int row, const std::string &column, ColumnType wanted)
+void DriverQuery::assertRequest(int row, const std::string &column, DriverColumn wanted)
 {
 	std::ostringstream oss;
 
@@ -49,69 +38,55 @@
 		oss << "Invalid row index " << row;
 		oss << ", expected [0.." << countRows() << "]";
 
-		throw Error(oss.str());
+		throw std::runtime_error(oss.str());
 	}
 
 	// Not found or bad column?
 	if (type(column) != wanted) {
 		oss << "Invalid or not found column `" << column << "'";
 
-		throw Error(oss.str());
+		throw std::runtime_error(oss.str());
 	}
 }
 
-Query::~Query()
+DriverQuery::~DriverQuery()
 {
 }
 
-template <>
-bool Query::get(int row, const std::string &column)
+DriverColumn DriverQuery::type(const std::string &column) const
 {
-	assertRequest(row, column, ColumnType::Boolean);
-
-	return getBoolean(row, column);
+	return m_impl->type(column);
 }
 
-template <>
-Date Query::get(int row, const std::string &column)
+int DriverQuery::countRows()
 {
-	assertRequest(row, column, ColumnType::Date);
-
-	return getDate(row, column);
+	return m_impl->countRows();
 }
 
-template <>
-double Query::get(int row, const std::string &column)
+int DriverQuery::countColumns()
 {
-	assertRequest(row, column, ColumnType::Double);
-
-	return getDouble(row, column);
+	return m_impl->countColumns();
 }
 
-template <>
-int Query::get(int row, const std::string &column)
+bool DriverQuery::isNull(int row, const std::string &column)
 {
-	assertRequest(row, column, ColumnType::Integer);
-
-	return getInt(row, column);
+	return m_impl->isNull(row, column);
 }
 
-template <>
-std::string Query::get(int row, const std::string &column)
+void DriverQuery::dump()
 {
-	assertRequest(row, column, ColumnType::String);
-
-	return getString(row, column);
+	m_impl->dump();
 }
 
 /* --------------------------------------------------------
- * Request class
+ * DriverRequest class
  * -------------------------------------------------------- */
 
-Request::Request(const std::string &command)
+DriverRequest::DriverRequest(Ptr impl, const std::string &command)
 	: m_pos(0)
 	, m_params(0)
 	, m_command(command)
+	, m_impl(impl)
 {
 	int i = -1;
 
@@ -119,17 +94,17 @@
 		++ m_params;
 }
 
-Request::~Request()
+DriverRequest::~DriverRequest()
 {
 }
 
-void Request::assertCorrect()
+void DriverRequest::assertCorrect()
 {
 	if (m_params <= 0)
 		throw std::runtime_error("no more arguments to set");
 }
 
-void Request::setValue(const std::string &value)
+void DriverRequest::setValue(const std::string &value)
 {
 	assertCorrect();
 
@@ -139,43 +114,7 @@
 	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()
+DriverRequest::operator std::string()
 {
 	return m_command;
 }
@@ -184,20 +123,32 @@
  * Driver class
  * -------------------------------------------------------- */
 
-Driver::Driver()
+void Driver::connect(const Params &params)
 {
+	m_impl->connect(params);
 }
 
-Driver::~Driver()
+DriverRequest Driver::prepare(const std::string &command)
 {
+	return m_impl->prepare(command);
+}
+
+DriverQuery Driver::query(const std::string &sql)
+{
+	return m_impl->query(sql);
 }
 
-const std::string &Driver::getError() const
+DriverQuery Driver::query(DriverRequest request)
 {
-	return m_error;
+	return query(static_cast<std::string>(request));
 }
 
-Query::Ptr Driver::query(Request::Ptr request)
+std::string Driver::description() const
 {
-	return query(static_cast<std::string>(*request));
+	return m_impl->description();
 }
+
+std::string Driver::version() const
+{
+	return m_impl->version();
+}
--- a/C++/Driver.h	Mon Mar 24 13:54:28 2014 +0100
+++ b/C++/Driver.h	Tue Mar 25 20:42:11 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * Driver.h -- generic SQL driver access
  *
- * Copyright (c) 2013, David Demelier <markand@malikania.fr>
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -19,20 +19,19 @@
 #ifndef _DRIVER_H_
 #define _DRIVER_H_
 
-#include <iostream>
+#include <ctime>
 #include <memory>
 #include <string>
 #include <unordered_map>
-
-#include "Date.h"
+#include <type_traits>
 
 /**
- * @enum ColumnType
+ * @enum DriverColumn
  * @brief The column type request
  *
  * Used for the drivers.
  */
-enum class ColumnType {
+enum class DriverColumn {
 	Invalid,			//! not found
 	Boolean,			//! bool or 0 / 1
 	Date,				//! date see Common/Date.h
@@ -41,6 +40,9 @@
 	String,				//! varchar to std::string
 };
 
+template <typename T>
+struct DriverTypeInfo : std::false_type { };
+
 /**
  * @class Query
  * @brief Class for querying the database
@@ -51,24 +53,101 @@
  *
  * @see Driver::query
  */
-class Query {
+class DriverQuery {
 public:
-	using Ptr = std::shared_ptr<Query>;
+	friend struct DriverTypeInfo<bool>;
+	friend struct DriverTypeInfo<time_t>;
+	friend struct DriverTypeInfo<double>;
+	friend struct DriverTypeInfo<int>;
+	friend struct DriverTypeInfo<std::string>;
+
+	class Impl {
+	public:
+		/**
+		 * Get a bool.
+		 *
+		 * @param row the row number
+		 * @param column the column
+		 * @return the value
+		 */
+		virtual bool getBoolean(int row, const std::string &column) = 0;
+
+		/**
+		 * Get a Date.
+		 *
+		 * @param row the row number
+		 * @param column the column
+		 * @return the value
+		 */
+		virtual time_t getDate(int row, const std::string &column) = 0;
+
+		/**
+		 * Get a double.
+		 *
+		 * @param row the row number
+		 * @param column the column
+		 * @return the value
+		 */
+		virtual double getDouble(int row, const std::string &column) = 0;
+
+		/**
+		 * Get a integer.
+		 *
+		 * @param row the row number
+		 * @param column the column
+		 * @return the value
+		 */
+		virtual int getInt(int row, const std::string &column) = 0;
 
-	/**
-	 * @class Error
-	 * @brief Query exception on query error
-	 */
-	class Error : public std::exception {
-	private:
-		std::string m_error;
+		/**
+		 * Get a string.
+		 *
+		 * @param row the row number
+		 * @param column the column
+		 * @return the value
+		 */
+		virtual std::string getString(int row, const std::string &column) = 0;
+
+		/**
+		 * Returns the type of a named column.
+		 *
+		 * @param column the column name
+		 * @return the type
+		 */
+		virtual DriverColumn type(const std::string &column) const = 0;
+
+		/**
+		 * Tells how many rows has been fetched.
+		 *
+		 * @return the number of rows
+		 */
+		virtual int countRows() = 0;
 
-	public:
-		Error(const std::string &error);
+		/**
+		 * Tells how many number of columns are present for each
+		 * row.
+		 *
+		 * @return the number of columns
+		 */
+		virtual int countColumns() = 0;
 
-		virtual const char *what() const throw();
+		/**
+		 * Tells if the column is null or not.
+		 *
+		 * @param row the row number
+		 * @param column the column
+		 * @return an true if null
+		 */
+		virtual bool isNull(int row, const std::string &column) = 0;
+
+		/**
+		 * Dump all rows and columns.
+		 */
+		virtual void dump() = 0;
 	};
 
+	using Ptr	= std::shared_ptr<Impl>;
+
 private:
 	/**
 	 * Check if the request is valid and throws an exception
@@ -79,59 +158,18 @@
 	 * @param type
 	 * @throw Error on error
 	 */
-	void assertRequest(int row, const std::string &column, ColumnType type);
+	void assertRequest(int row, const std::string &column, DriverColumn type);
 
 protected:
-	/**
-	 * Get a bool.
-	 *
-	 * @param row the row number
-	 * @param column the column
-	 * @return the value
-	 */
-	virtual bool getBoolean(int row, const std::string &column) = 0;
-
-	/**
-	 * Get a Date.
-	 *
-	 * @param row the row number
-	 * @param column the column
-	 * @return the value
-	 */
-	virtual Date getDate(int row, const std::string &column) = 0;
-
-	/**
-	 * Get a double.
-	 *
-	 * @param row the row number
-	 * @param column the column
-	 * @return the value
-	 */
-	virtual double getDouble(int row, const std::string &column) = 0;
-
-	/**
-	 * Get a integer.
-	 *
-	 * @param row the row number
-	 * @param column the column
-	 * @return the value
-	 */
-	virtual int getInt(int row, const std::string &column) = 0;
-
-	/**
-	 * Get a string.
-	 *
-	 * @param row the row number
-	 * @param column the column
-	 * @return the value
-	 */
-	virtual std::string getString(int row, const std::string &column) = 0;
+	Ptr		m_impl;
 
 public:
+	DriverQuery(Ptr impl);
+
 	/**
 	 * Default destructor.
 	 */
-	virtual ~Query();
+	virtual ~DriverQuery();
 
 	/**
 	 * Get a variable from a row and column.
@@ -149,7 +187,14 @@
 	 * @throw Query::Error on error
 	 */
 	template <class T>
-	T get(int row, const std::string &column);
+	T get(int row, const std::string &column)
+	{
+		static_assert(DriverTypeInfo<T>::value, "unsupported type");
+
+		assertRequest(row, column, DriverTypeInfo<T>::type);
+	
+		return DriverTypeInfo<T>::get(*this, row, column);
+	}
 
 	/**
 	 * Returns the type of a named column.
@@ -157,14 +202,14 @@
 	 * @param column the column name
 	 * @return the type
 	 */
-	virtual ColumnType type(const std::string &column) const = 0;
+	DriverColumn type(const std::string &column) const;
 
 	/**
 	 * Tells how many rows has been fetched.
 	 *
 	 * @return the number of rows
 	 */
-	virtual int countRows() = 0;
+	int countRows();
 
 	/**
 	 * Tells how many number of columns are present for each
@@ -172,7 +217,7 @@
 	 *
 	 * @return the number of columns
 	 */
-	virtual int countColumns() = 0;
+	int countColumns();
 
 	/**
 	 * Tells if the column is null or not.
@@ -181,12 +226,12 @@
 	 * @param column the column
 	 * @return an true if null
 	 */
-	virtual bool isNull(int row, const std::string &column) = 0;
+	bool isNull(int row, const std::string &column);
 
 	/**
 	 * Dump all rows and columns.
 	 */
-	virtual void dump() = 0;
+	void dump();
 };
 
 /**
@@ -195,74 +240,76 @@
  *
  * This helps creating class with SQL injection security and such.
  */
-class Request {
+class DriverRequest {
 public:
-	friend class Driver;
+	friend struct DriverTypeInfo<bool>;
+	friend struct DriverTypeInfo<time_t>;
+	friend struct DriverTypeInfo<double>;
+	friend struct DriverTypeInfo<int>;
+	friend struct DriverTypeInfo<std::string>;
+
+	class Impl {
+	public:
+		/**
+		 * 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(time_t value) = 0;
 
-	using Ptr	= std::shared_ptr<Request>;
+		/**
+		 * 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 bindInteger(int value) = 0;
+
+		/**
+		 * Bind a string.
+		 *
+		 * @param value the string
+		 * @return the string to use
+		 */
+		virtual std::string bindString(std::string value) = 0;
+	};
+
+	using Ptr	= std::shared_ptr<Impl>;
 
 private:
 	size_t		m_pos;
 	int		m_params;
 	std::string	m_command;
+	Ptr		m_impl;
 
 	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;
+public:
+	DriverRequest(Ptr impl, const std::string &command);
 
 	/**
-	 * 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();
+	virtual ~DriverRequest();
 
 	/**
 	 * Bind a value.
@@ -270,7 +317,12 @@
 	 * @param value the value
 	 */
 	template <typename T>
-	void bind(T value);
+	void bind(T value)
+	{
+		static_assert(DriverTypeInfo<T>::value, "unsupported type");
+
+		setValue(DriverTypeInfo<T>::bind(value));
+	}
 
 	/**
 	 * Convert the request to string.
@@ -288,46 +340,66 @@
  * does not include any DBMS code and just call virtual functions for
  * a simpler integration of new DBMS drivers.
  */
-class Driver : public std::enable_shared_from_this<Driver> {
-protected:
-	std::string m_error;
+class Driver {
+public:
+	class Impl;
+
+	using Params	= std::unordered_map<std::string, std::string>;
+	using Ptr	= std::shared_ptr<Impl>;
+
+	class Impl {
+	public:
+		/**
+		 * Create a synchronous connection, it waits and block until
+		 * the connection is made up to a specified timeout max.
+		 *
+		 * @param params a list of parameters.
+		 */
+		virtual void connect(const Params &params) = 0;
 
-	/**
-	 * Default constructor. Should not be used.
-	 *
-	 * @see Driver::create
-	 */
-	Driver();
+		/**
+		 * 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 DriverRequest prepare(const std::string &command) = 0;
+	
+		/**
+		 * Execute a query.
+		 *
+		 * @param query the SQL command
+		 * @return a result
+		 * @throw Query::Error on failure
+		 */
+		virtual DriverQuery query(const std::string &command) = 0;
+
+		/**
+		 * Get the driver connection description.
+		 *
+		 * @return the description
+		 */
+		virtual std::string description() const = 0;
+
+		/**
+		 * Get the driver version as a string.
+		 *
+		 * @return the version
+		 */
+		virtual std::string version() const = 0;
+	};
+
+protected:
+	Ptr		m_impl;
 
 public:
-	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
-	 * internal requests so it's easier to use shared_ptr.
-	 *
-	 * @return a shared_ptr
-	 */
-	template <class T>
-	static Ptr create()
-	{
-		T *t = new T();
-
-		return std::shared_ptr<T>(t);
-	}
+	Driver() = default;
 
 	/**
 	 * Virtual destructor.
 	 */
-	virtual ~Driver();
-
-	/**
-	 * Get the error.
-	 *
-	 * @return the error
-	 */
-	const std::string &getError() const;
+	virtual ~Driver() = default;
 
 	/**
 	 * Wrapper for std::string variant.
@@ -336,7 +408,7 @@
 	 * @return a result
 	 * @throw Query::Error on failure
 	 */
-	Query::Ptr query(Request::Ptr request);
+	DriverQuery query(DriverRequest request);
 
 	/**
 	 * Create a synchronous connection, it waits and block until
@@ -344,7 +416,7 @@
 	 *
 	 * @param params a list of parameters.
 	 */
-	virtual bool connect(const Params &params) = 0;
+	void connect(const Params &params);
 
 	/**
 	 * Prepare a request with the specified SQL command.
@@ -353,7 +425,7 @@
 	 * @return a request to use with query
 	 * @see query
 	 */
-	virtual Request::Ptr prepare(const std::string &command) = 0;
+	DriverRequest prepare(const std::string &command);
 
 	/**
 	 * Execute a query.
@@ -362,21 +434,97 @@
 	 * @return a result
 	 * @throw Query::Error on failure
 	 */
-	virtual Query::Ptr query(const std::string &command) = 0;
+	DriverQuery query(const std::string &command);
 
 	/**
 	 * Get the driver connection description.
 	 *
 	 * @return the description
 	 */
-	virtual std::string description() const = 0;
+	std::string description() const;
 
 	/**
 	 * Get the driver version as a string.
 	 *
 	 * @return the version
 	 */
-	virtual std::string version() const = 0;
+	std::string version() const;
+};
+
+template <>
+struct DriverTypeInfo<bool> : std::true_type {
+	static const DriverColumn	type = DriverColumn::Boolean;
+
+	static bool get(DriverQuery &query, int row, const std::string &column)
+	{
+		return query.m_impl->getBoolean(row, column);
+	}
+
+	static void bind(DriverRequest &request, bool value)
+	{
+		request.m_impl->bindBoolean(value);
+	}
+};
+
+template <>
+struct DriverTypeInfo<time_t> : std::true_type {
+	static const DriverColumn	type = DriverColumn::Date;
+
+	static time_t get(DriverQuery &query, int row, const std::string &column)
+	{
+		return query.m_impl->getDate(row, column);
+	}
+
+	static void bind(DriverRequest &request, time_t value)
+	{
+		request.m_impl->bindDate(value);
+	}
 };
 
+template <>
+struct DriverTypeInfo<double> : std::true_type {
+	static const DriverColumn	type = DriverColumn::Double;
+
+	static double get(DriverQuery &query, int row, const std::string &column)
+	{
+		return query.m_impl->getDouble(row, column);
+	}
+
+	static void bind(DriverRequest &request, double value)
+	{
+		request.m_impl->bindDouble(value);
+	}
+};
+
+template <>
+struct DriverTypeInfo<int> : std::true_type {
+	static const DriverColumn	type = DriverColumn::Integer;
+
+	static int get(DriverQuery &query, int row, const std::string &column)
+	{
+		return query.m_impl->getInt(row, column);
+	}
+
+	static void bind(DriverRequest &request, int value)
+	{
+		request.m_impl->bindInteger(value);
+	}
+};
+
+template <>
+struct DriverTypeInfo<std::string> : std::true_type {
+	static const DriverColumn	type = DriverColumn::String;
+
+	static std::string get(DriverQuery &query, int row, const std::string &column)
+	{
+		return query.m_impl->getString(row, column);
+	}
+
+	static void bind(DriverRequest &request, const std::string &value)
+	{
+		request.m_impl->bindString(value);
+	}
+};
+
+
 #endif // !_DRIVER_H_
--- a/C++/DriverPostgres.cpp	Mon Mar 24 13:54:28 2014 +0100
+++ b/C++/DriverPostgres.cpp	Tue Mar 25 20:42:11 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DriverPostgres.cpp -- PostgreSQL driver
  *
- * Copyright (c) 2013, David Demelier <markand@malikania.fr>
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -16,140 +16,164 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <iostream>
 #include <sstream>
+#include <vector>
 
 #include "DriverPostgres.h"
 
-/* --------------------------------------------------------
- * Query PostgreSQL (protected methods)
- * -------------------------------------------------------- */
+namespace {
+
+struct PGConnDeleter {
+	void operator()(PGconn *conn)
+	{
+		PQfinish(conn);
+	}
+};
 
-bool QueryPostgres::getBoolean(int row, const std::string &column)
-{
-	int idx = PQfnumber(m_result.get(), column.c_str());
-	std::string code = PQgetvalue(m_result.get(), row, idx);
+struct PGQueryDeleter {
+	void operator()(PGresult *result)
+	{
+		PQclear(result);
+	}
+};
 
-	return code[0] == 't';
+using PostgresResult	= std::shared_ptr<PGresult>;
+using PostgresConn	= std::shared_ptr<PGconn>;
+
 }
 
-Date QueryPostgres::getDate(int row, const std::string &column)
-{
-	int idx = PQfnumber(m_result.get(), column.c_str());
-	long timestamp = static_cast<long>(time(0));
-
-	try {
-		std::ostringstream oss;
-		std::string value, req;
-
-		value = PQgetvalue(m_result.get(), row, idx);
+/**
+ * @class QueryPostgres
+ * @brief Query implementation for PostgreSQL.
+ */
+class QueryPostgresImpl : public DriverQuery::Impl {
+private:
+	PostgresConn	m_connection;
+	PostgresResult	m_result;
 
-		/*
-		 * Convert the date using the SQL function so that user does
-		 * not require any explicit conversion itself.
-		 */
-		oss << "Select EXTRACT(EPOCH FROM TIMESTAMP '";
-		oss << value;
-		oss << "') AS RESULT";
-		req = oss.str();
+public:
+	/**
+	 * Constructor used by DriverPostgres
+	 *
+	 * @param result the result
+	 */
+	QueryPostgresImpl(PostgresConn conn, PostgresResult result);
 
-		Query::Ptr result = m_driver->query(req);
-		timestamp = result->get<double>(0, "RESULT");
-	} catch (...) { }
+	/**
+	 * @copydoc Query::getBoolean
+	 */
+	virtual bool getBoolean(int row, const std::string &column);
 
-	return Date(static_cast<time_t>(timestamp));
-}
+	/**
+	 * @copydoc Query::getDate
+	 */
+	virtual time_t getDate(int row, const std::string &column);
+
+	/**
+	 * @copydoc Query::getDouble
+	 */
+	virtual double getDouble(int row, const std::string &column);
 
-double QueryPostgres::getDouble(int row, const std::string &column)
-{
-	int idx = PQfnumber(m_result.get(), column.c_str());
+	/**
+	 * @copydoc Query::getInt
+	 */
+	virtual int getInt(int row, const std::string &column);
 
-	return std::stod(PQgetvalue(m_result.get(), row, idx));
-}
+	/**
+	 * @copydoc Query::getString
+	 */
+	virtual std::string getString(int row, const std::string &column);
 
-int QueryPostgres::getInt(int row, const std::string &column)
-{
-	int idx = PQfnumber(m_result.get(), column.c_str());
+	/**
+	 * @copydoc Query::type
+	 */
+	virtual DriverColumn type(const std::string &column) const;
 
-	return std::stoi(PQgetvalue(m_result.get(), row, idx));
-}
+	/**
+	 * @copydoc Query::countRows
+	 */
+	virtual int countRows();
 
-std::string QueryPostgres::getString(int row, const std::string &column)
-{
-	int idx = PQfnumber(m_result.get(), column.c_str());
+	/**
+	 * @copydoc Query::countColumns
+	 */
+	virtual int countColumns();
 
-	return std::string(PQgetvalue(m_result.get(), row, idx));
-}
+	/**
+	 * @copydoc Query::isNull
+	 */
+	virtual bool isNull(int row, const std::string &column);
 
-/* --------------------------------------------------------
- * Query PostgreSQL (public methods)
- * -------------------------------------------------------- */
+	/**
+	 * @copydoc Query::dump
+	 */
+	virtual void dump();
+};
 
-QueryPostgres::QueryPostgres(Driver::Ptr driver, PostgresResult result)
-{
-	m_driver = driver;
-	m_result = std::move(result);
-}
-
-QueryPostgres::~QueryPostgres()
+QueryPostgresImpl::QueryPostgresImpl(PostgresConn conn, PostgresResult result)
+	: m_connection(conn)
+	, m_result(result)
 {
 }
 
-ColumnType QueryPostgres::type(const std::string &column) const
+DriverColumn QueryPostgresImpl::type(const std::string &column) const
 {
-	ColumnType type;
+	DriverColumn type;
 	int pqType, index;
 	
 	index = PQfnumber(m_result.get(), column.c_str());
 	pqType = PQftype(m_result.get(), index);
 	switch (pqType) {
 	case 16:
-		type = ColumnType::Boolean;
+		type = DriverColumn::Boolean;
 		break;
 	case 1082:
 	case 1083:
 	case 1114:
-		type = ColumnType::Date;
+	case 1184:
+		type = DriverColumn::Date;
 		break;
 	case 1700:
 	case 700:
 	case 701:
-		type = ColumnType::Double;
+		type = DriverColumn::Double;
 		break;
 	case 20:
 	case 21:
 	case 23:
-		type = ColumnType::Integer;
+		type = DriverColumn::Integer;
 		break;
 	case 25:
 	case 1042:
 	case 1043:
-		type = ColumnType::String;
+		type = DriverColumn::String;
 		break;
 	default:
-		type = ColumnType::Invalid;
+		type = DriverColumn::Invalid;
 	}
 
 	return type;
 }
 
-int QueryPostgres::countRows()
+int QueryPostgresImpl::countRows()
 {
 	return PQntuples(m_result.get());
 }
 
-int QueryPostgres::countColumns()
+int QueryPostgresImpl::countColumns()
 {
 	return PQnfields(m_result.get());
 }
 
-bool QueryPostgres::isNull(int row, const std::string &column)
+bool QueryPostgresImpl::isNull(int row, const std::string &column)
 {
 	int idx = PQfnumber(m_result.get(), column.c_str());
 
 	return PQgetisnull(m_result.get(), row, idx) == 1;
 }
 
-void QueryPostgres::dump(void)
+void QueryPostgresImpl::dump(void)
 {
 	std::cout << "Dumping PostgreSQL result, ";
 	std::cout << countRows() << " rows, ";
@@ -166,12 +190,120 @@
 	}
 }
 
+bool QueryPostgresImpl::getBoolean(int row, const std::string &column)
+{
+	int idx = PQfnumber(m_result.get(), column.c_str());
+	std::string code = PQgetvalue(m_result.get(), row, idx);
+
+	return code[0] == 't';
+}
+
+time_t QueryPostgresImpl::getDate(int row, const std::string &column)
+{
+	int idx = PQfnumber(m_result.get(), column.c_str());
+	time_t timestamp = std::time(nullptr);
+
+	try {
+		std::ostringstream oss;
+		std::string value, req;
+
+		value = PQgetvalue(m_result.get(), row, idx);
+
+		/*
+		 * Convert the date using the SQL function so that user does
+		 * not require any explicit conversion itself.
+		 */
+		printf("%s\n", value.c_str());
+		oss << "Select EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE '";
+		oss << value;
+		oss << "') AS RESULT";
+		req = oss.str();
+
+		auto info = PQexec(m_connection.get(), oss.str().c_str());
+		auto status = PQresultStatus(info);
+
+		if (info != nullptr && (status == PGRES_COMMAND_OK ||
+		    status == PGRES_TUPLES_OK))
+		{
+			puts("SUCESS");
+			timestamp = atoi(PQgetvalue(info, 0, 0));
+			PQclear(info);
+		}
+	} catch (...) { }
+
+	return timestamp;
+}
+
+double QueryPostgresImpl::getDouble(int row, const std::string &column)
+{
+	int idx = PQfnumber(m_result.get(), column.c_str());
+
+	return std::stod(PQgetvalue(m_result.get(), row, idx));
+}
+
+int QueryPostgresImpl::getInt(int row, const std::string &column)
+{
+	int idx = PQfnumber(m_result.get(), column.c_str());
+
+	return std::stoi(PQgetvalue(m_result.get(), row, idx));
+}
+
+std::string QueryPostgresImpl::getString(int row, const std::string &column)
+{
+	int idx = PQfnumber(m_result.get(), column.c_str());
+
+	return std::string(PQgetvalue(m_result.get(), row, idx));
+}
+
 /* --------------------------------------------------------
- * Request PostgreSQL
+ * Request PostgreSQL Impl
  * -------------------------------------------------------- */
 
-RequestPostgres::RequestPostgres(std::shared_ptr<PGconn> conn, const std::string &command)
-	: Request(command)
+/**
+ * @class RequestPostgres
+ * @brief Request implementation for PostgreSQL.
+ */
+class RequestPostgres : public DriverRequest::Impl {
+private:
+	std::shared_ptr<PGconn> m_connection;
+
+protected:
+	/**
+	 * @copydoc Request::bindBoolean
+	 */
+	virtual std::string bindBoolean(bool value);
+
+	/**
+	 * @copydoc Request::bindDate
+	 */
+	virtual std::string bindDate(time_t value);
+
+	/**
+	 * @copydoc Request::bindDouble
+	 */
+	virtual std::string bindDouble(double value);
+
+	/**
+	 * @copydoc Request::bindInteger
+	 */
+	virtual std::string bindInteger(int value);
+
+	/**
+	 * @copydoc Request::bindString
+	 */
+	virtual std::string bindString(std::string value);
+
+public:
+	/**
+	 * Construct a request for PostgreSQL.
+	 *
+	 * @param conn the connection
+	 * @param command the command
+	 */
+	RequestPostgres(PostgresConn &conn);
+};
+
+RequestPostgres::RequestPostgres(PostgresConn &conn)
 {
 	m_connection = conn;
 }
@@ -181,13 +313,11 @@
 	return (value) ? "'t'" : "'f'";
 }
 
-std::string RequestPostgres::bindDate(Date value)
+std::string RequestPostgres::bindDate(time_t value)
 {
 	std::ostringstream oss;
 
-	oss << "to_timestamp(";
-	oss << value.getTimestamp();
-	oss << ")";
+	oss << "to_timestamp(" << value << ")";
 
 	return oss.str();
 }
@@ -197,7 +327,7 @@
 	return std::to_string(value);
 }
 
-std::string RequestPostgres::bindInt(int value)
+std::string RequestPostgres::bindInteger(int value)
 {
 	return std::to_string(value);
 }
@@ -218,20 +348,61 @@
 }
 
 /* --------------------------------------------------------
- * Driver PostgreSQL
+ * Driver PostgreSQL impl
  * -------------------------------------------------------- */
 
-DriverPostgres::DriverPostgres()
-{
-}
+/**
+ * @class DriverPostgres
+ * @brief Driver implementation for PostgreSQL.
+ */
+class DriverPostgresImpl : public Driver::Impl {
+private:
+	PostgresConn m_connection;
+
+	/**
+	 * Convert the Params from the config
+	 * to the PostgreSQL string.
+	 *
+	 * @param settings the table
+	 * @return a string to be used
+	 */
+	std::string convert(Driver::Params &settings);
+
+public:
+	/**
+	 * @copydoc Driver::connect
+	 */
+	virtual void connect(const Driver::Params &params);
 
-DriverPostgres::~DriverPostgres()
-{
-}
+	/**
+	 * @copydoc Driver::prepare
+	 */
+	virtual DriverRequest prepare(const std::string &command);
+
+	/**
+	 * @copydoc Driver::query
+	 */
+	virtual DriverQuery query(const std::string &command);
 
-std::string DriverPostgres::convert(Params &params)
+	/**
+	 * @copydoc Driver::description
+	 */
+	virtual std::string description() const;
+
+	/**
+	 * @copydoc Driver::version
+	 */
+	virtual std::string version() const;
+};
+
+std::string DriverPostgresImpl::convert(Driver::Params &params)
 {
 	std::ostringstream oss;
+	std::vector<std::string> required { "host", "port", "user", "database", "password" };
+
+	for (auto s : required)
+		if (params.count(s) <= 0)
+			throw std::runtime_error("missing parameter " + s);
 
 	oss << "host = " << params["host"] << " ";
 	oss << "port = " << params["port"] << " ";
@@ -242,55 +413,54 @@
 	return oss.str();
 }
 
-bool DriverPostgres::connect(const Params &params)
+void DriverPostgresImpl::connect(const Driver::Params &params)
 {
-	Params copy = params;
-	PGconn *conn = PQconnectdb(convert(copy).c_str());
+	auto copy = params;
+	auto conn = PQconnectdb(convert(copy).c_str());
 
-	if (conn == nullptr) {
-		m_error = strerror(ENOMEM);
-		return false;
-	}
+	if (conn == nullptr)
+		throw std::runtime_error(std::strerror(ENOMEM));
 
 	if (PQstatus(conn) == CONNECTION_BAD) {
-		m_error = PQerrorMessage(conn);
+		auto error = PQerrorMessage(conn);
 		PQfinish(conn);
 
-		return false;
+		throw std::runtime_error(error);
 	}
 
-	m_connection = std::shared_ptr<PGconn>(conn, PGDeleter());
-
-	return true;
+	m_connection = std::shared_ptr<PGconn>(conn, PGConnDeleter());
 }
 
-Request::Ptr DriverPostgres::prepare(const std::string &command)
+DriverRequest DriverPostgresImpl::prepare(const std::string &command)
 {
-	return std::make_shared<RequestPostgres>(m_connection, command);
+	return DriverRequest(std::make_shared<RequestPostgres>(m_connection), command);
 }
 
-Query::Ptr DriverPostgres::query(const std::string &cmd)
+DriverQuery DriverPostgresImpl::query(const std::string &cmd)
 {
 	PGresult *info;
 
 	// If NULL, the libpq said no memory
 	info = PQexec(m_connection.get(), cmd.c_str());
 	if (info == nullptr)
-		throw Query::Error(strerror(ENOMEM));
+		throw std::runtime_error(strerror(ENOMEM));
 
 	// If an error occured
 	int errorCode = PQresultStatus(info);
 	if (errorCode != PGRES_COMMAND_OK && errorCode != PGRES_TUPLES_OK) {
-		std::string error = PQresultErrorMessage(info);
+		auto error = PQresultErrorMessage(info);
 		PQclear(info);
-		throw Query::Error(error);
+
+		throw std::runtime_error(error);
 	}
 
-	return std::unique_ptr<Query>(new QueryPostgres(shared_from_this(),
-				      QueryPostgres::PostgresResult(info)));
+	auto result = std::shared_ptr<PGresult>(info, PGQueryDeleter());
+	auto impl = std::make_shared<QueryPostgresImpl>(m_connection, result);
+
+	return DriverQuery(impl);
 }
 
-std::string DriverPostgres::description() const
+std::string DriverPostgresImpl::description() const
 {
 	std::ostringstream oss;
 
@@ -303,7 +473,7 @@
 	return oss.str();
 }
 
-std::string DriverPostgres::version() const
+std::string DriverPostgresImpl::version() const
 {
 	std::ostringstream oss;
 
@@ -311,3 +481,12 @@
 
 	return oss.str();
 }
+
+/* --------------------------------------------------------
+ * Driver PostgreSQL
+ * -------------------------------------------------------- */
+
+DriverPostgres::DriverPostgres()
+{
+	m_impl = std::make_shared<DriverPostgresImpl>();
+}
--- a/C++/DriverPostgres.h	Mon Mar 24 13:54:28 2014 +0100
+++ b/C++/DriverPostgres.h	Tue Mar 25 20:42:11 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DriverPostgres.h -- PostgreSQL driver
  *
- * Copyright (c) 2013, David Demelier <markand@malikania.fr>
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -29,201 +29,9 @@
 
 #include "Driver.h"
 
-/**
- * @class QueryPostgres
- * @brief Query implementation for PostgreSQL.
- */
-class QueryPostgres : public Query {
-public:
-	struct PQQueryDeleter {
-		void operator()(PGresult *result)
-		{
-			PQclear(result);
-		}
-	};
-
-	using PostgresResult = std::unique_ptr<PGresult, PQQueryDeleter>;
-
-private:
-	PostgresResult m_result;
-	Driver::Ptr m_driver;
-
-protected:
-	/**
-	 * @copydoc Query::getBoolean
-	 */
-	virtual bool getBoolean(int row, const std::string &column);
-
-	/**
-	 * @copydoc Query::getDate
-	 */
-	virtual Date getDate(int row, const std::string &column);
-
-	/**
-	 * @copydoc Query::getDouble
-	 */
-	virtual double getDouble(int row, const std::string &column);
-
-	/**
-	 * @copydoc Query::getInt
-	 */
-	virtual int getInt(int row, const std::string &column);
-
-	/**
-	 * @copydoc Query::getString
-	 */
-	virtual std::string getString(int row, const std::string &column);
-
-public:
-	/**
-	 * Constructor used by DriverPostgres
-	 *
-	 * @param driver the driver
-	 * @param result the result
-	 */
-	QueryPostgres(Driver::Ptr driver, PostgresResult result);
-
-	/**
-	 * Default destructor.
-	 */
-	~QueryPostgres();
-
-	/**
-	 * @copydoc Query::type
-	 */
-	virtual ColumnType type(const std::string &column) const;
-
-	/**
-	 * @copydoc Query::countRows
-	 */
-	virtual int countRows();
-
-	/**
-	 * @copydoc Query::countColumns
-	 */
-	virtual int countColumns();
-
-	/**
-	 * @copydoc Query::isNull
-	 */
-	virtual bool isNull(int row, const std::string &column);
-
-	/**
-	 * @copydoc Query::dump
-	 */
-	virtual void dump();
-};
-
-/**
- * @class RequestPostgres
- * @brief Request implementation for PostgreSQL.
- */
-class RequestPostgres : public Request {
-private:
-	std::shared_ptr<PGconn> m_connection;
-
-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:
-	/**
-	 * Construct a request for PostgreSQL.
-	 *
-	 * @param conn the connection
-	 * @param command the command
-	 */
-	RequestPostgres(std::shared_ptr<PGconn> conn,
-			const std::string &command);
-};
-
-/**
- * @class DriverPostgres
- * @brief Driver implementation for PostgreSQL.
- */
 class DriverPostgres : public Driver {
 public:
-	friend class Driver;
-
-	struct PGDeleter {
-		void operator()(PGconn *conn)
-		{
-			PQfinish(conn);
-		}
-	};
-
-	using PostgresConn = std::shared_ptr<PGconn>;
-
-private:
-	PostgresConn m_connection;
-
-	/**
-	 * Convert the Params from the config
-	 * to the PostgreSQL string.
-	 *
-	 * @param settings the table
-	 * @return a string to be used
-	 */
-	std::string convert(Params &settings);
-
-protected:
-	/**
-	 * @copydoc Driver::Driver
-	 */
 	DriverPostgres();
-
-public:
-	/**
-	 * @copydoc Driver::~Driver
-	 */
-	~DriverPostgres();
-
-	/**
-	 * @copydoc Driver::connect
-	 */
-	virtual bool connect(const Params &params);
-
-	/**
-	 * @copydoc Driver::prepare
-	 */
-	virtual Request::Ptr prepare(const std::string &command);
-
-	/**
-	 * @copydoc Driver::query
-	 */
-	virtual Query::Ptr query(const std::string &command);
-
-	/**
-	 * @copydoc Driver::description
-	 */
-	virtual std::string description() const;
-
-	/**
-	 * @copydoc Driver::version
-	 */
-	virtual std::string version() const;
 };
 
 #endif // !_DRIVER_PG_H_