diff --git a/CEP/BB/ParmDB/configure.in b/CEP/BB/ParmDB/configure.in
index b348a1aadd525d95782ec54b49cb1fa077c4cd57..3afb7bfa30c65931e1478f5c689b8e405a2ce779 100644
--- a/CEP/BB/ParmDB/configure.in
+++ b/CEP/BB/ParmDB/configure.in
@@ -55,6 +55,10 @@ lofar_INTERNAL(LCS/Blob,Blob,,1,Blob/BlobHeader.h)
 lofar_INTERNAL(LCS/Common,Common,,1,Common/LofarTypedefs.h,,)
 lofar_AIPSPP(1,"-ltables -lscimath -lscimath_f -lcasa")
 
+lofar_EXTERNAL(boost,1,boost/logic/tribool.hpp,"")
+lofar_EXTERNAL(pgsql,1,libpq-fe.h,pq)
+lofar_EXTERNAL(pqxx,1,pqxx/pqxx, pqxx)
+
 dnl
 dnl Output Makefiles
 dnl
diff --git a/CEP/BB/ParmDB/include/ParmDB/Makefile.am b/CEP/BB/ParmDB/include/ParmDB/Makefile.am
index e555d64afcd893c0fcc289a98493b0c8679d60de..dbda7e7ead680ca67b6aa27d2f181bdfbf87162d 100644
--- a/CEP/BB/ParmDB/include/ParmDB/Makefile.am
+++ b/CEP/BB/ParmDB/include/ParmDB/Makefile.am
@@ -1,6 +1,6 @@
 INSTHDRS = \
 ParmValue.h ParmDomain.h ParmDBMeta.h \
-ParmDB.h ParmDBAIPS.h
+ParmDB.h ParmDBAIPS.h ParmDBPostgres.h
 
 NOINSTHDRS =
 
diff --git a/CEP/BB/ParmDB/include/ParmDB/ParmDBMeta.h b/CEP/BB/ParmDB/include/ParmDB/ParmDBMeta.h
index ff592308e24b5f481d360ad8451c05a3f8856948..ba67c9d01211670f9605f08425ac18f67fb37f53 100644
--- a/CEP/BB/ParmDB/include/ParmDB/ParmDBMeta.h
+++ b/CEP/BB/ParmDB/include/ParmDB/ParmDBMeta.h
@@ -26,8 +26,7 @@
 // \file
 // one line description.
 
