/*
 * 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);
                pgresult_check(self, rb_pgresult);
                rb_protect(rb_yield, self, &status);
                if(status == 0) {
                        result = PQexec(conn, "COMMIT");
                        rb_pgresult = new_pgresult(result);
                        pgresult_check(self, rb_pgresult);
                }
                else {
                        /* exception occurred, ROLLBACK and re-raise */
                        result = PQexec(conn, "ROLLBACK");
                        rb_pgresult = new_pgresult(result);
                        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;
}