Module: sip-router
Branch: master
Commit: fe977dfcb940b1c48dd26fe5fe61a25aed23b96a
URL:    
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=fe977dfcb940b1c48dd26fe5fe61a25aed23b96a

Author: Olle E. Johansson <[email protected]>
Committer: Olle E. Johansson <[email protected]>
Date:   Tue Apr  2 14:13:01 2013 +0200

db_mysql Add transaction support

Patch contributed via Google+ by Håkon Nassjöen <[email protected]>

---

 modules/db_mysql/km_db_mysql.c |    3 +
 modules/db_mysql/km_dbase.c    |  136 ++++++++++++++++++++++++++++++++++++++++
 modules/db_mysql/km_dbase.h    |   16 +++++
 modules/db_mysql/km_my_con.h   |   10 ++-
 4 files changed, 161 insertions(+), 4 deletions(-)

diff --git a/modules/db_mysql/km_db_mysql.c b/modules/db_mysql/km_db_mysql.c
index 8a51f3d..88cc481 100644
--- a/modules/db_mysql/km_db_mysql.c
+++ b/modules/db_mysql/km_db_mysql.c
@@ -116,6 +116,9 @@ int db_mysql_bind_api(db_func_t *dbb)
        dbb->insert_update    = db_mysql_insert_update;
        dbb->insert_delayed   = db_mysql_insert_delayed;
        dbb->affected_rows    = db_mysql_affected_rows;
+       dbb->start_transaction= db_mysql_start_transaction;
+       dbb->end_transaction  = db_mysql_end_transaction;
+       dbb->abort_transaction= db_mysql_abort_transaction;
 
        return 0;
 }
diff --git a/modules/db_mysql/km_dbase.c b/modules/db_mysql/km_dbase.c
index 029a674..7288b66 100644
--- a/modules/db_mysql/km_dbase.c
+++ b/modules/db_mysql/km_dbase.c
@@ -500,6 +500,142 @@ int db_mysql_affected_rows(const db1_con_t* _h)
        return (int)mysql_affected_rows(CON_CONNECTION(_h));
 }
 
+/**
+ * Starts a single transaction that will consist of one or more queries (SQL 
BEGIN)
+ * \param _h database handle
+ * \return 0 on success, negative on failure
+ */
+int db_mysql_start_transaction(db1_con_t* _h, db_locking_t _l)
+{
+       str begin_str = str_init("BEGIN");
+       str lock_start_str = str_init("LOCK TABLE ");
+       str lock_end_str  = str_init(" WRITE");
+       str lock_str = {0, 0};
+
+       if (!_h) {
+               LM_ERR("invalid parameter value\n");
+               return -1;
+       }
+
+       if (CON_TRANSACTION(_h) == 1) {
+               LM_ERR("transaction already started\n");
+               return -1;
+       }
+
+       if (db_mysql_raw_query(_h, &begin_str, NULL) < 0)
+       {
+               LM_ERR("executing raw_query\n");
+               return -1;
+       }
+
+       CON_TRANSACTION(_h) = 1;
+
+       switch(_l)
+       {
+       case DB_LOCKING_NONE:
+               break;
+       case DB_LOCKING_FULL:
+               /* Fall-thru */
+       case DB_LOCKING_WRITE:
+               if ((lock_str.s = pkg_malloc((lock_start_str.len + 
CON_TABLE(_h)->len + lock_end_str.len) * sizeof(char))) == NULL)
+               {
+                       LM_ERR("allocating pkg memory\n");
+                       goto error;
+               }
+
+               memcpy(lock_str.s, lock_start_str.s, lock_start_str.len);
+               lock_str.len += lock_start_str.len;
+               memcpy(lock_str.s + lock_str.len, CON_TABLE(_h)->s, 
CON_TABLE(_h)->len);
+               lock_str.len += CON_TABLE(_h)->len;
+               memcpy(lock_str.s + lock_str.len, lock_end_str.s, 
lock_end_str.len);
+               lock_str.len += lock_end_str.len;
+
+               if (db_mysql_raw_query(_h, &lock_str, NULL) < 0)
+               {
+                       LM_ERR("executing raw_query\n");
+                       goto error;
+               }
+
+               if (lock_str.s) pkg_free(lock_str.s);
+               break;
+
+       default:
+               LM_WARN("unrecognised lock type\n");
+               goto error;
+       }
+
+       return 0;
+
+error:
+       if (lock_str.s) pkg_free(lock_str.s);
+       db_mysql_abort_transaction(_h);
+       return -1;
+}
+
+/**
+ * Ends a transaction and commits the changes (SQL COMMIT)
+ * \param _h database handle
+ * \return 0 on success, negative on failure
+ */
+int db_mysql_end_transaction(db1_con_t* _h)
+{
+       str query_str = str_init("COMMIT");
+
+       if (!_h) {
+               LM_ERR("invalid parameter value\n");
+               return -1;
+       }
+
+       if (CON_TRANSACTION(_h) == 0) {
+               LM_ERR("transaction not in progress\n");
+               return -1;
+       }
+
+       if (db_mysql_raw_query(_h, &query_str, NULL) < 0)
+       {
+               LM_ERR("executing raw_query\n");
+               return -1;
+       }
+
+       /* Only _end_ the transaction after the raw_query.  That way, if the
+          raw_query fails, and the calling module does an abort_transaction()
+          to clean-up, a ROLLBACK will be sent to the DB. */
+       CON_TRANSACTION(_h) = 0;
+       return 0;
+}
+
+/**
+ * Ends a transaction and rollsback the changes (SQL ROLLBACK)
+ * \param _h database handle
+ * \return 1 if there was something to rollback, 0 if not, negative on failure
+ */
+int db_mysql_abort_transaction(db1_con_t* _h)
+{
+       str query_str = str_init("ROLLBACK");
+
+       if (!_h) {
+               LM_ERR("invalid parameter value\n");
+               return -1;
+       }
+
+       if (CON_TRANSACTION(_h) == 0) {
+               LM_DBG("nothing to rollback\n");
+               return 0;
+       }
+
+       /* Whether the rollback succeeds or not we need to _end_ the
+          transaction now or all future starts will fail */
+       CON_TRANSACTION(_h) = 0;
+
+       if (db_mysql_raw_query(_h, &query_str, NULL) < 0)
+       {
+               LM_ERR("executing raw_query\n");
+               return -1;
+       }
+
+       return 1;
+}
+
 
 /**
   * Insert a row into a specified table, update on duplicate key.
diff --git a/modules/db_mysql/km_dbase.h b/modules/db_mysql/km_dbase.h
index 3a567f2..52b2778 100644
--- a/modules/db_mysql/km_dbase.h
+++ b/modules/db_mysql/km_dbase.h
@@ -40,6 +40,7 @@
 #include "../../lib/srdb1/db_key.h"
 #include "../../lib/srdb1/db_op.h"
 #include "../../lib/srdb1/db_val.h"
+#include "../../lib/srdb1/db_locking.h"
 #include "../../str.h"
 
 /*! \brief
@@ -118,6 +119,21 @@ int db_mysql_last_inserted_id(const db1_con_t* _h);
  */
 int db_mysql_affected_rows(const db1_con_t* _h);
 