-#include <string>
-
+#include <Common/lofar_string.h>
 
 namespace LOFAR {
 //# Forward Declarations.
@@ -48,7 +47,7 @@ namespace ParmDB {
     ParmDBMeta (const std::string& type, const std::string& tableName);
 
     void setSQLMeta (const std::string& dbName, const std::string& userName,
-		     const std::string& dbPwd, const std::string& hostName);
+        const std::string& dbPwd, const std::string& hostName);
 
     const std::string& getType() const
       { return itsType; }
@@ -56,6 +55,18 @@ namespace ParmDB {
     const std::string& getTableName() const
       { return itsTableName; }
 
+    const std::string& getDBName() const
+      { return itsDBName; }
+      
+    const std::string& getUserName() const
+      { return itsUserName; }
+      
+    const std::string& getDBPwd() const
+      { return itsDBPwd; }
+    
+    const std::string& getHostName() const
+      { return itsHostName; }
+    
     // Write the object into a blob.
     friend BlobOStream& operator<< (BlobOStream&, const ParmDBMeta&);
 
diff --git a/CEP/BB/ParmDB/include/ParmDB/ParmDBPostgres.h b/CEP/BB/ParmDB/include/ParmDB/ParmDBPostgres.h
new file mode 100644
index 0000000000000000000000000000000000000000..d679fee27402cc4e1169bab6428b2d3686c22922
--- /dev/null
+++ b/CEP/BB/ParmDB/include/ParmDB/ParmDBPostgres.h
@@ -0,0 +1,151 @@
+//# ParmDBPostgres.h: 
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program is free software; you can redistribute it and/or modify
+//# it under the terms of the GNU General Public License as published by
+//# the Free Software Foundation; either version 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program is distributed in the hope that it will be useful,
+//# but WITHOUT ANY WARRANTY; without even the implied warranty of
+//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//# GNU General Public License for more details.
+//#
+//# You should have received a copy of the GNU General Public License
+//# along with this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#ifndef LOFAR_PARMDB_PARMDBPOSTGRES_H
+#define LOFAR_PARMDB_PARMDBPOSTGRES_H
+
+#if defined(HAVE_PQXX)
+# include <pqxx/connection>
+#else
+# error libpqxx, the C++ API to PostgreSQL, is required
+#endif
+
+#include <Common/lofar_string.h>
+#include <Common/lofar_smartptr.h>
+#include <ParmDB/ParmDB.h>
+
+#include <ParmDB/ParmValue.h>
+#include <Common/lofar_map.h>
+#include <Common/lofar_vector.h>
+
+namespace LOFAR
+{
+namespace ParmDB
+{
+
+class ParmDBPostgres: public ParmDBRep
+{
+public:
+    ParmDBPostgres(const string &database,
+        const string &user,
+        const string &password,
+        const string &host,
+        const string &port);
+
+//    ~ParmDBPostgres();
+
+    //# ParmDBRep interface implementation
+//    virtual void lock (bool lockForWrite);
+//    virtual void unlock();
+
+    // Get the domain range (time,freq) of the given parameters in the table.
+    // This is the minimum and maximum value of these axes for all parameters.
+    // An empty name pattern is the same as * (all parms).
+    // <group>
+    virtual ParmDomain getRange(const std::string& parmNamePattern) const;
+    virtual ParmDomain
+        getRange(const std::vector<std::string>& parmNames) const;
+
+    // Get the parameter values for the given parameter and domain.
+    // Note that the requested domain may contain multiple values.
+    // A selection on parentId is done if >= 0.
+    virtual ParmValueSet getValues(const std::string& parmName,
+        const ParmDomain& domain,
+        int parentId,
+        ParmDBRep::TableType);
+
+    // Get all values for a given domain and set of parm names.
+    // If the parm name vector is empty, all parm names are taken.
+    virtual void getValues(std::map<std::string,ParmValueSet>& result,
+        const std::vector<std::string>& parmNames,
+        const ParmDomain& domain,
+        int parentId,
+        ParmDBRep::TableType);
+
+    // Get the parameter values for the given parameters and domain.
+    // Only * and ? should be used in the pattern (no [] and {}).
+    // A selection on parentId is done if >= 0.
+    virtual void getValues(std::map<std::string,ParmValueSet>& result,
+        const std::string& parmNamePattern,
+        const ParmDomain& domain,
+        int parentId,
+        ParmDBRep::TableType);
+
+    // Put the value for the given parameter and domain.
+    // overwriteMask=true indicates that the solvableMask might be changed
+    // and should be overwritten in an existing record.
+    virtual void putValue(const std::string& parmName,
+        ParmValue& value,
+        ParmDBRep::TableType,
+        bool overwriteMask = true);
+
+    // Put the value for the given parameters and domain.
+    // It only writes the parameters that have the same DBSeqNr as this ParmDB.
+    // overwriteMask=true indicates that the solvableMask might be changed
+    // and should be overwritten in an existing record.
+    virtual void putValues(std::map<std::string,ParmValueSet>& values,
+        ParmDBRep::TableType,
+        bool overwriteMask = true);
+
+    // Delete the records for the given parameters and domain.
+    // If parentId>=0, only records with that parentid will be deleted.
+    virtual void deleteValues(const std::string& parmNamePattern,
+        const ParmDomain& domain,
+        int parentId,
+        ParmDBRep::TableType);
+
+    // Get the default value for the given parameters.
+    // Only * and ? should be used in the pattern (no [] and {}).
+    virtual void getDefValues(std::map<std::string,ParmValueSet>& result,
+        const std::string& parmNamePattern);
+
+    // Put the default value.
+    virtual void putDefValue(const std::string& parmName,
+        const ParmValue& value);
+
+    // Delete the default value records for the given parameters.
+    virtual void deleteDefValues(const std::string& parmNamePattern);
+
+    // Get the names of all parms matching the given (filename like) pattern.
+    virtual std::vector<std::string> getNames(const std::string& pattern,
+        ParmDBRep::TableType);
+
+    // Clear database or table
+    virtual void clearTables();
+
+private:
+    // Fill the map with default values.
+    virtual void fillDefMap(std::map<std::string,ParmValue>& defMap);
+
+    static string translatePattern(const string &pattern);
+
+    scoped_ptr<pqxx::connection>    itsConnection;
+};
+
+
+} //# namespace BBS
+} //# namespace LOFAR
+
+//# Include function templates.
+#include <ParmDB/ParmDBPostgres.tcc>
+
+#endif
diff --git a/CEP/BB/ParmDB/include/ParmDB/ParmDBPostgres.tcc b/CEP/BB/ParmDB/include/ParmDB/ParmDBPostgres.tcc
new file mode 100644
index 0000000000000000000000000000000000000000..e8b88b9a763914fa4753e20e2e45d689cd4eb233
--- /dev/null
+++ b/CEP/BB/ParmDB/include/ParmDB/ParmDBPostgres.tcc
@@ -0,0 +1,124 @@
+//# ParmDBPostgres.tcc: Utility function templates for Postgres ParmDB 
+//# implementation.
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program is free software; you can redistribute it and/or modify
+//# it under the terms of the GNU General Public License as published by
+//# the Free Software Foundation; either version 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program is distributed in the hope that it will be useful,
+//# but WITHOUT ANY WARRANTY; without even the implied warranty of
+//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//# GNU General Public License for more details.
+//#
+//# You should have received a copy of the GNU General Public License
+//# along with this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#ifndef LOFAR_PARMDB_PARMDBPOSTGRES_TCC
+#define LOFAR_PARMDB_PARMDBPOSTGRES_TCC
+
+#if defined(HAVE_PQXX)
+# include <pqxx/transactor>
+# include <pqxx/binarystring>
+#else
+# error libpqxx, the C++ API to PostgreSQL, is required
+#endif
+
+#include <Common/DataFormat.h>
+#include <Common/DataConvert.h>
+#include <Common/LofarLogger.h>
+#include <Common/lofar_vector.h>
+
+namespace LOFAR
+{
+namespace ParmDB
+{
+
+//# Function templates to pack/unpack a vector of (builtin) types to/from a 
+//# Postgres binary string literal (BYTEA).
+template<typename T>
+inline string pack_vector(pqxx::transaction_base &transaction,
+    const vector<T> &in)
+{
+    uchar format = static_cast<uchar>(LOFAR::dataFormat());
+
+    //# Construct a properly escaped string that consists of one uchar that
+    //# represents the host endianness, followed by the data.
+    return transaction.esc_raw(&format, 1)
+        + transaction.esc_raw(reinterpret_cast<const uchar*>(&in[0]),
+            sizeof(T) * in.size());
+}
+
+
+template<typename T>
+inline vector<T> unpack_vector(const pqxx::binarystring &in)
+{
+    ASSERT((in.size() - 1) % sizeof(T) == 0);
+
+    const uchar *bytes = in.data();
+    const size_t size = (in.size() - 1) / sizeof(T);
+    vector<T> result(size);
+
+    //# Copy data as elements of type T.
+    const T *data = reinterpret_cast<const T*>(&bytes[1]);
+    for(size_t i = 0; i < size; ++i)
+        result[i] = data[i];
+
+    //# Byte swap the result if necessary.
+    if(bytes[0] != static_cast<uchar>(LOFAR::dataFormat()))
+        dataConvert(static_cast<DataFormat>(bytes[0]),
+            &result[0],
+            result.size());
+
+    return result;
+}
+
+
+//# Template specialization for vector<bool>. Needed because vector<bool> does 
+//# not satisfy all the requirements of an STL container. In particular, it uses 
+//# proxies to represent access to individual bits, so &(in[0]) does not work.
+template<>
+inline string pack_vector<>(pqxx::transaction_base &transaction,
+    const vector<bool> &in)
+{
+    uchar format = static_cast<uchar>(LOFAR::dataFormat());
+
+    //# Copy the contents of the input vector.
+    uchar tmp[in.size()];
+    for(size_t i = 0; i < in.size(); ++i)
+        tmp[i] = static_cast<uchar>(in[i]);
+
+    return transaction.esc_raw(&format, 1)
+        + transaction.esc_raw(tmp, sizeof(bool) * in.size());
+}
+
+
+//# TODO: sizeof(bool) == 1 cannot assumed to be 1!
+template<>
+inline vector<bool> unpack_vector<>(const pqxx::binarystring &in)
+{
+    ASSERT(sizeof(bool) == 1);
+    ASSERT((in.size() - 1) % sizeof(bool) == 0);
+
+    const uchar *bytes = in.data();
+    const size_t size = (in.size() - 1) / sizeof(bool);
+    vector<bool> result(size);
+
+    const bool *data = reinterpret_cast<const bool*>(&bytes[1]);
+    for(size_t i = 0; i < size; ++i)
+        result[i] = data[i];
+
+    return result;
+}
+
+} //# namespace BBS
+} //# namespace LOFAR
+
+#endif
diff --git a/CEP/BB/ParmDB/include/ParmDB/ParmDBPostgresTransactors.h b/CEP/BB/ParmDB/include/ParmDB/ParmDBPostgresTransactors.h
new file mode 100644
index 0000000000000000000000000000000000000000..dbb7bf5d3f5a650dad4276a38da87ef7873e412a
--- /dev/null
+++ b/CEP/BB/ParmDB/include/ParmDB/ParmDBPostgresTransactors.h
@@ -0,0 +1,187 @@
+//# ParmDBPostgresTransactors.h: 
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program is free software; you can redistribute it and/or modify
+//# it under the terms of the GNU General Public License as published by
+//# the Free Software Foundation; either version 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program is distributed in the hope that it will be useful,
+//# but WITHOUT ANY WARRANTY; without even the implied warranty of
+//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//# GNU General Public License for more details.
+//#
+//# You should have received a copy of the GNU General Public License
+//# along with this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#ifndef LOFAR_PARMDB_PARMDBPOSTGRESTRANSACTORS_H
+#define LOFAR_PARMDB_PARMDBPOSTGRESTRANSACTORS_H
+
+#if defined(HAVE_PQXX)
+# include <pqxx/connection>
+# include <pqxx/transactor>
+# include <pqxx/result>
+#else
+# error libpqxx, the C++ API to PostgreSQL, is required
+#endif
+
+
+#include <Common/lofar_string.h>
+#include <Common/lofar_vector.h>
+#include <Common/lofar_map.h>
+#include <Common/lofar_sstream.h>
+#include <ParmDB/ParmValue.h>
+
+namespace LOFAR
+{
+namespace ParmDB
+{
+class ParmDomain;
+
+
+class PQGetDomain: public pqxx::transactor<>
+{
+public:
+    PQGetDomain(const string &regex, ParmDomain &domain);
+    PQGetDomain(const vector<string> &names, ParmDomain &domain);
+
+    void operator()(argument_type& transaction);
+    void on_commit();
+
+private:
+    string          itsRegex;
+    vector<string>  itsNames;
+    ParmDomain      &itsDomain;
+
+    // The result of the executed query must be stored internally, because
+    // it will be written in operator() and will be read in on_commit().
+    pqxx::result    itsPQResult;
+};
+
+
+class PQPutValue: public pqxx::transactor<>
+{
+public:
+    PQPutValue(const map<string, ParmValueSet> &values);
+    void operator()(argument_type& transaction);
+//    void on_commit();
+
+private:
+    const map<string, ParmValueSet> &itsValues;
+};
+
+
+class PQGetValues: public pqxx::transactor<>
+{
+public:
+    PQGetValues(const string &regex,
+        const ParmDomain &domain,
+        int parentId,
+        map<string, ParmValueSet> &result);
+    
+    PQGetValues(const vector<string> &names,
+        const ParmDomain &domain,
+        int parentId,
+        map<string, ParmValueSet> &result);
+    
+    void operator()(argument_type& transaction);
+    void on_commit();
+
+private:
+    ParmValue process(pqxx::result::tuple row);
+
+    string                      itsRegex;
+    vector<string>              itsNames;
+    ParmDomain                  itsDomain;
+    int                         itsParentId;
+    map<string, ParmValueSet>   &itsResult;
+
+    // The result of the executed query must be stored internally, because
+    // it will be written in operator() and will be read in on_commit().
+    pqxx::result itsPQResult;
+};
+
+
+class PQPutDefaultValue: public pqxx::transactor<>
+{
+public:
+    PQPutDefaultValue(const string &name, const ParmValue value);
+    void operator()(argument_type& transaction);
+//    void on_commit();
+
+private:
+    string      itsName;
+    ParmValue   itsValue;
+};
+
+
+class PQGetDefaultValues: public pqxx::transactor<>
+{
+public:
+    PQGetDefaultValues(const string &regex, map<string, ParmValueSet> &result);
+    void operator()(argument_type& transaction);
+    void on_commit();
+
+private:
+    ParmValue process(pqxx::result::tuple row);
+
+    string                      itsRegex;
+    map<string, ParmValueSet>   &itsResult;
+
+    // The result of the executed query must be stored internally, because
+    // it will be written in operator() and will be read in on_commit().
+    pqxx::result itsPQResult;
+};
+
+
+class PQGetNames: public pqxx::transactor<>
+{
+public:
+    PQGetNames(const string &regex, vector<string> &result);
+    void operator()(argument_type& transaction);
+    void on_commit();
+
+private:
+    string                      itsRegex;
+    vector<string>              &itsResult;
+
+    // The result of the executed query must be stored internally, because
+    // it will be written in operator() and will be read in on_commit().
+    pqxx::result itsPQResult;
+};
+
+class PQDeleteValues: public pqxx::transactor<>
+{
+public:
+    PQDeleteValues(const string &regex,
+        const ParmDomain &domain,
+        int parentId);
+    
+    void operator()(argument_type& transaction);
+
+private:
+    string                      itsRegex;
+    ParmDomain                  itsDomain;
+    int                         itsParentId;
+};
+
+class PQDeleteDefValues: public pqxx::transactor<>
+{
+public:
+    PQDeleteDefValues(const string &regex);
+    void operator()(argument_type& transaction);
+
+private:
+    string                      itsRegex;
+};
+
+} //# namespace BBS
+} //# namespace LOFAR
+
+#endif
diff --git a/CEP/BB/ParmDB/sql/create_parmdb.sql b/CEP/BB/ParmDB/sql/create_parmdb.sql
new file mode 100644
index 0000000000000000000000000000000000000000..45a32f0aa29bb60dc89efc4ab576a4a69f757369
--- /dev/null
+++ b/CEP/BB/ParmDB/sql/create_parmdb.sql
@@ -0,0 +1,5 @@
+DROP SCHEMA xp CASCADE;
+CREATE SCHEMA xp;
+
+\i create_parmdb_tables.sql;
+\i create_parmdb_functions.sql;
diff --git a/CEP/BB/ParmDB/sql/create_parmdb_functions.sql b/CEP/BB/ParmDB/sql/create_parmdb_functions.sql
new file mode 100644
index 0000000000000000000000000000000000000000..31a5627ffefbfe9193d1347308bdaea93137de27
--- /dev/null
+++ b/CEP/BB/ParmDB/sql/create_parmdb_functions.sql
@@ -0,0 +1,145 @@
+CREATE TYPE xp.iface_parm_value AS
+(
+    name            TEXT,
+    type            TEXT,
+    expression      TEXT,
+    constants       BYTEA,
+    shape           BYTEA,
+    mask            BYTEA,
+    perturbation    DOUBLE PRECISION,
+    pert_rel        BOOL,
+    domain          BOX,
+    coefficients    BYTEA
+);
+
+CREATE OR REPLACE FUNCTION xp.put_value(parm xp.iface_parm_value)
+RETURNS VOID AS
+$$
+    BEGIN
+        UPDATE xp.parameter
+            SET type = parm.type,
+                expression = parm.expression,
+                constants = parm.constants,
+                shape = parm.shape,
+                mask = parm.mask,
+                perturbation = parm.perturbation,
+                pert_rel = parm.pert_rel,
+                coefficients = parm.coefficients
+            WHERE name = parm.name
+            AND domain ~= parm.domain;
+        
+        IF NOT FOUND THEN
+            LOCK TABLE xp.parameter;
+            
+            UPDATE xp.parameter
+                SET type = parm.type,
+                    expression = parm.expression,
+                    constants = parm.constants,
+                    shape = parm.shape,
+                    mask = parm.mask,
+                    perturbation = parm.perturbation,
+                    pert_rel = parm.pert_rel,
+                    coefficients = parm.coefficients
+                WHERE name = parm.name
+                AND domain ~= parm.domain;
+            
+            IF NOT FOUND THEN
+                INSERT
+                    INTO xp.parameter
+                        (name,
+                        type,
+                        expression,
+                        constants,
+                        shape,
+                        mask,
+                        perturbation,
+                        pert_rel,
+                        coefficients,
+                        domain)
+                    VALUES
+                        (parm.name,
+                        parm.type,
+                        parm.expression,
+                        parm.constants,
+                        parm.shape,
+                        parm.mask,
+                        parm.perturbation,
+                        parm.pert_rel,
+                        parm.coefficients,
+                        parm.domain);
+            END IF;
+        END IF;
+    END;
+$$ LANGUAGE plpgsql;        
+
+
+CREATE TYPE xp.iface_parm_default_value AS
+(
+    name            TEXT,
+    type            TEXT,
+    expression      TEXT,
+    constants       BYTEA,
+    shape           BYTEA,
+    mask            BYTEA,
+    coefficients    BYTEA,
+    perturbation    DOUBLE PRECISION,
+    pert_rel        BOOL
+);
+
+
+CREATE OR REPLACE FUNCTION
+    xp.put_default_value(parm xp.iface_parm_default_value)
+RETURNS VOID AS
+$$
+    BEGIN
+        UPDATE xp.default_parameter
+            SET type = parm.type,
+                expression = parm.expression,
+                constants = parm.constants,
+                shape = parm.shape,
+                mask = parm.mask,
+                coefficients = parm.coefficients,
+                perturbation = parm.perturbation,
+                pert_rel = parm.pert_rel
+            WHERE name = parm.name;
+        
+        IF NOT FOUND THEN
+            LOCK TABLE xp.default_parameter;
+            
+            UPDATE xp.default_parameter
+                SET type = parm.type,
+                    expression = parm.expression,
+                    constants = parm.constants,
+                    shape = parm.shape,
+                    mask = parm.mask,
+                    coefficients = parm.coefficients,
+                    perturbation = parm.perturbation,
+                    pert_rel = parm.pert_rel
+                WHERE name = parm.name;
+            
+            IF NOT FOUND THEN
+                INSERT
+                    INTO xp.default_parameter
+                        (name,
+                        type,
+                        expression,
+                        constants,
+                        shape,
+                        mask,
+                        coefficients,
+                        perturbation,
+                        pert_rel)
+                    VALUES
+                        (parm.name,
+                        parm.type,
+                        parm.expression,
+                        parm.constants,
+                        parm.shape,
+                        parm.mask,
+                        parm.coefficients,
+                        parm.perturbation,
+                        parm.pert_rel);
+            END IF;
+        END IF;
+    END;
+$$ LANGUAGE plpgsql;        
diff --git a/CEP/BB/ParmDB/sql/create_parmdb_tables.sql b/CEP/BB/ParmDB/sql/create_parmdb_tables.sql
new file mode 100644
index 0000000000000000000000000000000000000000..45c1102fd5017744f3af73d89738f3b7a3091656
--- /dev/null
+++ b/CEP/BB/ParmDB/sql/create_parmdb_tables.sql
@@ -0,0 +1,32 @@
+CREATE TABLE xp.parameter
+(
+    id              SERIAL              PRIMARY KEY,
+    name            TEXT                NOT NULL,
+    type            TEXT                NOT NULL,
+    expression      TEXT                NOT NULL,
+    constants       BYTEA               ,
+    shape           BYTEA               NOT NULL,
+    mask            BYTEA               ,
+    perturbation    DOUBLE PRECISION    DEFAULT 1e-6,
+    pert_rel        BOOL                DEFAULT TRUE,
+    domain          BOX                 NOT NULL,
+    coefficients    BYTEA               NOT NULL
+);
+
+
+CREATE TABLE xp.default_parameter
+(
+    id              SERIAL              PRIMARY KEY,
+    name            TEXT                UNIQUE
+                                        NOT NULL,
+    type            TEXT                NOT NULL,
+    expression      TEXT                NOT NULL,
+    constants       BYTEA               ,
+    shape           BYTEA               NOT NULL,
+    mask            BYTEA               ,
+    coefficients    BYTEA               NOT NULL,
+    perturbation    DOUBLE PRECISION    DEFAULT 1e-6,
+    pert_rel        BOOL                DEFAULT TRUE
+);
+
+CREATE INDEX parameter_domain_idx ON xp.parameter USING gist(domain);
diff --git a/CEP/BB/ParmDB/src/Makefile.am b/CEP/BB/ParmDB/src/Makefile.am
index bd209160ab6595ed6d3c3966416f6617e3002fa2..807a67bc28e8e1346ed2ec9f230bc8da26628189 100644
--- a/CEP/BB/ParmDB/src/Makefile.am
+++ b/CEP/BB/ParmDB/src/Makefile.am
@@ -2,7 +2,7 @@ lib_LTLIBRARIES         = libparmdb.la
 
 libparmdb_la_SOURCES = \
 ParmValue.cc ParmDomain.cc ParmDBMeta.cc \
-ParmDB.cc ParmDBAIPS.cc
+ParmDB.cc ParmDBAIPS.cc ParmDBPostgres.cc ParmDBPostgresTransactors.cc
 
 
 # AM_YFLAGS               = -d -p KeyParse
diff --git a/CEP/BB/ParmDB/src/ParmDB.cc b/CEP/BB/ParmDB/src/ParmDB.cc
index 226431458522a3d608dac2b42f60dd69e5f629e5..a09fa98f7b8533192f5553fb363d44c0bad97462 100644
--- a/CEP/BB/ParmDB/src/ParmDB.cc
+++ b/CEP/BB/ParmDB/src/ParmDB.cc
@@ -20,8 +20,11 @@
 //#
 //# $Id$
 
+#include <lofar_config.h>
+
 #include <ParmDB/ParmDB.h>
 #include <ParmDB/ParmDBAIPS.h>
+#include <ParmDB/ParmDBPostgres.h>
 #include <Common/LofarLogger.h>
 #include <casa/Utilities/Regex.h>
 #include <casa/Utilities/GenSort.cc>     // for automatic template
@@ -129,6 +132,12 @@ ParmDB::ParmDB (const ParmDBMeta& ptm, bool forceNew)
     itsRep = new ParmDBAIPS (ptm.getTableName(), forceNew);
     ///  } else if (ptm.getType() == "bdb") {
     ///itsRep = new ParmDBBDB (ptm, forceNew);
+  } else if(ptm.getType() == "postgres") {
+    itsRep = new ParmDBPostgres(ptm.getDBName(),
+        ptm.getUserName(),
+        ptm.getDBPwd(),
+        ptm.getHostName(),
+        "");
   } else {
     ASSERTSTR(false, "unknown parmTableType: "<<ptm.getType());
   }
diff --git a/CEP/BB/ParmDB/src/ParmDBMeta.cc b/CEP/BB/ParmDB/src/ParmDBMeta.cc
index 0b47d45ee351230570327adf176670492a1b3d65..e1d044d8f7f7ffc01c88d82396ec2e7bb7dc0dda 100644
--- a/CEP/BB/ParmDB/src/ParmDBMeta.cc
+++ b/CEP/BB/ParmDB/src/ParmDBMeta.cc
@@ -20,6 +20,8 @@
 //#
 //#  $Id$
 
+#include <lofar_config.h>
+
 #include <ParmDB/ParmDBMeta.h>
 #include <Blob/BlobOStream.h>
 #include <Blob/BlobIStream.h>
diff --git a/CEP/BB/ParmDB/src/ParmDBPostgres.cc b/CEP/BB/ParmDB/src/ParmDBPostgres.cc
new file mode 100644
index 0000000000000000000000000000000000000000..37084b310a4a9c81d77b001d8314f3cb48420185
--- /dev/null
+++ b/CEP/BB/ParmDB/src/ParmDBPostgres.cc
@@ -0,0 +1,386 @@
+//# ParmDBPostgres.cc: 
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program is free software; you can redistribute it and/or modify
+//# it under the terms of the GNU General Public License as published by
+//# the Free Software Foundation; either version 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program is distributed in the hope that it will be useful,
+//# but WITHOUT ANY WARRANTY; without even the implied warranty of
+//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//# GNU General Public License for more details.
+//#
+//# You should have received a copy of the GNU General Public License
+//# along with this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#include <lofar_config.h>
+#include <ParmDB/ParmDBPostgres.h>
+
+#include <Common/lofar_set.h>
+#include <Common/LofarLogger.h>
+
+#include <ParmDB/ParmDBPostgresTransactors.h>
+
+
+namespace LOFAR
+{
+namespace ParmDB 
+{
+
+ParmDBPostgres::ParmDBPostgres(const string &database,
+    const string &user,
+    const string &password,
+    const string &host,
+    const string &port)
+{
+    //# Password not used yet.
+    string opts("dbname=" + database  + " user=" + user + " host=" + host);
+    if(!port.empty())
+        opts += " port=" + port;
+
+//    try
+//    {
+        LOG_DEBUG_STR("Connecting to database using options: " << opts);
+        itsConnection.reset(new pqxx::connection(opts));
+//    } CATCH_PQXX_AND_RETHROW;
+}
+
+
+//# Get the domain range (time,freq) of the given parameters in the table.
+//# This is the minimum and maximum value of these axes for all parameters.
+//# An empty name pattern is the same as * (all parms).
+ParmDomain ParmDBPostgres::getRange(const std::string &parmNamePattern) const
+{
+    ParmDomain result;
+
+    if(parmNamePattern.empty())
+        itsConnection->perform(PQGetDomain(translatePattern("*"), result));
+    else
+        itsConnection->perform(
+            PQGetDomain(translatePattern(parmNamePattern), result));
+    return result;
+}
+
+
+ParmDomain
+    ParmDBPostgres::getRange(const std::vector<std::string> &parmNames) const
+{
+    ParmDomain result;
+
+    itsConnection->perform(PQGetDomain(parmNames, result));
+    return result;
+}
+
+
+//# Get the parameter values for the given parameter and domain.
+//# Note that the requested domain may contain multiple values.
+//# A selection on parentId is done if >= 0.
+ParmValueSet ParmDBPostgres::getValues(const std::string &parmName,
+    const ParmDomain &domain,
+    int parentId,
+    ParmDBRep::TableType)
+{
+    vector<string> names;
+    map<string, ParmValueSet> result;
+    
+    names.push_back(parmName);
+    itsConnection->perform(PQGetValues(names, domain, parentId,
+        result));
+    
+    ASSERT(result.find(parmName) != result.end());
+    return result[parmName];
+}
+
+
+//# Get all values for a given domain and set of parm names.
+//# If the parm name vector is empty, all parm names are taken.
+void ParmDBPostgres::getValues(std::map<std::string,ParmValueSet> &result,
+    const std::vector<std::string> &parmNames,
+    const ParmDomain &domain,
+    int parentId,
+    ParmDBRep::TableType)
+{
+    itsConnection->perform(PQGetValues(parmNames, domain, parentId, 
+        result));
+}
+
+
+//# Get the parameter values for the given parameters and domain.
+//# Only * and ? should be used in the pattern (no [] and {}).
+//# A selection on parentId is done if >= 0.
+void ParmDBPostgres::getValues(std::map<std::string,ParmValueSet> &result,
+    const std::string &parmNamePattern,
+    const ParmDomain &domain,
+    int parentId,
+    ParmDBRep::TableType)
+{
+    itsConnection->perform(PQGetValues(translatePattern(parmNamePattern),
+            domain, parentId, result));
+}
+
+//# Put the value for the given parameter and domain.
+//# overwriteMask=true indicates that the solvableMask might be changed
+//# and should be overwritten in an existing record.
+void ParmDBPostgres::putValue(const std::string &parmName,
+    ParmValue& value,
+    ParmDBRep::TableType,
+    bool overwriteMask)
+{
+    LOG_DEBUG_STR("itsDBTabRef: " << value.rep().itsDBTabRef);
+    
+    map<string, ParmValueSet> values;
+    values[parmName].getValues().push_back(value);
+    itsConnection->perform(PQPutValue(values));
+}
+
+
+//# Put the value for the given parameters and domain.
+//# It only writes the parameters that have the same DBSeqNr as this ParmDB.
+//# overwriteMask=true indicates that the solvableMask might be changed
+//# and should be overwritten in an existing record.
+void ParmDBPostgres::putValues(std::map<std::string,ParmValueSet>& values,
+    ParmDBRep::TableType,
+    bool overwriteMask)
+{
+    itsConnection->perform(PQPutValue(values));
+}
+
+
+//# Delete the records for the given parameters and domain.
+//# If parentId>=0, only records with that parentid will be deleted.
+void ParmDBPostgres::deleteValues(const std::string& parmNamePattern,
+    const ParmDomain& domain,
+    int parentId,
+    ParmDBRep::TableType)
+{
+    itsConnection->perform(
+        PQDeleteValues(translatePattern(parmNamePattern), domain, parentId));
+}
+
+
+//# Get the default value for the given parameters.
+//# Only * and ? should be used in the pattern (no [] and {}).
+void ParmDBPostgres::getDefValues(std::map<std::string,ParmValueSet>& result,
+    const std::string& parmNamePattern)
+{
+    if(parmNamePattern.empty())
+        itsConnection->perform(
+            PQGetDefaultValues(translatePattern("*"), result));
+    else
+        itsConnection->perform(
+            PQGetDefaultValues(translatePattern(parmNamePattern), result));
+}
+
+
+//# Put the default value.
+void ParmDBPostgres::putDefValue(const std::string& parmName,
+    const ParmValue& value)
+{
+    itsConnection->perform(PQPutDefaultValue(parmName, value));
+    clearDefFilled();
+}
+
+
+//# Delete the default value records for the given parameters.
+void ParmDBPostgres::deleteDefValues(const std::string& parmNamePattern)
+{
+    itsConnection->perform(
+        PQDeleteDefValues(translatePattern(parmNamePattern)));
+    clearDefFilled();
+}
+
+
+//# Get the names of all parms matching the given (filename like) pattern.
+std::vector<std::string> ParmDBPostgres::getNames(const std::string& pattern,
+    ParmDBRep::TableType)
+{
+    vector<string> result;
+    
+    itsConnection->perform(PQGetNames(translatePattern(pattern), result));
+    return result;
+}    
+
+
+//# Clear database or table
+void ParmDBPostgres::clearTables()
+{
+    //# Not yet implemented.
+    ASSERT(false);
+}
+
+
+//# Fill the map with default values.
+void ParmDBPostgres::fillDefMap(std::map<std::string,ParmValue>& defMap)
+{
+    map<string, ParmValueSet> tmp;
+    
+    this->getDefValues(tmp, "*");
+    for(map<string, ParmValueSet>::const_iterator it = tmp.begin();
+        it != tmp.end();
+        ++it)
+    {
+        ASSERT(it->second.getValues().size() == 1);
+        defMap[it->first] = it->second.getValues()[0];
+    }
+}
+    
+//# Function to translate a shell pattern to a Postgres (POSIX) regular 
+//# expression. Note that the output is enclosed within a '^', '$' pair, because 
+//# normally the Postgres regex matching operator matches the pattern anywhere 
+//# in the string. Shell patterns, however, match at the beginning.
+string ParmDBPostgres::translatePattern(const string &pattern)
+{
+    const char regexMeta[14] = {'|', '.', '?', '+', '*', '^', '$', '(', ')', 
+        '[', ']', '{', '}', '\\'};
+    set<char> regexMetaChars(regexMeta, regexMeta + 14);
+    enum State{NORMAL, BRACKET, ESCAPE, ESCAPE_BRACKET};
+
+    ostringstream result;
+    result << "^";
+
+    size_t idx = 0;
+    size_t bracketPosition;
+    uint curlyBraceCount = 0;
+
+    State state = NORMAL;
+    while(idx < pattern.size())
+    {
+        switch(state)
+        {
+            case NORMAL:
+                switch(pattern[idx])
+                {
+                    //# Translate shell pattern meta characters.
+                    case '\\':
+                        state = ESCAPE;
+                        break;
+
+                    case '*':
+                        result << ".*";
+                        break;
+
+                    case '?':
+                        result << '.';
+                        break;
+
+                    case '{':
+                        curlyBraceCount++;
+                        result << "((";
+                        break;
+
+                    case ',':
+                        if(curlyBraceCount > 0)
+                            result << ")|(";
+                        else
+                            //# A literal ',' needs no escaping in the output 
+                            //# regex.
+                            result << ',';
+                        break;
+
+                    case '}':
+                        if(curlyBraceCount > 0)
+                        {
+                            curlyBraceCount--;
+                            result << "))";
+                        }
+                        else
+                            //# A literal '}' needs to be escaped in the output 
+                            //# regex.
+                            result << "\\}";
+                        break;
+
+                    case '[':
+                        bracketPosition = idx;
+                        state = BRACKET;
+                        result << pattern[idx];
+                        break;
+
+                    default:
+                        //# The current character is not a shell pattern 
+                        //# meta character, so it should be mapped to a non-
+                        //# meta character in the output regex.
+                        if(regexMetaChars.find(pattern[idx]) !=
+                            regexMetaChars.end())
+                        {
+                            result << '\\';
+                        }
+                        result << pattern[idx];
+                }
+                break;
+
+            case BRACKET:
+                //# '\' is stripped within brackets. To include a literal ']' 
+                //# put it at the first position. To include a literal '-' put 
+                //# it first or last.
+                switch(pattern[idx])
+                {
+                    //# Translate shell pattern meta characters.
+                    case '\\':
+                        state = ESCAPE_BRACKET;
+                        break;
+
+                    case '-':
+                    case '^':
+                        result << pattern[idx];
+                        break;
+
+                    case '!':
+                        result << ((idx - bracketPosition == 1) ? '^' : '!');
+                        break;
+
+                    case ']':
+                        //# ']' at the first position matches a literal ']'.
+                        if(idx - bracketPosition > 1)
+                            state = NORMAL;
+                        result << pattern[idx];
+                        break;
+
+                    default:
+                        //# In the output regex, meta characters lose their 
+                        //# meaning inside brackets. Therefore, non-meta 
+                        //# characters in the input shell pattern are passed 
+                        //# through to the output unaltered.
+                        result << pattern[idx];
+                }
+                break;
+
+            case ESCAPE:
+                //# A character following '\' should be interpreted as a 
+                //# non-meta character and should therefore map to a non- 
+                //# meta character in the output regex.
+                if(regexMetaChars.find(pattern[idx]) != 
+                    regexMetaChars.end())
+                {
+                    result << '\\';
+                }
+                result << pattern[idx];
+                state = NORMAL;
+                break;
+
+            case ESCAPE_BRACKET:
+                //# In the output regex, meta characters lose their meaning 
+                //# inside brackets. Specifically, '\' loses its meaning. 
+                //# Therefore, escaped characters in the input shell pattern are 
+                //# passed through to the output regex without the preceding 
+                //# '\'. Note that this implies that for instance [abc\]d] will 
+                //# not match a literal ']' but will result in an error.        
+                result << pattern[idx];
+                state = BRACKET;
+                break;
+        }
+        //# Move to the next input character.
+        idx++;
+    }
+    result << "$";
+    return result.str();
+}
+
+} //# namespace BBS
+} //# namespace LOFAR
diff --git a/CEP/BB/ParmDB/src/ParmDBPostgresTransactors.cc b/CEP/BB/ParmDB/src/ParmDBPostgresTransactors.cc
new file mode 100644
index 0000000000000000000000000000000000000000..514ca5b1d5da5f025ec7d140a5011db568fa9457
--- /dev/null
+++ b/CEP/BB/ParmDB/src/ParmDBPostgresTransactors.cc
@@ -0,0 +1,498 @@
+//# ParmDBPostgresTransactors.cc: 
+//#
+//# Copyright (C) 2007
+//# ASTRON (Netherlands Foundation for Research in Astronomy)
+//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//# This program is free software; you can redistribute it and/or modify
+//# it under the terms of the GNU General Public License as published by
+//# the Free Software Foundation; either version 2 of the License, or
+//# (at your option) any later version.
+//#
+//# This program is distributed in the hope that it will be useful,
+//# but WITHOUT ANY WARRANTY; without even the implied warranty of
+//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//# GNU General Public License for more details.
+//#
+//# You should have received a copy of the GNU General Public License
+//# along with this program; if not, write to the Free Software
+//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//# $Id$
+
+#include <lofar_config.h>
+#include <ParmDB/ParmDBPostgresTransactors.h>
+#include <ParmDB/ParmDBPostgres.h>
+
+namespace LOFAR
+{
+namespace ParmDB 
+{
+
+ParmDomain convert_domain(pqxx::result::field in)
+{
+    istringstream iss(in.as<string>());
+
+    istringstream::char_type ign;
+    double xs, xe, ys, ye;
+
+    LOG_DEBUG_STR("convert_domain input: " << in.as<string>());
+    
+    //# TODO: syntax/ioflag checking!
+    //iss >> ign; //# '('
+    iss >> ign; //# '('
+    iss >> xe;
+    iss >> ign; //# ','
+    iss >> ye;
+    iss >> ign; //# ')'
+    iss >> ign; //# ','
+    iss >> ign; //# '('
+    iss >> xs;
+    iss >> ign; //# ','
+    iss >> ys;
+
+    return ParmDomain(xs, xe, ys, ye);
+}
+
+string convert_domain(const ParmDomain &domain)
+{
+    const vector<double> &start = domain.getStart();
+    const vector<double> &end = domain.getEnd();
+
+    ASSERTSTR(start.size() == 2 && end.size() == 2,
+        "Only 2-D domains are currently supported.");
+
+    ostringstream result;
+    result << "((" << end[0] << "," << end[1] << "),"
+        "(" << start[0] << "," << start[1] << "))";
+
+    return result.str();
+}
+
+PQGetDomain::PQGetDomain(const string &regex, ParmDomain &domain)
+    :   itsRegex(regex),
+        itsDomain(domain)
+{
+}
+
+PQGetDomain::PQGetDomain(const vector<string> &names, ParmDomain &domain)
+    :   itsNames(names),
+        itsDomain(domain)
+{
+}
+
+void PQGetDomain::operator()(argument_type& transaction)
+{
+    ostringstream query;
+    
+    //# Postgres stores a box as ((right upper corner), (left lower corner)).
+    query << "SELECT "
+    "min((domain[1])[0]) AS xs,"
+    "min((domain[1])[1]) AS ys,"
+    "max((domain[0])[0]) AS xe,"
+    "max((domain[0])[1]) AS ye "
+    "FROM xp.parameter";
+
+    if(!itsRegex.empty())
+        query << " WHERE name ~ '" + transaction.esc(itsRegex) + "'";
+    else if(!itsNames.empty())
+    {
+        query << " WHERE name IN (";
+        for(vector<string>::const_iterator it = itsNames.begin();
+            it != itsNames.end();
+            ++it)
+        {
+            query << "'" + transaction.esc(*it) + "'";
+        }
+        query << ")";
+    }
+    query << ";";
+
+    LOG_DEBUG_STR("query: " << query.str());
+    itsPQResult = transaction.exec(query.str());
+}
+
+void PQGetDomain::on_commit()
+{
+    //# Aggregate functions always return a single row.
+    ASSERT(itsPQResult.size() == 1);
+
+    try
+    {
+        itsDomain = ParmDomain(itsPQResult.front()["xs"].as<double>(),
+            itsPQResult.front()["xe"].as<double>(),
+            itsPQResult.front()["ys"].as<double>(),
+            itsPQResult.front()["ye"].as<double>());
+    }
+    catch(PGSTD::domain_error &ex)
+    {
+        itsDomain = ParmDomain(0.0, 1.0, 0.0, 1.0);
+    }
+}
+
+
+PQPutValue::PQPutValue(const map<string, ParmValueSet> &values)
+    : itsValues(values)
+{
+}
+
+void PQPutValue::operator()(argument_type& transaction)
+{
+    for(map<string, ParmValueSet>::const_iterator map_it = itsValues.begin();
+        map_it != itsValues.end();
+        ++map_it)
+    {
+        const string &name = map_it->first;
+        const vector<ParmValue> &set = map_it->second.getValues();
+        
+        for(vector<ParmValue>::const_iterator set_it = set.begin();
+            set_it != set.end();
+            ++set_it)
+        {
+            const ParmValueRep &value = set_it->rep();
+
+            ostringstream query;
+            query << "SELECT xp.put_value";
+            query << "(ROW(";
+            query << "'" << transaction.esc(name) << "',";
+            query << "'" << transaction.esc(value.itsType) << "',";
+            query << "'" << transaction.esc(value.itsExpr) << "',";
+            if(!value.itsConstants.empty())
+                query << "'" << pack_vector(transaction, value.itsConstants)
+                    << "',";
+            else
+                query << "NULL,";
+
+            query << "'" << pack_vector(transaction, value.itsShape) << "',";
+            if(!value.itsSolvMask.empty())
+                query << "'" << pack_vector(transaction, value.itsSolvMask)
+                    << "',";
+            else
+                query << "NULL,";
+
+            query << value.itsPerturbation << ",";
+            query << (value.itsIsRelPert ? "true" : "false") << ",";
+            query << "'" << convert_domain(value.itsDomain) << "',";
+            query << "'" << pack_vector(transaction, value.itsCoeff) << "'";
+            query << "));";
+
+            LOG_DEBUG_STR("query: " << query.str());
+            transaction.exec(query.str());
+        }
+    }
+}
+
+//void PQPutValue::on_commit();
+
+
+PQGetValues::PQGetValues(const string &regex,
+    const ParmDomain &domain,
+    int parentId,
+    map<string, ParmValueSet> &result)
+    :   itsRegex(regex),
+        itsDomain(domain),
+        itsParentId(parentId),
+        itsResult(result)
+{
+}
+
+PQGetValues::PQGetValues(const vector<string> &names,
+    const ParmDomain &domain,
+    int parentId,
+    map<string, ParmValueSet> &result)
+    :   itsNames(names),
+        itsDomain(domain),
+        itsParentId(parentId),
+        itsResult(result)
+{
+}
+
+void PQGetValues::operator()(argument_type& transaction)
+{
+    LOG_DEBUG_STR("regex: " << itsRegex);
+    LOG_DEBUG_STR("quoted regex: " << transaction.esc(itsRegex));
+
+    ostringstream query;
+    query << "SELECT * FROM xp.parameter";
+    
+    if(!itsRegex.empty())
+        query << " WHERE name ~ '" << transaction.esc(itsRegex) << "'";
+    else if(itsNames.size() == 1)
+        query << " WHERE name = '" << transaction.esc(itsNames.front()) << "'";
+    else if(itsNames.size() > 1)
+    {
+        query << " WHERE name IN(";
+        for(vector<string>::const_iterator it = itsNames.begin();
+            it != itsNames.end();
+            ++it)
+        {
+            query << "'" + transaction.esc(*it) + "'";
+        }
+        query << ")";
+    }
+    
+    const vector<double> &start = itsDomain.getStart();
+    const vector<double> &end = itsDomain.getEnd();
+    if(start.size() == 2 && end.size() == 2)
+        query << " AND domain && " << "'" << convert_domain(itsDomain) << "'";
+    else
+        ASSERTSTR(start.empty() && end.empty(),
+            "Only 2-D domains are currently supported.");
+
+//    if(itsParentId >= 0)
+//        query << " AND parent_id = " << itsParentId;
+    query << ";";
+
+    LOG_DEBUG_STR("query: " << query.str());
+    itsPQResult = transaction.exec(query.str());
+}
+
+void PQGetValues::on_commit()
+{
+    for(pqxx::result::const_iterator it = itsPQResult.begin();
+        it != itsPQResult.end();
+        ++it)
+    {
+        ParmValueSet &set = itsResult[(*it)["name"].as<string>()];
+        set.getValues().push_back(process(*it));
+    }
+}
+
+ParmValue PQGetValues::process(pqxx::result::tuple row)
+{
+    ParmValue resultPointer;
+    ParmValueRep &result = resultPointer.rep();
+
+    if(!row["constants"].is_null())
+    {
+        vector<double> constants =
+            unpack_vector<double>(pqxx::binarystring(row["constants"]));
+        result.setType(row["type"].as<string>(), constants);
+    }
+    else
+        result.setType(row["type"].as<string>());
+
+    result.itsExpr      = row["expression"].as<string>();
+
+    vector<int> shape = unpack_vector<int>(pqxx::binarystring(row["shape"]));
+    vector<double> coefficients =
+        unpack_vector<double>(pqxx::binarystring(row["coefficients"]));
+
+    if(!row["mask"].is_null())
+    {
+        vector<bool> mask =
+            unpack_vector<bool>(pqxx::binarystring(row["mask"]));
+        bool tmp[mask.size()];
+        for(size_t i = 0; i < mask.size(); ++i)
+            tmp[i] = mask[i];
+
+        result.setCoeff(&coefficients[0], tmp, shape);
+    }
+    else
+        result.setCoeff(&coefficients[0], shape);
+
+    result.setDomain(convert_domain(row["domain"]));
+    result.setPerturbation(row["perturbation"].as<double>(),
+        row["pert_rel"].as<bool>());
+
+    result.itsWeight    = 0;
+    result.itsID        = row["id"].as<int>();
+    result.itsParentID  = 0;
+    result.itsTimeStamp = 0;
+    result.itsDBTabRef  = 0;
+    result.itsDBSeqNr   = 0;
+
+    return resultPointer;
+}
+
+
+PQPutDefaultValue::PQPutDefaultValue(const string &name, const ParmValue value)
+    :   itsName(name),
+        itsValue(value)
+{
+}
+
+void PQPutDefaultValue::operator()(argument_type& transaction)
+{
+    ostringstream query;
+    const ParmValueRep &value = itsValue.rep();
+
+    query << "SELECT xp.put_default_value(";
+    query << "ROW(";
+    query << "'" << transaction.esc(itsName) << "',";
+    query << "'" << transaction.esc(value.itsType) << "',";
+    query << "'" << transaction.esc(value.itsExpr) << "',";
+    if(!value.itsConstants.empty())
+        query << "'" << pack_vector(transaction, value.itsConstants) << "',";
+    else
+        query << "NULL,";
+
+    query << "'" << pack_vector(transaction, value.itsShape) << "',";
+    if(!value.itsSolvMask.empty())
+        query << "'" << pack_vector(transaction, value.itsSolvMask) << "',";
+    else
+        query << "NULL,";
+
+    query << "'" << pack_vector(transaction, value.itsCoeff) << "',";
+    query << value.itsPerturbation << ",";
+    query << (value.itsIsRelPert ? "true" : "false");
+    query << "));";
+
+    LOG_DEBUG_STR("query: " << query.str());
+
+    transaction.exec(query.str());
+}
+
+PQGetDefaultValues::PQGetDefaultValues(const string &regex,
+    map<string, ParmValueSet> &result)
+    :   itsRegex(regex),
+        itsResult(result)
+{
+}
+
+void PQGetDefaultValues::operator()(argument_type& transaction)
+{
+    LOG_DEBUG_STR("regex: " << itsRegex);
+    LOG_DEBUG_STR("quoted regex: " << transaction.esc(itsRegex));
+    itsPQResult = transaction.exec("SELECT * FROM xp.default_parameter"
+        " WHERE name ~ '" + transaction.esc(itsRegex) + "';");
+}
+
+void PQGetDefaultValues::on_commit()
+{
+    for(pqxx::result::const_iterator it = itsPQResult.begin();
+        it != itsPQResult.end();
+        ++it)
+    {
+        ParmValueSet tmp;
+        tmp.getValues().push_back(process(*it));
+        itsResult[(*it)["name"].as<string>()] = tmp;
+    }
+}
+
+ParmValue PQGetDefaultValues::process(pqxx::result::tuple row)
+{
+    ParmValue resultPointer;
+    ParmValueRep &result = resultPointer.rep();
+
+    if(!row["constants"].is_null())
+    {
+        vector<double> constants =
+            unpack_vector<double>(pqxx::binarystring(row["constants"]));
+        result.setType(row["type"].as<string>(), constants);
+    }
+    else
+        result.setType(row["type"].as<string>());
+
+    result.itsExpr      = row["expression"].as<string>();
+
+    vector<int> shape = unpack_vector<int>(pqxx::binarystring(row["shape"]));
+    vector<double> coefficients =
+        unpack_vector<double>(pqxx::binarystring(row["coefficients"]));
+
+    if(!row["mask"].is_null())
+    {
+        vector<bool> mask =
+            unpack_vector<bool>(pqxx::binarystring(row["mask"]));
+        bool tmp[mask.size()];
+        for(size_t i = 0; i < mask.size(); ++i)
+            tmp[i] = mask[i];
+
+        result.setCoeff(&coefficients[0], tmp, shape);
+    }
+    else
+        result.setCoeff(&coefficients[0], shape);
+
+    result.setPerturbation(row["perturbation"].as<double>(),
+        row["pert_rel"].as<bool>());
+
+    result.itsWeight    = 0;
+    result.itsID        = row["id"].as<int>();
+    result.itsParentID  = 0;
+    result.itsTimeStamp = 0;
+    result.itsDBTabRef  = 0;
+    result.itsDBSeqNr   = 0;
+
+    return resultPointer;
+}
+
+
+PQGetNames::PQGetNames(const string &regex, vector<string> &result)
+    :   itsRegex(regex),
+        itsResult(result)
+{
+}
+
+void PQGetNames::operator()(argument_type& transaction)
+{
+    LOG_DEBUG_STR("regex: " << itsRegex);
+    LOG_DEBUG_STR("quoted regex: " << transaction.esc(itsRegex));
+    itsPQResult = transaction.exec("SELECT DISTINCT name FROM xp.parameter"
+        " WHERE name ~ '" + transaction.esc(itsRegex) + "';");
+}
+
+void PQGetNames::on_commit()
+{
+    for(pqxx::result::const_iterator it = itsPQResult.begin();
+        it != itsPQResult.end();
+        ++it)
+    {
+        itsResult.push_back((*it)["name"].as<string>());
+    }
+}
+
+PQDeleteValues::PQDeleteValues(const string &regex,
+    const ParmDomain &domain,
+    int parentId)
+    :   itsRegex(regex),
+        itsDomain(domain),
+        itsParentId(parentId)
+{
+}
+    
+void PQDeleteValues::operator()(argument_type& transaction)
+{
+    LOG_DEBUG_STR("regex: " << itsRegex);
+    LOG_DEBUG_STR("quoted regex: " << transaction.esc(itsRegex));
+    
+    ostringstream query;
+//    query << "LOCK TABLE xp.parameter;";
+    query << "DELETE FROM xp.parameter"
+    " WHERE name ~ '" << transaction.esc(itsRegex) << "'";
+    
+    // TODO: should we delete all parms intersecting the domain
+    // or all that fall completely within the domain, or just the ones
+    // that exactly match the domain?
+    const vector<double> &start = itsDomain.getStart();
+    const vector<double> &end = itsDomain.getEnd();
+    if(start.size() == 2 && end.size() == 2)
+        query << " AND domain ~= " << "'" << convert_domain(itsDomain) << "'";
+    else
+        ASSERTSTR(start.empty() && end.empty(),
+            "Only 2-D domains are currently supported.");
+    
+//    if(itsParentId >= 0)
+//        query << " AND parent_id = " << itsParentId;
+    query << ";";
+    transaction.exec(query.str());
+}
+
+PQDeleteDefValues::PQDeleteDefValues(const string &regex)
+    : itsRegex(regex)
+{
+}
+
+void PQDeleteDefValues::operator()(argument_type& transaction)
+{
+    LOG_DEBUG_STR("regex: " << itsRegex);
+    LOG_DEBUG_STR("quoted regex: " << transaction.esc(itsRegex));
+    
+    ostringstream query;
+//    query << "LOCK TABLE xp.default_parameter;";
+    query << "DELETE FROM xp.default_parameter"
+    " WHERE name ~ '" << transaction.esc(itsRegex) << "';";
+    transaction.exec(query.str());
+}
+
+} //# namespace BBS
+} //# namespace LOFAR
diff --git a/CEP/BB/ParmDB/src/parmdb.cc b/CEP/BB/ParmDB/src/parmdb.cc
index 94225676464035d23c89684acbcb8c83411cba23..5d6d7de7ad9c2753689cc1169ca5fbdd10fee7fe 100644
--- a/CEP/BB/ParmDB/src/parmdb.cc
+++ b/CEP/BB/ParmDB/src/parmdb.cc
@@ -768,7 +768,7 @@ void doIt (bool noPrompt)
 	  parmtab = new LOFAR::ParmDB::ParmDB (meta);
 	} else if (cmd == CREATE)  {
 	  ASSERTSTR(parmtab==0, "OPEN or CREATE already done");
-	  // create dataBase	
+	  // create dataBase
 	  KeyValueMap kvmap = KeyParser::parse (cstr);
 	  string dbUser = kvmap.getString ("user", getUserName());
 	  string dbHost = kvmap.getString ("host", "dop50.astron.nl");
@@ -895,8 +895,11 @@ void doIt (bool noPrompt)
   parmtab = 0;
 }
 
