transaction (PGconn)

    /*
     * 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;
    }