+/*! \brief
+ * Starts transaction
+ */
+int db_mysql_start_transaction(db1_con_t* _h, db_locking_t _l);
+
+/*! \brief
+ * Commits transaction
+ */
+int db_mysql_end_transaction(db1_con_t* _h);
+
+/*! \brief
+ * Aborts transaction
+ */
+int db_mysql_abort_transaction(db1_con_t* _h);
+
 
 /*! \brief
  * Insert a row into table, update on duplicate key
diff --git a/modules/db_mysql/km_my_con.h b/modules/db_mysql/km_my_con.h
index 2624f34..33f2128 100644
--- a/modules/db_mysql/km_my_con.h
+++ b/modules/db_mysql/km_my_con.h
@@ -48,16 +48,18 @@ struct my_con {
        MYSQL* con;              /*!< Connection representation */
        MYSQL_ROW row;           /*!< Actual row in the result */
        time_t timestamp;        /*!< Timestamp of last query */
+       int transaction;         /*!< indicates whether a multi-query 
transaction is currently open */
 };
 
 
 /*
  * Some convenience wrappers
  */
-#define CON_RESULT(db_con)     (((struct my_con*)((db_con)->tail))->res)
-#define CON_CONNECTION(db_con) (((struct my_con*)((db_con)->tail))->con)
-#define CON_ROW(db_con)        (((struct my_con*)((db_con)->tail))->row)
-#define CON_TIMESTAMP(db_con)  (((struct my_con*)((db_con)->tail))->timestamp)
+#define CON_RESULT(db_con)      (((struct my_con*)((db_con)->tail))->res)
+#define CON_CONNECTION(db_con)  (((struct my_con*)((db_con)->tail))->con)
+#define CON_ROW(db_con)         (((struct my_con*)((db_con)->tail))->row)
+#define CON_TIMESTAMP(db_con)   (((struct my_con*)((db_con)->tail))->timestamp)
+#define CON_TRANSACTION(db_con) (((struct 
my_con*)((db_con)->tail))->transaction)
 
 
 /*! \brief


_______________________________________________
sr-dev mailing list
[email protected]
http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev

Reply via email to