-int main (int argc)
+int main (int argc, char *argv[])
 {
+  const char* progName = basename(argv[0]);
+  INIT_LOGGER(progName);
+  
   try {
     doIt (argc > 1);
   } catch (std::exception& x) {
diff --git a/CEP/BB/ParmDB/src/parmdb_main.cc b/CEP/BB/ParmDB/src/parmdb_main.cc
index 94225676464035d23c89684acbcb8c83411cba23..5d6d7de7ad9c2753689cc1169ca5fbdd10fee7fe 100644
--- a/CEP/BB/ParmDB/src/parmdb_main.cc
+++ b/CEP/BB/ParmDB/src/parmdb_main.cc
@@ -768,7 +768,7 @@ void doIt (bool noPrompt)
 	  parmtab = new LOFAR::ParmDB::ParmDB (meta);
 	} else if (cmd == CREATE)  {
 	  ASSERTSTR(parmtab==0, "OPEN or CREATE already done");
-	  // create dataBase	
+	  // create dataBase
 	  KeyValueMap kvmap = KeyParser::parse (cstr);
 	  string dbUser = kvmap.getString ("user", getUserName());
 	  string dbHost = kvmap.getString ("host", "dop50.astron.nl");
@@ -895,8 +895,11 @@ void doIt (bool noPrompt)
   parmtab = 0;
 }
 
-int main (int argc)
+int main (int argc, char *argv[])
 {
+  const char* progName = basename(argv[0]);
+  INIT_LOGGER(progName);
+  
   try {
     doIt (argc > 1);
   } catch (std::exception& x) {