diff --git a/.clang-format b/.clang-format
index e64581062d0d3235e61c69eff6c5a0bc9e87d3e1..a8b3f38e016941b5f2460afd73835f21c87050f6 100755
--- a/.clang-format
+++ b/.clang-format
@@ -49,7 +49,7 @@ BreakConstructorInitializers: AfterColon
 BreakInheritanceList: AfterColon
 BreakStringLiterals: true
 
-ColumnLimit:     140 # Set to 0 to turn off
+ColumnLimit:     120 # Set to 0 to turn off
 
 # Need? CommentPragmas:  '^ IWYU pragma:'
 
diff --git a/src/AttributeName.cpp b/src/AttributeName.cpp
index a07b1b8d7b7a9898172d5e399042828ee01b7790..fad6f8ef95ddd4169f7e2dfc2a6acd6cc1f111ac 100644
--- a/src/AttributeName.cpp
+++ b/src/AttributeName.cpp
@@ -99,8 +99,10 @@ const string &AttributeName::tangoHostWithDomain()
 
             if (status != 0)
             {
-                spdlog::error("Error: Unable to add domain to tango host: getaddrinfo failed with error: {}", gai_strerror(status));
-                return tango_host;
+                spdlog::error("Error: Unable to add domain to tango host: getaddrinfo failed with error: {}",
+                    gai_strerror(status));
+
+                return tangoHost();
             }
 
             for (rp = result; rp != nullptr; rp = rp->ai_next)
diff --git a/src/AttributeTraits.cpp b/src/AttributeTraits.cpp
index 7fa4bfb921dcf4af9b6c910182b3842663d8b36a..5a68d7456a1347840eb4b758ba56cd963e5cb7d5 100644
--- a/src/AttributeTraits.cpp
+++ b/src/AttributeTraits.cpp
@@ -28,9 +28,9 @@ namespace hdbpp
 void AttributeTraits::print(ostream &os) const
 {
     os << "AttributeTraits("
-       << "write_type: " << _attr_write_type << ", "
-       << "format_type: " << _attr_format << ", "
-       << "type: " << _attr_type << ")";
+       << "write_type: " << _attr_write_type << "(" << static_cast<unsigned int>(_attr_write_type) << "), "
+       << "format_type: " << _attr_format << "(" << static_cast<unsigned int>(_attr_format) << "), "
+       << "type: " << _attr_type << "(" << static_cast<unsigned int>(_attr_type) << ")";
 }
 
 } // namespace hdbpp
diff --git a/src/AttributeTraits.hpp b/src/AttributeTraits.hpp
index f7621e20a6d5ab6de565e37b7f330a572a8a9728..630d9da3004784e085b8e413e25732c4a988bb12 100644
--- a/src/AttributeTraits.hpp
+++ b/src/AttributeTraits.hpp
@@ -75,7 +75,8 @@ public:
 
     bool operator==(const AttributeTraits &other) const
     {
-        return _attr_write_type == other.writeType() && _attr_format == other.formatType() && _attr_type == other.type();
+        return _attr_write_type == other.writeType() && _attr_format == other.formatType() &&
+            _attr_type == other.type();
     }
 
     /// @brief Print the AttributeTraits object to the stream
diff --git a/src/ColumnCache.hpp b/src/ColumnCache.hpp
index f7350a3dd06436682d6ed371bdbd0e16c53f16d7..5fb83e7d08ff78532f5d3bc708f12ccefdc7f6db 100644
--- a/src/ColumnCache.hpp
+++ b/src/ColumnCache.hpp
@@ -127,7 +127,8 @@ namespace pqxx_conn
 
                 if (!tx.prepared(_fetch_all_query_name).exists())
                 {
-                    tx.conn().prepare(_fetch_all_query_name, QueryBuilder::fetchAllValuesQuery(_column_name, _table_name, _reference));
+                    tx.conn().prepare(_fetch_all_query_name,
+                        QueryBuilder::fetchAllValuesQuery(_column_name, _table_name, _reference));
 
                     _logger->trace("Created prepared statement for: {}", _fetch_all_query_name);
                 }
@@ -144,8 +145,8 @@ namespace pqxx_conn
         }
         catch (const pqxx::pqxx_exception &ex)
         {
-            string msg {"The database transaction failed. Unable to fetchAll for column: " + _column_name + " in table: " + _table_name +
-                ". Error: " + ex.base().what()};
+            string msg {"The database transaction failed. Unable to fetchAll for column: " + _column_name +
+                " in table: " + _table_name + ". Error: " + ex.base().what()};
 
             _logger->error("Error: An unexpected error occurred when trying to run the database query");
             _logger->error("Caught error: \"{}\"", ex.base().what());
@@ -182,7 +183,8 @@ namespace pqxx_conn
 
                     if (!tx.prepared(_fetch_id_query_name).exists())
                     {
-                        tx.conn().prepare(_fetch_id_query_name, QueryBuilder::fetchValueQuery(_column_name, _table_name, _reference));
+                        tx.conn().prepare(
+                            _fetch_id_query_name, QueryBuilder::fetchValueQuery(_column_name, _table_name, _reference));
 
                         _logger->trace("Created prepared statement for: {}", _fetch_id_query_name);
                     }
@@ -206,7 +208,8 @@ namespace pqxx_conn
                         }
                         else
                         {
-                            throw pqxx::unexpected_rows("More than one row returned for value lookup. Expected just one.");
+                            throw pqxx::unexpected_rows(
+                                "More than one row returned for value lookup. Expected just one.");
                         }
                     }
 
@@ -215,8 +218,8 @@ namespace pqxx_conn
             }
             catch (const pqxx::pqxx_exception &ex)
             {
-                string msg {"The database transaction failed. Unable to query column: " + _column_name + " in table: " + _table_name +
-                    ". Error: " + ex.base().what()};
+                string msg {"The database transaction failed. Unable to query column: " + _column_name +
+                    " in table: " + _table_name + ". Error: " + ex.base().what()};
 
                 _logger->error("Error: An unexpected error occurred when trying to run the database query");
                 _logger->error("Caught error: \"{}\"", ex.base().what());
diff --git a/src/DbConnection.cpp b/src/DbConnection.cpp
old mode 100755
new mode 100644
index e70eca0a8ad08f47080cb375c638b96fd32fa04f..35dc2eb6e935f97739c567cdcdb8cfb83ed51819
--- a/src/DbConnection.cpp
+++ b/src/DbConnection.cpp
@@ -70,7 +70,8 @@ namespace pqxx_conn
         // will destroy any existing cache objects managed by the unique pointers
         _conf_id_cache = make_unique<ColumnCache<int, std::string>>(_conn, CONF_TABLE_NAME, CONF_COL_ID, CONF_COL_NAME);
 
-        _error_desc_id_cache = make_unique<ColumnCache<int, std::string>>(_conn, ERR_TABLE_NAME, ERR_COL_ID, ERR_COL_ERROR_DESC);
+        _error_desc_id_cache = make_unique<ColumnCache<int, std::string>>(
+            _conn, ERR_TABLE_NAME, ERR_COL_ID, ERR_COL_ERROR_DESC);
 
         _event_id_cache = make_unique<ColumnCache<int, std::string>>(
             _conn, HISTORY_EVENT_TABLE_NAME, HISTORY_EVENT_COL_EVENT_ID, HISTORY_EVENT_COL_EVENT);
@@ -122,7 +123,8 @@ namespace pqxx_conn
         // this is an error case
         if (_conf_id_cache->valueExists(full_attr_name))
         {
-            string msg {"This attribute [" + full_attr_name + "] already exists in the database. Unable to add it again."};
+            string msg {
+                "This attribute [" + full_attr_name + "] already exists in the database. Unable to add it again."};
             _logger->error("Error: The attribute already exists in the database and can not be added again");
             _logger->error("Attribute details. Name: {} traits: {}", full_attr_name, traits);
             _logger->error("Throwing consistency error with message: \"{}\"", msg);
@@ -143,12 +145,15 @@ namespace pqxx_conn
 
                 auto row = tx.exec_prepared1(StoreAttribute,
                     full_attr_name,
+                    _query_builder.tableName(traits),
                     control_system,
                     att_domain,
                     att_family,
                     att_member,
                     att_name,
-                    _query_builder.tableName(traits));
+                    static_cast<unsigned int>(traits.type()),
+                    static_cast<unsigned int>(traits.formatType()),
+                    static_cast<unsigned int>(traits.writeType()));
 
                 tx.commit();
 
@@ -193,8 +198,10 @@ namespace pqxx_conn
 
         if (!_event_id_cache->valueExists(event))
         {
-            string msg {"The event [" + event + "] is missing in both the cache and database, this is an unrecoverable error."};
-            _logger->error("Event found missing, this occurred when storing event: {} for attribute: {}", event, full_attr_name);
+            string msg {
+                "The event [" + event + "] is missing in both the cache and database, this is an unrecoverable error."};
+            _logger->error(
+                "Event found missing, this occurred when storing event: {} for attribute: {}", event, full_attr_name);
             _logger->error("Throwing consistency error with message: \"{}\"", msg);
             Tango::Except::throw_exception("Consistency Error", msg, LOCATION_INFO);
         }
@@ -281,15 +288,15 @@ namespace pqxx_conn
                 tx.exec_prepared0(StoreParameterEvent,
                     _conf_id_cache->value(full_attr_name),
                     event_time,
-                    tx.quote(label),
-                    tx.quote(unit),
-                    tx.quote(standard_unit),
-                    tx.quote(display_unit),
-                    tx.quote(format),
-                    tx.quote(archive_rel_change),
-                    tx.quote(archive_abs_change),
-                    tx.quote(archive_period),
-                    tx.quote(description));
+                    label,
+                    unit,
+                    standard_unit,
+                    display_unit,
+                    format,
+                    archive_rel_change,
+                    archive_abs_change,
+                    archive_period,
+                    description);
 
                 tx.commit();
             });
@@ -307,8 +314,11 @@ namespace pqxx_conn
 
     //=============================================================================
     //=============================================================================
-    void DbConnection::storeDataEventError(
-        const std::string &full_attr_name, double event_time, int quality, const std::string &error_msg, const AttributeTraits &traits)
+    void DbConnection::storeDataEventError(const std::string &full_attr_name,
+        double event_time,
+        int quality,
+        const std::string &error_msg,
+        const AttributeTraits &traits)
     {
         assert(!full_attr_name.empty());
         assert(!error_msg.empty());
@@ -317,7 +327,8 @@ namespace pqxx_conn
         assert(_error_desc_id_cache != nullptr);
         assert(_event_id_cache != nullptr);
 
-        _logger->trace("Storing error message event for attribute {}. Error message: \"{}\"", full_attr_name, error_msg);
+        _logger->trace(
+            "Storing error message event for attribute {}. Error message: \"{}\"", full_attr_name, error_msg);
 
         checkConnection(LOCATION_INFO);
         checkAttributeExists(full_attr_name, LOCATION_INFO);
@@ -330,10 +341,13 @@ namespace pqxx_conn
         // double check it really exists....
         if (!_error_desc_id_cache->valueExists(error_msg))
         {
-            string msg {"The error message [" + error_msg + "] is missing in both the cache and database, this is an unrecoverable error."};
+            string msg {"The error message [" + error_msg +
+                "] is missing in both the cache and database, this is an unrecoverable error."};
 
-            _logger->error(
-                "Error message found missing, this occurred when storing msg: \"{}\" for attribute: {}", error_msg, full_attr_name);
+            _logger->error("Error message found missing, this occurred when storing msg: \"{}\" for attribute: {}",
+                error_msg,
+                full_attr_name);
+                
             _logger->error("Throwing consistency error with message: \"{}\"", msg);
             Tango::Except::throw_exception("Consistency Error", msg, LOCATION_INFO);
         }
@@ -346,8 +360,10 @@ namespace pqxx_conn
 
                 if (!tx.prepared(_query_builder.storeDataEventErrorName(traits)).exists())
                 {
-                    tx.conn().prepare(_query_builder.storeDataEventErrorName(traits), _query_builder.storeDataEventErrorQuery(traits));
-                    _logger->trace("Created prepared statement for: {}", _query_builder.storeDataEventErrorName(traits));
+                    tx.conn().prepare(_query_builder.storeDataEventErrorName(traits),
+                        _query_builder.storeDataEventErrorQuery(traits));
+                    _logger->trace(
+                        "Created prepared statement for: {}", _query_builder.storeDataEventErrorName(traits));
                 }
 
                 _logger->warn("{}", _error_desc_id_cache->value(error_msg));
@@ -446,7 +462,8 @@ namespace pqxx_conn
                 return row.at(0).as<int>();
             });
 
-            _logger->debug("Stored event {} for attribute {} and got database id for it: {}", event, full_attr_name, event_id);
+            _logger->debug(
+                "Stored event {} for attribute {} and got database id for it: {}", event, full_attr_name, event_id);
 
             // cache the new event id for future use
             _event_id_cache->cacheValue(event_id, event);
@@ -464,7 +481,8 @@ namespace pqxx_conn
     //=============================================================================
     void DbConnection::storeErrorMsg(const std::string &full_attr_name, const std::string &error_msg)
     {
-        _logger->debug("Error message \"{}\" needs adding to the database, by request of attribute {}", error_msg, full_attr_name);
+        _logger->debug(
+            "Error message \"{}\" needs adding to the database, by request of attribute {}", error_msg, full_attr_name);
 
         try
         {
@@ -485,8 +503,10 @@ namespace pqxx_conn
                 return row.at(0).as<int>();
             });
 
-            _logger->debug(
-                "Stored error message \"{}\" for attribute {} and got database id for it: {}", error_msg, full_attr_name, error_id);
+            _logger->debug("Stored error message \"{}\" for attribute {} and got database id for it: {}",
+                error_msg,
+                full_attr_name,
+                error_id);
 
             // cache the new error id for future use
             _error_desc_id_cache->cacheValue(error_id, error_msg);
