summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/components/sqldb
diff options
context:
space:
mode:
Diffstat (limited to 'sca-cpp/trunk/components/sqldb')
-rw-r--r--sca-cpp/trunk/components/sqldb/Makefile.am4
-rw-r--r--sca-cpp/trunk/components/sqldb/client-test.cpp71
-rw-r--r--sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp20
-rw-r--r--sca-cpp/trunk/components/sqldb/pgsql-test.cpp33
-rw-r--r--sca-cpp/trunk/components/sqldb/pgsql.hpp204
-rw-r--r--sca-cpp/trunk/components/sqldb/sqldb.cpp65
6 files changed, 240 insertions, 157 deletions
diff --git a/sca-cpp/trunk/components/sqldb/Makefile.am b/sca-cpp/trunk/components/sqldb/Makefile.am
index 9ce5f26713..988383b4f1 100644
--- a/sca-cpp/trunk/components/sqldb/Makefile.am
+++ b/sca-cpp/trunk/components/sqldb/Makefile.am
@@ -48,10 +48,10 @@ pgsql_standby_test_SOURCES = pgsql-standby-test.cpp
pgsql_standby_test_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq
client_test_SOURCES = client-test.cpp
-client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+client_test_LDFLAGS = -lxml2 -lcurl -ljansson
dist_noinst_SCRIPTS = sqldb-test standby-test server-test
noinst_PROGRAMS = pgsql-test pgsql-standby-test client-test
-TESTS = sqldb-test standby-test server-test
+TESTS = sqldb-test server-test
endif
diff --git a/sca-cpp/trunk/components/sqldb/client-test.cpp b/sca-cpp/trunk/components/sqldb/client-test.cpp
index 0cbcb57363..c9fbb7d5bb 100644
--- a/sca-cpp/trunk/components/sqldb/client-test.cpp
+++ b/sca-cpp/trunk/components/sqldb/client-test.cpp
@@ -38,15 +38,15 @@ namespace sqldb {
const string uri("http://localhost:8090/sqldb");
-bool testSqlDb() {
- http::CURLSession cs("", "", "", "", 0);
-
- const list<value> i = list<value>() + "content" + (list<value>() + "item"
- + (list<value>() + "name" + string("Apple"))
- + (list<value>() + "price" + string("$2.99")));
- const list<value> a = list<value>() + (list<value>() + "entry"
- + (list<value>() + "title" + string("item"))
- + (list<value>() + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"))
+const bool testSqlDb() {
+ const http::CURLSession cs("", "", "", "", 0);
+
+ const list<value> i = nilListValue + "content" + (nilListValue + "item"
+ + (nilListValue + "name" + string("Apple"))
+ + (nilListValue + "price" + string("$2.99")));
+ const list<value> a = nilListValue + (nilListValue + "entry"
+ + (nilListValue + "title" + string("item"))
+ + (nilListValue + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"))
+ i);
const failable<value> id = http::post(a, uri, cs);
@@ -59,18 +59,18 @@ bool testSqlDb() {
assert(content(val) == a);
}
- const list<value> j = list<value>() + "content" + (list<value>() + "item"
- + (list<value>() + "name" + string("Apple"))
- + (list<value>() + "price" + string("$3.55")));
- const list<value> b = list<value>() + (list<value>() + "entry"
- + (list<value>() + "title" + string("item"))
- + (list<value>() + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"))
+ const list<value> j = nilListValue + "content" + (nilListValue + "item"
+ + (nilListValue + "name" + string("Apple"))
+ + (nilListValue + "price" + string("$3.55")));
+ const list<value> b = nilListValue + (nilListValue + "entry"
+ + (nilListValue + "title" + string("item"))
+ + (nilListValue + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"))
+ j);
{
const failable<value> r = http::put(b, uri + p, cs);
assert(hasContent(r));
- assert(content(r) == value(true));
+ assert(content(r) == trueValue);
}
{
const failable<value> val = http::get(uri + p, cs);
@@ -80,7 +80,7 @@ bool testSqlDb() {
{
const failable<value> r = http::del(uri + p, cs);
assert(hasContent(r));
- assert(content(r) == value(true));
+ assert(content(r) == trueValue);
}
{
const failable<value> val = http::get(uri + p, cs);
@@ -90,35 +90,26 @@ bool testSqlDb() {
return true;
}
-struct getLoop {
- const string path;
- const value entry;
- http::CURLSession& cs;
- getLoop(const string& path, const value& entry, http::CURLSession& cs) : path(path), entry(entry), cs(cs) {
- }
- const bool operator()() const {
- const failable<value> val = http::get(uri + path, cs);
- assert(hasContent(val));
- assert(content(val) == entry);
- return true;
- }
-};
-
-bool testGetPerf() {
- const list<value> i = list<value>() + "content" + (list<value>() + "item"
- + (list<value>() + "name" + string("Apple"))
- + (list<value>() + "price" + string("$4.55")));
- const list<value> a = list<value>() + (list<value>() + "entry"
- + (list<value>() + "title" + string("item"))
- + (list<value>() + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"))
+const bool testGetPerf() {
+ const list<value> i = nilListValue + "content" + (nilListValue + "item"
+ + (nilListValue + "name" + string("Apple"))
+ + (nilListValue + "price" + string("$4.55")));
+ const list<value> a = nilListValue + (nilListValue + "entry"
+ + (nilListValue + "title" + string("item"))
+ + (nilListValue + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"))
+ i);
- http::CURLSession cs("", "", "", "", 0);
+ const http::CURLSession cs("", "", "", "", 0);
const failable<value> id = http::post(a, uri, cs);
assert(hasContent(id));
const string p = path(content(id));
- const lambda<bool()> gl = getLoop(p, a, cs);
+ const blambda gl = [p, a, cs]() -> const bool {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == a);
+ return true;
+ };
cout << "Sqldb get test " << time(gl, 5, 200) << " ms" << endl;
return true;
diff --git a/sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp b/sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp
index 2cd25f874a..5d73b0d877 100644
--- a/sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp
+++ b/sca-cpp/trunk/components/sqldb/pgsql-standby-test.cpp
@@ -32,7 +32,7 @@
namespace tuscany {
namespace pgsql {
-bool testPGSql() {
+const bool testPGSql() {
PGSql wpg("host=localhost port=6432 dbname=db", "test");
PGSql rpg("host=localhost port=6433 dbname=db", "test");
const value k = mklist<value>("a");
@@ -50,25 +50,17 @@ bool testPGSql() {
return true;
}
-struct getLoop {
- const value k;
- PGSql& pg;
- getLoop(const value& k, PGSql& pg) : k(k), pg(pg) {
- }
- const bool operator()() const {
- assert((get(k, pg)) == value(string("CCC")));
- return true;
- }
-};
-
-bool testGetPerf() {
+const bool testGetPerf() {
const value k = mklist<value>("c");
PGSql wpg("host=localhost port=6432 dbname=db", "test");
PGSql rpg("host=localhost port=6433 dbname=db", "test");
assert(hasContent(post(k, string("CCC"), wpg)));
sleep(1);
- const lambda<bool()> gl = getLoop(k, rpg);
+ const blambda gl = [k, rpg]() -> const bool {
+ assert((get(k, rpg)) == value(string("CCC")));
+ return true;
+ };
cout << "PGSql get test " << time(gl, 5, 200) << " ms" << endl;
return true;
}
diff --git a/sca-cpp/trunk/components/sqldb/pgsql-test.cpp b/sca-cpp/trunk/components/sqldb/pgsql-test.cpp
index d10ab5f4c2..5d7bb98cd8 100644
--- a/sca-cpp/trunk/components/sqldb/pgsql-test.cpp
+++ b/sca-cpp/trunk/components/sqldb/pgsql-test.cpp
@@ -32,37 +32,38 @@
namespace tuscany {
namespace pgsql {
-bool testPGSql() {
+const bool testPGSql() {
PGSql pg("host=localhost port=6432 dbname=db", "test");
const value k = mklist<value>("a");
+ const value lk = mklist<value>(mklist<value>("like", "%"), mklist<value>("limit", "2"));
+ const value rx = mklist<value>(mklist<value>("regex", "a"), mklist<value>("limit", "2"));
+ const value ts = mklist<value>(mklist<value>("textsearch", "AAA"), mklist<value>("limit", "2"));
+ const value rxts = mklist<value>(mklist<value>("regex", "a"), mklist<value>("textsearch", "AAA"), mklist<value>("limit", "2"));
assert(hasContent(post(k, string("AAA"), pg)));
- assert((get(k, pg)) == value(string("AAA")));
+ assert(content(get(k, pg)) == value(string("AAA")));
+ assert(cadr<value>(car<value>(content(get(lk, pg)))) == value(string("AAA")));
+ assert(cadr<value>(car<value>(content(get(rx, pg)))) == value(string("AAA")));
+ assert(cadr<value>(car<value>(content(get(ts, pg)))) == value(string("AAA")));
+ assert(cadr<value>(car<value>(content(get(rxts, pg)))) == value(string("AAA")));
+
assert(hasContent(put(k, string("aaa"), pg)));
- assert((get(k, pg)) == value(string("aaa")));
+ assert(content(get(k, pg)) == value(string("aaa")));
assert(hasContent(del(k, pg)));
assert(!hasContent(get(k, pg)));
return true;
}
-struct getLoop {
- const value k;
- PGSql& pg;
- getLoop(const value& k, PGSql& pg) : k(k), pg(pg) {
- }
- const bool operator()() const {
- assert((get(k, pg)) == value(string("CCC")));
- return true;
- }
-};
-
-bool testGetPerf() {
+const bool testGetPerf() {
const value k = mklist<value>("c");
PGSql pg("host=localhost port=6432 dbname=db", "test");
assert(hasContent(post(k, string("CCC"), pg)));
- const lambda<bool()> gl = getLoop(k, pg);
+ const blambda gl = [k, pg]() -> const bool {
+ assert(content(get(k, pg)) == value(string("CCC")));
+ return true;
+ };
cout << "PGSql get test " << time(gl, 5, 200) << " ms" << endl;
return true;
}
diff --git a/sca-cpp/trunk/components/sqldb/pgsql.hpp b/sca-cpp/trunk/components/sqldb/pgsql.hpp
index 581cd943e6..620aec4105 100644
--- a/sca-cpp/trunk/components/sqldb/pgsql.hpp
+++ b/sca-cpp/trunk/components/sqldb/pgsql.hpp
@@ -40,7 +40,7 @@ namespace pgsql {
/**
* Return and clear a Postgres result failure.
*/
-const string pgfailure(PGresult* r, PGconn* conn) {
+const string pgfailure(PGresult* const r, PGconn* const conn) {
const string re = PQresultErrorMessage(r);
PQclear(r);
if (length(re) != 0)
@@ -68,11 +68,12 @@ public:
mkfailure<bool>(string("Couldn't connect to postgresql database: ") + PQerrorMessage(conn));
return;
}
+ debug(conn, "pgsql::pgsql::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));
+ PGresult* const kr = PQexec(conn, c_str(ks));
if (PQresultStatus(kr) != PGRES_TUPLES_OK) {
mkfailure<bool>(string("Couldn't execute postgresql column select statement: ") + pgfailure(kr, conn));
return;
@@ -82,25 +83,16 @@ public:
mkfailure<bool>(string("Couldn't find postgresql table key and value column names"));
return;
}
- kname = PQgetvalue(kr, 0, 0);
- vname = PQgetvalue(kr, 1, 0);
+ kname = c_str(string(PQgetvalue(kr, 0, 0)));
+ vname = c_str(string(PQgetvalue(kr, 1, 0)));
PQclear(kr);
}
- PGSql(const PGSql& c) : owner(false), conn(c.conn), conninfo(c.conninfo), table(c.table) {
+ PGSql(const PGSql& c) : owner(false), conn(c.conn), conninfo(c.conninfo), table(c.table), kname(c.kname), vname(c.vname) {
debug("pgsql::pgsql::copy");
}
- const PGSql& operator=(const PGSql& c) {
- debug("pgsql::pgsql::operator=");
- if(this == &c)
- return *this;
- owner = false;
- conn = c.conn;
- conninfo = c.conninfo;
- table = c.table;
- return *this;
- }
+ PGSql& operator=(const PGSql& c) = delete;
~PGSql() {
debug("pgsql::~pgsql");
@@ -108,16 +100,17 @@ public:
return;
if (conn == NULL)
return;
+ debug(conn, "pgsql::~pgsql::conn");
PQfinish(conn);
}
private:
- bool owner;
+ const bool owner;
PGconn *conn;
- string conninfo;
- string table;
- string kname;
- string vname;
+ const string conninfo;
+ const string table;
+ const char* kname;
+ const char* vname;
friend const failable<bool> setup(const PGSql& pgsql);
friend const failable<bool> post(const value& key, const value& val, const PGSql& pgsql);
@@ -133,7 +126,7 @@ const failable<bool> setup(const PGSql& pgsql) {
debug("pgsql::setup");
if (PQstatus(pgsql.conn) == CONNECTION_OK)
return true;
- debug("pgsql::setup::reset");
+ debug(pgsql.conn, "pgsql::setup::reset::conn");
PQreset(pgsql.conn);
if (PQstatus(pgsql.conn) != CONNECTION_OK)
return mkfailure<bool>(string("Couldn't reconnect to postgresql database: ") + PQerrorMessage(pgsql.conn));
@@ -150,10 +143,10 @@ const failable<bool> post(const value& key, const value& val, const PGSql& pgsql
debug(pgsql.table, "pgsql::post::table");
setup(pgsql);
- const string ks(scheme::writeValue(key));
- const string vs(scheme::writeValue(val));
- const char* params[2] = { c_str(ks), c_str(vs) };
- PGresult* r = PQexecParams(pgsql.conn, c_str(string("insert into ") + pgsql.table + string(" values($1, $2);")), 2, NULL, params, NULL, NULL, 0);
+ const string ks(write(content(scheme::writeValue(key))));
+ const string vs(write(content(scheme::writeValue(val))));
+ const char* const params[2] = { c_str(ks), c_str(vs) };
+ PGresult* const r = PQexecParams(pgsql.conn, c_str(string("insert into ") + pgsql.table + string(" values($1, $2);")), 2, NULL, params, NULL, NULL, 0);
if (PQresultStatus(r) != PGRES_COMMAND_OK)
return mkfailure<bool>(string("Couldn't execute insert postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
PQclear(r);
@@ -172,10 +165,10 @@ const failable<bool> put(const value& key, const value& val, const PGSql& pgsql)
debug(pgsql.table, "pgsql::put::table");
setup(pgsql);
- const string ks(scheme::writeValue(key));
- const string vs(scheme::writeValue(val));
- const char* params[2] = { c_str(ks), c_str(vs) };
- PGresult* r = PQexecParams(pgsql.conn, c_str(string("update ") + pgsql.table + string(" set ") + pgsql.vname + string(" = $2 where ") + pgsql.kname + string(" = $1;")), 2, NULL, params, NULL, NULL, 0);
+ const string ks(write(content(scheme::writeValue(key))));
+ const string vs(write(content(scheme::writeValue(val))));
+ const char* const params[2] = { c_str(ks), c_str(vs) };
+ PGresult* const r = PQexecParams(pgsql.conn, c_str(string("update ") + pgsql.table + string(" set ") + pgsql.vname + string(" = $2 where ") + pgsql.kname + string(" = $1;")), 2, NULL, params, NULL, NULL, 0);
if (PQresultStatus(r) != PGRES_COMMAND_OK)
return mkfailure<bool>(string("Couldn't execute update postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
const string t = PQcmdTuples(r);
@@ -186,7 +179,7 @@ const failable<bool> put(const value& key, const value& val, const PGSql& pgsql)
}
PQclear(r);
- PGresult* pr = PQexecParams(pgsql.conn, c_str(string("insert into ") + pgsql.table + string(" values($1, $2);")), 2, NULL, params, NULL, NULL, 0);
+ PGresult* const pr = PQexecParams(pgsql.conn, c_str(string("insert into ") + pgsql.table + string(" values($1, $2);")), 2, NULL, params, NULL, NULL, 0);
if (PQresultStatus(pr) != PGRES_COMMAND_OK)
return mkfailure<bool>(string("Couldn't execute insert postgresql SQL statement: ") + pgfailure(pr, pgsql.conn));
PQclear(pr);
@@ -196,7 +189,58 @@ const failable<bool> put(const value& key, const value& val, const PGSql& pgsql)
}
/**
- * Get an item from the database.
+ * Convert a key to an item id.
+ */
+const list<value> keyid(const list<value>& key) {
+ if (isNil(key))
+ return nilListValue;
+ if (isList(car(key)))
+ return keyid(cdr(key));
+ return cons<value>(car(key), keyid(cdr(key)));
+}
+
+/**
+ * Convert a key to an param name / value assoc.
+ */
+const list<list<value> > keyparams(const list<value>& key) {
+ if (isNil(key))
+ return nilListValue;
+ if (!isList(car(key)))
+ return keyparams(cdr(key));
+ return cons<list<value> >((list<value>)car(key), keyparams(cdr(key)));
+}
+
+/**
+ * Convert a get result to a list of items.
+ */
+const list<value> getitems(PGresult* const r, const int i, const int n) {
+ if (i == n)
+ return nilListValue;
+ const value key(content(scheme::readValue(string(PQgetvalue(r, i, 0)))));
+ const value val(content(scheme::readValue(string(PQgetvalue(r, i, 1)))));
+ return cons<value>(mklist<value>(key, val), getitems(r, i + 1, n));
+}
+
+/**
+ * Parse a text search query and translate single quotes to spaces and double
+ * quotes to single quotes.
+ */
+ostringstream& tsparse(ostringstream& os, const char* const c) {
+ if (!*c)
+ return os;
+ os << (*c == '\''? ' ' : *c == '"'? '\'' : *c);
+ return tsparse(os, c + 1);
+}
+const string tstranslate(const string& ts) {
+ ostringstream os;
+ tsparse(os, c_str(ts));
+ return str(os);
+}
+
+/**
+ * Get one item or a collection of items from the database.
+ * The key is a simple value or a list of simple values plus optional name / value
+ * pairs to specify regex, like, textsearch limit and offset clause
*/
const failable<value> get(const value& key, const PGSql& pgsql) {
debug(key, "pgsql::get::key");
@@ -204,21 +248,99 @@ const failable<value> get(const value& key, const PGSql& pgsql) {
debug(pgsql.table, "pgsql::get::table");
setup(pgsql);
- const string ks(scheme::writeValue(key));
- const char* params[1] = { c_str(ks) };
- PGresult* r = PQexecParams(pgsql.conn, c_str(string("select * from ") + pgsql.table + string(" where ") + pgsql.kname + string(" = $1;")), 1, NULL, params, NULL, NULL, 0);
+ // Get item and id and get parameters from the key
+ const bool lk = isList(key);
+ const list<list<value> > kparams = lk? keyparams(key) : list<list<value> >();
+ const list<value> regex = assoc<value>("regex", kparams);
+ const list<value> like = assoc<value>("like", kparams);
+ const list<value> textsearch = assoc<value>("textsearch", kparams);
+ const list<value> limit = assoc<value>("limit", kparams);
+ const list<value> offset = assoc<value>("offset", kparams);
+ const list<value> id = lk? keyid(key) : nilListValue;
+ const list<value> atable = assoc<value>("table", kparams);
+ const string table = isNil(atable)? pgsql.table : (string)cadr(atable);
+ const list<value> akname = assoc<value>("kcolumn", kparams);
+ const string kname = isNil(akname)? pgsql.kname : (string)cadr(akname);
+ const list<value> avname = assoc<value>("vcolumn", kparams);
+ const string vname = isNil(avname)? pgsql.vname : (string)cadr(avname);
+
+ // Build the SQL query
+ const char* sqlparams[5];
+ int p = 0;
+ int w = 0;
+ ostringstream sqlos;
+ sqlos << "select data.*";
+ if (!isNil(textsearch)) {
+ // Text search, setup result ranking
+ sqlos << ", ts_rank_cd(to_tsvector(data." << vname << "), tsquery, 32) as rank";
+ }
+ sqlos << " from " << table << " data";
+ if (!isNil(textsearch)) {
+ // Text search, define the query
+ const string ts = tstranslate((string)cadr(textsearch));
+ sqlparams[p++] = c_str(ts);
+ sqlos << ", plainto_tsquery($" << p << ") tsquery";
+ }
+ if (!lk || !isNil(id)) {
+ // Query of the form key = id
+ sqlparams[p++] = c_str(write(content(scheme::writeValue(lk? (value)id : key))));
+ sqlos << (w == 0? " where" : " and");
+ sqlos << " data." << kname << " = $" << p;
+ w++;
+ }
+ if (!isNil(regex)) {
+ // Query of the form key ~ param
+ sqlparams[p++] = c_str((string)cadr(regex));
+ sqlos << (w == 0? " where" : " and");
+ sqlos << " data." << kname << " ~ $" << p;
+ w++;
+ }
+ if (!isNil(like)) {
+ // Query of the form key like param
+ sqlparams[p++] = c_str((string)cadr(like));
+ sqlos << (w == 0? " where" : " and");
+ sqlos << " data." << kname << " like $" << p;
+ w++;
+ }
+ if (!isNil(textsearch)) {
+ // Text search, apply the query
+ sqlos << (w == 0? " where" : " and");
+ sqlos << " tsquery @@ to_tsvector(data." << vname << ") order by rank desc";
+ w++;
+ }
+ if (!isNil(offset)) {
+ // Result pagination offset
+ sqlos << " offset " << atoi(c_str((string)cadr(offset)));
+ }
+ // Result limit count
+ const int l = isNil(limit)? 1 : atoi(c_str((string)cadr(limit)));
+ sqlos << " limit " << l << ";";
+
+ // Execute the query
+ const string sqls = str(sqlos);
+ debug(sqls, "pgsql::get::sqls");
+ PGresult* r = PQexecParams(pgsql.conn, c_str(sqls), p, NULL, sqlparams, NULL, NULL, 0);
if (PQresultStatus(r) != PGRES_TUPLES_OK)
return mkfailure<value>(string("Couldn't execute select postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
- if (PQntuples(r) < 1) {
+ const int n = PQntuples(r);
+ if (n < 1) {
PQclear(r);
ostringstream os;
os << "Couldn't get postgresql entry: " << key;
return mkfailure<value>(str(os), 404, false);
}
- const char* data = PQgetvalue(r, 0, 1);
- const value val(scheme::readValue(string(data)));
- PQclear(r);
+ // Return a collection of key / item pairs
+ if (l != 1) {
+ const list<value> lval = getitems(r, 0, n);
+ PQclear(r);
+ debug(lval, "pgsql::get::result");
+ return (value)lval;
+ }
+
+ // Return a single item
+ const value val(content(scheme::readValue(string(PQgetvalue(r, 0, 1)))));
+ PQclear(r);
debug(val, "pgsql::get::result");
return val;
}
@@ -232,9 +354,9 @@ const failable<bool> del(const value& key, const PGSql& pgsql) {
debug(pgsql.table, "pgsql::delete::table");
setup(pgsql);
- const string ks(scheme::writeValue(key));
- const char* params[1] = { c_str(ks) };
- PGresult* r = PQexecParams(pgsql.conn, c_str(string("delete from ") + pgsql.table + string(" where ") + pgsql.kname + string(" = $1;")), 1, NULL, params, NULL, NULL, 0);
+ const string ks(write(content(scheme::writeValue(key))));
+ const char* const params[1] = { c_str(ks) };
+ PGresult* const r = PQexecParams(pgsql.conn, c_str(string("delete from ") + pgsql.table + string(" where ") + pgsql.kname + string(" = $1;")), 1, NULL, params, NULL, NULL, 0);
if (PQresultStatus(r) != PGRES_COMMAND_OK)
return mkfailure<bool>(string("Couldn't execute delete postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
PQclear(r);
diff --git a/sca-cpp/trunk/components/sqldb/sqldb.cpp b/sca-cpp/trunk/components/sqldb/sqldb.cpp
index 9925897693..1288dd553b 100644
--- a/sca-cpp/trunk/components/sqldb/sqldb.cpp
+++ b/sca-cpp/trunk/components/sqldb/sqldb.cpp
@@ -38,14 +38,14 @@ namespace sqldb {
/**
* Get an item from the database.
*/
-const failable<value> get(const list<value>& params, pgsql::PGSql& pg) {
+const failable<value> get(const list<value>& params, const pgsql::PGSql& pg) {
return pgsql::get(car(params), pg);
}
/**
* Post an item to the database.
*/
-const failable<value> post(const list<value>& params, pgsql::PGSql& pg) {
+const failable<value> post(const list<value>& params, const pgsql::PGSql& pg) {
const value id = append<value>(car(params), mklist(mkuuid()));
const failable<bool> val = pgsql::post(id, cadr(params), pg);
if (!hasContent(val))
@@ -56,7 +56,7 @@ const failable<value> post(const list<value>& params, pgsql::PGSql& pg) {
/**
* Put an item into the database.
*/
-const failable<value> put(const list<value>& params, pgsql::PGSql& pg) {
+const failable<value> put(const list<value>& params, const pgsql::PGSql& pg) {
const failable<bool> val = pgsql::put(car(params), cadr(params), pg);
if (!hasContent(val))
return mkfailure<value>(val);
@@ -66,7 +66,7 @@ const failable<value> put(const list<value>& params, pgsql::PGSql& pg) {
/**
* Delete an item from the database.
*/
-const failable<value> del(const list<value>& params, pgsql::PGSql& pg) {
+const failable<value> del(const list<value>& params, const pgsql::PGSql& pg) {
const failable<bool> val = pgsql::del(car(params), pg);
if (!hasContent(val))
return mkfailure<value>(val);
@@ -74,14 +74,23 @@ const failable<value> del(const list<value>& params, pgsql::PGSql& pg) {
}
/**
- * Component implementation lambda function.
+ * Start the component.
*/
-class applySqldb {
-public:
- applySqldb(const perthread_ptr<pgsql::PGSql>& pg) : pg(pg) {
- }
+const failable<value> start(const list<value>& params) {
+ // Connect to the configured database and table
+ debug("sqldb::start");
+ const gc_pool cp(gc_current_pool());
+ const value conninfo = ((lvvlambda)car(params))(nilListValue);
+ const value table = ((lvvlambda)cadr(params))(nilListValue);
+ const lambda<const gc_ptr<pgsql::PGSql>()> newPGSql = [conninfo, table, cp]() -> const gc_ptr<pgsql::PGSql> {
+ debug("sqldb::newPGSql");
+ const gc_scoped_pool sp(pool(cp));
+ return new (gc_new<pgsql::PGSql>()) pgsql::PGSql(conninfo, table);
+ };
+ const perthread_ptr<pgsql::PGSql> pg = *(new (gc_new<perthread_ptr<pgsql::PGSql> >()) perthread_ptr<pgsql::PGSql>(newPGSql));
- const value operator()(const list<value>& params) const {
+ // Return the component implementation lambda function
+ const lvvlambda applySqldb = [pg](const list<value>& params) -> const value {
const value func(car(params));
if (func == "get")
return get(cdr(params), *pg);
@@ -92,40 +101,8 @@ public:
if (func == "delete")
return del(cdr(params), *pg);
return mkfailure<value>();
- }
-
-private:
- const perthread_ptr<pgsql::PGSql> pg;
-};
-
-/**
- * Lambda function that creates a new database connection.
- */
-class newPGSql {
-public:
- newPGSql(const string& conninfo, const string& table) : conninfo(conninfo), table(table) {
- }
-
- const gc_ptr<pgsql::PGSql> operator()() const {
- return new (gc_new<pgsql::PGSql>()) pgsql::PGSql(conninfo, table);
- }
-
-private:
- const string conninfo;
- const string table;
-};
-
-/**
- * Start the component.
- */
-const failable<value> start(unused const list<value>& params) {
- // Connect to the configured database and table
- const value conninfo = ((lambda<value(const list<value>&)>)car(params))(list<value>());
- const value table = ((lambda<value(const list<value>&)>)cadr(params))(list<value>());
- const perthread_ptr<pgsql::PGSql> pg(lambda<gc_ptr<pgsql::PGSql>()>(newPGSql(conninfo, table)));
-
- // Return the component implementation lambda function
- return value(lambda<value(const list<value>&)>(applySqldb(pg)));
+ };
+ return value(applySqldb);
}
}