From 5385e32a4c7745071b7d1df51eba41f5c47eab90 Mon Sep 17 00:00:00 2001
From: Alex Hill <alexander.hill@csiro.au>
Date: Mon, 9 Feb 2026 16:43:27 +0800
Subject: [PATCH] Use ON CONFLICT DO NOTHING when inserting data events

---
 CHANGELOG.md         | 3 +++
 src/QueryBuilder.cpp | 6 ++++--
 src/QueryBuilder.hpp | 6 ++++--
 3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 894e4c8..40ada18 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
 
 ## [Unreleased]
 
+### Changed
+- Attribute event inserts now are now executed with ON CONFLICT DO NOTHING.
+
 ## [2.4.3] - 2025-10-31
 
 ### Fixed
diff --git a/src/QueryBuilder.cpp b/src/QueryBuilder.cpp
index 176d491..801f077 100644
--- a/src/QueryBuilder.cpp
+++ b/src/QueryBuilder.cpp
@@ -279,7 +279,8 @@ auto QueryBuilder::storeDataEventErrorStatement(const AttributeTraits &traits) -
         query = query + ",TO_TIMESTAMP($" + to_string(++param_number) + ")";
 
         query = query + "," + "$" + to_string(++param_number);
-        query = query + "," + "$" + to_string(++param_number) + ")";
+        query = query + "," + "$" + to_string(++param_number) + ") " +
+                "ON CONFLICT (" + schema::DatColId + "," + schema::DatColDataTime + ") DO NOTHING";
 
         // cache the query string against the traits
         _data_event_error_queries.emplace(traits, query);
@@ -314,7 +315,8 @@ auto QueryBuilder::storeDataEventErrorString(const string &id,
                 id + "," +
                 "TO_TIMESTAMP(" + event_time + ")," +
                 quality + "," +
-                err_id + ")";
+                err_id + ") " +
+            "ON CONFLICT (" + schema::DatColId + "," + schema::DatColDataTime + ") DO NOTHING";
     // clang-format on
 
     return query;
diff --git a/src/QueryBuilder.hpp b/src/QueryBuilder.hpp
index 27528cd..877f492 100644
--- a/src/QueryBuilder.hpp
+++ b/src/QueryBuilder.hpp
@@ -369,7 +369,8 @@ auto QueryBuilder::storeDataEventStatement(const AttributeTraits &traits) -> con
                     "::" + query_utils::postgresCast<T>(traits.formatType());
         }
 
-        query = query + "," + "$" + pqxx::to_string(++param_number) + ")";
+        query = query + "," + "$" + pqxx::to_string(++param_number) + ") " +
+                "ON CONFLICT (" + schema::DatColId + "," + schema::DatColDataTime + ") DO NOTHING";
 
         // cache the query string against the traits
         _data_event_queries.emplace(traits, query);
@@ -438,7 +439,8 @@ auto QueryBuilder::storeDataEventString(const std::string &id,
         }
     }
 
-    query = query + "," + quality + ")";
+    query = query + "," + quality + ") " +
+            "ON CONFLICT (" + schema::DatColId + "," + schema::DatColDataTime + ") DO NOTHING";
 
     // now return the built query
     return query;
-- 
2.52.0

