On Thu, 2006-06-01 at 07:27 -0700, Rick Keiner wrote:
> What's the status of the API change? This would bump the rev to 1.3,
> correct? Any idea what the time frame is on this?
I got a bit sidetracked with the MySQL driver stuff, but I'm testing the
patch in my setup. I'm planning to test the whole thing a little bit
better and then commit to the trunk (i.e. this cannot go to 1.2.x, due
to binary compatibility requirements). I would like to tell you that
this is going to be tomorrow, but this depends on my work and other
commitments.
The code I'm testing (minus the MySQL required driver change, which I
still have to write) is attached. The only thing I can say about it for
now is that it compiles on my system.
--
Bojan
Index: include/apr_dbd.h
===================================================================
--- include/apr_dbd.h (revision 410915)
+++ include/apr_dbd.h (working copy)
@@ -170,6 +170,30 @@
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 new mode of transaction
+ */
+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
*
* @param driver - the driver
Index: include/private/apr_dbd_internal.h
===================================================================
--- include/private/apr_dbd_internal.h (revision 410915)
+++ include/private/apr_dbd_internal.h (working copy)
@@ -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 new mode of transaction
+ */
+ int (*transaction_mode_set)(apr_dbd_transaction_t *trans, int mode);
};
/* Export mutex lock/unlock for drivers that need it */
Index: dbd/apr_dbd_sqlite2.c
===================================================================
--- dbd/apr_dbd_sqlite2.c (revision 410915)
+++ dbd/apr_dbd_sqlite2.c (working copy)
@@ -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;
}
@@ -292,7 +295,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,
@@ -308,6 +312,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;
@@ -396,6 +417,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
Index: dbd/apr_dbd_sqlite3.c
===================================================================
--- dbd/apr_dbd_sqlite3.c (revision 410915)
+++ dbd/apr_dbd_sqlite3.c (working copy)
@@ -34,6 +34,7 @@
#define QUERY_MAX_ARGS 40
struct apr_dbd_transaction_t {
+ int mode;
int errnum;
apr_dbd_t *handle;
};
@@ -180,7 +181,7 @@
ret = sqlite3_finalize(stmt);
apr_dbd_mutex_unlock();
- if (sql->trans) {
+ if (TXN_NOTICE_ERRORS(sql->trans)) {
sql->trans->errnum = ret;
}
return ret;
@@ -281,7 +282,7 @@
ret = 0;
}
apr_dbd_mutex_unlock();
- if (sql->trans) {
+ if (TXN_NOTICE_ERRORS(sql->trans)) {
sql->trans->errnum = ret;
}
return ret;
@@ -387,7 +388,7 @@
ret = 0;
}
apr_dbd_mutex_unlock();
- if (sql->trans) {
+ if (TXN_NOTICE_ERRORS(sql->trans)) {
sql->trans->errnum = ret;
}
@@ -524,7 +525,7 @@
}
apr_dbd_mutex_unlock();
- if (sql->trans) {
+ if (TXN_NOTICE_ERRORS(sql->trans)) {
sql->trans->errnum = ret;
}
return ret;
@@ -578,7 +579,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 {
@@ -590,6 +592,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;
@@ -675,6 +694,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
Index: dbd/apr_dbd_oracle.c
===================================================================
--- dbd/apr_dbd_oracle.c (revision 410915)
+++ dbd/apr_dbd_oracle.c (working copy)
@@ -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
Index: dbd/apr_dbd_pgsql.c
===================================================================
--- dbd/apr_dbd_pgsql.c (revision 410915)
+++ dbd/apr_dbd_pgsql.c (working copy)
@@ -37,6 +37,7 @@
#define QUERY_MAX_ARGS 40
struct apr_dbd_transaction_t {
+ int mode;
int errnum;
apr_dbd_t *handle;
};
@@ -79,6 +80,19 @@
return sql->trans->errnum;
}
if (seek) { /* synchronous query */
+ if (TXN_IGNORE_ERRORS(sql->trans)) {
+ 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);
@@ -91,10 +105,36 @@
ret = PGRES_FATAL_ERROR;
}
if (ret != 0) {
- if (sql->trans) {
+ if (TXN_IGNORE_ERRORS(sql->trans)) {
+ 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)) {
+ 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));
@@ -107,11 +147,50 @@
apr_pool_cleanup_null);
}
else {
+ if (TXN_IGNORE_ERRORS(sql->trans)) {
+ 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)) {
+ 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)) {
+ 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));
@@ -209,6 +288,21 @@
if (sql->trans && sql->trans->errnum) {
return sql->trans->errnum;
}
+
+ if (TXN_IGNORE_ERRORS(sql->trans)) {
+ 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);
@@ -222,9 +316,41 @@
else {
ret = PGRES_FATAL_ERROR;
}
- if (sql->trans) {
- sql->trans->errnum = ret;
+
+ if (ret != 0){
+ if (TXN_IGNORE_ERRORS(sql->trans)) {
+ 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)) {
+ 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;
}
@@ -369,6 +495,20 @@
return sql->trans->errnum;
}
+ if (TXN_IGNORE_ERRORS(sql->trans)) {
+ 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);
@@ -389,9 +529,40 @@
ret = PGRES_FATAL_ERROR;
}
- if (sql->trans) {
- sql->trans->errnum = ret;
+ if (ret != 0){
+ if (TXN_IGNORE_ERRORS(sql->trans)) {
+ 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)) {
+ 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;
}
@@ -431,6 +602,20 @@
}
if (seek) { /* synchronous query */
+ if (TXN_IGNORE_ERRORS(sql->trans)) {
+ 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);
@@ -452,10 +637,38 @@
ret = PGRES_FATAL_ERROR;
}
if (ret != 0) {
- if (sql->trans) {
+ if (TXN_IGNORE_ERRORS(sql->trans)) {
+ 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)) {
+ 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));
@@ -468,6 +681,20 @@
apr_pool_cleanup_null);
}
else {
+ if (TXN_IGNORE_ERRORS(sql->trans)) {
+ 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);
@@ -477,10 +704,37 @@
values, 0, 0, 0);
}
if (rv == 0) {
- if (sql->trans) {
+ if (TXN_IGNORE_ERRORS(sql->trans)) {
+ 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)) {
+ 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));
@@ -489,9 +743,6 @@
(*results)->handle = sql->conn;
}
- if (sql->trans) {
- sql->trans->errnum = ret;
- }
return ret;
}
@@ -551,7 +802,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");
}
@@ -573,6 +825,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;
@@ -662,6 +931,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
Index: dbd/apr_dbd.c
===================================================================
--- dbd/apr_dbd.c (revision 410915)
+++ dbd/apr_dbd.c (working copy)
@@ -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)
{