]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
driver-mysql: Rollback a failed multi-statement transaction
authorSiavash Tavakoli <siavash.tavakoli@open-xchange.com>
Thu, 8 Apr 2021 16:08:54 +0000 (17:08 +0100)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Wed, 21 Apr 2021 09:54:02 +0000 (09:54 +0000)
If transaction failed, send "ROLLBACK" statement.

src/lib-sql/driver-mysql.c

index d382cd3fbf5d8de6d28451d4c3a024516cd0f9f9..78510eabf4e3f2336a175c7d0e04c1424b4d3617 100644 (file)
@@ -66,6 +66,7 @@ struct mysql_transaction_context {
 
        bool failed:1;
        bool committed:1;
+       bool commit_started:1;
 };
 
 extern const struct sql_db driver_mysql_db;
@@ -653,7 +654,10 @@ static int driver_mysql_try_commit_s(struct mysql_transaction_context *ctx)
                        return -1;
                /* we got disconnected, retry */
                return 0;
+       } else if (multi) {
+               ctx->commit_started = TRUE;
        }
+
        while (_ctx->head != NULL) {
                if (transaction_send_query(ctx, _ctx->head->query,
                                           _ctx->head->affected_rows) < 0)
@@ -702,11 +706,26 @@ driver_mysql_transaction_rollback(struct sql_transaction_context *_ctx)
        struct mysql_transaction_context *ctx =
                (struct mysql_transaction_context *)_ctx;
 
-       if (ctx->failed)
+       if (ctx->failed) {
+               bool rolledback = FALSE;
+               const char *orig_error = t_strdup(ctx->error);
+               if (ctx->commit_started) {
+                       /* reset failed flag so ROLLBACK is actually sent.
+                          otherwise, transaction_send_query() will return
+                          without trying to send the query. */
+                       ctx->failed = FALSE;
+                       if (transaction_send_query(ctx, "ROLLBACK", NULL) < 0)
+                               e_debug(event_create_passthrough(_ctx->event)->
+                                       add_str("error", ctx->error)->event(),
+                                       "Rollback failed: %s", ctx->error);
+                       else
+                               rolledback = TRUE;
+               }
                e_debug(sql_transaction_finished_event(_ctx)->
-                       add_str("error", ctx->error)->event(),
-                       "Transaction failed: %s", ctx->error);
-       else if (ctx->committed)
+                       add_str("error", orig_error)->event(),
+                       "Transaction failed: %s%s", orig_error,
+                       rolledback ? " - Rolled back" : "");
+       } else if (ctx->committed)
                e_debug(sql_transaction_finished_event(_ctx)->event(),
                        "Transaction committed");
        else