@@ -524,8 +544,10 @@ namespace pqxx_conn
     {
         if (isClosed())
         {
-            string msg {"Connection to database is closed. Ensure it has been opened before trying to use the connection."};
-            _logger->error("Error: The DbConnection is showing a closed connection status, open it before using store functions");
+            string msg {
+                "Connection to database is closed. Ensure it has been opened before trying to use the connection."};
+            _logger->error(
+                "Error: The DbConnection is showing a closed connection status, open it before using store functions");
             _logger->error("Throwing connection error with message: \"{}\"", msg);
             Tango::Except::throw_exception("Connecion Error", msg, location);
         }
@@ -533,7 +555,8 @@ namespace pqxx_conn
 
     //=============================================================================
     //=============================================================================
-    void DbConnection::handlePqxxError(const string &msg, const string &what, const string &query, const std::string &location)
+    void DbConnection::handlePqxxError(
+        const string &msg, const string &what, const string &query, const std::string &location)
     {
         string full_msg {"The database transaction failed. " + msg};
         _logger->error("Error: An unexpected error occurred when trying to run the database query");
diff --git a/src/DbConnection.hpp b/src/DbConnection.hpp
index 804af4b3c417866d995aeb9fb47facb75304eaf4..c3597ad7ee54730386df5d6a46842b3a030d5af4 100644
--- a/src/DbConnection.hpp
+++ b/src/DbConnection.hpp
@@ -84,8 +84,11 @@ namespace pqxx_conn
             std::unique_ptr<vector<T>> value_w,
             const AttributeTraits &traits);
 
-        void storeDataEventError(
-            const std::string &full_attr_name, double event_time, int quality, const std::string &error_msg, const AttributeTraits &traits);
+        void storeDataEventError(const std::string &full_attr_name,
+            double event_time,
+            int quality,
+            const std::string &error_msg,
+            const AttributeTraits &traits);
 
         // fetch API
         std::string fetchLastHistoryEvent(const std::string &full_attr_name);
@@ -97,7 +100,8 @@ namespace pqxx_conn
         void checkAttributeExists(const std::string &full_attr_name, const std::string &location);
         void checkConnection(const std::string &location);
 
-        void handlePqxxError(const std::string &msg, const std::string &what, const std::string &query, const std::string &location);
+        void handlePqxxError(
+            const std::string &msg, const std::string &what, const std::string &query, const std::string &location);
 
         // this object builds and caches queries for the database
         QueryBuilder _query_builder;
diff --git a/src/DbConnection.tpp b/src/DbConnection.tpp
old mode 100755
new mode 100644
index 1ad978ceb684557e442ba0d3e8cb9c6727cf5b54..068589343b8028890bfd60a750feda8b53ef2955
--- a/src/DbConnection.tpp
+++ b/src/DbConnection.tpp
@@ -26,6 +26,27 @@ namespace hdbpp
 {
 namespace pqxx_conn
 {
+    namespace store_data_utils
+    {
+        template<typename T>
+        struct Preprocess
+        {
+            static void run(std::unique_ptr<std::vector<T>> &, pqxx::work &) {}
+        };
+
+        //=============================================================================
+        //=============================================================================
+        template<>
+        struct Preprocess<std::string>
+        {
+            static void run(std::unique_ptr<std::vector<std::string>> &value, pqxx::work &tx)
+            {
+                for (auto &str : *value)
+                    str = tx.quote(str);
+            }
+        };
+    } // namespace store_data_utils
+
     //=============================================================================
     //=============================================================================
     template<typename T>
@@ -38,8 +59,11 @@ namespace pqxx_conn
     {
         assert(!full_attr_name.empty());
 
-        _logger->trace("Storing data event for attribute {} with traits {}, value_r valid: {}, value_w valid: {}", 
-            full_attr_name, traits, value_r->size() > 0, value_w->size() > 0);
+        _logger->trace("Storing data event for attribute {} with traits {}, value_r valid: {}, value_w valid: {}",
+            full_attr_name,
+            traits,
+            value_r->size() > 0,
+            value_w->size() > 0);
 
         checkConnection(LOCATION_INFO);
         checkAttributeExists(full_attr_name, LOCATION_INFO);
@@ -53,13 +77,14 @@ namespace pqxx_conn
                 // queries often
                 if (!tx.prepared(_query_builder.storeDataEventName(traits)).exists())
                 {
-                    tx.conn().prepare(_query_builder.storeDataEventName(traits), _query_builder.storeDataEventQuery<T>(traits));
+                    tx.conn().prepare(
+                        _query_builder.storeDataEventName(traits), _query_builder.storeDataEventQuery<T>(traits));
                 }
 
                 // get the pqxx prepared statement invocation object to allow us to
                 // bind each parameter in turn, this gives us the flexibility to bind
                 // conditional parameters (as long as the query string matches)
-                pqxx::prepare::invocation inv = tx.prepared(_query_builder.storeDataEventName(traits));
+                auto inv = tx.prepared(_query_builder.storeDataEventName(traits));
 
                 // this lambda stores the data value correctly into the invocation,
                 // we must treat scalar/spectrum in different ways, one is a single
@@ -68,6 +93,9 @@ namespace pqxx_conn
                 auto store_value = [&tx, &inv, &traits](auto &value) {
                     if (value && value->size() > 0)
                     {
+                        // this ensures strings are quoted and escaped, other types are ignored
+                        store_data_utils::Preprocess<T>::run(value, tx);
+
                         // for a scalar, store the first element of the vector,
                         // we do not expect more than 1 element, for an array, store
                         // the entire vector
diff --git a/src/HdbppTimescaleDb.cpp b/src/HdbppTimescaleDb.cpp
old mode 100755
new mode 100644
index b0b7ab45af00405da60362d340a3cae463882007..4d8c2d7bb427b2e12559d87ad53ef72f933a7fd4
--- a/src/HdbppTimescaleDb.cpp
+++ b/src/HdbppTimescaleDb.cpp
@@ -21,6 +21,7 @@
 
 #include "DbConnection.hpp"
 #include "HdbppTxDataEvent.hpp"
+#include "HdbppTxDataEventError.hpp"
 #include "HdbppTxHistoryEvent.hpp"
 #include "HdbppTxNewAttribute.hpp"
 #include "HdbppTxParameterEvent.hpp"
@@ -36,14 +37,14 @@ namespace hdbpp
 // declaring this variable here removes it from the header, and keeps the header clean.
 // It is allocated in the constructor. It can be abstracted further to allow easy plug
 // in of different backends at a later point
-unique_ptr<pqxx_conn::DbConnection> conn;
+unique_ptr<pqxx_conn::DbConnection> Conn;
 
 // simple class to gather utility functions that were previously part of HdbppTimescaleDb,
 // removes them from the header and keeps it clean for includes
 struct HdbppTimescaleDbUtils
 {
     static string getConfigParam(const map<string, string> &conf, const string &param, bool mandatory);
-    static map<string, string> extractConfig(vector<string> str, const string &separator);
+    static map<string, string> extractConfig(vector<string> config, const string &separator);
 };
 
 //=============================================================================
@@ -119,10 +120,10 @@ HdbppTimescaleDb::HdbppTimescaleDb(const vector<string> &configuration)
     spdlog::info("Manatory config parameter connect_string: {}", connection_string);
 
     // allocate a connection to store data with
-    conn = make_unique<pqxx_conn::DbConnection>();
+    Conn = make_unique<pqxx_conn::DbConnection>();
 
     // now bring up the connection
-    conn->connect(connection_string);
+    Conn->connect(connection_string);
     spdlog::info("Started libhdbpp-timescale shared library successfully");
 }
 
@@ -130,8 +131,8 @@ HdbppTimescaleDb::HdbppTimescaleDb(const vector<string> &configuration)
 //=============================================================================
 HdbppTimescaleDb::~HdbppTimescaleDb()
 {
-    if (conn->isOpen())
-        conn->disconnect();
+    if (Conn->isOpen())
+        Conn->disconnect();
 }
 
 //=============================================================================
@@ -147,28 +148,30 @@ void HdbppTimescaleDb::insert_Attr(Tango::EventData *event_data, HdbEventDataTyp
     {
         spdlog::trace("Event type is error for attribute: {}", event_data->attr_name);
 
-        conn->createTx<HdbppTxDataEvent>()
+        Conn->createTx<HdbppTxDataEventError>()
             .withName(event_data->attr_name)
             .withTraits(static_cast<Tango::AttrWriteType>(event_data_type.write_type),
                 static_cast<Tango::AttrDataFormat>(event_data_type.data_format),
                 event_data_type.data_type)
             .withError(string(event_data->errors[0].desc))
             .withEventTime(event_data->attr_value->get_date())
-            .withQuality(static_cast<int>(event_data->attr_value->get_quality()))
+            .withQuality(event_data->attr_value->get_quality())
             .store();
     }
     else
     {
+        spdlog::trace("Event type is data for attribute: {}", event_data->attr_name);
+
         // build a data event request, this will store 0 or more data elements,
         // pending on type, format and quality
-        conn->createTx<HdbppTxDataEvent>()
+        Conn->createTx<HdbppTxDataEvent>()
             .withName(event_data->attr_name)
             .withTraits(static_cast<Tango::AttrWriteType>(event_data_type.write_type),
                 static_cast<Tango::AttrDataFormat>(event_data_type.data_format),
                 event_data_type.data_type)
             .withAttribute(event_data->attr_value)
             .withEventTime(event_data->attr_value->get_date())
-            .withQuality(static_cast<int>(event_data->attr_value->get_quality()))
+            .withQuality(event_data->attr_value->get_quality())
             .store();
     }
 }
@@ -180,7 +183,7 @@ void HdbppTimescaleDb::insert_param_Attr(Tango::AttrConfEventData *conf_event_da
     assert(conf_event_data);
     spdlog::trace("Insert parameter event request for attribute: {}", conf_event_data->attr_name);
 
-    conn->createTx<HdbppTxParameterEvent>()
+    Conn->createTx<HdbppTxParameterEvent>()
         .withName(conf_event_data->attr_name)
         .withEventTime(conf_event_data->get_date())
         .withAttrInfo(*(conf_event_data->attr_conf))
@@ -189,7 +192,8 @@ void HdbppTimescaleDb::insert_param_Attr(Tango::AttrConfEventData *conf_event_da
 
 //=============================================================================
 //=============================================================================
-void HdbppTimescaleDb::configure_Attr(std::string fqdn_attr_name, int type, int format, int write_type, unsigned int ttl)
+void HdbppTimescaleDb::configure_Attr(
+    std::string fqdn_attr_name, int type, int format, int write_type, unsigned int ttl)
 {
     assert(!fqdn_attr_name.empty());
     spdlog::trace("Insert new attribute request for attribute: {}", fqdn_attr_name);
@@ -199,13 +203,13 @@ void HdbppTimescaleDb::configure_Attr(std::string fqdn_attr_name, int type, int
     // forgive the ugly casting, but for some reason we receive the enum values
     // already cast to ints, we cast them back to enums so they function as
     // enums again
-    conn->createTx<HdbppTxNewAttribute>()
+    Conn->createTx<HdbppTxNewAttribute>()
         .withName(fqdn_attr_name)
         .withTraits(static_cast<Tango::AttrWriteType>(write_type), static_cast<Tango::AttrDataFormat>(format), type)
         .store();
 
     // add a start event
-    conn->createTx<HdbppTxHistoryEvent>().withName(fqdn_attr_name).withEvent(events::StartEvent).store();
+    Conn->createTx<HdbppTxHistoryEvent>().withName(fqdn_attr_name).withEvent(events::StartEvent).store();
 }
 
 //=============================================================================
@@ -224,7 +228,7 @@ void HdbppTimescaleDb::event_Attr(std::string fqdn_attr_name, unsigned char even
 {
     assert(!fqdn_attr_name.empty());
     spdlog::trace("History event request for attribute: {}", fqdn_attr_name);
-    conn->createTx<HdbppTxHistoryEvent>().withName(fqdn_attr_name).withEvent(event).store();
+    Conn->createTx<HdbppTxHistoryEvent>().withName(fqdn_attr_name).withEvent(event).store();
 }
 
 //=============================================================================
@@ -239,6 +243,6 @@ AbstractDB *HdbppTimescaleDbFactory::create_db(vector<string> configuration)
 //=============================================================================
 DBFactory *getDBFactory()
 {
-	auto *factory = new hdbpp::HdbppTimescaleDbFactory();
-	return static_cast<DBFactory*>(factory);
+    auto *factory = new hdbpp::HdbppTimescaleDbFactory();
+    return static_cast<DBFactory *>(factory);
 }
diff --git a/src/HdbppTxDataEvent.hpp b/src/HdbppTxDataEvent.hpp
old mode 100755
new mode 100644
index 1caf99f9909d4373ec3dbe042008110ad38394b4..a1f5b23655b20bc1173a26e95758cb8a36aec48b
--- a/src/HdbppTxDataEvent.hpp
+++ b/src/HdbppTxDataEvent.hpp
@@ -20,40 +20,21 @@
 #ifndef _HDBPP_TX_DATA_EVENT_HPP
 #define _HDBPP_TX_DATA_EVENT_HPP
 
-#include "AttributeTraits.hpp"
-#include "HdbppTxBase.hpp"
-#include "LibUtils.hpp"
-
-#include <iostream>
-#include <string>
+#include "HdbppTxDataEventBase.hpp"
 
 namespace hdbpp
 {
 template<typename Conn>
-class HdbppTxDataEvent : public HdbppTxBase<Conn>
+class HdbppTxDataEvent : public HdbppTxDataEventBase<Conn, HdbppTxDataEvent>
 {
-public:
-    // TODO check fully tested
-    // TODO when storing INVALID events, i.e. empty or bad quality, do we need to generate an event time, or is the given one still valid?
-    // TODO Quality is an enum?
-    // TODO auto add new attribute feature
+private:
+    // help clean up the code a little
+    using Base = HdbppTxDataEventBase<Conn, HdbppTxDataEvent>;
 
-    HdbppTxDataEvent(Conn &conn) : HdbppTxBase<Conn>(conn) {}
+public:
+    HdbppTxDataEvent(Conn &conn) : HdbppTxDataEventBase<Conn, HdbppTxDataEvent>(conn) {}
     virtual ~HdbppTxDataEvent() {}
 
-    HdbppTxDataEvent<Conn> &withName(const std::string &fqdn_attr_name)
-    {
-        _attr_name = AttributeName {fqdn_attr_name};
-        return *this;
-    }
-
-    HdbppTxDataEvent<Conn> &withTraits(Tango::AttrWriteType write, Tango::AttrDataFormat format, unsigned int type)
-    {
-        _traits = AttributeTraits(write, format, type);
-        _traits_set = true;
-        return *this;
-    }
-
     HdbppTxDataEvent<Conn> &withAttribute(Tango::DeviceAttribute *dev_attr)
     {
         // just set the pointer here, we will do a full event data extraction at
@@ -63,24 +44,6 @@ public:
         return *this;
     }
 
-    HdbppTxDataEvent<Conn> &withEventTime(Tango::TimeVal tv)
-    {
-        _event_time = tv.tv_sec + tv.tv_usec / 1.0e6;
-        return *this;
-    }
-
-    HdbppTxDataEvent<Conn> &withQuality(int quality)
-    {
-        _quality = quality;
-        return *this;
-    }
-
-    HdbppTxDataEvent<Conn> &withError(const string &error_msg)
-    {
-        _error_msg = error_msg;
-        return *this;
-    }
-
     HdbppTxDataEvent<Conn> &store();
 
     /// @brief Print the HdbppTxDataEvent object to the stream
@@ -93,23 +56,8 @@ private:
     template<typename T>
     void doStore();
 
-    // store an error to the database
-    void doStoreError();
-
-    AttributeName _attr_name;
-    AttributeTraits _traits;
-
-    std::string _error_msg;
-    int _quality = Tango::ATTR_INVALID;
-
     // the device attribute to extract the value from
     Tango::DeviceAttribute *_dev_attr = nullptr;
-
-    // time this parameter change event was generated
-    double _event_time = 0;
-
-    // force user to set traits
-    bool _traits_set = false;
 };
 
 //=============================================================================
@@ -117,63 +65,63 @@ private:
 template<typename Conn>
 HdbppTxDataEvent<Conn> &HdbppTxDataEvent<Conn>::store()
 {
-    if (_attr_name.empty())
+    if (Base::attributeName().empty())
     {
         std::string msg {"AttributeName is reporting empty. Unable to complete the transaction."};
         spdlog::error("Error: {}", msg);
         Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
     }
-    else if (!_traits_set)
+    else if (!Base::traitsSet())
     {
         std::string msg {"AttributeTraits are not set. Unable to complete the transaction."};
-        spdlog::error("Error: {}", msg);
+        spdlog::error("Error: {} For attribute {}", msg, Base::attributeName());
         Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
     }
     else if (!_dev_attr)
     {
         std::string msg {"Device Attribute is not set. Unable to complete the transaction."};
-        spdlog::error("Error: {}", msg);
+        spdlog::error("Error: {} For attribute {}", msg, Base::attributeName());
         Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
     }
     else if (HdbppTxBase<Conn>::connection().isClosed())
     {
         string msg {"The connection is reporting it is closed. Unable to store data event."};
-        spdlog::error("Error: {}", msg);
+        spdlog::error("Error: {} For attribute {}", msg, Base::attributeName());
         Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
     }
 
     // disable is_empty exception
     _dev_attr->reset_exceptions(Tango::DeviceAttribute::isempty_flag);
 
-    // check for error messages, if we have one set, assume this is an error
-    // event and store it as so
-    if (!_error_msg.empty())
+    // translate the Tango Type into a C++ type via templates, inside
+    // doStore the data is extracted and then stored
+    switch (Base::attributeTraits().type())
     {
-        // store the error message
-        doStoreError();
-    }
-    else
-    {
-        // translate the Tango Type into a C++ type via templates, inside
-        // doStore the data is extracted and then stored
-        switch (_traits.type())
-        {
-            //case Tango::DEV_BOOLEAN: this->template doStore<bool>(); break;
-            case Tango::DEV_SHORT: this->template doStore<int16_t>(); break;
-            case Tango::DEV_LONG: this->template doStore<int32_t>(); break;
-            case Tango::DEV_LONG64: this->template doStore<int64_t>(); break;
-            case Tango::DEV_FLOAT: this->template doStore<float>(); break;
-            case Tango::DEV_DOUBLE: this->template doStore<double>(); break;
-            case Tango::DEV_UCHAR: this->template doStore<uint8_t>(); break;
-            case Tango::DEV_USHORT: this->template doStore<uint16_t>(); break;
-            case Tango::DEV_ULONG: this->template doStore<uint32_t>(); break;
-            case Tango::DEV_ULONG64: this->template doStore<uint64_t>(); break;
-            case Tango::DEV_STRING: this->template doStore<std::string>(); break;
-            case Tango::DEV_STATE: this->template doStore<int32_t>(); break;
-            // TODO enable these calls.
+        // TODO enable commented out calls.
+        //case Tango::DEV_BOOLEAN: this->template doStore<bool>(); break;
+        case Tango::DEV_SHORT: this->template doStore<int16_t>(); break;
+        case Tango::DEV_LONG: this->template doStore<int32_t>(); break;
+        case Tango::DEV_LONG64: this->template doStore<int64_t>(); break;
+        case Tango::DEV_FLOAT: this->template doStore<float>(); break;
+        case Tango::DEV_DOUBLE: this->template doStore<double>(); break;
+        case Tango::DEV_UCHAR: this->template doStore<uint8_t>(); break;
+        case Tango::DEV_USHORT: this->template doStore<uint16_t>(); break;
+        case Tango::DEV_ULONG: this->template doStore<uint32_t>(); break;
+        case Tango::DEV_ULONG64: this->template doStore<uint64_t>(); break;
+        case Tango::DEV_STRING: this->template doStore<std::string>(); break;
+        case Tango::DEV_STATE:
+            this->template doStore<int32_t>();
+            break;
             //case Tango::DEV_ENUM: this->template doStore<?>(); break;
             //case Tango::DEV_ENCODED: this->template doStore<vector<uint8_t>>(); break;
-        }
+
+        default:
+            std::string msg {
+                "HdbppTxDataEvent built for unsupported type: " + std::to_string(Base::attributeTraits().type()) +
+                ", for attribute: [" + Base::attributeName().fullAttributeName() + "]"};
+
+            spdlog::error("Error: {}", msg);
+            Tango::Except::throw_exception("Runtime Error", msg, LOCATION_INFO);
     }
 
     // success in running the store command, so set the result as true
@@ -195,19 +143,31 @@ void HdbppTxDataEvent<Conn>::doStore()
         // we still store the event, but with no event data, so filter them
         // here, and if we detect one, do not extract data, instead return
         // a vector with no elements in
-        if (has_data && !_dev_attr->is_empty() && _quality != Tango::ATTR_INVALID)
+        if (has_data && !_dev_attr->is_empty() && Base::quality() != Tango::ATTR_INVALID)
         {
             // attempt to extract data, if none is received then clear
             // the unique_ptr as a signal to following functions there is no data
             if (!extractor(*value))
             {
-                std::string msg {"Failed to extract the attribute data for attribute: [" + _attr_name.fullAttributeName() +
-                    "] and off type: [" + std::to_string(_traits.type()) + "]"};
+                std::string msg {"Failed to extract the attribute data for attribute: [" +
+                    Base::attributeName().fullAttributeName() + "] and off type: [" +
+                    std::to_string(Base::attributeTraits().type()) + "]"};
 
                 spdlog::error("Error: {}", msg);
                 Tango::Except::throw_exception("Runtime Error", msg, LOCATION_INFO);
             }
         }
+        // log some more unusual conditions
+        else if (Base::quality() == Tango::ATTR_INVALID)
+        {
+            spdlog::trace("Quality is {} for attribute: [{}], no data extracted",
+                Base::quality(),
+                Base::attributeName().fqdnAttributeName());
+        }
+        else if (_dev_attr->is_empty())
+        {
+            spdlog::trace("Attribute [{}] empty, no data extracted", Base::attributeName().fqdnAttributeName());
+        }
 
         // release ownership of the unique_ptr back to the caller
         return std::move(value);
@@ -215,23 +175,15 @@ void HdbppTxDataEvent<Conn>::doStore()
 
     // attempt to store the error in the database, any exceptions are left to
     // propergate to the caller
-    HdbppTxBase<Conn>::connection().template storeDataEvent<T>(HdbppTxBase<Conn>::attrNameForStorage(_attr_name),
-        _event_time,
-        _quality,
-        std::move(value([this](std::vector<T> &v) { return _dev_attr->extract_read(v); }, _traits.hasReadData())),
-        std::move(value([this](std::vector<T> &v) { return _dev_attr->extract_set(v); }, _traits.hasWriteData())),
-        _traits);
-}
-
-//=============================================================================
-//=============================================================================
-template<typename Conn>
-void HdbppTxDataEvent<Conn>::doStoreError()
-{
-    // attempt to store the error in the database, any exceptions are left to
-    // propergate to the caller
-    HdbppTxBase<Conn>::connection().storeDataEventError(
-        HdbppTxBase<Conn>::attrNameForStorage(_attr_name), _event_time, _quality, _error_msg, _traits);
+    HdbppTxBase<Conn>::connection().template storeDataEvent<T>(
+        HdbppTxBase<Conn>::attrNameForStorage(Base::attributeName()),
+        Base::eventTime(),
+        Base::quality(),
+        std::move(value(
+            [this](std::vector<T> &v) { return _dev_attr->extract_read(v); }, Base::attributeTraits().hasReadData())),
+        std::move(value(
+            [this](std::vector<T> &v) { return _dev_attr->extract_set(v); }, Base::attributeTraits().hasWriteData())),
+        Base::attributeTraits());
 }
 
 //=============================================================================
@@ -242,16 +194,8 @@ void HdbppTxDataEvent<Conn>::print(std::ostream &os) const noexcept
     // TODO can not print tango objects, the operator<< are not const correct!
 
     os << "HdbppTxDataEvent(base: ";
-    HdbppTxBase<Conn>::print(os);
-
-    os << ", "
-       << "_event_time: " << _event_time << ", "
-       << "_attr_name: " << _attr_name << ", "
-       << "_traits: " << _traits << ", "
-       << "_traits_set: " << _traits_set << ", "
-       << "_error_msg: " << _error_msg << ", "
-       << "_quality: " << _quality << ", "
-       << "_event_time: " << _event_time << ")";
+    HdbppTxDataEventBase<Conn, HdbppTxDataEvent>::print(os);
+    os << ")";
 }
 
 } // namespace hdbpp
diff --git a/src/HdbppTxDataEventBase.hpp b/src/HdbppTxDataEventBase.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..836474852cd374c5ae791def39f6b263d8774a06
--- /dev/null
+++ b/src/HdbppTxDataEventBase.hpp
@@ -0,0 +1,118 @@
+/* Copyright (C) : 2014-2019
+   European Synchrotron Radiation Facility
+   BP 220, Grenoble 38043, FRANCE
+
+   This file is part of libhdb++timescale.
+
+   libhdb++timescale is free software: you can redistribute it and/or modify
+   it under the terms of the Lesser GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   libhdb++timescale 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 Lesser
+   GNU General Public License for more details.
+
+   You should have received a copy of the Lesser GNU General Public License
+   along with libhdb++timescale.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _HDBPP_TX_DATA_EVENT_BASE_HPP
+#define _HDBPP_TX_DATA_EVENT_BASE_HPP
+
+#include "AttributeName.hpp"
+#include "AttributeTraits.hpp"
+#include "HdbppTxBase.hpp"
+#include "LibUtils.hpp"
+
+#include <iostream>
+#include <string>
+
+namespace hdbpp
+{
+template<typename Conn, template<typename> class Derived>
+class HdbppTxDataEventBase : public HdbppTxBase<Conn>
+{
+public:
+    // TODO when storing INVALID events, i.e. empty or bad quality, do we need to generate an event time, or is the given one still valid?
+    // TODO auto add new attribute feature
+
+    HdbppTxDataEventBase(Conn &conn) : HdbppTxBase<Conn>(conn) {}
+    virtual ~HdbppTxDataEventBase() {}
+
+    Derived<Conn> &withName(const std::string &fqdn_attr_name)
+    {
+        _attr_name = AttributeName {fqdn_attr_name};
+        return static_cast<Derived<Conn> &>(*this);
+    }
+
+    Derived<Conn> &withTraits(Tango::AttrWriteType write, Tango::AttrDataFormat format, unsigned int type)
+    {
+        _traits = AttributeTraits(write, format, type);
+        _traits_set = true;
+        return static_cast<Derived<Conn> &>(*this);
+    }
+
+    Derived<Conn> &withTraits(AttributeTraits &traits)
+    {
+        _traits = traits;
+        _traits_set = true;
+        return static_cast<Derived<Conn> &>(*this);
+    }
+
+    Derived<Conn> &withEventTime(Tango::TimeVal tv)
+    {
+        _event_time = tv.tv_sec + tv.tv_usec / 1.0e6;
+        return static_cast<Derived<Conn> &>(*this);
+    }
+
+    Derived<Conn> &withQuality(Tango::AttrQuality quality)
+    {
+        _quality = quality;
+        return static_cast<Derived<Conn> &>(*this);
+    }
+
+    /// @brief Print the HdbppTxDataEventBase object to the stream
+    virtual void print(std::ostream &os) const noexcept override;
+
+protected:
+    // release the private data safely for the derived classes
+    AttributeName &attributeName() { return _attr_name; }
+    const AttributeTraits &attributeTraits() const { return _traits; }
+    Tango::AttrQuality quality() const { return _quality; }
+    double eventTime() const { return _event_time; }
+    bool traitsSet() const { return _traits_set; }
+
+private:
+    AttributeName _attr_name;
+    AttributeTraits _traits;
+    Tango::AttrQuality _quality = Tango::ATTR_INVALID;
+
+    // time this parameter change event was generated
+    double _event_time = 0;
+
+    // force user to set traits
+    bool _traits_set = false;
+};
+
+//=============================================================================
+//=============================================================================
+template<typename Conn, template<typename> class Derived>
+void HdbppTxDataEventBase<Conn, Derived>::print(std::ostream &os) const noexcept
+{
+    // TODO can not print tango objects, the operator<< are not const correct!
+
+    os << "HdbppTxDataEventBase(base: ";
+    HdbppTxBase<Conn>::print(os);
+
+    os << ", "
+       << "_event_time: " << _event_time << ", "
+       << "_attr_name: " << _attr_name << ", "
+       << "_traits: " << _traits << ", "
+       << "_traits_set: " << _traits_set << ", "
+       << "_quality: " << _quality << ", "
+       << "_event_time: " << _event_time << ")";
+}
+
+} // namespace hdbpp
+#endif // _HDBPP_TX_DATA_EVENT_BASE_HPP
diff --git a/src/HdbppTxDataEventError.hpp b/src/HdbppTxDataEventError.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b4a00599929e5a1b645440f4316736a3f858e7bd
--- /dev/null
+++ b/src/HdbppTxDataEventError.hpp
@@ -0,0 +1,109 @@
+/* Copyright (C) : 2014-2019
+   European Synchrotron Radiation Facility
+   BP 220, Grenoble 38043, FRANCE
+
+   This file is part of libhdb++timescale.
+
+   libhdb++timescale is free software: you can redistribute it and/or modify
+   it under the terms of the Lesser GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   libhdb++timescale 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 Lesser
+   GNU General Public License for more details.
+
+   You should have received a copy of the Lesser GNU General Public License
+   along with libhdb++timescale.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _HDBPP_TX_DATA_EVENT_ERROR_HPP
+#define _HDBPP_TX_DATA_EVENT_ERROR_HPP
+
+#include "HdbppTxDataEventBase.hpp"
+
+namespace hdbpp
+{
+template<typename Conn>
+class HdbppTxDataEventError : public HdbppTxDataEventBase<Conn, HdbppTxDataEventError>
+{
+private:
+    // help clean up the code a little
+    using Base = HdbppTxDataEventBase<Conn, HdbppTxDataEventError>;
+
+public:
+    HdbppTxDataEventError(Conn &conn) : HdbppTxDataEventBase<Conn, HdbppTxDataEventError>(conn) {}
+    virtual ~HdbppTxDataEventError() {}
+
+    HdbppTxDataEventError<Conn> &withError(const string &error_msg)
+    {
+        _error_msg = error_msg;
+        return *this;
+    }
+
+    HdbppTxDataEventError<Conn> &store();
+
+    /// @brief Print the HdbppTxDataEventError object to the stream
+    void print(std::ostream &os) const noexcept override;
+
+private:
+    std::string _error_msg;
+};
+
+//=============================================================================
+//=============================================================================
+template<typename Conn>
+HdbppTxDataEventError<Conn> &HdbppTxDataEventError<Conn>::store()
+{
+    if (Base::attributeName().empty())
+    {
+        std::string msg {"AttributeName is reporting empty. Unable to complete the transaction."};
+        spdlog::error("Error: {}", msg);
+        Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
+    }
+    else if (!Base::traitsSet())
+    {
+        std::string msg {"AttributeTraits are not set. Unable to complete the transaction."};
+        spdlog::error("Error: {} For attribute {}", msg, Base::attributeName());
+        Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
+    }
+    else if (_error_msg.empty())
+    {
+        std::string msg {"Error message is not set. Unable to complete the transaction."};
+        spdlog::error("Error: {} For attribute {}", msg, Base::attributeName());
+        Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
+    }
+    else if (HdbppTxBase<Conn>::connection().isClosed())
+    {
+        string msg {"The connection is reporting it is closed. Unable to store data event."};
+        spdlog::error("Error: {} For attribute {}", msg, Base::attributeName());
+        Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
+    }
+
+    // attempt to store the error in the database, any exceptions are left to
+    // propergate to the caller
+    HdbppTxBase<Conn>::connection().storeDataEventError(HdbppTxBase<Conn>::attrNameForStorage(Base::attributeName()),
+        Base::eventTime(),
+        Base::quality(),
+        _error_msg,
+        Base::attributeTraits());
+
+    // success in running the store command, so set the result as true
+    HdbppTxBase<Conn>::setResult(true);
+    return *this;
+}
+
+//=============================================================================
+//=============================================================================
+template<typename Conn>
+void HdbppTxDataEventError<Conn>::print(std::ostream &os) const noexcept
+{
+    os << "HdbppTxDataEventError(base: ";
+    HdbppTxDataEventBase<Conn, HdbppTxDataEventError>::print(os);
+
+    os << ", "
+       << "_error_msg: " << _error_msg << ")";
+}
+
+} // namespace hdbpp
+#endif // _HDBPP_TX_DATA_EVENT_ERROR_HPP
diff --git a/src/HdbppTxHistoryEvent.hpp b/src/HdbppTxHistoryEvent.hpp
index 497dcdc2e3098425782d9a41f377119c715c6212..dc499b7624ee6ec3de71175f4d06ebcbd2c4be1f 100644
--- a/src/HdbppTxHistoryEvent.hpp
+++ b/src/HdbppTxHistoryEvent.hpp
@@ -104,13 +104,13 @@ HdbppTxHistoryEvent<Conn> &HdbppTxHistoryEvent<Conn>::store()
     if (_event.empty())
     {
         std::string msg {"The event string is reporting empty. Unable to complete the transaction."};
-        spdlog::error("Error: {}", msg);
+        spdlog::error("Error: {} For attribute {}", msg, _attr_name);
         Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
     }
     else if (HdbppTxBase<Conn>::connection().isClosed())
     {
         std::string msg {"The connection is reporting it is closed. Unable to store event."};
-        spdlog::error("Error: {}", msg);
+        spdlog::error("Error: {} For attribute {}", msg, _attr_name);
         Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
     }
 
@@ -119,11 +119,18 @@ HdbppTxHistoryEvent<Conn> &HdbppTxHistoryEvent<Conn>::store()
     // record a crash event before the next start event
     if (_event == events::StartEvent)
     {
-        auto last_event = HdbppTxBase<Conn>::connection().fetchLastHistoryEvent(HdbppTxBase<Conn>::attrNameForStorage(_attr_name));
+        auto last_event = HdbppTxBase<Conn>::connection().fetchLastHistoryEvent(
+            HdbppTxBase<Conn>::attrNameForStorage(_attr_name));
 
         // check the last event was a StartEvent
         if (last_event == events::StartEvent)
         {
+            spdlog::trace("Detected a double: {} event for attribute: {}, storing a {}: before second {}:",
+                events::StartEvent,
+                _attr_name.fqdnAttributeName(),
+                events::CrashEvent,
+                events::StartEvent);
+
             // insert the crash event
             HdbppTxBase<Conn>::connection()
                 .template createTx<HdbppTxHistoryEvent>()
diff --git a/src/HdbppTxNewAttribute.hpp b/src/HdbppTxNewAttribute.hpp
index 38091dca11e123b225a01eacfc441901a3af0335..2c9c5cca00ba47d2f65611a06d9b2a7c2f867448 100644
--- a/src/HdbppTxNewAttribute.hpp
+++ b/src/HdbppTxNewAttribute.hpp
@@ -76,13 +76,13 @@ HdbppTxNewAttribute<Conn> &HdbppTxNewAttribute<Conn>::store()
     else if (!_traits_set)
     {
         std::string msg {"AttributeTraits are not set. Unable to complete the transaction."};
-        spdlog::error("Error: {}", msg);
+        spdlog::error("Error: {} For attribute {}", msg, _attr_name);
         Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
     }
     else if (HdbppTxBase<Conn>::connection().isClosed())
     {
         std::string msg {"The connection is reporting it is closed. Unable to store new attribute."};
-        spdlog::error("Error: {}", msg);
+        spdlog::error("Error: {} For attribute {}", msg, _attr_name);
         Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
     }
 
diff --git a/src/HdbppTxParameterEvent.hpp b/src/HdbppTxParameterEvent.hpp
index d9c5e027ac04290e726c73e8c267b6321957484e..1911020ed22795898a904c4ace3793aae3d69d1b 100644
--- a/src/HdbppTxParameterEvent.hpp
+++ b/src/HdbppTxParameterEvent.hpp
@@ -91,19 +91,19 @@ HdbppTxParameterEvent<Conn> &HdbppTxParameterEvent<Conn>::store()
     else if (!_attr_info_ex_set)
     {
         std::string msg {"AttributeInfo is not set. Unable to complete the transaction."};
-        spdlog::error("Error: {}", msg);
+        spdlog::error("Error: {} For attribute {}", msg, _attr_name);
         Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
     }
     else if (_event_time == 0)
     {
         std::string msg {"Event time is not set. Unable to complete the transaction."};
-        spdlog::error("Error: {}", msg);
+        spdlog::error("Error: {} For attribute {}", msg, _attr_name);
         Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
     }
     else if (HdbppTxBase<Conn>::connection().isClosed())
     {
         string msg {"The connection is reporting it is closed. Unable to store parameter event."};
-        spdlog::error("Error: {}", msg);
+        spdlog::error("Error: {} For attribute {}", msg, _attr_name);
         Tango::Except::throw_exception("Invalid Argument", msg, LOCATION_INFO);
     }
 
diff --git a/src/LibUtils.cpp b/src/LibUtils.cpp
old mode 100755
new mode 100644
index 54e5219e32d5f9fb6e72a1db4023fea14ab70ecb..414f04fe8e5b23a9f433a53000cdcf448b15362e
--- a/src/LibUtils.cpp
+++ b/src/LibUtils.cpp
@@ -84,7 +84,22 @@ ostream &operator<<(ostream &os, Tango::AttributeDataType type)
     return os;
 }
 
-const int LoggerThreadCount = 1;
+//=============================================================================
+//=============================================================================
+ostream &operator<<(ostream &os, Tango::AttrQuality quality)
+{
+    switch (quality)
+    {
+        case Tango::ATTR_VALID: os << "ATTR_VALID"; return os;
+        case Tango::ATTR_INVALID: os << "ATTR_INVALID"; return os;
+        case Tango::ATTR_ALARM: os << "ATTR_ALARM"; return os;
+        case Tango::ATTR_CHANGING: os << "ATTR_CHANGING"; return os;
+        case Tango::ATTR_WARNING: os << "ATTR_WARNING"; return os;
+    }
+
+    os << "UNKNOWN";
+    return os;
+}
 
 //=============================================================================
 //=============================================================================
@@ -92,7 +107,7 @@ void LogConfigurator::initLogging(bool enable_file, bool enable_console, const s
 {
     try
     {
-        spdlog::init_thread_pool(8192, LoggerThreadCount);
+        spdlog::init_thread_pool(8192, 1);
 
         vector<spdlog::sink_ptr> sinks;
 
@@ -105,8 +120,11 @@ void LogConfigurator::initLogging(bool enable_file, bool enable_console, const s
         if (sinks.empty())
             sinks.push_back(make_shared<spdlog::sinks::null_sink_mt>());
 
-        auto logger = make_shared<spdlog::async_logger>(
-            LibLoggerName, sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::overrun_oldest);
+        auto logger = make_shared<spdlog::async_logger>(LibLoggerName,
+            sinks.begin(),
+            sinks.end(),
+            spdlog::thread_pool(),
+            spdlog::async_overflow_policy::overrun_oldest);
 
         spdlog::register_logger(logger);
         spdlog::flush_every(std::chrono::seconds(1));
diff --git a/src/LibUtils.hpp b/src/LibUtils.hpp
old mode 100755
new mode 100644
index 988192d11866247b24a08e69141c88b18a52d0b9..b569ac879b74338e1bb85c62dcc75dbf3510d0a6
--- a/src/LibUtils.hpp
+++ b/src/LibUtils.hpp
@@ -50,6 +50,7 @@ auto operator<<(std::ostream &os, const T &t) -> decltype(t.print(os), static_ca
 std::ostream &operator<<(std::ostream &os, Tango::AttrWriteType write_type);
 std::ostream &operator<<(std::ostream &os, Tango::AttrDataFormat format);
 std::ostream &operator<<(std::ostream &os, Tango::AttributeDataType type);
+std::ostream &operator<<(std::ostream &os, Tango::AttrQuality quality);
 
 // SPDLOG config and setup
 const string LibLoggerName = "hdbpp";
diff --git a/src/PqxxExtension.hpp b/src/PqxxExtension.hpp
old mode 100755
new mode 100644
index c99ca56b27d4ecb85ec180de4664c2c546d3f355..c4d7961583864203ca19fdca52120ffa26ac89d1
--- a/src/PqxxExtension.hpp
+++ b/src/PqxxExtension.hpp
@@ -30,8 +30,6 @@ namespace pqxx
 {
 namespace internal
 {
-    // these specialisations help pull the data from results
-    // using the name of the traits specialisation.
     template<>
     struct type_name<uint8_t>
     {
diff --git a/src/QueryBuilder.cpp b/src/QueryBuilder.cpp
index 35aa828feca402b6ca4961f74958b98246727749..aff4ba424b888b6b24169a24cde4fc865e7361e6 100644
--- a/src/QueryBuilder.cpp
+++ b/src/QueryBuilder.cpp
@@ -30,7 +30,7 @@ namespace pqxx_conn
 {
     namespace query_utils
     {
-        // these specialisation just return the correct postgres cast for the insert queries,
+        // these specializations just return the correct postgres cast for the insert queries,
         // this is important for the custom types, since the library libpqxx and postgres will
         // not know how to store them.
         template<>
@@ -130,16 +130,29 @@ namespace pqxx_conn
         static string query =
             "INSERT INTO " + CONF_TABLE_NAME + " (" +
                 CONF_COL_NAME + "," +
-                CONF_COL_DATA_TYPE_ID + "," +
+                CONF_COL_TYPE_ID + "," +
+                CONF_COL_FORMAT_TYPE_ID + "," +
+                CONF_COL_WRITE_TYPE_ID + "," +
+                CONF_COL_TABLE_NAME + "," +
                 CONF_COL_CS_NAME + "," + 
                 CONF_COL_DOMAIN + "," +
                 CONF_COL_FAMILY + "," +
                 CONF_COL_MEMBER + "," +
                 CONF_COL_LAST_NAME + ") (" +
-                "SELECT " +
-                    "$1," + CONF_TYPE_COL_TYPE_ID + ",$2,$3,$4,$5,$6 " +
-                "FROM " + CONF_TYPE_TABLE_NAME + " " +
-                "WHERE " + CONF_TYPE_COL_TYPE + " = $7) RETURNING " + CONF_COL_ID;
+                "SELECT " + 
+                    "$1," + 
+                    CONF_TYPE_COL_TYPE_ID + "," + 
+                    CONF_FORMAT_COL_FORMAT_ID + "," + 
+                    CONF_WRITE_COL_WRITE_ID + 
+                    ",$2,$3,$4,$5,$6,$7 " +
+                "FROM " + 
+                    CONF_TYPE_TABLE_NAME + ", " +
+                    CONF_FORMAT_TABLE_NAME + ", " +
+                    CONF_WRITE_TABLE_NAME + " " +
+                "WHERE " + CONF_TYPE_TABLE_NAME + "." + CONF_TYPE_COL_TYPE_NUM + " = $8 " + 
+                "AND " + CONF_FORMAT_TABLE_NAME + "." + CONF_FORMAT_COL_FORMAT_NUM + " = $9 " + 
+                "AND " + CONF_WRITE_TABLE_NAME + "." + CONF_WRITE_COL_WRITE_NUM + " = $10) " +
+                "RETURNING " + CONF_COL_ID;
         // clang-format on
 
         return query;
@@ -216,7 +229,8 @@ namespace pqxx_conn
             auto query = "INSERT INTO " + QueryBuilder::tableName(traits) + " (" + DAT_COL_ID + "," + DAT_COL_DATA_TIME;
 
             // split to ensure increments are in the correct order
-            query = query + "," + DAT_COL_QUALITY + "," + DAT_COL_ERROR_DESC_ID + ") VALUES ($" + to_string(++param_number);
+            query = query + "," + DAT_COL_QUALITY + "," + DAT_COL_ERROR_DESC_ID + ") VALUES ($" +
+                to_string(++param_number);
 
             query = query + ",TO_TIMESTAMP($" + to_string(++param_number) + ")";
 
@@ -252,14 +266,16 @@ namespace pqxx_conn
 
     //=============================================================================
     //=============================================================================
-    const string QueryBuilder::fetchAllValuesQuery(const string &column_name, const string &table_name, const string &reference)
+    const string QueryBuilder::fetchAllValuesQuery(
+        const string &column_name, const string &table_name, const string &reference)
     {
         return "SELECT " + column_name + ", " + reference + " " + "FROM " + table_name;
     }
 
     //=============================================================================
     //=============================================================================
-    const string QueryBuilder::fetchValueQuery(const string &column_name, const string &table_name, const string &reference)
+    const string QueryBuilder::fetchValueQuery(
+        const string &column_name, const string &table_name, const string &reference)
     {
         return "SELECT " + column_name + " " + "FROM " + table_name + " WHERE " + reference + "=$1";
     }
@@ -297,8 +313,7 @@ namespace pqxx_conn
 
                 return string("Unknown");
             }() +
-            "_" +
-            [&traits]() {
+            "_" + [&traits]() {
                 switch (traits.type())
                 {
                     case Tango::DEV_DOUBLE: return TYPE_DEV_DOUBLE;
@@ -318,13 +333,13 @@ namespace pqxx_conn
                 }
 
                 return string("Unknown");
-            }() +
-            "_" + (traits.isReadOnly() ? TYPE_RO : TYPE_RW);
+            }();
     }
 
     //=============================================================================
     //=============================================================================
-    const string &QueryBuilder::handleCache(map<AttributeTraits, string> &cache, const AttributeTraits &traits, const string &stub)
+    const string &QueryBuilder::handleCache(
+        map<AttributeTraits, string> &cache, const AttributeTraits &traits, const string &stub)
     {
         auto result = cache.find(traits);
 
@@ -353,7 +368,8 @@ namespace pqxx_conn
     {
         os << "QueryBuilder(cached "
            << "data_event: name/query " << _data_event_query_names.size() << "/" << _data_event_queries.size() << ", "
-           << "data_event_error: name/query " << _data_event_error_query_names.size() << "/" << _data_event_error_queries.size() << ")";
+           << "data_event_error: name/query " << _data_event_error_query_names.size() << "/"
+           << _data_event_error_queries.size() << ")";
     }
 } // namespace pqxx_conn
 } // namespace hdbpp
diff --git a/src/QueryBuilder.hpp b/src/QueryBuilder.hpp
index f9687bdeb8d7299e34ef211b0eb29bb85f10d4a7..38c7fb2b0d3056c28b2fc1ed2784fe87d2ecac28 100644
--- a/src/QueryBuilder.hpp
+++ b/src/QueryBuilder.hpp
@@ -118,7 +118,8 @@ namespace pqxx_conn
 
     private:
         // generic function to handle caching items into the cache maps
-        const string &handleCache(std::map<AttributeTraits, std::string> &cache, const AttributeTraits &traits, const std::string &stub);
+        const string &handleCache(
+            std::map<AttributeTraits, std::string> &cache, const AttributeTraits &traits, const std::string &stub);
 
         // cached query names, these are built from the traits object
         std::map<AttributeTraits, std::string> _data_event_query_names;
@@ -160,11 +161,13 @@ namespace pqxx_conn
 
             // add the read parameter with cast
             if (traits.hasReadData())
-                query = query + "," + "$" + to_string(++param_number) + "::" + query_utils::postgresCast<T>(traits.isArray());
+                query = query + "," + "$" + to_string(++param_number) +
+                    "::" + query_utils::postgresCast<T>(traits.isArray());
 
             // add the write parameter with cast
             if (traits.hasWriteData())
-                query = query + "," + "$" + to_string(++param_number) + "::" + query_utils::postgresCast<T>(traits.isArray());
+                query = query + "," + "$" + to_string(++param_number) +
+                    "::" + query_utils::postgresCast<T>(traits.isArray());
 
             query = query + "," + "$" + to_string(++param_number) + ")";
 
diff --git a/src/TimescaleSchema.hpp b/src/TimescaleSchema.hpp
index 2a7cc1f02e9502d01a9fb4074b3bb21d7a8f40b8..8bdf14ae96465c335e3db1e82dbabccc2fbbab14 100644
--- a/src/TimescaleSchema.hpp
+++ b/src/TimescaleSchema.hpp
@@ -47,17 +47,15 @@ namespace pqxx_conn
     const std::string TYPE_DEV_STATE = "devstate";
     const std::string TYPE_DEV_ENCODED = "devencoded";
     const std::string TYPE_DEV_ENUM = "devenum";
-    const std::string TYPE_RO = "ro";
-    const std::string TYPE_RW = "rw";
 
     // att_conf table
     const std::string CONF_TABLE_NAME = "att_conf";
     const std::string CONF_COL_ID = "att_conf_id";
     const std::string CONF_COL_NAME = "att_name";
-    const std::string CONF_COL_DATA_TYPE_ID = "att_conf_data_type_id";
-    const std::string CONF_COL_TYPE = "type";
-    const std::string CONF_COL_WRITE_TYPE = "write_type";
-    const std::string CONF_COL_FORMAT_TYPE = "format_type";
+    const std::string CONF_COL_TYPE_ID = "att_conf_type_id";
+    const std::string CONF_COL_FORMAT_TYPE_ID = "att_conf_format_id";
+    const std::string CONF_COL_WRITE_TYPE_ID = "att_conf_write_id";
+    const std::string CONF_COL_TABLE_NAME = "table_name";
     const std::string CONF_COL_CS_NAME = "cs_name";
     const std::string CONF_COL_DOMAIN = "domain";
     const std::string CONF_COL_FAMILY = "family";
@@ -65,16 +63,30 @@ namespace pqxx_conn
     const std::string CONF_COL_LAST_NAME = "name";
     const std::string CONF_COL_TTL = "ttl";
 
-    // att_conf_data_type table
-    const std::string CONF_TYPE_TABLE_NAME = "att_conf_data_type";
-    const std::string CONF_TYPE_COL_TYPE_ID = "att_conf_data_type_id";
-    const std::string CONF_TYPE_COL_TYPE = "data_type";
+    // att_conf_type table
+    const std::string CONF_TYPE_TABLE_NAME = "att_conf_type";
+    const std::string CONF_TYPE_COL_TYPE_ID = "att_conf_type_id";
+    const std::string CONF_TYPE_COL_TYPE = "type";
+    const std::string CONF_TYPE_COL_TYPE_NUM = "type_num";
+
+    // att_conf_format table
+    const std::string CONF_FORMAT_TABLE_NAME = "att_conf_format";
+    const std::string CONF_FORMAT_COL_FORMAT_ID = "att_conf_format_id";
+    const std::string CONF_FORMAT_COL_FORMAT = "format";
+    const std::string CONF_FORMAT_COL_FORMAT_NUM = "format_num";
+
+    // att_conf_write table
+    const std::string CONF_WRITE_TABLE_NAME = "att_conf_write";
+    const std::string CONF_WRITE_COL_WRITE_ID = "att_conf_write_id";
+    const std::string CONF_WRITE_COL_WRITE = "write";
+    const std::string CONF_WRITE_COL_WRITE_NUM = "write_num";
 
     // att_history table
     const std::string HISTORY_TABLE_NAME = "att_history";
     const std::string HISTORY_COL_ID = "att_conf_id";
     const std::string HISTORY_COL_EVENT_ID = "att_history_event_id";
     const std::string HISTORY_COL_TIME = "event_time";
+    const std::string HISTORY_COL_DETAILS = "details";
 
     // att_history_event table
     const std::string HISTORY_EVENT_TABLE_NAME = "att_history_event";
@@ -95,6 +107,7 @@ namespace pqxx_conn
     const std::string PARAM_COL_ARCHIVEABSCHANGE = "archive_abs_change";
     const std::string PARAM_COL_ARCHIVEPERIOD = "archive_period";
     const std::string PARAM_COL_DESCRIPTION = "description";
+    const std::string PARAM_COL_DETAILS = "details";
 
     // att_error_desc table
     const std::string ERR_TABLE_NAME = "att_error_desc";
@@ -110,13 +123,17 @@ namespace pqxx_conn
     const std::string DAT_COL_VALUE_W = "value_w";
     const std::string DAT_COL_QUALITY = "quality";
     const std::string DAT_COL_ERROR_DESC_ID = "att_error_desc_id";
+    const std::string DAT_COL_DETAILS = "details";
+
+    // special fields for enums
+    const std::string DAT_COL_DAT_COL_VALUE_R_LABEL = "value_r_label";
+    const std::string DAT_COL_DAT_COL_VALUE_W_LABEL = "value_w_label";
 
     // special fields for image tables
     const std::string DAT_IMG_COL_DIMX_R = "dim_x_r";
     const std::string DAT_IMG_COL_DIMY_R = "dim_y_r";
     const std::string DAT_IMG_COL_DIMX_W = "dim_x_w";
     const std::string DAT_IMG_COL_DIMY_W = "dim_y_w";
-
 } // namespace pqxx_conn
 } // namespace hdbpp
 #endif // _TIMESCALE_SCHEMA_HPP
diff --git a/test/AttributeNameTests.cpp b/test/AttributeNameTests.cpp
index a6606f6069440b9d3af7b1162c07c48647812a46..dd970688446659b85b1919c49149084eed59350a 100644
--- a/test/AttributeNameTests.cpp
+++ b/test/AttributeNameTests.cpp
@@ -39,7 +39,10 @@ SCENARIO("AttributeName supports fully qualified attribute name", "[attribute-na
         }
         WHEN("Full attribute name is requested")
         {
-            THEN("Valid full attribute name returned") { REQUIRE(attribute_name.fullAttributeName() == TestAttrFullAttrName); }
+            THEN("Valid full attribute name returned")
+            {
+                REQUIRE(attribute_name.fullAttributeName() == TestAttrFullAttrName);
+            }
         }
         WHEN("Tango host is requested")
         {
@@ -79,11 +82,17 @@ SCENARIO("AttributeName supports fully qualified attribute name missing tango pr
 
         WHEN("Fully qualified domain name requested")
         {
-            THEN("Valid fqdn is returned") { REQUIRE(attribute_name.fqdnAttributeName() == TestAttrFQDNameNoTangoQual); }
+            THEN("Valid fqdn is returned")
+            {
+                REQUIRE(attribute_name.fqdnAttributeName() == TestAttrFQDNameNoTangoQual);
+            }
         }
         WHEN("Full attribute name is requested")
         {
-            THEN("Valid full attribute name returned") { REQUIRE(attribute_name.fullAttributeName() == TestAttrFullAttrName); }
+            THEN("Valid full attribute name returned")
+            {
+                REQUIRE(attribute_name.fullAttributeName() == TestAttrFullAttrName);
+            }
         }
         WHEN("Tango host is requested")
         {
@@ -127,7 +136,10 @@ SCENARIO("AttributeName supports fully qualified attribute name but no network d
         }
         WHEN("Full attribute name is requested")
         {
-            THEN("Valid full attribute name returned") { REQUIRE(attribute_name.fullAttributeName() == TestAttrFullAttrName); }
+            THEN("Valid full attribute name returned")
+            {
+                REQUIRE(attribute_name.fullAttributeName() == TestAttrFullAttrName);
+            }
         }
         WHEN("Tango host is requested")
         {
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 9f75b08c9b0fd721e2754b3e2b51fa1765e2ceb8..ee7f2f576a3a76e633797cdb9b27bd6c1c149fef 100755
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -16,6 +16,9 @@ set(TEST_SOURCES
     ${CMAKE_CURRENT_SOURCE_DIR}/AttributeTraitsTests.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/ColumnCacheTests.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/DbConnectionTests.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/HdbppTxBaseTests.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/HdbppTxDataEventTests.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/HdbppTxDataEventErrorTests.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/HdbppTxNewAttributeTests.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/HdbppTxHistoryEventTests.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/HdbppTxParameterEventTests.cpp
diff --git a/test/ColumnCacheTests.cpp b/test/ColumnCacheTests.cpp
index 20555dfaf34b418d88087143402373a3cc56a5ef..bb59050d0cc0b82871d7c75f01629c8672d705f0 100644
--- a/test/ColumnCacheTests.cpp
+++ b/test/ColumnCacheTests.cpp
@@ -45,8 +45,8 @@ const int NewValue2Id = 12;
 
 void createColumnCacheTestDb(pqxx::work &tx)
 {
-    tx.exec("CREATE TEMP TABLE " + TableName + " (" + IdCol + " serial, " + ReferenceCol + " text, " + "PRIMARY KEY (" + IdCol +
-        ")) ON COMMIT PRESERVE ROWS;");
+    tx.exec("CREATE TEMP TABLE " + TableName + " (" + IdCol + " serial, " + ReferenceCol + " text, " + "PRIMARY KEY (" +
+        IdCol + ")) ON COMMIT PRESERVE ROWS;");
 
     tx.exec("INSERT INTO " + TableName + "(" + ReferenceCol + ") VALUES (" + tx.quote(Ref1) + ");");
     tx.exec("INSERT INTO " + TableName + "(" + ReferenceCol + ") VALUES (" + tx.quote(Ref2) + ");");
@@ -255,7 +255,8 @@ SCENARIO("Clearing the cache does not stop entries being cached again", "[db-acc
     conn->disconnect();
 }
 
-SCENARIO("ColumnCache will fetch values from db and cache them as they are requested by reference", "[db-access][column-cache][psql]")
+SCENARIO("ColumnCache will fetch values from db and cache them as they are requested by reference",
+    "[db-access][column-cache][psql]")
 {
     auto conn = connectDb();
 
diff --git a/test/DbConnectionTests.cpp b/test/DbConnectionTests.cpp
old mode 100755
new mode 100644
index db21b09fb39632806b95932d93dda92d1f32ba19..166c81dde6df0a38bcc3783262706d8b3dadae84
--- a/test/DbConnectionTests.cpp
+++ b/test/DbConnectionTests.cpp
@@ -20,6 +20,7 @@
 #include "DbConnection.hpp"
 #include "HdbppDefines.hpp"
 #include "LibUtils.hpp"
+#include "QueryBuilder.hpp"
 #include "TestHelpers.hpp"
 #include "TimescaleSchema.hpp"
 #include "catch2/catch.hpp"
@@ -55,8 +56,8 @@ void clearTable(pqxx::connection &conn, const string &table_name)
 // wrapper to store an attribute
 void storeTestAttribute(DbConnection &conn, const AttributeTraits &traits)
 {
-    REQUIRE_NOTHROW(
-        conn.storeAttribute(TestAttrFinalName, TestAttrCs, TestAttrDomain, TestAttrFamily, TestAttrMember, TestAttrName, traits));
+    REQUIRE_NOTHROW(conn.storeAttribute(
+        TestAttrFinalName, TestAttrCs, TestAttrDomain, TestAttrFamily, TestAttrMember, TestAttrName, traits));
 }
 
 // wrapper to store some event data, and return the data for comparison
@@ -157,11 +158,13 @@ bool compareVector<double>(const vector<double> &lhs, const vector<double> &rhs)
 // taking the original data as a reference, this function loads the last line of data and compares
 // it to the reference data as a test
 template<typename T>
-void checkStoreTestEventData(pqxx::connection &test_conn, const AttributeTraits &traits, const tuple<vector<T>, vector<T>> &data)
+void checkStoreTestEventData(
+    pqxx::connection &test_conn, const AttributeTraits &traits, const tuple<vector<T>, vector<T>> &data)
 {
     pqxx::work tx {test_conn};
 
-    auto data_row(tx.exec1("SELECT * FROM " + query_builder.tableName(traits) + " ORDER BY " + DAT_COL_DATA_TIME + " LIMIT 1"));
+    auto data_row(
+        tx.exec1("SELECT * FROM " + query_builder.tableName(traits) + " ORDER BY " + DAT_COL_DATA_TIME + " LIMIT 1"));
 
     auto attr_row(tx.exec1("SELECT * FROM " + CONF_TABLE_NAME));
     tx.commit();
@@ -192,7 +195,8 @@ void checkStoreTestEventData(pqxx::connection &test_conn, const AttributeTraits
 }
 }; // namespace psql_conn_test
 
-SCENARIO("The DbConnection class can open a valid connection to a postgres node", "[db-access][hdbpp-db-access][db-connection][psql]")
+SCENARIO("The DbConnection class can open a valid connection to a postgres node",
+    "[db-access][hdbpp-db-access][db-connection][psql]")
 {
     GIVEN("An unconnected DbConnection object")
     {
@@ -213,7 +217,8 @@ SCENARIO("The DbConnection class can open a valid connection to a postgres node"
     }
 }
 
-SCENARIO("The DbConnection class handles a bad connection attempt with an exception", "[db-access][hdbpp-db-access][db-connection][psql]")
+SCENARIO("The DbConnection class handles a bad connection attempt with an exception",
+    "[db-access][hdbpp-db-access][db-connection][psql]")
 {
     GIVEN("An unconnected DbConnection object")
     {
@@ -264,24 +269,44 @@ SCENARIO("Storing Attributes in the database", "[db-access][hdbpp-db-access][db-
             {
                 {
                     pqxx::work tx {test_conn};
-                    auto r(tx.exec1("SELECT * FROM " + CONF_TABLE_NAME));
+                    auto attr_row(tx.exec1("SELECT * FROM " + CONF_TABLE_NAME));
+
+                    auto type_row(tx.exec1("SELECT " + CONF_TYPE_COL_TYPE_ID + " FROM " + CONF_TYPE_TABLE_NAME +
+                        " WHERE " + CONF_TYPE_COL_TYPE_NUM + " = " + std::to_string(traits.type())));
+
+                    auto format_row(tx.exec1("SELECT " + CONF_FORMAT_COL_FORMAT_ID + " FROM " + CONF_FORMAT_TABLE_NAME +
+                        " WHERE " + CONF_FORMAT_COL_FORMAT_NUM + " = " + std::to_string(traits.formatType())));
+
+                    auto access_row(tx.exec1("SELECT " + CONF_WRITE_COL_WRITE_ID + " FROM " + CONF_WRITE_TABLE_NAME +
+                        " WHERE " + CONF_WRITE_COL_WRITE_NUM + " = " + std::to_string(traits.writeType())));
+
                     tx.commit();
 
-                    REQUIRE(r.at(CONF_COL_NAME).as<string>() == TestAttrFQDName);
-                    REQUIRE(r.at(CONF_COL_CS_NAME).as<string>() == TestAttrCs);
-                    REQUIRE(r.at(CONF_COL_DOMAIN).as<string>() == TestAttrDomain);
-                    REQUIRE(r.at(CONF_COL_FAMILY).as<string>() == TestAttrFamily);
-                    REQUIRE(r.at(CONF_COL_MEMBER).as<string>() == TestAttrMember);
-                    REQUIRE(r.at(CONF_COL_LAST_NAME).as<string>() == TestAttrName);
+                    REQUIRE(attr_row.at(CONF_COL_NAME).as<string>() == TestAttrFQDName);
+                    REQUIRE(attr_row.at(CONF_COL_CS_NAME).as<string>() == TestAttrCs);
+                    REQUIRE(attr_row.at(CONF_COL_DOMAIN).as<string>() == TestAttrDomain);
+                    REQUIRE(attr_row.at(CONF_COL_FAMILY).as<string>() == TestAttrFamily);
+                    REQUIRE(attr_row.at(CONF_COL_MEMBER).as<string>() == TestAttrMember);
+                    REQUIRE(attr_row.at(CONF_COL_LAST_NAME).as<string>() == TestAttrName);
+                    REQUIRE(attr_row.at(CONF_COL_TABLE_NAME).as<string>() == QueryBuilder().tableName(traits));
+                    REQUIRE(attr_row.at(CONF_COL_TYPE_ID).as<int>() == type_row.at(CONF_TYPE_COL_TYPE_ID).as<int>());
+                    REQUIRE(attr_row.at(CONF_COL_FORMAT_TYPE_ID).as<int>() ==
+                        format_row.at(CONF_FORMAT_COL_FORMAT_ID).as<int>());
+                    REQUIRE(attr_row.at(CONF_COL_WRITE_TYPE_ID).as<int>() ==
+                        access_row.at(CONF_WRITE_COL_WRITE_ID).as<int>());
                 }
             }
             AND_WHEN("Trying to store the attribute again")
             {
                 THEN("An exception is throw as the entry already exists in the database")
                 {
-                    REQUIRE_THROWS_AS(
-                        conn.storeAttribute(
-                            TestAttrFinalName, TestAttrCs, TestAttrDomain, TestAttrFamily, TestAttrMember, TestAttrName, traits),
+                    REQUIRE_THROWS_AS(conn.storeAttribute(TestAttrFinalName,
+                                          TestAttrCs,
+                                          TestAttrDomain,
+                                          TestAttrFamily,
+                                          TestAttrMember,
+                                          TestAttrName,
+                                          traits),
                         Tango::DevFailed);
                 }
             }
@@ -314,8 +339,13 @@ SCENARIO("Storing Attributes in a disconnected state", "[db-access][hdbpp-db-acc
 
             THEN("An exception is throw as the database connection is down")
             {
-                REQUIRE_THROWS_AS(conn.storeAttribute(
-                                      TestAttrFinalName, TestAttrCs, TestAttrDomain, TestAttrFamily, TestAttrMember, TestAttrName, traits),
+                REQUIRE_THROWS_AS(conn.storeAttribute(TestAttrFinalName,
+                                      TestAttrCs,
+                                      TestAttrDomain,
+                                      TestAttrFamily,
+                                      TestAttrMember,
+                                      TestAttrName,
+                                      traits),
                     Tango::DevFailed);
             }
         }
@@ -362,7 +392,8 @@ SCENARIO("Storing History Events in the database", "[db-access][hdbpp-db-access]
                     REQUIRE(event_row.at(HISTORY_EVENT_COL_EVENT).as<string>() == events::PauseEvent);
 
                     // check event id matches event table id
-                    REQUIRE(event_row.at(HISTORY_EVENT_COL_EVENT_ID).as<int>() == history_row.at(HISTORY_COL_EVENT_ID).as<int>());
+                    REQUIRE(event_row.at(HISTORY_EVENT_COL_EVENT_ID).as<int>() ==
+                        history_row.at(HISTORY_COL_EVENT_ID).as<int>());
 
                     // check attribute id match
                     REQUIRE(attr_row.at(CONF_COL_ID).as<int>() == history_row.at(HISTORY_COL_ID).as<int>());
@@ -389,7 +420,8 @@ SCENARIO("Storing History Events in the database", "[db-access][hdbpp-db-access]
                             REQUIRE(attr_row.at(CONF_COL_ID).as<int>() == row.at(HISTORY_COL_ID).as<int>());
 
                             // check event id matches event table id
-                            REQUIRE(row.at(HISTORY_COL_EVENT_ID).as<int>() == event_result.at(HISTORY_COL_EVENT_ID).as<int>());
+                            REQUIRE(row.at(HISTORY_COL_EVENT_ID).as<int>() ==
+                                event_result.at(HISTORY_COL_EVENT_ID).as<int>());
                         }
                     }
                 }
@@ -666,8 +698,8 @@ SCENARIO("Storing event data which is invalid", "[db-access][hdbpp-db-access][db
             {
                 {
                     pqxx::work tx {test_conn};
-                    auto data_row(tx.exec1("SELECT * FROM " + psql_conn_test::query_builder.tableName(traits) + " ORDER BY " +
-                        DAT_COL_DATA_TIME + " LIMIT 1"));
+                    auto data_row(tx.exec1("SELECT * FROM " + psql_conn_test::query_builder.tableName(traits) +
+                        " ORDER BY " + DAT_COL_DATA_TIME + " LIMIT 1"));
                     auto attr_row(tx.exec1("SELECT * FROM " + CONF_TABLE_NAME));
                     tx.commit();
 
@@ -692,8 +724,8 @@ SCENARIO("Storing event data which is invalid", "[db-access][hdbpp-db-access][db
             {
                 {
                     pqxx::work tx {test_conn};
-                    auto data_row(tx.exec1("SELECT * FROM " + psql_conn_test::query_builder.tableName(traits) + " ORDER BY " +
-                        DAT_COL_DATA_TIME + " LIMIT 1"));
+                    auto data_row(tx.exec1("SELECT * FROM " + psql_conn_test::query_builder.tableName(traits) +
+                        " ORDER BY " + DAT_COL_DATA_TIME + " LIMIT 1"));
                     auto attr_row(tx.exec1("SELECT * FROM " + CONF_TABLE_NAME));
                     tx.commit();
 
@@ -712,7 +744,8 @@ SCENARIO("Storing event data which is invalid", "[db-access][hdbpp-db-access][db
         test_conn.disconnect();
 }
 
-TEST_CASE("Storing event data of all Tango type combinations in the database", "[db-access][hdbpp-db-access][db-connection][psql]")
+TEST_CASE("Storing event data of all Tango type combinations in the database",
+    "[db-access][hdbpp-db-access][db-connection][psql]")
 {
     DbConnection conn;
     REQUIRE_NOTHROW(conn.connect(postgres_db::HdbppConnectionString));
@@ -756,6 +789,7 @@ TEST_CASE("Storing event data of all Tango type combinations in the database", "
 
                     switch (traits.type())
                     {
+                            // TODO enable commented out calls.
                             //case Tango::DEV_BOOLEAN:
                             //psql_conn_test::checkStoreTestEventData(
                             //test_conn, traits, psql_conn_test::storeTestEventData<Tango::DEV_BOOLEAN>(conn, traits));
@@ -810,8 +844,9 @@ TEST_CASE("Storing event data of all Tango type combinations in the database", "
                             break;
 
                         case Tango::DEV_ULONG64:
-                            psql_conn_test::checkStoreTestEventData(
-                                test_conn, traits, psql_conn_test::storeTestEventData<Tango::DEV_ULONG64>(conn, traits));
+                            psql_conn_test::checkStoreTestEventData(test_conn,
+                                traits,
+                                psql_conn_test::storeTestEventData<Tango::DEV_ULONG64>(conn, traits));
 
                             break;
 
@@ -917,15 +952,16 @@ SCENARIO("Storing data events as errors", "[db-access][hdbpp-db-access][db-conne
 
         WHEN("Storing a new error message in the database")
         {
-            REQUIRE_NOTHROW(conn.storeDataEventError(TestAttrFinalName, event_time, Tango::ATTR_VALID, error_msg, traits));
+            REQUIRE_NOTHROW(
+                conn.storeDataEventError(TestAttrFinalName, event_time, Tango::ATTR_VALID, error_msg, traits));
 
             THEN("Then both the event and history event exists in the database, and can be read back and verified")
             {
                 {
                     pqxx::work tx {test_conn};
 
-                    auto data_row(tx.exec1("SELECT * FROM " + psql_conn_test::query_builder.tableName(traits) + " ORDER BY " +
-                        DAT_COL_DATA_TIME + " LIMIT 1"));
+                    auto data_row(tx.exec1("SELECT * FROM " + psql_conn_test::query_builder.tableName(traits) +
+                        " ORDER BY " + DAT_COL_DATA_TIME + " LIMIT 1"));
 
                     auto attr_row(tx.exec1("SELECT * FROM " + CONF_TABLE_NAME));
                     auto error_row(tx.exec1("SELECT * FROM " + ERR_TABLE_NAME));
@@ -939,15 +975,19 @@ SCENARIO("Storing data events as errors", "[db-access][hdbpp-db-access][db-conne
             }
             AND_WHEN("A second error is stored with the same message")
             {
-                REQUIRE_NOTHROW(conn.storeDataEventError(TestAttrFinalName, event_time, Tango::ATTR_VALID, error_msg, traits));
+                gettimeofday(&tv, NULL);
+                event_time = tv.tv_sec + tv.tv_usec / 1.0e6;
+
+                REQUIRE_NOTHROW(
+                    conn.storeDataEventError(TestAttrFinalName, event_time, Tango::ATTR_VALID, error_msg, traits));
 
                 THEN("The same error id is used in the event data")
                 {
                     {
                         pqxx::work tx {test_conn};
 
-                        auto data_row(tx.exec1("SELECT * FROM " + psql_conn_test::query_builder.tableName(traits) + " ORDER BY " +
-                            DAT_COL_DATA_TIME + " LIMIT 1"));
+                        auto data_row(tx.exec1("SELECT * FROM " + psql_conn_test::query_builder.tableName(traits) +
+                            " ORDER BY " + DAT_COL_DATA_TIME + " LIMIT 1"));
 
                         auto attr_row(tx.exec1("SELECT * FROM " + CONF_TABLE_NAME));
                         auto error_row(tx.exec1("SELECT * FROM " + ERR_TABLE_NAME));
@@ -1014,7 +1054,8 @@ SCENARIO("Fetching the last event after it has just been stored", "[db-access][h
         test_conn.disconnect();
 }
 
-SCENARIO("When no exevts have been stored, no error is thrown requesting the last event", "[hdbpp-tx][hdbpp-tx-history-event]")
+SCENARIO("When no events have been stored, no error is thrown requesting the last event",
+    "[db-access][hdbpp-db-access][db-connection][psql]")
 {
     DbConnection conn;
     REQUIRE_NOTHROW(conn.connect(postgres_db::HdbppConnectionString));
@@ -1024,6 +1065,9 @@ SCENARIO("When no exevts have been stored, no error is thrown requesting the las
 
     GIVEN("A valid DbConnection connected to a hdbpp database with no attribute nor history event stored in it")
     {
+        psql_conn_test::clearTable(test_conn, HISTORY_TABLE_NAME);
+        psql_conn_test::clearTable(test_conn, HISTORY_EVENT_TABLE_NAME);
+
         WHEN("Requesting the last event")
         {
             string event;
diff --git a/test/HdbppTxBaseTests.cpp b/test/HdbppTxBaseTests.cpp
index 3fdf9bcdf5df6a5b15cd9faf4166625d860181d2..aac37b22581f5a38fcf0bc1d6bf0a48f6860a574 100644
--- a/test/HdbppTxBaseTests.cpp
+++ b/test/HdbppTxBaseTests.cpp
@@ -37,7 +37,10 @@ class MockConnection
 class TestHdbppTxBase : public HdbppTxBase<MockConnection>
 {
 public:
-    static string testAttrNameForStorage(AttributeName &attr_name) { return HdbppTxBase<MockConnection>::attrNameForStorage(attr_name); }
+    static string testAttrNameForStorage(AttributeName &attr_name)
+    {
+        return HdbppTxBase<MockConnection>::attrNameForStorage(attr_name);
+    }
 };
 }; // namespace hdbpp_base_test
 
diff --git a/test/HdbppTxDataEventErrorTests.cpp b/test/HdbppTxDataEventErrorTests.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b032e1ad3d2a8508815ec147d0e321d29f2ff770
--- /dev/null
+++ b/test/HdbppTxDataEventErrorTests.cpp
@@ -0,0 +1,227 @@
+/* Copyright (C) : 2014-2019
+   European Synchrotron Radiation Facility
+   BP 220, Grenoble 38043, FRANCE
+
+   This file is part of libhdb++timescale.
+
+   libhdb++timescale is free software: you can redistribute it and/or modify
+   it under the terms of the Lesser GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   libhdb++timescale 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 Lesser
+   GNU General Public License for more details.
+
+   You should have received a copy of the Lesser GNU General Public License
+   along with libhdb++timescale.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include "ConnectionBase.hpp"
+#include "HdbppTxDataEventError.hpp"
+#include "HdbppTxFactory.hpp"
+#include "TestHelpers.hpp"
+#include "catch2/catch.hpp"
+
+using namespace std;
+using namespace hdbpp;
+using namespace hdbpp_test::attr_name;
+
+namespace hdbpp_data_event_test_error
+{
+const string TestError = "A test error message";
+
+// Mock connection to test the HdbppTxDataEvent class, only
+// implements the functions that storeAttribute use, nothing more
+class MockConnection : public ConnectionBase, public HdbppTxFactory<MockConnection>
+{
+public:
+    // Enforced connection API from ConnectionBase
+    void connect(const string &) override { _conn_state = true; }
+    void disconnect() override { _conn_state = false; }
+    bool isOpen() const noexcept { return _conn_state; }
+    bool isClosed() const noexcept { return !isOpen(); }
+
+    void storeDataEventError(const std::string &full_attr_name,
+        double event_time,
+        int quality,
+        const std::string &error_msg,
+        const AttributeTraits &traits)
+    {
+        if (store_attribute_triggers_ex)
+            throw runtime_error("A test exception");
+
+        // record the data for comparison
+        att_name = full_attr_name;
+        att_event_time = event_time;
+        // TODO make it Tango::AttrQuality for API
+        att_quality = (Tango::AttrQuality)quality;
+        att_traits = traits;
+        att_error_msg = error_msg;
+    }
+
+    // expose the results of the store function so they can be checked
+    // in the results
+
+    // storeDataEvent/storeDataEventError results
+    string att_name;
+    double att_event_time = 0;
+    Tango::AttrQuality att_quality;
+    AttributeTraits att_traits;
+    string att_error_msg;
+    bool store_attribute_triggers_ex = false;
+
+private:
+    // connection is always open unless test specifies closed
+    bool _conn_state = true;
+};
+}; // namespace hdbpp_data_event_test_error
+
+SCENARIO("Construct a valid HdbppTxDataEventError error event for storage", "[hdbpp-tx][hdbpp-tx-data-event-error]")
+{
+    hdbpp_data_event_test_error::MockConnection conn;
+
+    // ugly, how is this dealt with in Tango!?!
+    struct timeval tv;
+    struct Tango::TimeVal tango_tv;
+    gettimeofday(&tv, NULL);
+    tango_tv.tv_sec = tv.tv_sec;
+    tango_tv.tv_usec = tv.tv_usec;
+    tango_tv.tv_nsec = 0;
+
+    GIVEN("An HdbppTxDataEventError object with no data set")
+    {
+        auto tx = conn.createTx<HdbppTxDataEventError>();
+        auto traits = AttributeTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE);
+
+        WHEN("Configuring an HdbppTxDataEventError object with an error")
+        {
+            REQUIRE_NOTHROW(tx.withName(TestAttrFQDName)
+                                .withTraits(traits)
+                                .withEventTime(tango_tv)
+                                .withQuality(Tango::ATTR_VALID)
+                                .withError(hdbpp_data_event_test_error::TestError));
+
+            REQUIRE_NOTHROW(tx.store());
+
+            THEN("The data is the same as that passed via method chaining, and there is no data")
+            {
+                REQUIRE(conn.att_name == TestAttrFinalName);
+                REQUIRE(conn.att_event_time == (tango_tv.tv_sec + tango_tv.tv_usec / 1.0e6));
+                REQUIRE(conn.att_quality == Tango::ATTR_VALID);
+                REQUIRE(conn.att_traits == traits);
+                REQUIRE(conn.att_error_msg == hdbpp_data_event_test_error::TestError);
+            }
+        }
+    }
+}
+
+SCENARIO("When attempting to store invalid HdbppTxDataEventError states, errors are thrown",
+    "[hdbpp-tx][hdbpp-tx-data-event-error]")
+{
+    hdbpp_data_event_test_error::MockConnection conn;
+
+    // ugly, how is this dealt with in Tango!?!
+    struct timeval tv;
+    struct Tango::TimeVal tango_tv;
+    gettimeofday(&tv, NULL);
+    tango_tv.tv_sec = tv.tv_sec;
+    tango_tv.tv_usec = tv.tv_usec;
+    tango_tv.tv_nsec = 0;
+
+    GIVEN("An HdbppTxDataEventError object with no data set")
+    {
+        auto traits = AttributeTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE);
+        auto tx = conn.createTx<HdbppTxDataEventError>();
+
+        WHEN("Attempting to store without setting data")
+        {
+            THEN("An exception is raised and result is false")
+            {
+                REQUIRE_THROWS(tx.store());
+                REQUIRE(!tx.result());
+            }
+        }
+        WHEN("Attempting to store with just name set")
+        {
+            tx.withName(TestAttrFQDName);
+
+            THEN("An exception is raised and result is false")
+            {
+                REQUIRE_THROWS(tx.store());
+                REQUIRE(!tx.result());
+            }
+            AND_WHEN("Setting the AtributeTraits and trying again")
+            {
+                tx.withTraits(traits);
+
+                THEN("An exception is raised and result is false")
+                {
+                    REQUIRE_THROWS(tx.store());
+                    REQUIRE(!tx.result());
+                }
+                AND_WHEN("Setting the error message and trying again")
+                {
+                    tx.withError(hdbpp_data_event_test_error::TestError);
+
+                    THEN("No exception is raised")
+                    {
+                        REQUIRE_NOTHROW(tx.store());
+                        REQUIRE(tx.result());
+                    }
+                }
+            }
+        }
+        WHEN("Attempting to store with valid data, but disconnected connection")
+        {
+            conn.disconnect();
+            REQUIRE(conn.isClosed());
+
+            auto tx = conn.createTx<HdbppTxDataEventError>();
+
+            REQUIRE_NOTHROW(tx.withName(TestAttrFQDName)
+                                .withTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE)
+                                .withEventTime(tango_tv)
+                                .withQuality(Tango::ATTR_VALID)
+                                .withError(hdbpp_data_event_test_error::TestError));
+
+            THEN("An exception is raised and result is false")
+            {
+                REQUIRE_THROWS(tx.store());
+                REQUIRE(!tx.result());
+            }
+        }
+    }
+}
+
+SCENARIO("HdbppTxDataEventError Simulated exception received", "[hdbpp-tx][hdbpp-tx-data-event-error]")
+{
+    hdbpp_data_event_test_error::MockConnection conn;
+
+    // ugly, how is this dealt with in Tango!?!
+    struct timeval tv;
+    struct Tango::TimeVal tango_tv;
+    gettimeofday(&tv, NULL);
+    tango_tv.tv_sec = tv.tv_sec;
+    tango_tv.tv_usec = tv.tv_usec;
+    tango_tv.tv_nsec = 0;
+
+    GIVEN("An HdbppTxDataEventError object with name and traits set")
+    {
+        auto traits = AttributeTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE);
+        auto tx = conn.createTx<HdbppTxDataEventError>();
+
+        REQUIRE_NOTHROW(tx.withName(TestAttrFQDName)
+                            .withTraits(traits)
+                            .withEventTime(tango_tv)
+                            .withQuality(Tango::ATTR_VALID)
+                            .withError(hdbpp_data_event_test_error::TestError));
+
+        WHEN("Storing the transaction with a triggered exception set")
+        {
+            conn.store_attribute_triggers_ex = true;
+
+            THEN("An exception is raised") { REQUIRE_THROWS_AS(tx.store(), runtime_error); }
+        }
+    }
+}
\ No newline at end of file
diff --git a/test/HdbppTxDataEventTests.cpp b/test/HdbppTxDataEventTests.cpp
index dff837641939ae28738d84eb65ee98d687af18a9..cdc2378ef1bb3e8db927ad6c05c30300078193e6 100644
--- a/test/HdbppTxDataEventTests.cpp
+++ b/test/HdbppTxDataEventTests.cpp
@@ -18,43 +18,105 @@
    along with libhdb++timescale.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include "ConnectionBase.hpp"
-#include "HdbppTxEventData.hpp"
+#include "HdbppTxDataEvent.hpp"
 #include "HdbppTxFactory.hpp"
 #include "TestHelpers.hpp"
 #include "catch2/catch.hpp"
 
 using namespace std;
-using namespace tango;
 using namespace hdbpp;
 using namespace hdbpp_test::attr_name;
+using namespace hdbpp_test::data_gen;
 
 namespace hdbpp_data_event_test
 {
-DeviceAttribute createDeviceAttribute(const AttributeTrits &traits)
+Tango::DeviceAttribute createDeviceAttribute(const AttributeTraits &traits)
 {
-    switch (traits.type())
-    {
-        //case Tango::DEV_BOOLEAN: return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_BOOLEAN>(traits));
-        case Tango::DEV_SHORT: return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_SHORT>(traits));
-        case Tango::DEV_LONG: return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_LONG>(traits));
-        case Tango::DEV_LONG64: return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_LONG64>(traits));
-        case Tango::DEV_FLOAT: return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_FLOAT>(traits));
-        case Tango::DEV_DOUBLE: return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_DOUBLE>(traits));
-        case Tango::DEV_UCHAR: return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_UCHAR>(traits));
-        case Tango::DEV_USHORT: return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_USHORT>(traits));
-        case Tango::DEV_ULONG: return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_ULONG>(traits));
-        case Tango::DEV_ULONG64: return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_ULONG64>(traits));
-        case Tango::DEV_STRING: return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_STRING>(traits));
-        case Tango::DEV_STATE:
-            return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_STATE>(traits));
-            //case Tango::DEV_ENUM: return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_BOOLEAN>(traits));
-            //case Tango::DEV_ENCODED: return DeviceAttribute attr(TestAttrFQDName, *generateData<Tango::DEV_BOOLEAN>(traits));
-    }
+    // this is all one messy hack as Tango is not easy to use in a unit test, in this case, we can not
+    // set up and create a DeviceAttribute easy. Instead we use the publicly (!!) available variables
+    auto attr_gen = [&traits](int size_x, int size_y) {
+        switch (traits.type())
+        {
+            // TODO enable commented out calls.
+            case Tango::DEV_BOOLEAN:
+                return Tango::DeviceAttribute(
+                    TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_BOOLEAN>(false, size_x + size_y));
+
+            case Tango::DEV_SHORT:
+                return Tango::DeviceAttribute(
+                    TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_SHORT>(false, size_x + size_y));
+
+            case Tango::DEV_LONG:
+                return Tango::DeviceAttribute(
+                    TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_LONG>(false, size_x + size_y));
+
+            case Tango::DEV_LONG64:
+                return Tango::DeviceAttribute(
+                    TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_LONG64>(false, size_x + size_y));
+
+            case Tango::DEV_FLOAT:
+                return Tango::DeviceAttribute(
+                    TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_FLOAT>(false, size_x + size_y));
+
+            case Tango::DEV_DOUBLE:
+                return Tango::DeviceAttribute(
+                    TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_DOUBLE>(false, size_x + size_y));
+
+            case Tango::DEV_UCHAR:
+                return Tango::DeviceAttribute(
+                    TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_UCHAR>(false, size_x + size_y));
+
+            case Tango::DEV_USHORT:
+                return Tango::DeviceAttribute(
+                    TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_USHORT>(false, size_x + size_y));
+
+            case Tango::DEV_ULONG:
+                return Tango::DeviceAttribute(
+                    TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_ULONG>(false, size_x + size_y));
+
+            case Tango::DEV_ULONG64:
+                return Tango::DeviceAttribute(
+                    TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_ULONG64>(false, size_x + size_y));
+
+            case Tango::DEV_STRING:
+                return Tango::DeviceAttribute(
+                    TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_STRING>(false, size_x + size_y));
+
+            case Tango::DEV_STATE:
+                return Tango::DeviceAttribute(
+                    TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_STATE>(false, size_x + size_y));
+
+                //case Tango::DEV_ENUM:
+                //return Tango::DeviceAttribute(TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_ENUM>(false, size_x + size_y));
+
+                //case Tango::DEV_ENCODED:
+                //return Tango::DeviceAttribute(TestAttrFQDName.c_str(), *generateSpectrumData<Tango::DEV_ENCODED>(false, size_x + size_y));
+        }
+
+        throw runtime_error("Control should not reach here");
+        return Tango::DeviceAttribute();
+    };
+
+    auto select_size = [](bool has_data, int size) {
+        if (has_data)
+            return size;
+
+        return 1;
+    };
+
+    // hack hack hack.... this mess of forced public (!) variable setting actually
+    // sets up the consitions for valid extracts inside the HdbppTxDataEvent class.
+    // Should the Tango API ever be improved then this hack is doomed.
+    auto attr = attr_gen(select_size(traits.hasReadData(), 1), select_size(traits.hasWriteData(), 1));
+    attr.dim_x = select_size(traits.hasReadData(), 1);
+    attr.dim_y = select_size(traits.hasWriteData(), 1);
+    attr.w_dim_x = select_size(traits.hasReadData(), 1);
+    attr.w_dim_y = select_size(traits.hasWriteData(), 1);
+    return attr;
 }
 
 // Mock connection to test the HdbppTxDataEvent class, only
 // implements the functions that storeAttribute use, nothing more
-template<typename T>
 class MockConnection : public ConnectionBase, public HdbppTxFactory<MockConnection>
 {
 public:
@@ -64,7 +126,7 @@ public:
     bool isOpen() const noexcept { return _conn_state; }
     bool isClosed() const noexcept { return !isOpen(); }
 
-    template<typename U>
+    template<typename T>
     void storeDataEvent(const std::string &full_attr_name,
         double event_time,
         int quality,
@@ -72,32 +134,30 @@ public:
         std::unique_ptr<vector<T>> value_w,
         const AttributeTraits &traits)
     {
-        att_name = full_attr_name;
-        att_event_time = event_time;
-        att_quality = quality;
-        att_traits = traits;
-        att_value_r = *value_r;
-        attr_value_w = *value_w;
-    }
+        if (store_attribute_triggers_ex)
+            throw runtime_error("A test exception");
 
-    void storeDataEventError(
-        const std::string &full_attr_name, double event_time, int quality, const std::string &error_msg, const AttributeTraits &traits);
-    {
+        // record the data for comparison
         att_name = full_attr_name;
         att_event_time = event_time;
-        att_quality = quality;
+        // TODO make it Tango::AttrQuality for API
+        att_quality = (Tango::AttrQuality)quality;
         att_traits = traits;
-        att_error_msg = error_msg;
+        data_size_r = value_r->size();
+        data_size_w = value_w->size();
     }
 
+    // expose the results of the store function so they can be checked
+    // in the results
+
+    // storeDataEvent/storeDataEventError results
     string att_name;
-    double att_event_time;
-    int att_quality;
+    double att_event_time = 0;
+    Tango::AttrQuality att_quality;
     AttributeTraits att_traits;
-    string att_error_msg;
-
-    vector<T> attr_value_r;
-    vector<T> attr_value_w;
+    int data_size_r = -1;
+    int data_size_w = -1;
+    bool store_attribute_triggers_ex = false;
 
 private:
     // connection is always open unless test specifies closed
@@ -105,92 +165,171 @@ private:
 };
 }; // namespace hdbpp_data_event_test
 
-SCENARIO("Construct a valid HdbppTxEventData data event for storage", "[hdbpp-tx][hdbpp-txt-data-event]")
+SCENARIO("Construct a valid HdbppTxDataEvent data event for storage", "[hdbpp-tx][hdbpp-tx-data-event]")
 {
     hdbpp_data_event_test::MockConnection conn;
 
-    // seriously ugly, how is this dealt with in Tango!?!
+    // ugly, how is this dealt with in Tango!?!
+    struct timeval tv;
+    struct Tango::TimeVal tango_tv;
     gettimeofday(&tv, NULL);
     tango_tv.tv_sec = tv.tv_sec;
     tango_tv.tv_usec = tv.tv_usec;
     tango_tv.tv_nsec = 0;
 
-    GIVEN("An empty HdbppTxEventData object")
+    GIVEN("Traits for a device attribute")
     {
-        auto attr = createDeviceAttribute(AttributeTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE));
-        auto tx = conn.createTx<HdbppTxEventData>();
+        auto traits = AttributeTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE);
 
-        WHEN("Configuring the HdbppTxEventData object with event chaining")
+        WHEN("Configuring an HdbppTxDataEvent object as a scalar data event and storing")
         {
-            tx.withName(TestAttrFQDName).withTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE);
-            .withEventTime(tango_tv).withQuality(Tango::ATTR_VALID).withAttribute(&attr);
+            auto attr = hdbpp_data_event_test::createDeviceAttribute(traits);
+            auto tx = conn.createTx<HdbppTxDataEvent>();
+
+            REQUIRE_NOTHROW(tx.withName(TestAttrFQDName)
+                                .withTraits(traits)
+                                .withEventTime(tango_tv)
+                                .withQuality(Tango::ATTR_VALID)
+                                .withAttribute(&attr));
+
+            REQUIRE_NOTHROW(tx.store());
+
+            THEN("The data is the same as that passed via method chaining")
+            {
+                REQUIRE(conn.att_name == TestAttrFinalName);
+                REQUIRE(conn.att_event_time == (tango_tv.tv_sec + tango_tv.tv_usec / 1.0e6));
+                REQUIRE(conn.att_quality == Tango::ATTR_VALID);
+                REQUIRE(conn.att_traits == traits);
+                REQUIRE(conn.data_size_r == 1);
+                REQUIRE(conn.data_size_w == 0);
+            }
+        }
+        WHEN("Configuring an HdbppTxDataEvent object as a spectrum data event")
+        {
+            auto attr = hdbpp_data_event_test::createDeviceAttribute(traits);
+            auto tx = conn.createTx<HdbppTxDataEvent>();
+
+            REQUIRE_NOTHROW(tx.withName(TestAttrFQDName)
+                                .withTraits(traits)
+                                .withEventTime(tango_tv)
+                                .withQuality(Tango::ATTR_VALID)
+                                .withAttribute(&attr));
 
-            THEN("Then storing the transaction does not raise an exception") { REQUIRE_NOTHROW(tx.store()); }
-            AND_WHEN("The result of the store is examined after storing")
+            REQUIRE_NOTHROW(tx.store());
+
+            THEN("The data is the same as that passed via method chaining")
             {
-                THEN("The data is the same as that passed via method chaining") {}
+                REQUIRE(conn.att_name == TestAttrFinalName);
+                REQUIRE(conn.att_event_time == (tango_tv.tv_sec + tango_tv.tv_usec / 1.0e6));
+                REQUIRE(conn.att_quality == Tango::ATTR_VALID);
+                REQUIRE(conn.att_traits == traits);
+                REQUIRE(conn.data_size_r > 0);
+                REQUIRE(conn.data_size_w == 0);
             }
         }
     }
 }
 
-SCENARIO("Construct a valid HdbppTxEventData error event for storage", "[hdbpp-tx][hdbpp-txt-data-event]")
+SCENARIO("An invalid quality results in an HdbppTxDataEvent event with no data", "[hdbpp-tx][hdbpp-tx-data-event]")
 {
-    string error_msg = "Test error";
     hdbpp_data_event_test::MockConnection conn;
 
-    // seriously ugly, how is this dealt with in Tango!?!
+    // ugly, how is this dealt with in Tango!?!
+    struct timeval tv;
+    struct Tango::TimeVal tango_tv;
     gettimeofday(&tv, NULL);
     tango_tv.tv_sec = tv.tv_sec;
     tango_tv.tv_usec = tv.tv_usec;
     tango_tv.tv_nsec = 0;
 
-    GIVEN("An empty HdbppTxEventData object")
+    GIVEN("An HdbppTxDataEvent object with no data set")
     {
-        auto attr = createDeviceAttribute(AttributeTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE));
-        auto tx = conn.createTx<HdbppTxEventData>();
+        auto traits = AttributeTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE);
+        auto attr = hdbpp_data_event_test::createDeviceAttribute(traits);
+        auto tx = conn.createTx<HdbppTxDataEvent>();
 
-        WHEN("Configuring the HdbppTxEventData object with event chaining")
+        WHEN("Configuring an HdbppTxDataEvent object with an invalid quality")
         {
-            tx.withName(TestAttrFQDName).withTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE);
-            .withEventTime(tango_tv).withQuality(Tango::ATTR_VALID).withError(error_msg);
+            REQUIRE_NOTHROW(tx.withName(TestAttrFQDName)
+                                .withTraits(traits)
+                                .withEventTime(tango_tv)
+                                .withQuality(Tango::ATTR_INVALID)
+                                .withAttribute(&attr));
+
+            REQUIRE_NOTHROW(tx.store());
 
-            THEN("Then storing the transaction does not raise an exception") { REQUIRE_NOTHROW(tx.store()); }
-            AND_WHEN("The result of the store is examined after storing")
+            THEN("The data is the same as that passed via method chaining")
             {
-                THEN("The data is the same as that passed via method chaining")
-                {
-                    REQUIRE(conn.att_name == TestAttrFinalName);
-                    REQUIRE(conn.att_event_time == (tango_tv.tv_sec + tango_tv.tv_usec / 1.0e6));
-                    REQUIRE(conn.att_quality == Tango::ATTR_VALID);
-                    REQUIRE(conn.att_error_msg == error_msg);
-                    REQUIRE(conn.att_traits == AttributeTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE));
-                }
+                REQUIRE(conn.att_name == TestAttrFinalName);
+                REQUIRE(conn.att_event_time == (tango_tv.tv_sec + tango_tv.tv_usec / 1.0e6));
+                REQUIRE(conn.att_quality == Tango::ATTR_INVALID);
+                REQUIRE(conn.att_traits == traits);
+                REQUIRE(conn.data_size_r == 0);
+                REQUIRE(conn.data_size_w == 0);
             }
         }
     }
 }
 
-SCENARIO("An invalid quality results in an HdbppTxEventData event with no data", "[hdbpp-tx][hdbpp-txt-data-event]")
+SCENARIO("A DeviceAttribute with no data results in an HdbppTxDataEvent event with no data",
+    "[hdbpp-tx][hdbpp-tx-data-event]")
 {
     hdbpp_data_event_test::MockConnection conn;
 
-    GIVEN("An AttributeName object with valid name")
+    // ugly, how is this dealt with in Tango!?!
+    struct timeval tv;
+    struct Tango::TimeVal tango_tv;
+    gettimeofday(&tv, NULL);
+    tango_tv.tv_sec = tv.tv_sec;
+    tango_tv.tv_usec = tv.tv_usec;
+    tango_tv.tv_nsec = 0;
+
+    GIVEN("An HdbppTxDataEvent object with no data set")
     {
-        WHEN("Requesting the name for storage")
+        Tango::DeviceAttribute attr;
+        auto traits = AttributeTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE);
+        auto tx = conn.createTx<HdbppTxDataEvent>();
+
+        WHEN("Configuring an HdbppTxDataEvent object with an empty DeviceAttribute")
         {
-            THEN("The name is valid and as expected") {}
+            REQUIRE_NOTHROW(tx.withName(TestAttrFQDName)
+                                .withTraits(traits)
+                                .withEventTime(tango_tv)
+                                .withQuality(Tango::ATTR_VALID)
+                                .withAttribute(&attr));
+
+            REQUIRE_NOTHROW(tx.store());
+
+            THEN("The data is the same as that passed via method chaining")
+            {
+                REQUIRE(conn.att_name == TestAttrFinalName);
+                REQUIRE(conn.att_event_time == (tango_tv.tv_sec + tango_tv.tv_usec / 1.0e6));
+                REQUIRE(conn.att_quality == Tango::ATTR_VALID);
+                REQUIRE(conn.att_traits == traits);
+                REQUIRE(conn.data_size_r == 0);
+                REQUIRE(conn.data_size_w == 0);
+            }
         }
     }
 }
 
-SCENARIO("When attempting to store invalid HdbppTxEventData states, errors are thrown", "[hdbpp-tx][hdbpp-txt-data-event]")
+SCENARIO(
+    "When attempting to store invalid HdbppTxDataEvent states, errors are thrown", "[hdbpp-tx][hdbpp-tx-data-event]")
 {
     hdbpp_data_event_test::MockConnection conn;
 
-    GIVEN("An HdbppTxNewAttribute object with no data set")
+    // ugly, how is this dealt with in Tango!?!
+    struct timeval tv;
+    struct Tango::TimeVal tango_tv;
+    gettimeofday(&tv, NULL);
+    tango_tv.tv_sec = tv.tv_sec;
+    tango_tv.tv_usec = tv.tv_usec;
+    tango_tv.tv_nsec = 0;
+
+    GIVEN("An HdbppTxDataEvent object with no data set")
     {
-        auto tx = conn.createTx<HdbppTxNewAttribute>();
+        auto traits = AttributeTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE);
+        auto tx = conn.createTx<HdbppTxDataEvent>();
 
         WHEN("Attempting to store without setting data")
         {
@@ -202,18 +341,48 @@ SCENARIO("When attempting to store invalid HdbppTxEventData states, errors are t
         }
         WHEN("Attempting to store with just name set")
         {
+            tx.withName(TestAttrFQDName);
+
             THEN("An exception is raised and result is false")
             {
-                REQUIRE_THROWS(tx.withName(TestAttrFQDName).store());
+                REQUIRE_THROWS(tx.store());
                 REQUIRE(!tx.result());
             }
+            AND_WHEN("Setting the AtributeTraits and trying again")
+            {
+                tx.withTraits(traits);
+
+                THEN("An exception is raised and result is false")
+                {
+                    REQUIRE_THROWS(tx.store());
+                    REQUIRE(!tx.result());
+                }
+                AND_WHEN("Setting the DeviceAttribute and trying again")
+                {
+                    auto attr = hdbpp_data_event_test::createDeviceAttribute(traits);
+                    tx.withAttribute(&attr);
+
+                    THEN("No exception is raised")
+                    {
+                        REQUIRE_NOTHROW(tx.store());
+                        REQUIRE(tx.result());
+                    }
+                }
+            }
         }
         WHEN("Attempting to store with valid data, but disconnected connection")
         {
             conn.disconnect();
             REQUIRE(conn.isClosed());
 
-            REQUIRE_NOTHROW(tx.withName(TestAttrFQDName).withTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE));
+            auto attr = hdbpp_data_event_test::createDeviceAttribute(traits);
+            auto tx = conn.createTx<HdbppTxDataEvent>();
+
+            REQUIRE_NOTHROW(tx.withName(TestAttrFQDName)
+                                .withTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE)
+                                .withEventTime(tango_tv)
+                                .withQuality(Tango::ATTR_VALID)
+                                .withAttribute(&attr));
 
             THEN("An exception is raised and result is false")
             {
@@ -224,26 +393,98 @@ SCENARIO("When attempting to store invalid HdbppTxEventData states, errors are t
     }
 }
 
-SCENARIO("Can store every tango data type", "[hdbpp-tx][hdbpp-txt-data-event]")
+TEST_CASE("Creating HdbppTxDataEvents for each tango type and storing them", "[db-access][hdbpp-tx-data-event]")
 {
     hdbpp_data_event_test::MockConnection conn;
 
-    GIVEN("An AttributeName object with valid name")
+    // ugly, how is this dealt with in Tango!?!
+    struct timeval tv;
+    struct Tango::TimeVal tango_tv;
+    gettimeofday(&tv, NULL);
+    tango_tv.tv_sec = tv.tv_sec;
+    tango_tv.tv_usec = tv.tv_usec;
+    tango_tv.tv_nsec = 0;
+
+    // TODO remaining types
+    vector<unsigned int> types {
+        //Tango::DEV_BOOLEAN#,
+        Tango::DEV_DOUBLE,
+        Tango::DEV_FLOAT,
+        Tango::DEV_STRING,
+        Tango::DEV_LONG,
+        Tango::DEV_ULONG,
+        Tango::DEV_LONG64,
+        Tango::DEV_ULONG64,
+        Tango::DEV_SHORT,
+        Tango::DEV_USHORT,
+        Tango::DEV_UCHAR,
+        Tango::DEV_STATE,
+        /* Tango::DEV_ENCODED, 
+        Tango::DEV_ENUM */};
+
+    vector<Tango::AttrWriteType> write_types {Tango::READ, Tango::WRITE, Tango::READ_WRITE, Tango::READ_WITH_WRITE};
+    vector<Tango::AttrDataFormat> format_types {Tango::SCALAR, Tango::SPECTRUM};
+
+    // loop for every combination of type in Tango
+    for (auto &type : types)
     {
-        WHEN("Requesting the name for storage")
+        for (auto &format : format_types)
         {
-            THEN("The name is valid and as expected") {}
+            for (auto &write : write_types)
+            {
+                AttributeTraits traits {write, format, type};
+
+                DYNAMIC_SECTION("Storing with traits: " << traits)
+                {
+                    auto attr = hdbpp_data_event_test::createDeviceAttribute(traits);
+                    auto tx = conn.createTx<HdbppTxDataEvent>();
+
+                    REQUIRE_NOTHROW(tx.withName(TestAttrFQDName)
+                                        .withTraits(traits)
+                                        .withEventTime(tango_tv)
+                                        .withQuality(Tango::ATTR_VALID)
+                                        .withAttribute(&attr)
+                                        .store());
+
+                    REQUIRE(conn.att_name == TestAttrFinalName);
+                    REQUIRE(conn.att_event_time == (tango_tv.tv_sec + tango_tv.tv_usec / 1.0e6));
+                    REQUIRE(conn.att_quality == Tango::ATTR_VALID);
+                    REQUIRE(conn.att_traits == traits);
+
+                    if (traits.hasReadData())
+                        REQUIRE(conn.data_size_r > 0);
+
+                    if (traits.hasWriteData())
+                        REQUIRE(conn.data_size_w > 0);
+                }
+            }
         }
     }
 }
 
-SCENARIO("HdbppTxHistoryEvent Simulated exception received", "[hdbpp-tx][hdbpp-txt-data-event]")
+SCENARIO("HdbppTxDataEvent Simulated exception received", "[hdbpp-tx][hdbpp-tx-data-event]")
 {
     hdbpp_data_event_test::MockConnection conn;
 
-    GIVEN("An HdbppTxHistoryEvent object with name and traits set")
+    // ugly, how is this dealt with in Tango!?!
+    struct timeval tv;
+    struct Tango::TimeVal tango_tv;
+    gettimeofday(&tv, NULL);
+    tango_tv.tv_sec = tv.tv_sec;
+    tango_tv.tv_usec = tv.tv_usec;
+    tango_tv.tv_nsec = 0;
+
+    GIVEN("An HdbppTxHisHdbppTxDatatoryEventEvent object with name and traits set")
     {
-        auto tx = conn.createTx<HdbppTxHistoryEvent>().withName(TestAttrFQDName).withEvent(events::StartEvent);
+        auto traits = AttributeTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE);
+        auto attr = hdbpp_data_event_test::createDeviceAttribute(traits);
+        auto tx = conn.createTx<HdbppTxDataEvent>();
+
+        REQUIRE_NOTHROW(tx.withName(TestAttrFQDName)
+                            .withTraits(traits)
+                            .withEventTime(tango_tv)
+                            .withQuality(Tango::ATTR_VALID)
+                            .withAttribute(&attr));
 
         WHEN("Storing the transaction with a triggered exception set")
         {
diff --git a/test/HdbppTxHistoryEventTests.cpp b/test/HdbppTxHistoryEventTests.cpp
old mode 100755
new mode 100644
index 76bcae50f5a999fbec7bc39687cfa835564b748d..2c627f46fb1ff60c65286c3349d7663a871a1c46
--- a/test/HdbppTxHistoryEventTests.cpp
+++ b/test/HdbppTxHistoryEventTests.cpp
@@ -103,7 +103,8 @@ SCENARIO("Construct and store HdbppTxHistoryEvent data without error", "[hdbpp-t
     }
 }
 
-SCENARIO("When attempting to store invalid HdbppTxHistoryEvent states, errors are thrown", "[hdbpp-tx][hdbpp-tx-history-event]")
+SCENARIO("When attempting to store invalid HdbppTxHistoryEvent states, errors are thrown",
+    "[hdbpp-tx][hdbpp-tx-history-event]")
 {
     hdbpp_hist_event_test::MockConnection conn;
 
@@ -158,7 +159,8 @@ SCENARIO("When attempting to store invalid HdbppTxHistoryEvent states, errors ar
     }
 }
 
-SCENARIO("HdbppTxHistoryEvent's overloaded functions return identical results without error", "[hdbpp-tx][hdbpp-tx-history-event]")
+SCENARIO("HdbppTxHistoryEvent's overloaded functions return identical results without error",
+    "[hdbpp-tx][hdbpp-tx-history-event]")
 {
     hdbpp_hist_event_test::MockConnection conn;
 
diff --git a/test/HdbppTxNewAttributeTests.cpp b/test/HdbppTxNewAttributeTests.cpp
index baf80bc0321029c1ad36cd00acc64843f15daef9..1a4f78668a2632fff3229d590c6aa37fa2d1d48b 100644
--- a/test/HdbppTxNewAttributeTests.cpp
+++ b/test/HdbppTxNewAttributeTests.cpp
@@ -72,7 +72,6 @@ public:
     string new_att_member;
     string new_att_name;
     AttributeTraits att_traits;
-
     bool store_attribute_triggers_ex = false;
 
 private:
@@ -117,7 +116,8 @@ SCENARIO("Construct and store HdbppTxNewAttribute data without error", "[hdbpp-t
     }
 }
 
-SCENARIO("When attempting to store invalid HdbppTxNewAttribute states, errors are thrown", "[hdbpp-tx][hdbpp-tx-new-attribute]")
+SCENARIO("When attempting to store invalid HdbppTxNewAttribute states, errors are thrown",
+    "[hdbpp-tx][hdbpp-tx-new-attribute]")
 {
     hdbpp_new_attr_test::MockConnection conn;
 
@@ -163,7 +163,9 @@ SCENARIO("HdbppTxNewAttribute Simulated exception received", "[hdbpp-tx][hdbpp-t
 
     GIVEN("An HdbppTxNewAttribute object with name and traits set")
     {
-        auto tx = conn.createTx<HdbppTxNewAttribute>().withName(TestAttrFQDName).withTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE);
+        auto tx = conn.createTx<HdbppTxNewAttribute>()
+                      .withName(TestAttrFQDName)
+                      .withTraits(Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE);
 
         WHEN("Storing the transaction with a triggered exception set")
         {
diff --git a/test/HdbppTxParameterEventTests.cpp b/test/HdbppTxParameterEventTests.cpp
index c9f12f6f554e4633600aec0763dbf80feac26116..f8819423a71fc74ba25f328a99e83eb3268a3036 100644
--- a/test/HdbppTxParameterEventTests.cpp
+++ b/test/HdbppTxParameterEventTests.cpp
@@ -122,7 +122,7 @@ SCENARIO("Construct and store HdbppTxParameterEvent data without error", "[hdbpp
     struct timeval tv;
     struct Tango::TimeVal tango_tv;
 
-    // seriously ugly, how is this dealt with in Tango!?!
+    // ugly, how is this dealt with in Tango!?!
     gettimeofday(&tv, NULL);
     tango_tv.tv_sec = tv.tv_sec;
     tango_tv.tv_usec = tv.tv_usec;
@@ -134,7 +134,9 @@ SCENARIO("Construct and store HdbppTxParameterEvent data without error", "[hdbpp
 
         WHEN("Passing a valid configuration with method chaining")
         {
-            tx.withName(TestAttrFQDName).withAttrInfo(hdbpp_param_test::createAttributeInfoEx()).withEventTime(tango_tv);
+            tx.withName(TestAttrFQDName)
+                .withAttrInfo(hdbpp_param_test::createAttributeInfoEx())
+                .withEventTime(tango_tv);
 
             THEN("No exception is raised when storing the transaction") { REQUIRE_NOTHROW(tx.store()); }
             AND_WHEN("The result of the store is examined after storing")
@@ -161,14 +163,15 @@ SCENARIO("Construct and store HdbppTxParameterEvent data without error", "[hdbpp
     }
 }
 
-SCENARIO("When attempting to store invalid HdbppTxParameterEvent states, errors are thrown", "[hdbpp-tx][hdbpp-tx-parameter-event]")
+SCENARIO("When attempting to store invalid HdbppTxParameterEvent states, errors are thrown",
+    "[hdbpp-tx][hdbpp-tx-parameter-event]")
 {
     hdbpp_param_test::MockConnection conn;
 
     struct timeval tv;
     struct Tango::TimeVal tango_tv;
 
-    // seriously ugly, how is this dealt with in Tango!?!
+    // ugly, how is this dealt with in Tango!?!
     gettimeofday(&tv, NULL);
     tango_tv.tv_sec = tv.tv_sec;
     tango_tv.tv_usec = tv.tv_usec;
@@ -221,7 +224,9 @@ SCENARIO("When attempting to store invalid HdbppTxParameterEvent states, errors
             conn.disconnect();
             REQUIRE(conn.isClosed());
 
-            tx.withName(TestAttrFQDName).withEventTime(tango_tv).withAttrInfo(hdbpp_param_test::createAttributeInfoEx());
+            tx.withName(TestAttrFQDName)
+                .withEventTime(tango_tv)
+                .withAttrInfo(hdbpp_param_test::createAttributeInfoEx());
 
             THEN("An exception is raised and result is false")
             {
@@ -239,7 +244,7 @@ SCENARIO("HdbppTxParameterEvent Simulated exception received", "[hdbpp-tx][hdbpp
     struct timeval tv;
     struct Tango::TimeVal tango_tv;
 
-    // seriously ugly, how is this dealt with in Tango!?!
+    // ugly, how is this dealt with in Tango!?!
     gettimeofday(&tv, NULL);
     tango_tv.tv_sec = tv.tv_sec;
     tango_tv.tv_usec = tv.tv_usec;
diff --git a/test/QueryBuilderTests.cpp b/test/QueryBuilderTests.cpp
index 23d2494660eb1998a361826fb8cc5680893e086c..21befb7fc54679b4e185c8149005e0bca01de8f9 100644
--- a/test/QueryBuilderTests.cpp
+++ b/test/QueryBuilderTests.cpp
@@ -26,96 +26,72 @@ using namespace hdbpp;
 using namespace hdbpp::pqxx_conn;
 using namespace Catch::Matchers;
 
-SCENARIO("Creating valid database table names for SCALAR", "[query-string]")
+SCENARIO("storeDataEventQuery() returns the correct Value fields for the given traits", "[query-string]")
 {
-    QueryBuilder query_builder;
-
-    GIVEN("An Attribute traits configured for scalar")
+    GIVEN("A query builder object with nothing cached")
     {
-        AttributeTraits traits {Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE};
+        QueryBuilder query_builder;
 
-        WHEN("Requesting a table name for the traits")
+        WHEN("Requesting a query string for traits configured for Tango::READ")
         {
-            auto result = query_builder.tableName(traits);
-
-            THEN("The result must include the TYPE_SCALAR from the schema") { REQUIRE_THAT(result, Contains(TYPE_SCALAR)); }
+            AttributeTraits traits {Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE};
+            auto result = query_builder.storeDataEventQuery<double>(traits);
+
+            THEN("The result must include the DAT_COL_VALUE_R field only")
+            {
+                REQUIRE_THAT(result, Contains(DAT_COL_VALUE_R));
+                REQUIRE_THAT(result, !Contains(DAT_COL_VALUE_W));
+                REQUIRE_THAT(result, Contains("$4"));
+                REQUIRE_THAT(result, !Contains("$5"));
+            }
         }
-    }
-}
-
-SCENARIO("Creating valid database table names for SPECTRUM", "[query-string]")
-{
-    QueryBuilder query_builder;
-
-    GIVEN("An Attribute traits configured for spectrum")
-    {
-        AttributeTraits traits {Tango::READ, Tango::SPECTRUM, Tango::DEV_DOUBLE};
-
-        WHEN("Requesting a table name for the traits")
+        WHEN("Requesting a query string for traits configured for Tango::WRITE")
         {
-            auto result = query_builder.tableName(traits);
-
-            THEN("The result must include the TYPE_ARRAY from the schema") { REQUIRE_THAT(result, Contains(TYPE_ARRAY)); }
+            AttributeTraits traits {Tango::WRITE, Tango::SCALAR, Tango::DEV_DOUBLE};
+            auto result = query_builder.storeDataEventQuery<double>(traits);
+
+            THEN("The result must include the DAT_COL_VALUE_W field only")
+            {
+                REQUIRE_THAT(result, !Contains(DAT_COL_VALUE_R));
+                REQUIRE_THAT(result, Contains(DAT_COL_VALUE_W));
+                REQUIRE_THAT(result, Contains("$4"));
+                REQUIRE_THAT(result, !Contains("$5"));
+            }
         }
-    }
-}
-
-SCENARIO("Creating valid database table names for IMAGE", "[query-string]")
-{
-    QueryBuilder query_builder;
-
-    GIVEN("An Attribute traits configured for image")
-    {
-        AttributeTraits traits {Tango::READ, Tango::IMAGE, Tango::DEV_DOUBLE};
-
-        WHEN("Requesting a table name for the traits")
+        WHEN("Requesting a query string for traits configured for Tango::READ_WRITE")
         {
-            auto result = query_builder.tableName(traits);
-
-            THEN("The result must include the TYPE_IMAGE from the schema") { REQUIRE_THAT(result, Contains(TYPE_IMAGE)); }
+            AttributeTraits traits {Tango::READ_WRITE, Tango::SCALAR, Tango::DEV_DOUBLE};
+            auto result = query_builder.storeDataEventQuery<double>(traits);
+
+            THEN("The result must include both the DAT_COL_VALUE_R and DAT_COL_VALUE_W field")
+            {
+                REQUIRE_THAT(result, Contains(DAT_COL_VALUE_R));
+                REQUIRE_THAT(result, Contains(DAT_COL_VALUE_W));
+                REQUIRE_THAT(result, Contains("$4"));
+                REQUIRE_THAT(result, Contains("$5"));
+            }
         }
-    }
-}
-
-SCENARIO("Creating valid database table names for DEV_BOOLEAN", "[query-string]")
-{
-    QueryBuilder query_builder;
-
-    GIVEN("An Attribute traits configured for boolean")
-    {
-        AttributeTraits traits {Tango::READ, Tango::SCALAR, Tango::DEV_BOOLEAN};
-
-        WHEN("Requesting a table name for the traits")
+        WHEN("Requesting a query string for traits configured for Tango::READ_WITH_WRITE")
         {
-            auto result = query_builder.tableName(traits);
-
-            THEN("The result must include the TYPE_DEV_BOOLEAN from the schema") { REQUIRE_THAT(result, Contains(TYPE_DEV_BOOLEAN)); }
+            AttributeTraits traits {Tango::READ_WITH_WRITE, Tango::SCALAR, Tango::DEV_DOUBLE};
+            auto result = query_builder.storeDataEventQuery<double>(traits);
+
+            THEN("The result must include both the DAT_COL_VALUE_R and DAT_COL_VALUE_W field")
+            {
+                REQUIRE_THAT(result, Contains(DAT_COL_VALUE_R));
+                REQUIRE_THAT(result, Contains(DAT_COL_VALUE_W));
+                REQUIRE_THAT(result, Contains("$4"));
+                REQUIRE_THAT(result, Contains("$5"));
+            }
         }
     }
 }
 
-SCENARIO("Creating valid database table names for DEV_UCHAR", "[query-string]")
+SCENARIO("Creating valid insert queries with storeDataEventErrorQuery()", "[query-string]")
 {
     QueryBuilder query_builder;
 
-    GIVEN("An Attribute traits configured for unsigned char")
-    {
-        AttributeTraits traits {Tango::READ, Tango::SCALAR, Tango::DEV_UCHAR};
-
-        WHEN("Requesting a table name for the traits")
-        {
-            auto result = query_builder.tableName(traits);
-
-            THEN("The result must include the TYPE_DEV_UCHAR from the schema") { REQUIRE_THAT(result, Contains(TYPE_DEV_UCHAR)); }
-        }
-    }
-}
-
-SCENARIO("Creating valid database table names for DEV_DOUBLE", "[query-string]")
-{
-    QueryBuilder query_builder;
-
-    GIVEN("An Attribute traits configured for unsigned char")
+    GIVEN("An Attribute traits configured for scalar")
     {
         AttributeTraits traits {Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE};
 
@@ -123,75 +99,68 @@ SCENARIO("Creating valid database table names for DEV_DOUBLE", "[query-string]")
         {
             auto result = query_builder.tableName(traits);
 
-            THEN("The result must include the TYPE_DEV_DOUBLE from the schema") { REQUIRE_THAT(result, Contains(TYPE_DEV_DOUBLE)); }
+            THEN("The result must include the TYPE_SCALAR from the schema")
+            {
+                REQUIRE_THAT(result, Contains(TYPE_SCALAR));
+            }
         }
     }
 }
 
-SCENARIO("Creating valid database table names for DEV_FLOAT", "[query-string]")
+TEST_CASE("Creating valid database table names for types", "[query-string]")
 {
-    QueryBuilder query_builder;
-
-    GIVEN("An Attribute traits configured for unsigned char")
+    vector<unsigned int> types {Tango::DEV_DOUBLE,
+        Tango::DEV_FLOAT,
+        Tango::DEV_STRING,
+        Tango::DEV_LONG,
+        Tango::DEV_ULONG,
+        Tango::DEV_LONG64,
+        Tango::DEV_ULONG64,
+        Tango::DEV_SHORT,
+        Tango::DEV_USHORT,
+        Tango::DEV_BOOLEAN,
+        Tango::DEV_UCHAR,
+        Tango::DEV_STATE,
+        Tango::DEV_ENCODED,
+        Tango::DEV_ENUM};
+
+    vector<Tango::AttrWriteType> write_types {Tango::READ, Tango::WRITE, Tango::READ_WRITE, Tango::READ_WITH_WRITE};
+    vector<Tango::AttrDataFormat> format_types {Tango::SCALAR, Tango::SPECTRUM, Tango::IMAGE};
+
+    vector<string> types_str {TYPE_DEV_DOUBLE,
+        TYPE_DEV_FLOAT,
+        TYPE_DEV_STRING,
+        TYPE_DEV_LONG,
+        TYPE_DEV_ULONG,
+        TYPE_DEV_LONG64,
+        TYPE_DEV_ULONG64,
+        TYPE_DEV_SHORT,
+        TYPE_DEV_USHORT,
+        TYPE_DEV_BOOLEAN,
+        TYPE_DEV_UCHAR,
+        TYPE_DEV_STATE,
+        TYPE_DEV_ENCODED,
+        TYPE_DEV_ENUM};
+
+    vector<string> format_types_str {TYPE_SCALAR, TYPE_ARRAY, TYPE_IMAGE};
+
+    // loop for every combination of type in Tango
+    for (unsigned int t = 0; t < types.size(); ++t)
     {
-        AttributeTraits traits {Tango::READ, Tango::SCALAR, Tango::DEV_FLOAT};
-
-        WHEN("Requesting a table name for the traits")
+        for (unsigned int f = 0; f < format_types.size(); ++f)
         {
-            auto result = query_builder.tableName(traits);
-
-            THEN("The result must include the TYPE_DEV_FLOAT from the schema") { REQUIRE_THAT(result, Contains(TYPE_DEV_FLOAT)); }
-        }
-    }
-}
-
-SCENARIO("Creating valid database table names for DEV_STRING", "[query-string]")
-{
-    QueryBuilder query_builder;
-
-    GIVEN("An Attribute traits configured for unsigned char")
-    {
-        AttributeTraits traits {Tango::READ, Tango::SCALAR, Tango::DEV_STRING};
-
-        WHEN("Requesting a table name for the traits")
-        {
-            auto result = query_builder.tableName(traits);
-
-            THEN("The result must include the TYPE_DEV_STRING from the schema") { REQUIRE_THAT(result, Contains(TYPE_DEV_STRING)); }
-        }
-    }
-}
-
-SCENARIO("Creating valid database table names for DEV_LONG", "[query-string]")
-{
-    QueryBuilder query_builder;
-
-    GIVEN("An Attribute traits configured for unsigned char")
-    {
-        AttributeTraits traits {Tango::READ, Tango::SCALAR, Tango::DEV_LONG};
-
-        WHEN("Requesting a table name for the traits")
-        {
-            auto result = query_builder.tableName(traits);
-
-            THEN("The result must include the TYPE_DEV_LONG from the schema") { REQUIRE_THAT(result, Contains(TYPE_DEV_LONG)); }
-        }
-    }
-}
-
-SCENARIO("Creating valid database table names for DEV_ULONG", "[query-string]")
-{
-    QueryBuilder query_builder;
-
-    GIVEN("An Attribute traits configured for unsigned char")
-    {
-        AttributeTraits traits {Tango::READ, Tango::SCALAR, Tango::DEV_ULONG};
-
-        WHEN("Requesting a table name for the traits")
-        {
-            auto result = query_builder.tableName(traits);
-
-            THEN("The result must include the TYPE_DEV_ULONG from the schema") { REQUIRE_THAT(result, Contains(TYPE_DEV_ULONG)); }
+            for (unsigned int w = 0; w < write_types.size(); ++w)
+            {
+                QueryBuilder query_builder;
+                AttributeTraits traits {write_types[w], format_types[f], types[t]};
+
+                DYNAMIC_SECTION("Testing table name for traits: " << traits)
+                {
+                    auto result = query_builder.tableName(traits);
+                    REQUIRE_THAT(result, Contains(types_str[t]));
+                    REQUIRE_THAT(result, Contains(format_types_str[f]));
+                }
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/test/TestHelpers.hpp b/test/TestHelpers.hpp
index f1be72358ee5c4fe154a487e0da22d65012222c3..b4ad8e35bb0729a55798fb428a7558c5bb998ccb 100644
--- a/test/TestHelpers.hpp
+++ b/test/TestHelpers.hpp
@@ -45,7 +45,8 @@ namespace attr_name
 {
     // mock test data
     const std::string TestAttrFQDName = "tango://localhost.server.com:10000/test-domain/test-family/test-member/test";
-    const std::string TestAttrFQDNameNoTangoQual = "localhost.server.com:10000/test-domain/test-family/test-member/test";
+    const std::string TestAttrFQDNameNoTangoQual =
+        "localhost.server.com:10000/test-domain/test-family/test-member/test";
     const std::string TestAttrFQDNameNoDomain = "tango://localhost:10000/test-domain/test-family/test-member/test";
 
     const std::string TestAttrCs = "new_cs";
diff --git a/test/main.cpp b/test/main.cpp
index d8d04122e74129644740bb9f5899a9ddd6a2e357..2a7e0b16f87e03f7caeebbcacaa094c1999e92fe 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -26,7 +26,7 @@ int main(int argc, char *argv[])
 {
     // console only warning level logging
     hdbpp::LogConfigurator::initLogging(false, true);
-    hdbpp::LogConfigurator::setLoggingLevel(spdlog::level::warn);
+    hdbpp::LogConfigurator::setLoggingLevel(spdlog::level::trace);
 
     int result = Catch::Session().run(argc, argv);