/*
 * call-seq:
 *    conn.send_prepare( stmt_name, sql [, param_types ] ) -> nil
 *
 * Prepares statement _sql_ with name _name_ to be executed later.
 * Sends prepare command asynchronously, and returns immediately.
 * On failure, it raises a PGError exception.
 *
 * +param_types+ is an optional parameter to specify the Oids of the 
 * types of the parameters.
 *
 * If the types are not specified, they will be inferred by PostgreSQL.
 * Instead of specifying type oids, it's recommended to simply add
 * explicit casts in the query to ensure that the right type is used.
 *
 * For example: "SELECT $1::int"
 * 
 * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
 * inside the SQL query.
 */
static VALUE
pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
{
    PGconn *conn = get_pgconn(self);
    int result;
    VALUE name, command, in_paramtypes;
    VALUE param;
    VALUE error;
    int i = 0;
    int nParams = 0;
    Oid *paramTypes = NULL;

    rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
    Check_Type(name, T_STRING);
    Check_Type(command, T_STRING);

    if(! NIL_P(in_paramtypes)) {
        Check_Type(in_paramtypes, T_ARRAY);
        nParams = RARRAY_LEN(in_paramtypes);
        paramTypes = ALLOC_N(Oid, nParams); 
        for(i = 0; i < nParams; i++) {
            param = rb_ary_entry(in_paramtypes, i);
            Check_Type(param, T_FIXNUM);
            if(param == Qnil)
                paramTypes[i] = 0;
            else
                paramTypes[i] = NUM2INT(param);
        }
    }
    result = PQsendPrepare(conn, StringValuePtr(name), StringValuePtr(command),
            nParams, paramTypes);

    xfree(paramTypes);

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