exec (PGconn)

    /*
     * call-seq:
     *    conn.exec(sql, *bind_values)
     *
     * Sends SQL query request specified by _sql_ to the PostgreSQL.
     * Returns a PGresult instance on success.
     * On failure, it raises a PGError exception.
     *
     * +bind_values+ represents values for the PostgreSQL bind parameters found in the +sql+.  PostgreSQL bind parameters are presented as $1, $1, $2, etc.
     */
    static VALUE
    pgconn_exec(argc, argv, obj)
        int argc;
        VALUE *argv;
        VALUE obj;
    {
        PGconn *conn = get_pgconn(obj);
        PGresult *result = NULL;
        VALUE command, params;
        char *msg;

        rb_scan_args(argc, argv, "1*", &command, &params);

        Check_Type(command, T_STRING);

        if (RARRAY(params)->len <= 0) {
            result = PQexec(conn, StringValuePtr(command));
        }
        else {
            int len = RARRAY(params)->len;
            int i;
    #ifdef HAVE_PQEXECPARAMS
            VALUE* ptr = RARRAY(params)->ptr;
            char const** values = ALLOCA_N(char const*, len);
            int* lengths = ALLOCA_N(int, len);
            int* formats = ALLOCA_N(int, len);
            for (i = 0; i < len; i++, ptr++) {
                translate_to_pg(*ptr, values+i, lengths+i, formats+i);
            }
            result = PQexecParams(conn, StringValuePtr(command), len, NULL, values, lengths, formats, 0);
    #else
            for (i = 0; i < len; i++) {
                rb_ary_store(params, i, pgconn_s_quote(rb_cPGconn, rb_ary_entry(params, i)));
            }
            result = PQexecParams_compat(conn, command, params);
    #endif
        }

        if (!result) {
            rb_raise(rb_ePGError, PQerrorMessage(conn));
        }

        switch (PQresultStatus(result)) {
        case PGRES_TUPLES_OK:
        case PGRES_COPY_OUT:
        case PGRES_COPY_IN:
        case PGRES_EMPTY_QUERY:
        case PGRES_COMMAND_OK: {
          VALUE pg_result = pgresult_new(result);
          if (rb_block_given_p()) {
              return rb_ensure(rb_yield, pg_result, pgresult_clear, pg_result);
          }
          else {
              return pg_result;
          }
        }

        case PGRES_BAD_RESPONSE:
        case PGRES_FATAL_ERROR:
        case PGRES_NONFATAL_ERROR:
          msg = RSTRING(rb_str_new2(PQresultErrorMessage(result)))->ptr;
          break;
        default:
          msg = "internal error : unknown result status.";
          break;
        }
        PQclear(result);
        rb_raise(rb_ePGError, msg);
    }