Skip to main content

testlo/
testlo.rs

1/*!
2 * Test using large objects with libpq
3 *
4 * <https://github.com/postgres/postgres/blob/REL_16_0/src/test/examples/testlo.c>
5 */
6
7fn main() -> libpq::errors::Result {
8    let mut args = std::env::args();
9
10    if args.len() < 4 {
11        panic!(
12            "usage: {} database_name in_filename out_filename",
13            args.next().unwrap()
14        );
15    }
16
17    let database = args.nth(1).unwrap();
18    let in_filename = args.next().unwrap();
19    let out_filename = args.next().unwrap();
20
21    /*
22     * set up the connection
23     */
24    let conn = libpq::Connection::set_db(None, None, None, None, Some(&database))?;
25
26    /* Set always-secure search path, so malicious users can't take control. */
27    let res = conn.exec("SELECT pg_catalog.set_config('search_path', '', false)");
28    if res.status() != libpq::Status::TuplesOk {
29        panic!("SET failed: {:?}", conn.error_message());
30    }
31
32    conn.exec("begin");
33    println!("importing file \"{in_filename}\" ...");
34    let lobj_oid = libpq::lo::import(&conn, &in_filename);
35
36    println!("\tas large object {lobj_oid}.");
37
38    println!("picking out bytes 1000-2000 of the large object");
39    pickout(&conn, lobj_oid, 1_000, 1_000)?;
40
41    println!("overwriting bytes 1000-2000 of the large object with X's");
42    overwrite(&conn, lobj_oid, 1_000, 1_000)?;
43
44    println!("exporting large object to file \"{out_filename}\" ...");
45    libpq::lo::export(&conn, &out_filename, lobj_oid)?;
46
47    conn.exec("end");
48
49    Ok(())
50}
51
52fn pickout(
53    conn: &libpq::Connection,
54    lobj_id: libpq::Oid,
55    start: i32,
56    len: usize,
57) -> libpq::errors::Result {
58    let lobj = libpq::lo::open(conn, lobj_id, libpq::lo::Inv::READ)?;
59
60    lobj.lseek(start, libpq::lo::Seek::Set)?;
61
62    let mut nread = 0;
63
64    while len - nread > 0 {
65        let mut buf = lobj.read(len - nread)?;
66        let nbytes = buf.len();
67        buf.insert(nbytes, '\0');
68        eprint!(">>> {buf}");
69        nread += nbytes;
70        if nbytes == 0 {
71            break; /* no more data? */
72        }
73    }
74    eprintln!();
75
76    Ok(())
77}
78
79fn overwrite(
80    conn: &libpq::Connection,
81    lobj_id: libpq::Oid,
82    start: i32,
83    len: usize,
84) -> libpq::errors::Result {
85    let lobj = libpq::lo::open(conn, lobj_id, libpq::lo::Inv::WRITE)?;
86
87    lobj.lseek(start, libpq::lo::Seek::Set)?;
88    let mut buf = "X".repeat(len);
89    buf.insert(len - 1, '\0');
90
91    let mut nwritten = 0;
92    while len - nwritten > 0 {
93        let nbytes = lobj.write(&buf[nwritten..len - nwritten])?;
94        nwritten += nbytes;
95    }
96    eprintln!();
97
98    Ok(())
99}