diff options
author | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2010-04-08 07:17:49 +0000 |
---|---|---|
committer | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2010-04-08 07:17:49 +0000 |
commit | e79215ecc3479e44484c0cfa7c41c980af6e32f4 (patch) | |
tree | 5fd61b5a917400ecf6b8507e6367c849f1b82999 /sca-cpp/trunk/components/sqldb/pgsql.hpp | |
parent | e7a60b5b6b205b03dfdf58f9abf336eaeefb3f75 (diff) |
Simple SQL database component implementation, using PostgreSQL.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@931801 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-cpp/trunk/components/sqldb/pgsql.hpp')
-rw-r--r-- | sca-cpp/trunk/components/sqldb/pgsql.hpp | 184 |
1 files changed, 183 insertions, 1 deletions
diff --git a/sca-cpp/trunk/components/sqldb/pgsql.hpp b/sca-cpp/trunk/components/sqldb/pgsql.hpp index 6743a4a3f5..b6b2cab331 100644 --- a/sca-cpp/trunk/components/sqldb/pgsql.hpp +++ b/sca-cpp/trunk/components/sqldb/pgsql.hpp @@ -22,13 +22,195 @@ #ifndef tuscany_pgsql_hpp #define tuscany_pgsql_hpp +#include <libpq-fe.h> + #include "string.hpp" #include "list.hpp" #include "value.hpp" #include "monad.hpp" +#include "../../modules/scheme/eval.hpp" namespace tuscany { -namespace sqldb { +namespace pgsql { + +/** + * Return and clear a Postgres result failure. + */ +const string pgfailure(PGresult* r) { + const string e = PQresultErrorMessage(r); + PQclear(r); + return e; +} + +/** + * Represents a PGSql connection. + */ +class PGSql { +public: + PGSql() : owner(false) { + } + + PGSql(const string& conninfo, const string& table) : owner(true), conninfo(conninfo), table(table) { + init(); + } + + PGSql(const PGSql& c) : owner(false) { + conninfo = c.conninfo; + conn = c.conn; + table = c.table; + } + + ~PGSql() { + if (!owner) + return; + PQfinish(conn); + } + +private: + bool owner; + PGconn *conn; + string conninfo; + string table; + + friend const failable<bool> post(const value& key, const value& val, const PGSql& pgsql); + friend const failable<bool> put(const value& key, const value& val, const PGSql& pgsql); + friend const failable<value> get(const value& key, const PGSql& pgsql); + friend const failable<bool> del(const value& key, const PGSql& pgsql); + + /** + * Initialize the database connection + */ + const failable<bool> init() { + conn = PQconnectdb(c_str(conninfo)); + if (PQstatus(conn) != CONNECTION_OK) + return mkfailure<bool>(string("Could not connect to database: ") + PQerrorMessage(conn)); + + // Find the name of the first column in the target table + // Assume that's the key we need to use + string ks = string("select a.attname from pg_attribute a, pg_class c where a.attrelid = c.relfilenode and c.relname = '") + table + string("' and a.attnum in (1, 2) order by a.attnum;"); + PGresult* kr = PQexec(conn, c_str(ks)); + if (PQresultStatus(kr) != PGRES_TUPLES_OK) + return mkfailure<bool>(string("Could not execute column select statement: ") + pgfailure(kr)); + if (PQntuples(kr) != 2) { + PQclear(kr); + return mkfailure<bool>(string("Could not find table key and value column names")); + } + const string kname = PQgetvalue(kr, 0, 0); + const string vname = PQgetvalue(kr, 1, 0); + PQclear(kr); + + // Prepare the post, put, get and delete statements + { + PGresult* r = PQprepare(conn, "post", c_str(string("insert into ") + table + string(" values($1, $2);")), 2, NULL); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not prepare post SQL statement: ") + pgfailure(r)); + PQclear(r); + } + { + PGresult* r = PQprepare(conn, "put", c_str(string("update ") + table + string(" set ") + vname + string(" = $2 where ") + kname + string(" = $1;")), 2, NULL); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not prepare put SQL statement: ") + pgfailure(r)); + PQclear(r); + } + { + PGresult* r = PQprepare(conn, "get", c_str(string("select * from ") + table + string(" where ") + kname + string(" = $1;")), 1, NULL); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not prepare get SQL statement: ") + pgfailure(r)); + PQclear(r); + } + { + PGresult* r = PQprepare(conn, "delete", c_str(string("delete from ") + table + string(" where ") + kname + string(" = $1;")), 1, NULL); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not prepare delete SQL statement: ") + pgfailure(r)); + PQclear(r); + } + return true; + } +}; + +/** + * Post a new item to the database. + */ +const failable<bool> post(const value& key, const value& val, const PGSql& pgsql) { + debug(key, "pgsql::post::key"); + debug(val, "pgsql::post::value"); + debug(pgsql.table, "pgsql::post::table"); + + const string ks(scheme::writeValue(key)); + const string vs(scheme::writeValue(val)); + const char* params[2] = { c_str(ks), c_str(vs) }; + PGresult* r = PQexecPrepared(pgsql.conn, "post", 2, params, NULL, NULL, 0); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not execute post SQL statement: ") + pgfailure(r)); + PQclear(r); + + debug(true, "pgsql::post::result"); + return true; +} + +/** + * Update an item in the database. If the item doesn't exist it is added. + */ +const failable<bool> put(const value& key, const value& val, const PGSql& pgsql) { + debug(key, "pgsql::put::key"); + debug(val, "pgsql::put::value"); + debug(pgsql.table, "pgsql::put::table"); + + const string ks(scheme::writeValue(key)); + const string vs(scheme::writeValue(val)); + const char* params[2] = { c_str(ks), c_str(vs) }; + PGresult* r = PQexecPrepared(pgsql.conn, "put", 2, params, NULL, NULL, 0); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not execute put SQL statement: ") + pgfailure(r)); + PQclear(r); + + debug(true, "pgsql::put::result"); + return true; +} + +/** + * Get an item from the database. + */ +const failable<value> get(const value& key, const PGSql& pgsql) { + debug(key, "pgsql::get::key"); + debug(pgsql.table, "pgsql::get::table"); + + const string ks(scheme::writeValue(key)); + const char* params[1] = { c_str(ks) }; + PGresult* r = PQexecPrepared(pgsql.conn, "get", 1, params, NULL, NULL, 0); + if (PQresultStatus(r) != PGRES_TUPLES_OK) + return mkfailure<value>(string("Could not execute get SQL statement: ") + pgfailure(r)); + if (PQntuples(r) < 1) { + PQclear(r); + return mkfailure<value>(string("Could not get entry: ") + PQerrorMessage(pgsql.conn)); + } + const char* data = PQgetvalue(r, 0, 1); + const value val(scheme::readValue(string(data))); + PQclear(r); + + debug(val, "pgsql::get::result"); + return val; +} + +/** + * Delete an item from the database + */ +const failable<bool> del(const value& key, const PGSql& pgsql) { + debug(key, "pgsql::delete::key"); + debug(pgsql.table, "pgsql::delete::table"); + + const string ks(scheme::writeValue(key)); + const char* params[1] = { c_str(ks) }; + PGresult* r = PQexecPrepared(pgsql.conn, "delete", 1, params, NULL, NULL, 0); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not execute delete SQL statement: ") + pgfailure(r)); + PQclear(r); + + debug(true, "pgsql::delete::result"); + return true; +} +} +} #endif /* tuscany_pgsql_hpp */ |