/*
 * call-seq:
 *    conn.transaction { |conn| ... } -> nil
 *
 * Executes a +BEGIN+ at the start of the block,
 * and a +COMMIT+ at the end of the block, or 
 * +ROLLBACK+ if any exception occurs.
 */
static VALUE
pgconn_transaction(VALUE self)
{
    PGconn *conn = get_pgconn(self);
    PGresult *result;
    VALUE rb_pgresult;
    int status;

    if (rb_block_given_p()) {
        result = PQexec(conn, "BEGIN");
        rb_pgresult = new_pgresult(result, conn);
        pgresult_check(self, rb_pgresult);
        rb_protect(rb_yield, self, &status);
        if(status == 0) {
            result = PQexec(conn, "COMMIT");
            rb_pgresult = new_pgresult(result, conn);
            pgresult_check(self, rb_pgresult);
        }
        else {
            /* exception occurred, ROLLBACK and re-raise */
            result = PQexec(conn, "ROLLBACK");
            rb_pgresult = new_pgresult(result, conn);
            pgresult_check(self, rb_pgresult);
            rb_jump_tag(status);
        }

    }
    else {
        /* no block supplied? */
        rb_raise(rb_eArgError, "Must supply block for PGconn#transaction");
    }
    return Qnil;
}