summaryrefslogtreecommitdiffstats
path: root/sandbox/sebastien/cpp/apr-2/components/sqldb
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-12-25 01:49:19 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-12-25 01:49:19 +0000
commitdc15dc32bb3348c760ba3643c083af7e0c8e43fe (patch)
tree2823b9165d5c3a8a1bc96b3d071f86101bb995b4 /sandbox/sebastien/cpp/apr-2/components/sqldb
parent088b2e47386078c79781a448e0b6e458ddaae23c (diff)
Create a sandbox branch to experiment with latest APR.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1052740 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sandbox/sebastien/cpp/apr-2/components/sqldb')
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/Makefile.am55
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/client-test.cpp130
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql35
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-backup41
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-conf105
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-conf122
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-test.cpp88
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-start29
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-stop27
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-test.cpp82
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql.hpp262
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/server-test44
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/sqldb-test32
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.componentType29
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.composite34
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.cpp124
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/standby-test39
17 files changed, 1278 insertions, 0 deletions
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/sqldb/Makefile.am
new file mode 100644
index 0000000000..4cd27e967c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/Makefile.am
@@ -0,0 +1,55 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+if WANT_SQLDB
+
+INCLUDES = -I${PGSQL_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/sqldb
+
+dist_comp_SCRIPTS = pgsql-conf pgsql-start pgsql-stop pgsql pgsql-standby-conf pgsql-backup
+compdir=$(prefix)/components/sqldb
+
+comp_DATA = pgsql.prefix
+pgsql.prefix: $(top_builddir)/config.status
+ echo ${PGSQL_PREFIX} >pgsql.prefix
+
+EXTRA_DIST = sqldb.composite sqldb.componentType
+
+comp_LTLIBRARIES = libsqldb.la
+noinst_DATA = libsqldb.so
+
+libsqldb_la_SOURCES = sqldb.cpp
+libsqldb_la_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq
+libsqldb.so:
+ ln -s .libs/libsqldb.so
+
+pgsql_test_SOURCES = pgsql-test.cpp
+pgsql_test_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq
+
+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
+
+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
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/client-test.cpp
new file mode 100644
index 0000000000..4e5c067633
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/client-test.cpp
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test SQL database component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+
+namespace tuscany {
+namespace sqldb {
+
+const string uri("http://localhost:8090/sqldb");
+
+bool testSqlDb() {
+ http::CURLSession cs("", "", "");
+
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+
+ const string p = path(content(id));
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == a);
+ }
+
+ const list<value> j = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$3.55"));
+ const list<value> b = mklist<value>(string("item"), 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));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == b);
+ }
+ {
+ const failable<value> r = http::del(uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(!hasContent(val));
+ }
+
+ 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>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$4.55"));
+ const value a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ http::CURLSession cs("", "", "");
+ 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);
+ cout << "Sqldb get test " << time(gl, 5, 200) << " ms" << endl;
+
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::sqldb::testSqlDb();
+ tuscany::sqldb::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql
new file mode 100755
index 0000000000..dab30e642b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Run SQL command
+here=`readlink -f $0`; here=`dirname $here`
+pgsql_prefix=`cat $here/pgsql.prefix`
+
+if [ "$2" = "" ]; then
+ host="localhost"
+ port="5432"
+ cmd="$1"
+else
+ host="$1"
+ port="$2"
+ cmd="$3"
+fi
+
+$pgsql_prefix/bin/psql -h $host -p $port -c "$cmd" db
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-backup b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-backup
new file mode 100755
index 0000000000..fad59236bf
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-backup
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Backup postgresql data directory
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+if [ "$2" = "" ]; then
+ host="localhost"
+ port="5432"
+else
+ host="$2"
+ port="$3"
+fi
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+$pgsql_prefix/bin/psql -h $host -p $port -c "SELECT pg_start_backup('backup', true)" db 1>>$root/logs/postgresql 2>&1
+
+echo "Content-type: application/x-compressed"
+echo
+
+tar -C $root/sqldb -cz data
+
+$pgsql_prefix/bin/psql -h $host -p $port -c "SELECT pg_stop_backup()" db 1>>$root/logs/postgresql 2>&1
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-conf b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-conf
new file mode 100755
index 0000000000..f5cc2d23e3
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-conf
@@ -0,0 +1,105 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Configure a postgresql master server
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+addr=$2
+if [ "$addr" = "" ]; then
+ ip="*"
+ port="5432"
+else
+ ip=`$here/../../modules/http/httpd-addr ip $addr`
+ if [ "$ip" = "" ]; then
+ ip="*"
+ fi
+ port=`$here/../../modules/http/httpd-addr port $addr`
+fi
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+mkdir -p $root/sqldb/data
+chmod 700 $root/sqldb/data
+mkdir -p $root/sqldb/archive
+mkdir -p $root/logs
+if [ ! -f $root/sqldb/data/postgresql.conf ]; then
+ $pgsql_prefix/bin/pg_ctl init -D $root/sqldb/data 1>>$root/logs/postgresql 2>&1
+ cp $root/sqldb/data/postgresql.conf $root/sqldb/data/postgresql-init.conf
+ cp $root/sqldb/data/pg_hba.conf $root/sqldb/data/pg_hba-init.conf
+fi
+
+# Generate server configuration
+cp $root/sqldb/data/postgresql-init.conf $root/sqldb/data/postgresql.conf
+cat >>$root/sqldb/data/postgresql.conf <<EOF
+
+# Generated by: pgsql-conf $*
+
+# Listen
+listen_addresses = '$ip'
+port = $port
+
+# Setup archival
+archive_mode = on
+archive_command = 'cp %p $root/sqldb/archive/%f'
+
+# Setup hot standby with streaming replication
+wal_level = hot_standby
+max_wal_senders = 5
+wal_keep_segments = 32
+
+EOF
+
+# Generate client auth configuration
+cp $root/sqldb/data/pg_hba-init.conf $root/sqldb/data/pg_hba.conf
+cat >>$root/sqldb/data/pg_hba.conf <<EOF
+
+# Generated by: pgsql-conf $*
+# TYPE DATABASE USER CIDR-ADDRESS METHOD
+host all all samenet trust
+host replication all samenet trust
+
+EOF
+
+# Create the db
+$pgsql_prefix/bin/pg_ctl start -w -D $root/sqldb/data -l $root/logs/postgresql 1>>$root/logs/postgresql 2>&1
+$pgsql_prefix/bin/createdb -h localhost -p $port db 1>>$root/logs/postgresql 2>&1
+$pgsql_prefix/bin/pg_ctl stop -w -D $root/sqldb/data 1>>$root/logs/postgresql 2>&1
+
+# Generate database backup script
+mkdir -p $root/sqldb/scripts
+cat >$root/sqldb/scripts/backup <<EOF
+#!/bin/sh
+$here/pgsql-backup $root localhost $port
+EOF
+chmod 700 $root/sqldb/scripts/backup
+
+# Configure HTTPD to serve backup and archive files
+if [ -f "$root/conf/httpd.conf" ]; then
+ cat >>$root/conf/httpd.conf <<EOF
+# Generated by: pgsql-conf $*
+
+# Serve PostgreSQL backup and WAL archive files
+ScriptAlias /pgsql-backup "$root/sqldb/scripts/backup"
+Alias /pgsql-archive "$root/sqldb/archive"
+
+EOF
+
+fi
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-conf b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-conf
new file mode 100755
index 0000000000..cbfd90b48c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-conf
@@ -0,0 +1,122 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Configure a postgresql hot standby server
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+# Server address
+addr=$2
+if [ "$addr" = "" ]; then
+ ip="*"
+ port="5432"
+else
+ ip=`$here/../../modules/http/httpd-addr ip $addr`
+ if [ "$ip" = "" ]; then
+ ip="*"
+ fi
+ port=`$here/../../modules/http/httpd-addr port $addr`
+fi
+
+# Master server address
+if [ "$3" = "" ]; then
+ mhost="localhost"
+ mport="5432"
+ mhttpport="80"
+else
+ mhost="$3"
+ mport="$4"
+ mhttpport="$5"
+fi
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+mkdir -p $root/sqldb/data
+chmod 700 $root/sqldb/data
+mkdir -p $root/sqldb/archive
+mkdir -p $root/logs
+
+# Initialize from a backup of the master
+if [ ! -f $root/sqldb/data/postgresql.conf ]; then
+ (wget http://$mhost:$mhttpport/pgsql-backup -O - | tar -C $root/sqldb -xz) 1>>$root/logs/postgresql 2>&1
+ rm -rf $root/sqldb/data/postmaster.pid $root/sqldb/data/pg_xlog
+ mkdir -p $root/sqldb/data/pg_xlog/archive_status
+ chmod 700 $root/sqldb/data/pg_xlog/archive_status
+fi
+
+# Generate server configuration
+cp $root/sqldb/data/postgresql-init.conf $root/sqldb/data/postgresql.conf
+cat >>$root/sqldb/data/postgresql.conf <<EOF
+
+# Generated by: standby-conf $*
+
+# Listen
+listen_addresses = '$ip'
+port = $port
+
+# Setup archival
+archive_mode = on
+archive_command = 'cp %p $root/sqldb/archive/%f'
+
+# Setup hot standby with streaming replication
+wal_level = hot_standby
+max_wal_senders = 5
+wal_keep_segments = 32
+
+# Enable hot standby
+hot_standby = on
+
+EOF
+
+# Generate recovery configuration
+cat >$root/sqldb/data/recovery.conf << EOF
+# Generated by: pgsql-slave-conf $*
+
+# Start in standby mode
+standby_mode = 'on'
+primary_conninfo = 'host=$mhost port=$mport'
+
+# Failover
+trigger_file = '$root/sqldb/failover'
+
+restore_command = 'wget http://$mhost:$mhttpport/pgsql-archive/%f -O "%p"'
+
+EOF
+
+# Generate database backup script
+mkdir -p $root/sqldb/scripts
+cat >$root/sqldb/scripts/backup <<EOF
+#!/bin/sh
+$here/pgsql-backup $root localhost $port
+EOF
+chmod 700 $root/sqldb/scripts/backup
+
+# Configure HTTPD to serve backup and archive files
+if [ -f "$root/conf/httpd.conf" ]; then
+ cat >>$root/conf/httpd.conf <<EOF
+# Generated by: pgsql-conf $*
+
+# Serve PostgreSQL backup and WAL archive files
+ScriptAlias /pgsql-backup "$root/sqldb/scripts/backup"
+Alias /pgsql-archive "$root/sqldb/archive"
+
+EOF
+
+fi
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-test.cpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-test.cpp
new file mode 100644
index 0000000000..44f0a4a9e6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-test.cpp
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test PostgreSQL hot standby support.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "pgsql.hpp"
+
+namespace tuscany {
+namespace pgsql {
+
+bool testPGSql() {
+ PGSql wpg("host=localhost port=5432 dbname=db", "test");
+ PGSql rpg("host=localhost port=5433 dbname=db", "test");
+ const value k = mklist<value>("a");
+
+ assert(hasContent(post(k, string("AAA"), wpg)));
+ sleep(1);
+ assert((get(k, rpg)) == value(string("AAA")));
+ assert(hasContent(put(k, string("aaa"), wpg)));
+ sleep(1);
+ assert((get(k, rpg)) == value(string("aaa")));
+ assert(hasContent(del(k, wpg)));
+ sleep(1);
+ assert(!hasContent(get(k, rpg)));
+
+ 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 value k = mklist<value>("c");
+ PGSql wpg("host=localhost port=5432 dbname=db", "test");
+ PGSql rpg("host=localhost port=5433 dbname=db", "test");
+ assert(hasContent(post(k, string("CCC"), wpg)));
+ sleep(1);
+
+ const lambda<bool()> gl = getLoop(k, rpg);
+ cout << "PGSql get test " << time(gl, 5, 200) << " ms" << endl;
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::pgsql::testPGSql();
+ tuscany::pgsql::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-start b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-start
new file mode 100755
index 0000000000..3f03d0b4dc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-start
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Start postgresql
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+mkdir -p $root/sqldb
+mkdir -p $root/logs
+$pgsql_prefix/bin/pg_ctl start -w -D $root/sqldb/data -l $root/logs/postgresql 1>>$root/logs/postgresql 2>&1
+sleep 1
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-stop b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-stop
new file mode 100755
index 0000000000..eefade47d2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-stop
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Stop postgresql
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+mkdir -p $root/logs
+$pgsql_prefix/bin/pg_ctl stop -w -D $root/sqldb/data 1>>$root/logs/postgresql 2>&1
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-test.cpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-test.cpp
new file mode 100644
index 0000000000..1019667285
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-test.cpp
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test PostgreSQL access functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "pgsql.hpp"
+
+namespace tuscany {
+namespace pgsql {
+
+bool testPGSql() {
+ PGSql pg("host=localhost port=5432 dbname=db", "test");
+ const value k = mklist<value>("a");
+
+ assert(hasContent(post(k, string("AAA"), pg)));
+ assert((get(k, pg)) == value(string("AAA")));
+ assert(hasContent(put(k, string("aaa"), pg)));
+ assert((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 value k = mklist<value>("c");
+ PGSql pg("host=localhost port=5432 dbname=db", "test");
+ assert(hasContent(post(k, string("CCC"), pg)));
+
+ const lambda<bool()> gl = getLoop(k, pg);
+ cout << "PGSql get test " << time(gl, 5, 200) << " ms" << endl;
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::pgsql::testPGSql();
+ tuscany::pgsql::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql.hpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql.hpp
new file mode 100644
index 0000000000..f4da8db220
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql.hpp
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_pgsql_hpp
+#define tuscany_pgsql_hpp
+
+/**
+ * PostgreSQL access functions.
+ */
+
+#include <libpq-fe.h>
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/scheme/eval.hpp"
+
+namespace tuscany {
+namespace pgsql {
+
+/**
+ * Return and clear a Postgres result failure.
+ */
+const string pgfailure(PGresult* r, PGconn* conn) {
+ const string re = PQresultErrorMessage(r);
+ PQclear(r);
+ if (length(re) != 0)
+ return re;
+ const string ce = PQerrorMessage(conn);
+ return ce;
+}
+
+/**
+ * Represents a PGSql connection.
+ */
+class PGSql {
+public:
+ PGSql() : owner(false) {
+ }
+
+ PGSql(const string& conninfo, const string& table) : owner(true), conn(NULL), conninfo(conninfo), table(table) {
+ conn = PQconnectdb(c_str(conninfo));
+ if (PQstatus(conn) != CONNECTION_OK) {
+ mkfailure<bool>(string("Could not connect to postgresql database: ") + PQerrorMessage(conn));
+ return;
+ }
+ setup(true);
+ }
+
+ PGSql(const PGSql& c) : owner(false), conn(c.conn), conninfo(c.conninfo), table(c.table) {
+ }
+
+ ~PGSql() {
+ if (!owner)
+ return;
+ if (conn == NULL)
+ return;
+ PQfinish(conn);
+ }
+
+private:
+ bool owner;
+ PGconn *conn;
+ string conninfo;
+ string table;
+
+ friend const failable<bool> setup(const PGSql& pgsql);
+ 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);
+
+ /**
+ * Setup the database connection.
+ */
+ const failable<bool> setup(const bool init) const {
+
+ // Check the status of the connection and reconnect if necessary
+ if (!init) {
+ if (PQstatus(conn) == CONNECTION_OK)
+ return true;
+ debug("pgsql::setup::reset");
+ PQreset(conn);
+ if (PQstatus(conn) != CONNECTION_OK)
+ return mkfailure<bool>(string("Could not reconnect to postgresql database: ") + PQerrorMessage(conn));
+ }
+ debug("pgsql::setup::init");
+
+ // 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 postgresql column select statement: ") + pgfailure(kr, conn));
+ if (PQntuples(kr) != 2) {
+ PQclear(kr);
+ return mkfailure<bool>(string("Could not find postgresql 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 postgresql SQL statement: ") + pgfailure(r, conn));
+ 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 postgresql SQL statement: ") + pgfailure(r, conn));
+ 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 postgresql SQL statement: ") + pgfailure(r, conn));
+ 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 postgresql SQL statement: ") + pgfailure(r, conn));
+ PQclear(r);
+ }
+ return true;
+ }
+};
+
+/**
+ * Setup the database connection if necessary.
+ */
+const failable<bool> setup(const PGSql& pgsql) {
+ return pgsql.setup(false);
+}
+
+/**
+ * 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.conninfo, "pgsql::post::conninfo");
+ 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 = PQexecPrepared(pgsql.conn, "post", 2, params, NULL, NULL, 0);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not execute insert postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
+ 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.conninfo, "pgsql::put::conninfo");
+ 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 = PQexecPrepared(pgsql.conn, "put", 2, params, NULL, NULL, 0);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not execute update postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
+ const string t = PQcmdTuples(r);
+ if (t != "0") {
+ PQclear(r);
+ debug(true, "pgsql::put::result");
+ return true;
+ }
+ PQclear(r);
+
+ PGresult* pr = PQexecPrepared(pgsql.conn, "post", 2, params, NULL, NULL, 0);
+ if (PQresultStatus(pr) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not execute insert postgresql SQL statement: ") + pgfailure(pr, pgsql.conn));
+ PQclear(pr);
+
+ 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.conninfo, "pgsql::get::conninfo");
+ debug(pgsql.table, "pgsql::get::table");
+ setup(pgsql);
+
+ 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 select postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
+ if (PQntuples(r) < 1) {
+ PQclear(r);
+ return mkfailure<value>(string("Could not get postgresql 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.conninfo, "pgsql::delete::conninfo");
+ debug(pgsql.table, "pgsql::delete::table");
+ setup(pgsql);
+
+ 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 postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
+ PQclear(r);
+
+ debug(true, "pgsql::delete::result");
+ return true;
+}
+
+}
+}
+
+#endif /* tuscany_pgsql_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/server-test b/sandbox/sebastien/cpp/apr-2/components/sqldb/server-test
new file mode 100755
index 0000000000..c07d3b0510
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/server-test
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Setup
+../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs
+./pgsql-conf tmp
+./pgsql-start tmp
+./pgsql "drop table test;" 1>/dev/null 2>&1
+./pgsql "create table test(key text, value text);" 1>/dev/null 2>&1
+
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite sqldb.composite
+EOF
+
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+./pgsql-stop tmp
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb-test b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb-test
new file mode 100755
index 0000000000..e910ae0059
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb-test
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Setup
+./pgsql-conf tmp
+./pgsql-start tmp
+./pgsql "drop table test;" 1>/dev/null 2>&1
+./pgsql "create table test(key text, value text);" 1>/dev/null 2>&1
+
+# Test
+./pgsql-test 2>/dev/null
+rc=$?
+
+# Cleanup
+./pgsql-stop tmp
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.componentType b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.componentType
new file mode 100644
index 0000000000..5aa6d8e30f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.componentType
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="sqldb"/>
+ <property name="conninfo" type="xsd:string">host=localhost port=5432 dbname=db</property>
+ <property name="table" type=xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.composite b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.composite
new file mode 100644
index 0000000000..1511e66024
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.composite
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="sqldb">
+
+ <component name="sqldb">
+ <implementation.cpp path="." library="libsqldb"/>
+ <property name="conninfo">host=localhost port=5432 dbname=db</property>
+ <property name="table">test</property>
+ <service name="sqldb">
+ <t:binding.http uri="sqldb"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.cpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.cpp
new file mode 100644
index 0000000000..0524b00bd2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.cpp
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * PostgreSQL-based database component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "pgsql.hpp"
+
+namespace tuscany {
+namespace sqldb {
+
+/**
+ * Get an item from the database.
+ */
+const failable<value> get(const list<value>& params, 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 value id = append<value>(car(params), mklist(mkuuid()));
+ const failable<bool> val = pgsql::post(id, cadr(params), pg);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return id;
+}
+
+/**
+ * Put an item into the database.
+ */
+const failable<value> put(const list<value>& params, pgsql::PGSql& pg) {
+ const failable<bool> val = pgsql::put(car(params), cadr(params), pg);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Delete an item from the database.
+ */
+const failable<value> del(const list<value>& params, pgsql::PGSql& pg) {
+ const failable<bool> val = pgsql::del(car(params), pg);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Component implementation lambda function.
+ */
+class applySqldb {
+public:
+ applySqldb(pgsql::PGSql& pg) : pg(pg) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const value func(car(params));
+ if (func == "get")
+ return get(cdr(params), pg);
+ if (func == "post")
+ return post(cdr(params), pg);
+ if (func == "put")
+ return put(cdr(params), pg);
+ if (func == "delete")
+ return del(cdr(params), pg);
+ return tuscany::mkfailure<tuscany::value>();
+ }
+
+private:
+ pgsql::PGSql& pg;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(unused const list<value>& params) {
+ // Connect to the configured database and table
+ const value conninfo = ((lambda<value(list<value>)>)car(params))(list<value>());
+ const value table = ((lambda<value(list<value>)>)cadr(params))(list<value>());
+ pgsql::PGSql& pg = *(new (gc_new<pgsql::PGSql>()) pgsql::PGSql(conninfo, table));
+
+ // Return the component implementation lambda function
+ return value(lambda<value(const list<value>&)>(applySqldb(pg)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::sqldb::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/standby-test b/sandbox/sebastien/cpp/apr-2/components/sqldb/standby-test
new file mode 100755
index 0000000000..9e56bfc039
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/standby-test
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Setup
+../../modules/http/httpd-conf tmp/master localhost 8090 tmp/master/htdocs
+./pgsql-conf tmp/master 5432
+./pgsql-start tmp/master
+./pgsql localhost 5432 "drop table test;" 1>/dev/null 2>&1
+./pgsql localhost 5432 "create table test(key text, value text);" 1>/dev/null 2>&1
+../../modules/http/httpd-start tmp/master
+sleep 2
+./pgsql-standby-conf tmp/standby 5433 localhost 5432 8090
+./pgsql-start tmp/standby
+
+# Test
+./pgsql-standby-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp/master
+./pgsql-stop tmp/standby
+./pgsql-stop tmp/master
+return $rc