From dev-return-16525-apmail-apr-dev-archive=apr.apache.org@apr.apache.org Tue Jun 06 03:03:10 2006 Return-Path: Delivered-To: apmail-apr-dev-archive@www.apache.org Received: (qmail 73944 invoked from network); 6 Jun 2006 03:03:10 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 6 Jun 2006 03:03:10 -0000 Received: (qmail 45847 invoked by uid 500); 6 Jun 2006 03:03:09 -0000 Delivered-To: apmail-apr-dev-archive@apr.apache.org Received: (qmail 45495 invoked by uid 500); 6 Jun 2006 03:03:08 -0000 Mailing-List: contact dev-help@apr.apache.org; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Id: Delivered-To: mailing list dev@apr.apache.org Received: (qmail 45484 invoked by uid 99); 6 Jun 2006 03:03:08 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 05 Jun 2006 20:03:08 -0700 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: domain of bojan@rexursive.com designates 203.171.74.242 as permitted sender) Received: from [203.171.74.242] (HELO beauty.rexursive.com) (203.171.74.242) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 05 Jun 2006 20:03:06 -0700 Received: by beauty.rexursive.com (Postfix, from userid 48) id A3F35255DF3; Tue, 6 Jun 2006 13:02:42 +1000 (EST) Received: from cache1.syd.ops.aspac.uu.net (cache1.syd.ops.aspac.uu.net [203.166.96.235]) by www.rexursive.com (Horde MIME library) with HTTP; Tue, 06 Jun 2006 13:02:42 +1000 Message-ID: <20060606130242.kkpm9w4vswwgskwg@www.rexursive.com> Date: Tue, 06 Jun 2006 13:02:42 +1000 From: Bojan Smojver To: dev@apr.apache.org Subject: Re: Transaction modes, explicit rollbacks etc. References: <20060601142732.59688.qmail@web30003.mail.mud.yahoo.com> In-Reply-To: <20060601142732.59688.qmail@web30003.mail.mud.yahoo.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=_1c0d97hwny4k" Content-Transfer-Encoding: 7bit User-Agent: Internet Messaging Program (IMP) H3 (4.1.1) X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N This message is in MIME format. --=_1c0d97hwny4k Content-Type: text/plain; charset=ISO-8859-1; DelSp="Yes"; format="flowed" Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Quoting Rick Keiner : > What's the status of the API change? This would bump the rev to 1.3, =20 > correct? Any idea what the time frame is on this? OK, here is the summary: Database | Explicit ROLLBACK | Ignore TXN errors ------------------------------------------------ pgsql | Yes | Yes ------------------------------------------------ mysql | Yes (InnoDB) | Yes ------------------------------------------------ sqlite3 | Yes | Yes ------------------------------------------------ sqlite2 | Not tested | Not tested ------------------------------------------------ oracle | Not tested | Not tested ------------------------------------------------ I had to make some changes to the PostgreSQL patch - there were subtle =20 bugs related to result sets. So, I'm attaching a new patch for =20 reference. A patch against the latest version of MySQL driver is also =20 attached. I'm not forseeing problems with SQLite2 - the code is much the same as =20 for SQLite3, so it should work. I just don't have the environment =20 handy to test. As for Oracle, this needs to be tested by folks that understand both =20 the driver and the backend properly. Skeleton code is attached, feel =20 free to have a go at it. --=20 Bojan --=_1c0d97hwny4k Content-Type: text/x-patch; charset=ISO-8859-1; name="apr_dbd-trans-dual-mode.patch" Content-Disposition: attachment; filename="apr_dbd-trans-dual-mode.patch" Content-Transfer-Encoding: quoted-printable Index: include/apr_dbd.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- include/apr_dbd.h=09(revision 411975) +++ include/apr_dbd.h=09(working copy) @@ -174,6 +174,30 @@ apr_pool_t *pool, apr_dbd_transaction_t *trans); =20 +#define APR_DBD_TRANSACTION_COMMIT 0x00 /**< commit the transaction= */ +#define APR_DBD_TRANSACTION_ROLLBACK 0x01 /**< rollback the transacti= on */ +#define APR_DBD_TRANSACTION_IGNORE_ERRORS 0x02 /**< ignore transaction err= ors */ + +/** 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 *drive= r, + 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 *drive= r, + 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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- include/private/apr_dbd_internal.h=09(revision 411975) +++ include/private/apr_dbd_internal.h=09(working copy) @@ -29,6 +29,17 @@ extern "C" { #endif =20 +#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 @@ =20 /** 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); }; =20 /* Export mutex lock/unlock for drivers that need it */ Index: dbd/apr_dbd_sqlite2.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- dbd/apr_dbd_sqlite2.c=09(revision 411975) +++ dbd/apr_dbd_sqlite2.c=09(working copy) @@ -29,6 +29,7 @@ #include "apr_dbd_internal.h" =20 struct apr_dbd_transaction_t { + int mode; int errnum; apr_dbd_t *handle; }; @@ -108,7 +109,9 @@ ret =3D 0; } else { - sql->trans->errnum =3D ret; + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum =3D ret; + } } =20 return ret; @@ -214,7 +217,7 @@ ret =3D 0; } =20 - if (sql->trans) { + if (TXN_NOTICE_ERRORS(sql->trans)) { sql->trans->errnum =3D ret; } =20 @@ -292,7 +295,8 @@ int ret =3D -1; /* no transaction is an error cond */ =20 if (trans) { - if (trans->errnum) { + /* rollback on error or explicit rollback request */ + if (trans->errnum || TXN_DO_ROLLBACK(trans)) { trans->errnum =3D 0; ret =3D dbd_sqlite_query(trans->handle, &rows, @@ -308,6 +312,23 @@ return ret; } =20 +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 =3D (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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- dbd/apr_dbd_sqlite3.c=09(revision 411975) +++ dbd/apr_dbd_sqlite3.c=09(working copy) @@ -34,6 +34,7 @@ #define QUERY_MAX_ARGS 40 =20 struct apr_dbd_transaction_t { + int mode; int errnum; apr_dbd_t *handle; }; @@ -180,7 +181,7 @@ ret =3D sqlite3_finalize(stmt); apr_dbd_mutex_unlock(); =20 - if (sql->trans) { + if (TXN_NOTICE_ERRORS(sql->trans)) { sql->trans->errnum =3D ret; } return ret; @@ -281,7 +282,7 @@ ret =3D 0; } apr_dbd_mutex_unlock(); - if (sql->trans) { + if (TXN_NOTICE_ERRORS(sql->trans)) { sql->trans->errnum =3D ret; } return ret; @@ -387,7 +388,7 @@ ret =3D 0; } apr_dbd_mutex_unlock(); - if (sql->trans) { + if (TXN_NOTICE_ERRORS(sql->trans)) { sql->trans->errnum =3D ret; } =20 @@ -524,7 +525,7 @@ } apr_dbd_mutex_unlock(); =20 - if (sql->trans) { + if (TXN_NOTICE_ERRORS(sql->trans)) { sql->trans->errnum =3D ret; } return ret; @@ -578,7 +579,8 @@ int nrows =3D 0; =20 if (trans) { - if (trans->errnum) { + /* rollback on error or explicit rollback request */ + if (trans->errnum || TXN_DO_ROLLBACK(trans)) { trans->errnum =3D 0; ret =3D dbd_sqlite3_query(trans->handle, &nrows, "ROLLBACK"); } else { @@ -590,6 +592,23 @@ return ret; } =20 +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 =3D (mode & TXN_MODE_BITS); +} + static apr_dbd_t *dbd_sqlite3_open(apr_pool_t *pool, const char *params) { apr_dbd_t *sql =3D 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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- dbd/apr_dbd_oracle.c=09(revision 411975) +++ dbd/apr_dbd_oracle.c=09(working copy) @@ -123,6 +123,7 @@ static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans); =20 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 =3D TRANS_ERROR; } return 1; @@ -1277,7 +1278,7 @@ #endif /* fallthrough */ default: - if (trans) { + if (TXN_NOTICE_ERRORS(trans)) { trans->status =3D TRANS_ERROR; } return 1; @@ -1383,7 +1384,7 @@ #endif /* fallthrough */ default: - if (trans) { + if (TXN_NOTICE_ERRORS(trans)) { trans->status =3D 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 =3D 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 =3D TRANS_ERROR; } return 1; @@ -1664,7 +1665,12 @@ status =3D OCITransRollback(handle->svc, handle->err, OCI_DEFAU= LT); break; default: - status =3D OCITransCommit(handle->svc, handle->err, OCI_DEFAULT= ); + /* rollback on explicit rollback request */ + if (TXN_DO_ROLLBACK(trans)) { + status =3D OCITransRollback(handle->svc, handle->err, OCI_D= EFAULT); + } else { + status =3D OCITransCommit(handle->svc, handle->err, OCI_DEF= AULT); + } break; } =20 @@ -1682,6 +1688,23 @@ return ret; } =20 +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 =3D (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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- dbd/apr_dbd_pgsql.c=09(revision 411975) +++ dbd/apr_dbd_pgsql.c=09(working copy) @@ -37,6 +37,7 @@ #define QUERY_MAX_ARGS 40 =20 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)) { + PGresult *res =3D PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP")= ; + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum =3D PGRES_FATAL_ERROR; + } + } res =3D PQexec(sql->conn, query); if (res) { ret =3D PQresultStatus(res); @@ -91,10 +105,38 @@ ret =3D PGRES_FATAL_ERROR; } if (ret !=3D 0) { - if (sql->trans) { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, + "ROLLBACK TO SAVEPOINT APR_DBD_TXN_S= P"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum =3D PGRES_FATAL_ERROR; + } + } else if (TXN_NOTICE_ERRORS(sql->trans)){ sql->trans->errnum =3D ret; } return ret; + } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, + "RELEASE SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum =3D PGRES_FATAL_ERROR; + } + } } if (!*results) { *results =3D apr_pcalloc(pool, sizeof(apr_dbd_results_t)); @@ -107,11 +149,52 @@ apr_pool_cleanup_null); } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP")= ; + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum =3D PGRES_FATAL_ERROR; + } + } if (PQsendQuery(sql->conn, query) =3D=3D 0) { - if (sql->trans) { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, + "ROLLBACK TO SAVEPOINT APR_DBD_TXN_S= P"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum =3D PGRES_FATAL_ERROR; + } + } else if (TXN_NOTICE_ERRORS(sql->trans)){ sql->trans->errnum =3D 1; } return 1; + } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, + "RELEASE SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum =3D PGRES_FATAL_ERROR; + } + } } if (*results =3D=3D NULL) { *results =3D apr_pcalloc(pool, sizeof(apr_dbd_results_t)); @@ -209,6 +292,21 @@ if (sql->trans && sql->trans->errnum) { return sql->trans->errnum; } + + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum =3D PGRES_FATAL_ERROR; + } + } + res =3D PQexec(sql->conn, query); if (res) { ret =3D PQresultStatus(res); @@ -222,9 +320,43 @@ else { ret =3D PGRES_FATAL_ERROR; } - if (sql->trans) { - sql->trans->errnum =3D ret; + =20 + if (ret !=3D 0){ + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, + "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else if (TXN_NOTICE_ERRORS(sql->trans)){ + sql->trans->errnum =3D ret; + } + } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, + "RELEASE SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } } + return ret; } =20 @@ -369,6 +501,20 @@ return sql->trans->errnum; } =20 + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum =3D PGRES_FATAL_ERROR; + } + } + if (statement->prepared) { res =3D PQexecPrepared(sql->conn, statement->name, nargs, values, 0= , 0, 0); @@ -389,9 +535,42 @@ ret =3D PGRES_FATAL_ERROR; } =20 - if (sql->trans) { - sql->trans->errnum =3D ret; + if (ret !=3D 0){ + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, + "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else if (TXN_NOTICE_ERRORS(sql->trans)){ + sql->trans->errnum =3D ret; + } + } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, + "RELEASE SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } } + return ret; } =20 @@ -431,6 +610,20 @@ } =20 if (seek) { /* synchronous query */ + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP")= ; + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } if (statement->prepared) { res =3D PQexecPrepared(sql->conn, statement->name, nargs, value= s, 0, 0, 0); @@ -452,10 +645,40 @@ ret =3D PGRES_FATAL_ERROR; } if (ret !=3D 0) { - if (sql->trans) { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, + "ROLLBACK TO SAVEPOINT APR_DBD_TXN_S= P"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else if (TXN_NOTICE_ERRORS(sql->trans)){ sql->trans->errnum =3D ret; } return ret; + } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, + "RELEASE SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } } if (!*results) { *results =3D apr_pcalloc(pool, sizeof(apr_dbd_results_t)); @@ -468,6 +691,20 @@ apr_pool_cleanup_null); } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP")= ; + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } if (statement->prepared) { rv =3D PQsendQueryPrepared(sql->conn, statement->name, nargs, v= alues, 0, 0, 0); @@ -477,10 +714,40 @@ values, 0, 0, 0); } if (rv =3D=3D 0) { - if (sql->trans) { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, + "ROLLBACK TO SAVEPOINT APR_DBD_TXN_S= P"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else if (TXN_NOTICE_ERRORS(sql->trans)){ sql->trans->errnum =3D 1; } return 1; + } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res =3D PQexec(sql->conn, + "RELEASE SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + ret =3D PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum =3D ret; + return PGRES_FATAL_ERROR; + } + } } if (!*results) { *results =3D apr_pcalloc(pool, sizeof(apr_dbd_results_t)); @@ -489,9 +756,6 @@ (*results)->handle =3D sql->conn; } =20 - if (sql->trans) { - sql->trans->errnum =3D ret; - } return ret; } =20 @@ -551,7 +815,8 @@ PGresult *res; int ret =3D -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 =3D 0; res =3D PQexec(trans->handle->conn, "ROLLBACK"); } @@ -573,6 +838,23 @@ return ret; } =20 +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 =3D (mode & TXN_MODE_BITS); +} + static apr_dbd_t *dbd_pgsql_open(apr_pool_t *pool, const char *params) { apr_dbd_t *sql; @@ -662,6 +944,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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- dbd/apr_dbd.c=09(revision 411975) +++ dbd/apr_dbd.c=09(working copy) @@ -208,6 +208,19 @@ return driver->end_transaction(trans); } =20 +APU_DECLARE(int) apr_dbd_transaction_mode_get(const apr_dbd_driver_t *drive= r, + apr_dbd_transaction_t *trans) +{ + return driver->transaction_mode_get(trans); +} + +APU_DECLARE(int) apr_dbd_transaction_mode_set(const apr_dbd_driver_t *drive= r, + 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) { --=_1c0d97hwny4k Content-Type: text/x-patch; charset=ISO-8859-1; name="apr_dbd-trans-dual-mode-mysql.patch" Content-Disposition: attachment; filename="apr_dbd-trans-dual-mode-mysql.patch" Content-Transfer-Encoding: quoted-printable Index: apr_dbd_mysql.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- apr_dbd_mysql.c=09(revision 46) +++ apr_dbd_mysql.c=09(working copy) @@ -65,6 +65,9 @@ }; =20 struct apr_dbd_transaction_t { +#if APU_MAJOR_VERSION >=3D 2 || (APU_MAJOR_VERSION =3D=3D 1 && APU_MINOR_VE= RSION >=3D 3) + int mode; +#endif int errnum; apr_dbd_t *handle; }; @@ -117,7 +120,11 @@ ret =3D mysql_errno(sql->conn); } =20 +#if APU_MAJOR_VERSION >=3D 2 || (APU_MAJOR_VERSION =3D=3D 1 && APU_MINOR_VE= RSION >=3D 3) + if (TXN_NOTICE_ERRORS(sql->trans)) { +#else if (sql->trans) { +#endif sql->trans->errnum =3D ret; } return ret; @@ -246,7 +253,11 @@ ret =3D mysql_errno(sql->conn); } *nrows =3D mysql_affected_rows(sql->conn); +#if APU_MAJOR_VERSION >=3D 2 || (APU_MAJOR_VERSION =3D=3D 1 && APU_MINOR_VE= RSION >=3D 3) + if (TXN_NOTICE_ERRORS(sql->trans)) { +#else if (sql->trans) { +#endif sql->trans->errnum =3D ret; } return ret; @@ -345,7 +356,11 @@ } *nrows =3D mysql_stmt_affected_rows(statement->stmt); } +#if APU_MAJOR_VERSION >=3D 2 || (APU_MAJOR_VERSION =3D=3D 1 && APU_MINOR_VE= RSION >=3D 3) + if (TXN_NOTICE_ERRORS(sql->trans)) { +#else if (sql->trans) { +#endif sql->trans->errnum =3D ret; } return ret; @@ -388,7 +403,11 @@ } *nrows =3D mysql_stmt_affected_rows(statement->stmt); } +#if APU_MAJOR_VERSION >=3D 2 || (APU_MAJOR_VERSION =3D=3D 1 && APU_MINOR_VE= RSION >=3D 3) + if (TXN_NOTICE_ERRORS(sql->trans)) { +#else if (sql->trans) { +#endif sql->trans->errnum =3D ret; } return ret; @@ -469,7 +488,11 @@ if (ret !=3D 0) { ret =3D mysql_stmt_errno(statement->stmt); } +#if APU_MAJOR_VERSION >=3D 2 || (APU_MAJOR_VERSION =3D=3D 1 && APU_MINOR_VE= RSION >=3D 3) + if (TXN_NOTICE_ERRORS(sql->trans)) { +#else if (sql->trans) { +#endif sql->trans->errnum =3D ret; } return ret; @@ -551,7 +574,11 @@ if (ret !=3D 0) { ret =3D mysql_stmt_errno(statement->stmt); } +#if APU_MAJOR_VERSION >=3D 2 || (APU_MAJOR_VERSION =3D=3D 1 && APU_MINOR_VE= RSION >=3D 3) + if (TXN_NOTICE_ERRORS(sql->trans)) { +#else if (sql->trans) { +#endif sql->trans->errnum =3D ret; } return ret; @@ -560,7 +587,12 @@ { int ret =3D -1; if (trans) { +#if APU_MAJOR_VERSION >=3D 2 || (APU_MAJOR_VERSION =3D=3D 1 && APU_MINOR_VE= RSION >=3D 3) + /* rollback on error or explicit rollback request */ + if (trans->errnum || TXN_DO_ROLLBACK(trans)) { +#else if (trans->errnum) { +#endif trans->errnum =3D 0; ret =3D mysql_rollback(trans->handle->conn); } @@ -591,6 +623,24 @@ handle->trans =3D *trans; return (*trans)->errnum; } +#if APU_MAJOR_VERSION >=3D 2 || (APU_MAJOR_VERSION =3D=3D 1 && APU_MINOR_VE= RSION >=3D 3) +static int dbd_mysql_transaction_mode_get(apr_dbd_transaction_t *trans) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode; +} + +static int dbd_mysql_transaction_mode_set(apr_dbd_transaction_t *trans, + int mode) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode =3D (mode & TXN_MODE_BITS); +} +#endif static apr_dbd_t *dbd_mysql_open(apr_pool_t *pool, const char *params) { static const char *const delims =3D " \r\n\t;|,"; @@ -752,7 +802,9 @@ dbd_mysql_pselect #if APU_MAJOR_VERSION >=3D 2 || (APU_MAJOR_VERSION =3D=3D 1 && APU_MINOR_VE= RSION >=3D 3) , - dbd_mysql_get_name + dbd_mysql_get_name, + dbd_mysql_transaction_mode_get, + dbd_mysql_transaction_mode_set #endif }; =20 --=_1c0d97hwny4k--