From 3bc5964793f1700551b7db8107a939c98f1d1be1 Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Sun, 13 Jun 2021 21:29:25 +0100
Subject: Add transaction support

---
 lib/dbConn.cpp           | 18 ++++++++++++++++++
 lib/dbConn.h             | 22 ++++++++++++++++++++++
 lib/input/mysqlConn.cpp  | 20 ++++++++++++++++++++
 lib/input/mysqlConn.h    |  4 ++++
 lib/output/pq/pqConn.cpp | 18 ++++++++++++++++++
 lib/output/pq/pqConn.h   |  4 ++++
 6 files changed, 86 insertions(+)
 create mode 100644 lib/dbConn.cpp

(limited to 'lib')

diff --git a/lib/dbConn.cpp b/lib/dbConn.cpp
new file mode 100644
index 0000000..380910a
--- /dev/null
+++ b/lib/dbConn.cpp
@@ -0,0 +1,18 @@
+#include "dbConn.h"
+
+namespace MyGrate {
+	Tx::Tx(DbConn * c) : conn {c}
+	{
+		conn->beginTx();
+	}
+
+	Tx::~Tx()
+	{
+		if (std::uncaught_exceptions()) {
+			conn->rollbackTx();
+		}
+		else {
+			conn->commitTx();
+		}
+	}
+}
diff --git a/lib/dbConn.h b/lib/dbConn.h
index 3f14dcb..ffdd2e0 100644
--- a/lib/dbConn.h
+++ b/lib/dbConn.h
@@ -24,6 +24,28 @@ namespace MyGrate {
 		virtual void query(const char * const, const std::initializer_list<DbValue> &) = 0;
 
 		virtual DbPrepStmtPtr prepare(const char * const, std::size_t nParams) = 0;
+
+		virtual void beginTx() = 0;
+		virtual void commitTx() = 0;
+		virtual void rollbackTx() = 0;
+	};
+
+	class Tx {
+	public:
+		explicit Tx(DbConn *);
+		Tx(const Tx &) = delete;
+		Tx(Tx &&) = delete;
+		~Tx();
+
+		template<typename C>
+		auto
+		operator()(C && callback)
+		{
+			return callback();
+		}
+
+	private:
+		DbConn * conn;
 	};
 }
 
diff --git a/lib/input/mysqlConn.cpp b/lib/input/mysqlConn.cpp
index 362f9ea..99c2891 100644
--- a/lib/input/mysqlConn.cpp
+++ b/lib/input/mysqlConn.cpp
@@ -52,4 +52,24 @@ namespace MyGrate::Input {
 	{
 		return std::make_unique<MySQLPrepStmt>(q, this);
 	}
+
+	void
+	MySQLConn::beginTx()
+	{
+		verify<MySQLErr>(!mysql_autocommit(this, false), "Auto commit off", this);
+	}
+
+	void
+	MySQLConn::commitTx()
+	{
+		verify<MySQLErr>(!mysql_commit(this), "Commit", this);
+		verify<MySQLErr>(!mysql_autocommit(this, true), "Auto commit on", this);
+	}
+
+	void
+	MySQLConn::rollbackTx()
+	{
+		verify<MySQLErr>(!mysql_rollback(this), "Rollback", this);
+		verify<MySQLErr>(!mysql_autocommit(this, true), "Auto commit on", this);
+	}
 }
diff --git a/lib/input/mysqlConn.h b/lib/input/mysqlConn.h
index dfb408f..bd53616 100644
--- a/lib/input/mysqlConn.h
+++ b/lib/input/mysqlConn.h
@@ -29,6 +29,10 @@ namespace MyGrate::Input {
 		void query(const char * const q, const std::initializer_list<DbValue> &) override;
 
 		DbPrepStmtPtr prepare(const char * const, std::size_t) override;
+
+		void beginTx() override;
+		void commitTx() override;
+		void rollbackTx() override;
 	};
 }
 
diff --git a/lib/output/pq/pqConn.cpp b/lib/output/pq/pqConn.cpp
index 309b704..ba95cad 100644
--- a/lib/output/pq/pqConn.cpp
+++ b/lib/output/pq/pqConn.cpp
@@ -43,6 +43,24 @@ namespace MyGrate::Output::Pq {
 		return std::make_unique<PqPrepStmt>(q, n, this);
 	}
 
+	void
+	PqConn::beginTx()
+	{
+		query("BEGIN");
+	}
+
+	void
+	PqConn::commitTx()
+	{
+		query("COMMIT");
+	}
+
+	void
+	PqConn::rollbackTx()
+	{
+		query("ROLLBACK");
+	}
+
 	void
 	PqConn::notice_processor(void * p, const char * n)
 	{
diff --git a/lib/output/pq/pqConn.h b/lib/output/pq/pqConn.h
index 6db9bcf..3b27f97 100644
--- a/lib/output/pq/pqConn.h
+++ b/lib/output/pq/pqConn.h
@@ -32,6 +32,10 @@ namespace MyGrate::Output::Pq {
 
 		DbPrepStmtPtr prepare(const char * const, std::size_t nParams) override;
 
+		void beginTx() override;
+		void commitTx() override;
+		void rollbackTx() override;
+
 		const std::string connstr;
 
 	private:
-- 
cgit v1.2.3