You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by bo...@apache.org on 2006/06/14 07:42:11 UTC

svn commit: r414087 - in /apr/apr-util/trunk: CHANGES dbd/apr_dbd.c dbd/apr_dbd_oracle.c dbd/apr_dbd_pgsql.c dbd/apr_dbd_sqlite2.c dbd/apr_dbd_sqlite3.c include/apr_dbd.h include/private/apr_dbd_internal.h

Author: bojan
Date: Tue Jun 13 22:42:10 2006
New Revision: 414087

URL: http://svn.apache.org/viewvc?rev=414087&view=rev
Log:
Implement DBD transaction modes

Modified:
    apr/apr-util/trunk/CHANGES
    apr/apr-util/trunk/dbd/apr_dbd.c
    apr/apr-util/trunk/dbd/apr_dbd_oracle.c
    apr/apr-util/trunk/dbd/apr_dbd_pgsql.c
    apr/apr-util/trunk/dbd/apr_dbd_sqlite2.c
    apr/apr-util/trunk/dbd/apr_dbd_sqlite3.c
    apr/apr-util/trunk/include/apr_dbd.h
    apr/apr-util/trunk/include/private/apr_dbd_internal.h

Modified: apr/apr-util/trunk/CHANGES
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/CHANGES?rev=414087&r1=414086&r2=414087&view=diff
==============================================================================
--- apr/apr-util/trunk/CHANGES (original)
+++ apr/apr-util/trunk/CHANGES Tue Jun 13 22:42:10 2006
@@ -1,5 +1,8 @@
 Changes with APR-util 1.3.0
 
+  *) Implement DBD transaction modes
+     [Bojan Smojver with help from many on the APR list]
+
   *) Implement prepared statement support in SQLite3 DBD driver
      [Bojan Smojver]
 

Modified: apr/apr-util/trunk/dbd/apr_dbd.c
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/dbd/apr_dbd.c?rev=414087&r1=414086&r2=414087&view=diff
==============================================================================
--- apr/apr-util/trunk/dbd/apr_dbd.c (original)
+++ apr/apr-util/trunk/dbd/apr_dbd.c Tue Jun 13 22:42:10 2006
@@ -208,6 +208,19 @@
     return driver->end_transaction(trans);
 }
 
