/home/martin/workspace/OpenStreetNav/src/psql/Statement.h
Go to the documentation of this file.
00001 #ifndef PSQL_STATEMENT_H_
00002 #define PSQL_STATEMENT_H_
00003 
00004 #include "Database.h"
00005 #include "PgSqlException.h"
00006 #include "CopyTypes.h"
00007 #include "BindTypes.h"
00008 #include <libpqtypes.h>
00009 #include <tuple>
00010 #include "../util.h"
00011 
00012 namespace psql
00013 {
00014 
00015 class IStatement
00016 {
00017 };
00018 
00019 template<typename BindTypes>
00020 PGresult* execBT(PGconn* conn, PGparam* param, std::string const& sql)
00021 {
00022     auto res = PQparamExec(conn, param, sql.c_str(), 1);
00023     if (res == NULL)
00024         throw PgSqlException("Error retrieving statement result: " + std::string(PQgeterror()));
00025     return res;
00026 }
00027 
00028 template<>
00029 PGresult* execBT<BindTypes<> >(PGconn* conn, PGparam*, std::string const& sql);
00030 
00031 template<typename BindTypes>
00032 PGresult* execPrepBT(PGconn* conn, PGparam* param, std::string const& name)
00033 {
00034     auto res = PQparamExecPrepared(conn, param, name.c_str(), 1);
00035     if (res == NULL)
00036         throw PgSqlException("Error retrieving statement result: " + std::string(PQgeterror()));
00037     return res;
00038 }
00039 
00040 template<>
00041 PGresult* execPrepBT<BindTypes<> >(PGconn* conn, PGparam*, std::string const& name);
00042 
00043 
00050 template < typename BindTypes, typename RetTypes, typename CopyTypes = CopyTypes<> >
00051 class Statement : IStatement
00052 {
00053 private:
00054     void check_param()
00055     {
00056         if (param == NULL)
00057             throw PgSqlException("Error creating PGparam object: " + std::string(PQgeterror()));
00058     }
00059 public:
00063     Statement():
00064         db(NULL),
00065         param(NULL),
00066         res(NULL),
00067         cp(false)
00068     {
00069     }
00070 
00076     Statement(std::string const& sql, Database& db):
00077         db(&db),
00078         sql(sql),
00079         prep(false),
00080         param(PQparamCreate(db.get_db())),
00081         res(NULL),
00082         cp(false)
00083     {
00084         check_param();
00085     }
00092     Statement(std::string const& name, std::string const& sql, Database& db):
00093         db(&db),
00094         name(name),
00095         sql(sql),
00096         prep(true),
00097         param(PQparamCreate(db.get_db())),
00098         res(NULL),
00099         cp(false)
00100     {
00101         db.regist(name, sql, this);
00102         check_param();
00103     }
00104     ~Statement()
00105     {
00106         if (db == NULL)
00107             return;
00108         if (prep)
00109             db->unregist(name, this);
00110         if (res != NULL)
00111             PQclear(res);
00112         if (cp)
00113             end_copy();
00114         PQparamClear(param);
00115     }
00116 
00117     Statement& operator=(Statement const&) = delete;
00118     Statement(Statement<BindTypes, RetTypes, CopyTypes> const&) = delete;
00124     Statement& operator=(Statement && other)
00125     {
00126         if (db != NULL)
00127         {
00128             if (prep)
00129                 db->unregist(name, this);
00130             if (res != NULL)
00131                 PQclear(res);
00132         }
00133         db = other.db;
00134         other.db = NULL;
00135         res = other.res;
00136         prep = other.prep;
00137         sql = other.sql;
00138         name = other.name;
00139         param = other.param;
00140         cp = other.cp;
00141         return *this;
00142     }
00147     Statement(Statement && other):
00148         db(NULL),
00149         param(NULL),
00150         res(NULL)
00151     {
00152         *this = std::move(other);
00153     }
00154 
00160     template<typename... Args>
00161     void execute(Args... args)
00162     {
00163         if (res != NULL)
00164             PQclear(res);
00165         res = NULL;
00166 
00167         bt.put(param, args...);
00168         if (prep)
00169             res = execPrepBT<BindTypes>(db->get_db(), param, name);
00170         else
00171             res = execBT<BindTypes>(db->get_db(), param, sql);
00172 
00173         if (PQresultStatus(res) == PGRES_COPY_IN)
00174             cp = true;
00175     }
00176 
00182     typename RetTypes::RowType get_row(int row)
00183     {
00184         if (res == NULL)
00185             throw PgSqlException("get_values called with no result");
00186         return rt.get_values(res, row);
00187     }
00188 
00193     int row_count()
00194     {
00195         if (res == NULL)
00196             return 0;
00197         if (PQresultStatus(res) == PGRES_TUPLES_OK)
00198             return PQntuples(res);
00199         return 0;
00200     }
00201 
00206     int64_t affected_rows()
00207     {
00208         if (res == NULL)
00209             return 0;
00210         std::string aff(PQcmdTuples(res));
00211         if (aff == "")
00212             return 0;
00213         return util::parse<int64_t>(aff);
00214     }
00215 
00220     bool copying()
00221     {
00222         return cp;
00223     }
00224 
00228     void end_copy()
00229     {
00230         auto conn = db->get_db();
00231         cp = false;
00232         auto result = PQputCopyEnd(conn, NULL);
00233         if (result == 0)
00234             throw PgSqlException("Sorry copy for asynchronous connections is not implemented");
00235         if (result == -1)
00236             throw PgSqlException("Error sending end copy request: " + std::string(PQerrorMessage(conn)));
00237         res = PQgetResult(conn);
00238         if (res == NULL
00239                 || PQresultStatus(res) == PGRES_BAD_RESPONSE
00240                 || PQresultStatus(res) == PGRES_FATAL_ERROR)
00241             throw PgSqlException("Error executing statement: " + std::string(PQerrorMessage(conn)));
00242 
00243     }
00244 
00249     template<typename... Args>
00250     void copy_data(Args... args)
00251     {
00252         ct.copy(*db, args...);
00253     }
00254 
00259     std::string get_sql() const
00260     {
00261         return sql;
00262     }
00263 
00264 private:
00265     Database* db;
00266     std::string name;
00267     std::string sql;
00268     bool prep;
00269     BindTypes bt;
00270     RetTypes rt;
00271     CopyTypes ct;
00272     PGparam* param;
00273     PGresult* res;
00274     bool cp;
00275 };
00276 
00277 }
00278 
00279 #endif
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines