insert_table (PGconn)

    /*
     * call-seq:
     *    conn.insert_table( table, values )
     *
     * Inserts contents of the _values_ Array into the _table_.
     */
    static VALUE
    pgconn_insert_table(obj, table, values)
        VALUE obj, table, values;
    {
        PGconn *conn = get_pgconn(obj);
        PGresult *result;
        VALUE s, buffer;
        int i, j;
        int res = 0;

        Check_Type(table, T_STRING);
        Check_Type(values, T_ARRAY);
        i = RARRAY(values)->len;
        while (i--) {
            if (TYPE(RARRAY(RARRAY(values)->ptr[i])) != T_ARRAY) {
                rb_raise(rb_ePGError, "second arg must contain some kind of arrays.");
            }
        }

        buffer = rb_str_new(0, RSTRING(table)->len + 17 + 1);
        /* starts query */
        snprintf(RSTRING(buffer)->ptr, RSTRING(buffer)->len, "copy %s from stdin ", StringValuePtr(table));

        result = PQexec(conn, StringValuePtr(buffer));
        if (!result){
            rb_raise(rb_ePGError, PQerrorMessage(conn));
        }
        PQclear(result);

        for (i = 0; i < RARRAY(values)->len; i++) {
            struct RArray *row = RARRAY(RARRAY(values)->ptr[i]);
            buffer = rb_tainted_str_new(0,0);
            for (j = 0; j < row->len; j++) {
                if (j > 0) rb_str_cat(buffer, "\t", 1);
                if (NIL_P(row->ptr[j])) {
                    rb_str_cat(buffer, "\\N",2);
                } else {
                    s = rb_obj_as_string(row->ptr[j]);
                    rb_funcall(s,pg_gsub_bang_id,2,pg_escape_regex,pg_escape_str);
                    rb_str_cat(buffer, StringValuePtr(s), RSTRING(s)->len);
                }
            }
            rb_str_cat(buffer, "\n\0", 2);
            /* sends data */
            PQputline(conn, StringValuePtr(buffer));
        }
        PQputline(conn, "\\.\n");
        res = PQendcopy(conn);

        return obj;
    }