+APU_DECLARE(int) apr_dbd_transaction_mode_get(const apr_dbd_driver_t *driver,
+                                              apr_dbd_transaction_t *trans)
+{
+    return driver->transaction_mode_get(trans);
+}
+
+APU_DECLARE(int) apr_dbd_transaction_mode_set(const apr_dbd_driver_t *driver,
+                                              apr_dbd_transaction_t *trans,
+                                              int mode)
+{
+    return driver->transaction_mode_set(trans, mode);
+}
+
 APU_DECLARE(apr_status_t) apr_dbd_close(const apr_dbd_driver_t *driver,
                                         apr_dbd_t *handle)
 {

Modified: apr/apr-util/trunk/dbd/apr_dbd_oracle.c
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/dbd/apr_dbd_oracle.c?rev=414087&r1=414086&r2=414087&view=diff
==============================================================================
--- apr/apr-util/trunk/dbd/apr_dbd_oracle.c (original)
+++ apr/apr-util/trunk/dbd/apr_dbd_oracle.c Tue Jun 13 22:42:10 2006
@@ -123,6 +123,7 @@
 static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans);
 
 struct apr_dbd_transaction_t {
+    int mode;
     enum { TRANS_NONE, TRANS_ERROR, TRANS_1, TRANS_2 } status;
     apr_dbd_t *handle;
     OCITrans *trans;
@@ -1234,7 +1235,7 @@
 #endif
         /* fallthrough */
     default:
-        if (trans) {
+        if (TXN_NOTICE_ERRORS(trans)) {
             trans->status = TRANS_ERROR;
         }
         return 1;
@@ -1277,7 +1278,7 @@
 #endif
             /* fallthrough */
         default:
-            if (trans) {
+            if (TXN_NOTICE_ERRORS(trans)) {
                 trans->status = TRANS_ERROR;
             }
             return 1;
@@ -1383,7 +1384,7 @@
 #endif
         /* fallthrough */
     default:
-        if (trans) {
+        if (TXN_NOTICE_ERRORS(trans)) {
             trans->status = TRANS_ERROR;
         }
         return 1;
@@ -1476,7 +1477,7 @@
         printf("Executing prepared statement: %s\n", sql->buf);
 #endif
     default:
-        if (trans) {
+        if (TXN_NOTICE_ERRORS(trans)) {
             trans->status = TRANS_ERROR;
         }
         return 1;
@@ -1571,7 +1572,7 @@
         printf("Executing prepared statement: %s\n", sql->buf);
 #endif
     default:
-        if (trans) {
+        if (TXN_NOTICE_ERRORS(trans)) {
             trans->status = TRANS_ERROR;
         }
         return 1;
@@ -1664,7 +1665,12 @@
             status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT);
             break;
         default:
-            status = OCITransCommit(handle->svc, handle->err, OCI_DEFAULT);
+            /* rollback on explicit rollback request */
+            if (TXN_DO_ROLLBACK(trans)) {
+                status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT);
+            } else {
+                status = OCITransCommit(handle->svc, handle->err, OCI_DEFAULT);
+            }
             break;
         }
 
@@ -1682,6 +1688,23 @@
     return ret;
 }
 
+static int dbd_oracle_transaction_mode_get(apr_dbd_transaction_t *trans)
+{
+    if (!trans)
+        return APR_DBD_TRANSACTION_COMMIT;
+
+    return trans->mode;
+}
+
+static int dbd_oracle_transaction_mode_set(apr_dbd_transaction_t *trans,
+                                           int mode)
+{
+    if (!trans)
+        return APR_DBD_TRANSACTION_COMMIT;
+
+    return trans->mode = (mode & TXN_MODE_BITS);
+}
+
 /* This doesn't work for BLOB because of NULLs, but it can fake it
  * if the BLOB is really a string
  */
@@ -1910,6 +1933,8 @@
     dbd_oracle_pvselect,
     dbd_oracle_pquery,
     dbd_oracle_pselect,
-    dbd_oracle_get_name
+    dbd_oracle_get_name,
+    dbd_oracle_transaction_mode_get,
+    dbd_oracle_transaction_mode_set
 };
 #endif

Modified: apr/apr-util/trunk/dbd/apr_dbd_pgsql.c
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/dbd/apr_dbd_pgsql.c?rev=414087&r1=414086&r2=414087&view=diff
==============================================================================
--- apr/apr-util/trunk/dbd/apr_dbd_pgsql.c (original)
+++ apr/apr-util/trunk/dbd/apr_dbd_pgsql.c Tue Jun 13 22:42:10 2006
@@ -37,6 +37,7 @@
 #define QUERY_MAX_ARGS 40
 
 struct apr_dbd_transaction_t {
+    int mode;
     int errnum;
     apr_dbd_t *handle;
 };
@@ -86,6 +87,19 @@
         return sql->trans->errnum;
     }
     if (seek) { /* synchronous query */
+        if (TXN_IGNORE_ERRORS(sql->trans)) {
+            PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
+            if (res) {
+                ret = PQresultStatus(res);
+                PQclear(res);
+                if (!dbd_pgsql_is_success(ret)) {
+                    sql->trans->errnum = ret;
+                    return PGRES_FATAL_ERROR;
+                }
+            } else {
+                return sql->trans->errnum = PGRES_FATAL_ERROR;
+            }
+        }
         res = PQexec(sql->conn, query);
         if (res) {
             ret = PQresultStatus(res);
@@ -98,10 +112,38 @@
             ret = PGRES_FATAL_ERROR;
         }
         if (ret != 0) {
-            if (sql->trans) {
+            if (TXN_IGNORE_ERRORS(sql->trans)) {
+                PGresult *res = PQexec(sql->conn,
+                                       "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
+                if (res) {
+                    ret = PQresultStatus(res);
+                    PQclear(res);
+                    if (!dbd_pgsql_is_success(ret)) {
+                        sql->trans->errnum = ret;
+                        return PGRES_FATAL_ERROR;
+                    }
+                } else {
+                    return sql->trans->errnum = PGRES_FATAL_ERROR;
+                }
+            } else if (TXN_NOTICE_ERRORS(sql->trans)){
                 sql->trans->errnum = ret;
             }
             return ret;
+        } else {
+            if (TXN_IGNORE_ERRORS(sql->trans)) {
+                PGresult *res = PQexec(sql->conn,
+                                       "RELEASE SAVEPOINT APR_DBD_TXN_SP");
+                if (res) {
+                    ret = PQresultStatus(res);
+                    PQclear(res);
+                    if (!dbd_pgsql_is_success(ret)) {
+                        sql->trans->errnum = ret;
+                        return PGRES_FATAL_ERROR;
+                    }
+                } else {
+                    return sql->trans->errnum = PGRES_FATAL_ERROR;
+                }
+            }
         }
         if (!*results) {
             *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
@@ -114,11 +156,52 @@
                                   apr_pool_cleanup_null);
     }
     else {
+        if (TXN_IGNORE_ERRORS(sql->trans)) {
+            PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
+            if (res) {
+                ret = PQresultStatus(res);
+                PQclear(res);
+                if (!dbd_pgsql_is_success(ret)) {
+                    sql->trans->errnum = ret;
+                    return PGRES_FATAL_ERROR;
+                }
+            } else {
+                return sql->trans->errnum = PGRES_FATAL_ERROR;
+            }
+        }
         if (PQsendQuery(sql->conn, query) == 0) {
-            if (sql->trans) {
+            if (TXN_IGNORE_ERRORS(sql->trans)) {
+                PGresult *res = PQexec(sql->conn,
+                                       "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
+                if (res) {
+                    ret = PQresultStatus(res);
+                    PQclear(res);
+                    if (!dbd_pgsql_is_success(ret)) {
+                        sql->trans->errnum = ret;
+                        return PGRES_FATAL_ERROR;
+                    }
+                } else {
+                    return sql->trans->errnum = PGRES_FATAL_ERROR;
+                }
+            } else if (TXN_NOTICE_ERRORS(sql->trans)){
                 sql->trans->errnum = 1;
             }
             return 1;
+        } else {
+            if (TXN_IGNORE_ERRORS(sql->trans)) {
+                PGresult *res = PQexec(sql->conn,
+                                       "RELEASE SAVEPOINT APR_DBD_TXN_SP");
+                if (res) {
+                    ret = PQresultStatus(res);
+                    PQclear(res);
+                    if (!dbd_pgsql_is_success(ret)) {
+                        sql->trans->errnum = ret;
+                        return PGRES_FATAL_ERROR;
+                    }
+                } else {
+                    return sql->trans->errnum = PGRES_FATAL_ERROR;
+                }
+            }
         }
         if (*results == NULL) {
             *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
@@ -215,6 +298,21 @@
     if (sql->trans && sql->trans->errnum) {
         return sql->trans->errnum;
     }
+
+    if (TXN_IGNORE_ERRORS(sql->trans)) {
+        PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
+        if (res) {
+            ret = PQresultStatus(res);
+            PQclear(res);
+            if (!dbd_pgsql_is_success(ret)) {
+                sql->trans->errnum = ret;
+                return PGRES_FATAL_ERROR;
+            }
+        } else {
+            return sql->trans->errnum = PGRES_FATAL_ERROR;
+        }
+    }
+
     res = PQexec(sql->conn, query);
     if (res) {
         ret = PQresultStatus(res);
@@ -228,9 +326,43 @@
     else {
         ret = PGRES_FATAL_ERROR;
     }
-    if (sql->trans) {
-        sql->trans->errnum = ret;
+    
+    if (ret != 0){
+        if (TXN_IGNORE_ERRORS(sql->trans)) {
+            PGresult *res = PQexec(sql->conn,
+                                   "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
+            if (res) {
+                ret = PQresultStatus(res);
+                PQclear(res);
+                if (!dbd_pgsql_is_success(ret)) {
+                    sql->trans->errnum = ret;
+                    return PGRES_FATAL_ERROR;
+                }
+            } else {
+                sql->trans->errnum = ret;
+                return PGRES_FATAL_ERROR;
+            }
+        } else if (TXN_NOTICE_ERRORS(sql->trans)){
+            sql->trans->errnum = ret;
+        }
+    } else {
+        if (TXN_IGNORE_ERRORS(sql->trans)) {
+            PGresult *res = PQexec(sql->conn,
+                                   "RELEASE SAVEPOINT APR_DBD_TXN_SP");
+            if (res) {
+                ret = PQresultStatus(res);
+                PQclear(res);
+                if (!dbd_pgsql_is_success(ret)) {
+                    sql->trans->errnum = ret;
+                    return PGRES_FATAL_ERROR;
+                }
+            } else {
+                sql->trans->errnum = ret;
+                return PGRES_FATAL_ERROR;
+            }
+        }
     }
+
     return ret;
 }
 
@@ -375,6 +507,20 @@
         return sql->trans->errnum;
     }
 
+    if (TXN_IGNORE_ERRORS(sql->trans)) {
+        PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
+        if (res) {
+            ret = PQresultStatus(res);
+            PQclear(res);
+            if (!dbd_pgsql_is_success(ret)) {
+                sql->trans->errnum = ret;
+                return PGRES_FATAL_ERROR;
+            }
+        } else {
+            return sql->trans->errnum = PGRES_FATAL_ERROR;
+        }
+    }
+
     if (statement->prepared) {
         res = PQexecPrepared(sql->conn, statement->name, nargs, values, 0, 0,
                              0);
@@ -395,9 +541,42 @@
         ret = PGRES_FATAL_ERROR;
     }
 
-    if (sql->trans) {
-        sql->trans->errnum = ret;
+    if (ret != 0){
+        if (TXN_IGNORE_ERRORS(sql->trans)) {
+            PGresult *res = PQexec(sql->conn,
+                                   "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
+            if (res) {
+                ret = PQresultStatus(res);
+                PQclear(res);
+                if (!dbd_pgsql_is_success(ret)) {
+                    sql->trans->errnum = ret;
+                    return PGRES_FATAL_ERROR;
+                }
+            } else {
+                sql->trans->errnum = ret;
+                return PGRES_FATAL_ERROR;
+            }
+        } else if (TXN_NOTICE_ERRORS(sql->trans)){
+            sql->trans->errnum = ret;
+        }
+    } else {
+        if (TXN_IGNORE_ERRORS(sql->trans)) {
+            PGresult *res = PQexec(sql->conn,
+                                   "RELEASE SAVEPOINT APR_DBD_TXN_SP");
+            if (res) {
+                ret = PQresultStatus(res);
+                PQclear(res);
+                if (!dbd_pgsql_is_success(ret)) {
+                    sql->trans->errnum = ret;
+                    return PGRES_FATAL_ERROR;
+                }
+            } else {
+                sql->trans->errnum = ret;
+                return PGRES_FATAL_ERROR;
+            }
+        }
     }
+
     return ret;
 }
 
@@ -436,6 +615,20 @@
     }
 
     if (seek) { /* synchronous query */
+        if (TXN_IGNORE_ERRORS(sql->trans)) {
+            PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
+            if (res) {
+                ret = PQresultStatus(res);
+                PQclear(res);
+                if (!dbd_pgsql_is_success(ret)) {
+                    sql->trans->errnum = ret;
+                    return PGRES_FATAL_ERROR;
+                }
+            } else {
+                sql->trans->errnum = ret;
+                return PGRES_FATAL_ERROR;
+            }
+        }
         if (statement->prepared) {
             res = PQexecPrepared(sql->conn, statement->name, nargs, values, 0,
                                  0, 0);
@@ -457,10 +650,40 @@
             ret = PGRES_FATAL_ERROR;
         }
         if (ret != 0) {
-            if (sql->trans) {
+            if (TXN_IGNORE_ERRORS(sql->trans)) {
+                PGresult *res = PQexec(sql->conn,
+                                       "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
+                if (res) {
+                    ret = PQresultStatus(res);
+                    PQclear(res);
+                    if (!dbd_pgsql_is_success(ret)) {
+                        sql->trans->errnum = ret;
+                        return PGRES_FATAL_ERROR;
+                    }
+                } else {
+                    sql->trans->errnum = ret;
+                    return PGRES_FATAL_ERROR;
+                }
+            } else if (TXN_NOTICE_ERRORS(sql->trans)){
                 sql->trans->errnum = ret;
             }
             return ret;
+        } else {
+            if (TXN_IGNORE_ERRORS(sql->trans)) {
+                PGresult *res = PQexec(sql->conn,
+                                       "RELEASE SAVEPOINT APR_DBD_TXN_SP");
+                if (res) {
+                    ret = PQresultStatus(res);
+                    PQclear(res);
+                    if (!dbd_pgsql_is_success(ret)) {
+                        sql->trans->errnum = ret;
+                        return PGRES_FATAL_ERROR;
+                    }
+                } else {
+                    sql->trans->errnum = ret;
+                    return PGRES_FATAL_ERROR;
+                }
+            }
         }
         if (!*results) {
             *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
@@ -473,6 +696,20 @@
                                   apr_pool_cleanup_null);
     }
     else {
+        if (TXN_IGNORE_ERRORS(sql->trans)) {
+            PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
+            if (res) {
+                ret = PQresultStatus(res);
+                PQclear(res);
+                if (!dbd_pgsql_is_success(ret)) {
+                    sql->trans->errnum = ret;
+                    return PGRES_FATAL_ERROR;
+                }
+            } else {
+                sql->trans->errnum = ret;
+                return PGRES_FATAL_ERROR;
+            }
+        }
         if (statement->prepared) {
             rv = PQsendQueryPrepared(sql->conn, statement->name, nargs, values,
                                      0, 0, 0);
@@ -482,10 +719,40 @@
                                    values, 0, 0, 0);
         }
         if (rv == 0) {
-            if (sql->trans) {
+            if (TXN_IGNORE_ERRORS(sql->trans)) {
+                PGresult *res = PQexec(sql->conn,
+                                       "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP");
+                if (res) {
+                    ret = PQresultStatus(res);
+                    PQclear(res);
+                    if (!dbd_pgsql_is_success(ret)) {
+                        sql->trans->errnum = ret;
+                        return PGRES_FATAL_ERROR;
+                    }
+                } else {
+                    sql->trans->errnum = ret;
+                    return PGRES_FATAL_ERROR;
+                }
+            } else if (TXN_NOTICE_ERRORS(sql->trans)){
                 sql->trans->errnum = 1;
             }
             return 1;
+        } else {
+            if (TXN_IGNORE_ERRORS(sql->trans)) {
+                PGresult *res = PQexec(sql->conn,
+                                       "RELEASE SAVEPOINT APR_DBD_TXN_SP");
+                if (res) {
+                    ret = PQresultStatus(res);
+                    PQclear(res);
+                    if (!dbd_pgsql_is_success(ret)) {
+                        sql->trans->errnum = ret;
+                        return PGRES_FATAL_ERROR;
+                    }
+                } else {
+                    sql->trans->errnum = ret;
+                    return PGRES_FATAL_ERROR;
+                }
+            }
         }
         if (!*results) {
             *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
@@ -494,9 +761,6 @@
         (*results)->handle = sql->conn;
     }
 
-    if (sql->trans) {
-        sql->trans->errnum = ret;
-    }
     return ret;
 }
 
@@ -554,7 +818,8 @@
     PGresult *res;
     int ret = -1;                /* no transaction is an error cond */
     if (trans) {
-        if (trans->errnum) {
+        /* rollback on error or explicit rollback request */
+        if (trans->errnum || TXN_DO_ROLLBACK(trans)) {
             trans->errnum = 0;
             res = PQexec(trans->handle->conn, "ROLLBACK");
         }
@@ -576,6 +841,23 @@
     return ret;
 }
 
+static int dbd_pgsql_transaction_mode_get(apr_dbd_transaction_t *trans)
+{
+    if (!trans)
+        return APR_DBD_TRANSACTION_COMMIT;
+
+    return trans->mode;
+}
+
+static int dbd_pgsql_transaction_mode_set(apr_dbd_transaction_t *trans,
+                                          int mode)
+{
+    if (!trans)
+        return APR_DBD_TRANSACTION_COMMIT;
+
+    return trans->mode = (mode & TXN_MODE_BITS);
+}
+
 static apr_dbd_t *dbd_pgsql_open(apr_pool_t *pool, const char *params)
 {
     apr_dbd_t *sql;
@@ -665,6 +947,8 @@
     dbd_pgsql_pvselect,
     dbd_pgsql_pquery,
     dbd_pgsql_pselect,
-    dbd_pgsql_get_name
+    dbd_pgsql_get_name,
+    dbd_pgsql_transaction_mode_get,
+    dbd_pgsql_transaction_mode_set
 };
 #endif

Modified: apr/apr-util/trunk/dbd/apr_dbd_sqlite2.c
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/dbd/apr_dbd_sqlite2.c?rev=414087&r1=414086&r2=414087&view=diff
==============================================================================
--- apr/apr-util/trunk/dbd/apr_dbd_sqlite2.c (original)
+++ apr/apr-util/trunk/dbd/apr_dbd_sqlite2.c Tue Jun 13 22:42:10 2006
@@ -29,6 +29,7 @@
 #include "apr_dbd_internal.h"
 
 struct apr_dbd_transaction_t {
+    int mode;
     int errnum;
     apr_dbd_t *handle;
 };
@@ -108,7 +109,9 @@
         ret = 0;
     }
     else {
-        sql->trans->errnum = ret;
+        if (TXN_NOTICE_ERRORS(sql->trans)) {
+            sql->trans->errnum = ret;
+        }
     }
 
     return ret;
@@ -214,7 +217,7 @@
         ret = 0;
     }
 
-    if (sql->trans) {
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
         sql->trans->errnum = ret;
     }
 
@@ -297,7 +300,8 @@
     int ret = -1;               /* no transaction is an error cond */
 
     if (trans) {
-        if (trans->errnum) {
+        /* rollback on error or explicit rollback request */
+        if (trans->errnum || TXN_DO_ROLLBACK(trans)) {
             trans->errnum = 0;
             ret =
                 dbd_sqlite_query(trans->handle, &rows,
@@ -313,6 +317,23 @@
     return ret;
 }
 
+static int dbd_sqlite_transaction_mode_get(apr_dbd_transaction_t *trans)
+{
+    if (!trans)
+        return APR_DBD_TRANSACTION_COMMIT;
+
+    return trans->mode;
+}
+
+static int dbd_sqlite_transaction_mode_set(apr_dbd_transaction_t *trans,
+                                           int mode)
+{
+    if (!trans)
+        return APR_DBD_TRANSACTION_COMMIT;
+
+    return trans->mode = (mode & TXN_MODE_BITS);
+}
+
 static apr_dbd_t *dbd_sqlite_open(apr_pool_t * pool, const char *params_)
 {
     apr_dbd_t *sql;
@@ -401,6 +422,8 @@
     dbd_sqlite_pvselect,
     dbd_sqlite_pquery,
     dbd_sqlite_pselect,
-    dbd_sqlite_get_name
+    dbd_sqlite_get_name,
+    dbd_sqlite_transaction_mode_get,
+    dbd_sqlite_transaction_mode_set
 };
 #endif

Modified: apr/apr-util/trunk/dbd/apr_dbd_sqlite3.c
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/dbd/apr_dbd_sqlite3.c?rev=414087&r1=414086&r2=414087&view=diff
==============================================================================
--- apr/apr-util/trunk/dbd/apr_dbd_sqlite3.c (original)
+++ apr/apr-util/trunk/dbd/apr_dbd_sqlite3.c Tue Jun 13 22:42:10 2006
@@ -32,6 +32,7 @@
 #define MAX_RETRY_SLEEP 100000
 
 struct apr_dbd_transaction_t {
+    int mode;
     int errnum;
     apr_dbd_t *handle;
 };
@@ -178,7 +179,7 @@
     ret = sqlite3_finalize(stmt);
     apr_dbd_mutex_unlock();
 
-    if (sql->trans) {
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
         sql->trans->errnum = ret;
     }
     return ret;
@@ -279,7 +280,7 @@
         ret = 0;
     }
     apr_dbd_mutex_unlock();
-    if (sql->trans) {
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
         sql->trans->errnum = ret;
     }
     return ret;
@@ -391,7 +392,7 @@
         ret = 0;
     }
     apr_dbd_mutex_unlock();
-    if (sql->trans) {
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
         sql->trans->errnum = ret;
     }
 
@@ -525,7 +526,7 @@
     }
     apr_dbd_mutex_unlock();
 
-    if (sql->trans) {
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
         sql->trans->errnum = ret;
     }
     return ret;
@@ -576,7 +577,8 @@
     int nrows = 0;
 
     if (trans) {
-        if (trans->errnum) {
+        /* rollback on error or explicit rollback request */
+        if (trans->errnum || TXN_DO_ROLLBACK(trans)) {
             trans->errnum = 0;
             ret = dbd_sqlite3_query(trans->handle, &nrows, "ROLLBACK");
         } else {
@@ -588,6 +590,23 @@
     return ret;
 }
 
+static int dbd_sqlite3_transaction_mode_get(apr_dbd_transaction_t *trans)
+{
+    if (!trans)
+        return APR_DBD_TRANSACTION_COMMIT;
+
+    return trans->mode;
+}
+
+static int dbd_sqlite3_transaction_mode_set(apr_dbd_transaction_t *trans,
+                                            int mode)
+{
+    if (!trans)
+        return APR_DBD_TRANSACTION_COMMIT;
+
+    return trans->mode = (mode & TXN_MODE_BITS);
+}
+
 static apr_dbd_t *dbd_sqlite3_open(apr_pool_t *pool, const char *params)
 {
     apr_dbd_t *sql = NULL;
@@ -673,6 +692,8 @@
     dbd_sqlite3_pvselect,
     dbd_sqlite3_pquery,
     dbd_sqlite3_pselect,
-    dbd_sqlite3_get_name
+    dbd_sqlite3_get_name,
+    dbd_sqlite3_transaction_mode_get,
+    dbd_sqlite3_transaction_mode_set
 };
 #endif

Modified: apr/apr-util/trunk/include/apr_dbd.h
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/include/apr_dbd.h?rev=414087&r1=414086&r2=414087&view=diff
==============================================================================
--- apr/apr-util/trunk/include/apr_dbd.h (original)
+++ apr/apr-util/trunk/include/apr_dbd.h Tue Jun 13 22:42:10 2006
@@ -152,9 +152,12 @@
  *  @param handle - the db connection
  *  @param trans - ptr to a transaction.  May be null on entry
  *  @return 0 for success or error code
- *  @remarks If any of the query/select calls during a transaction return
- *  non-zero status code, the transaction will inherit this code and any
- *  further query/select calls will fail immediately.
+ *  @remarks Note that transaction modes, set by calling
+ *  apr_dbd_transaction_mode_set(), will affect all query/select calls within
+ *  a transaction. By default, any error in query/select during a transaction
+ *  will cause the transaction to inherit the error code and any further
+ *  query/select calls will fail immediately. Put transaction in "ignore
+ *  errors" mode to avoid that. Use "rollback" mode to do explicit rollback.
  */
 APU_DECLARE(int) apr_dbd_transaction_start(const apr_dbd_driver_t *driver,
                                            apr_pool_t *pool,
@@ -173,6 +176,30 @@
 APU_DECLARE(int) apr_dbd_transaction_end(const apr_dbd_driver_t *driver,
                                          apr_pool_t *pool,
                                          apr_dbd_transaction_t *trans);
+
+#define APR_DBD_TRANSACTION_COMMIT        0x00  /**< commit the transaction */
+#define APR_DBD_TRANSACTION_ROLLBACK      0x01  /**< rollback the transaction */
+#define APR_DBD_TRANSACTION_IGNORE_ERRORS 0x02  /**< ignore transaction errors */
+
+/** apr_dbd_transaction_mode_get: get the mode of transaction
+ *
+ *  @param driver - the driver
+ *  @param trans  - the transaction
+ *  @return mode of transaction
+ */
+APU_DECLARE(int) apr_dbd_transaction_mode_get(const apr_dbd_driver_t *driver,
+                                              apr_dbd_transaction_t *trans);
+
+/** apr_dbd_transaction_mode_set: set the mode of transaction
+ *
+ *  @param driver - the driver
+ *  @param trans  - the transaction
+ *  @param mode   - new mode of the transaction
+ *  @return the mode of transaction in force after the call
+ */
+APU_DECLARE(int) apr_dbd_transaction_mode_set(const apr_dbd_driver_t *driver,
+                                              apr_dbd_transaction_t *trans,
+                                              int mode);
 
 /** apr_dbd_query: execute an SQL query that doesn't return a result set
  *

Modified: apr/apr-util/trunk/include/private/apr_dbd_internal.h
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/include/private/apr_dbd_internal.h?rev=414087&r1=414086&r2=414087&view=diff
==============================================================================
--- apr/apr-util/trunk/include/private/apr_dbd_internal.h (original)
+++ apr/apr-util/trunk/include/private/apr_dbd_internal.h Tue Jun 13 22:42:10 2006
@@ -29,6 +29,17 @@
 extern "C" {
 #endif
 
+#define TXN_IGNORE_ERRORS(t) \
+  ((t) && ((t)->mode & APR_DBD_TRANSACTION_IGNORE_ERRORS))
+#define TXN_NOTICE_ERRORS(t) \
+  ((t) && !((t)->mode & APR_DBD_TRANSACTION_IGNORE_ERRORS))
+
+#define TXN_DO_COMMIT(t)   (!((t)->mode & APR_DBD_TRANSACTION_ROLLBACK))
+#define TXN_DO_ROLLBACK(t) ((t)->mode & APR_DBD_TRANSACTION_ROLLBACK)
+
+#define TXN_MODE_BITS \
+  (APR_DBD_TRANSACTION_ROLLBACK|APR_DBD_TRANSACTION_IGNORE_ERRORS)
+
 struct apr_dbd_driver_t {
     /** name */
     const char *name;
@@ -82,9 +93,9 @@
 
     /** transaction: start a transaction.  May be a no-op.
      *
-     *  @param pool - a pool to use for error messages (if any).
+     *  @param pool   - a pool to use for error messages (if any).
      *  @param handle - the connection
-     *  @param transaction - ptr to a transaction.  May be null on entry
+     *  @param trans  - ptr to a transaction.  May be null on entry
      *  @return 0 for success or error code
      */
     int (*start_transaction)(apr_pool_t *pool, apr_dbd_t *handle,
@@ -94,7 +105,7 @@
      *  (commit on success, rollback on error).
      *  May be a no-op.
      *
-     *  @param transaction - the transaction.
+     *  @param trans - the transaction.
      *  @return 0 for success or error code
      */
     int (*end_transaction)(apr_dbd_transaction_t *trans);
@@ -254,6 +265,21 @@
      *  @return param name, or NULL if col is out of bounds.
      */
     const char* (*get_name)(const apr_dbd_results_t *res, int col);
+
+    /** transaction_mode_get: get the mode of transaction
+     *
+     *  @param trans - the transaction.
+     *  @return mode of transaction
+     */
+    int (*transaction_mode_get)(apr_dbd_transaction_t *trans);
+
+    /** transaction_mode_set: get the mode of transaction
+     *
+     *  @param trans - the transaction.
+     *  @param mode  - new mode of the transaction
+     *  @return the mode of transaction in force after the call
+     */
+    int (*transaction_mode_set)(apr_dbd_transaction_t *trans, int mode);
 };
 
 /* Export mutex lock/unlock for drivers that need it */