send_query_prepared (PGconn)

    /*
     * call-seq:
     *    conn.send_query_prepared( statement_name [, params, result_format ] )
     *      -> nil
     *
     * Execute prepared named statement specified by _statement_name_
     * asynchronously, and returns immediately.
     * On failure, it raises a PGError exception.
     *
     * +params+ is an array of the optional bind parameters for the
     * SQL query. Each element of the +params+ array may be either:
     *   a hash of the form:
     *     {:value  => String (value of bind parameter)
     *      :format => Fixnum (0 for text, 1 for binary)
     *     }
     *   or, it may be a String. If it is a string, that is equivalent to the hash:
     *     { :value => <string value>, :format => 0 }
     *
     * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
     * inside the SQL query. The 0th element of the +params+ array is bound
     * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
     *
     * The optional +result_format+ should be 0 for text results, 1
     * for binary.
     */
    static VALUE
    pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
    {
            PGconn *conn = get_pgconn(self);
            int result;
            VALUE name, params, in_res_fmt;
            VALUE param, param_value, param_format;
            VALUE param_value_tmp;
            VALUE sym_value, sym_format;
            VALUE gc_array;
            VALUE error;
            int i = 0;
            int nParams;
            char ** paramValues;
            int *paramLengths;
            int *paramFormats;
            int resultFormat;

            rb_scan_args(argc, argv, "12", &name, &params, &in_res_fmt);
            Check_Type(name, T_STRING);

            if(NIL_P(params)) {
                    params = rb_ary_new2(0);
                    resultFormat = 0;
            }
            else {
                    Check_Type(params, T_ARRAY);
            }

            if(NIL_P(in_res_fmt)) {
                    resultFormat = 0;
            }
            else {
                    resultFormat = NUM2INT(in_res_fmt);
            }

            gc_array = rb_ary_new();
            rb_gc_register_address(&gc_array);
            sym_value = ID2SYM(rb_intern("value"));
            sym_format = ID2SYM(rb_intern("format"));
            nParams = RARRAY(params)->len;
            paramValues = ALLOC_N(char *, nParams);
            paramLengths = ALLOC_N(int, nParams);
            paramFormats = ALLOC_N(int, nParams);
            for(i = 0; i < nParams; i++) {
                    param = rb_ary_entry(params, i);
                    if (TYPE(param) == T_HASH) {
                            param_value_tmp = rb_hash_aref(param, sym_value);
                            if(param_value_tmp == Qnil)
                                    param_value = param_value_tmp;
                            else
                                    param_value = rb_obj_as_string(param_value_tmp);
                            param_format = rb_hash_aref(param, sym_format);
                    }
                    else {
                            if(param == Qnil)
                                    param_value = param;
                            else
                                    param_value = rb_obj_as_string(param);
                            param_format = INT2NUM(0);
                    }

                    if(param_value == Qnil) {
                            paramValues[i] = NULL;
                            paramLengths[i] = 0;
                    }
                    else {
                            Check_Type(param_value, T_STRING);
                            /* make sure param_value doesn't get freed by the GC */
                            rb_ary_push(gc_array, param_value);
                            paramValues[i] = StringValuePtr(param_value);
                            paramLengths[i] = RSTRING_LEN(param_value);
                    }

                    if(param_format == Qnil)
                            paramFormats[i] = 0;
                    else
                            paramFormats[i] = NUM2INT(param_format);
            }

            result = PQsendQueryPrepared(conn, StringValuePtr(name), nParams,
                    (const char * const *)paramValues, paramLengths, paramFormats,
                    resultFormat);

            rb_gc_unregister_address(&gc_array);

            free(paramValues);
            free(paramLengths);
            free(paramFormats);

            if(result == 0) {
                    error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
                    rb_iv_set(error, "@connection", self);
                    rb_exc_raise(error);
            }
            return Qnil;
    }